Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | 1 // Copyright 2015 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
| 4 | 4 |
| 5 package swarming | 5 package swarming |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "encoding/json" | 9 "encoding/json" |
| 10 "fmt" | 10 "fmt" |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 107 *swarming.SwarmingRpcsTaskResult, error) { | 107 *swarming.SwarmingRpcsTaskResult, error) { |
| 108 | 108 |
| 109 trc := sc.Task.Result(taskID) | 109 trc := sc.Task.Result(taskID) |
| 110 srtr, err := trc.Do() | 110 srtr, err := trc.Do() |
| 111 if err != nil { | 111 if err != nil { |
| 112 return nil, err | 112 return nil, err |
| 113 } | 113 } |
| 114 return srtr, nil | 114 return srtr, nil |
| 115 } | 115 } |
| 116 | 116 |
| 117 // getSwarming fetches both the swarming task data and log data, and returns | |
| 118 // the task result, the log string, task error, and log error. | |
| 117 func getSwarming(c context.Context, server string, taskID string) ( | 119 func getSwarming(c context.Context, server string, taskID string) ( |
| 118 » *swarming.SwarmingRpcsTaskResult, string, error) { | 120 » *swarming.SwarmingRpcsTaskResult, string, error, error) { |
| 119 | 121 |
| 120 var log string | 122 var log string |
| 121 var sr *swarming.SwarmingRpcsTaskResult | 123 var sr *swarming.SwarmingRpcsTaskResult |
| 122 var errLog, errRes error | 124 var errLog, errRes error |
| 123 | 125 |
| 124 // Detour: Return debugging results, useful for development. | 126 // Detour: Return debugging results, useful for development. |
| 125 if server == "debug" { | 127 if server == "debug" { |
| 126 sr, errRes = getDebugSwarmingResult(taskID) | 128 sr, errRes = getDebugSwarmingResult(taskID) |
| 127 log, errLog = getDebugTaskOutput(taskID) | 129 log, errLog = getDebugTaskOutput(taskID) |
| 128 » » if errLog != nil { | 130 » » return sr, log, errRes, errLog |
| 129 » » » return sr, log, errLog | |
| 130 » » } | |
| 131 » » return sr, log, errRes | |
| 132 } | 131 } |
| 133 | 132 |
| 134 sc, err := getSwarmingClient(c, server) | 133 sc, err := getSwarmingClient(c, server) |
| 135 if err != nil { | 134 if err != nil { |
| 136 » » return nil, "", err | 135 » » return nil, "", err, nil |
| 137 } | 136 } |
| 138 | 137 |
| 139 var wg sync.WaitGroup | 138 var wg sync.WaitGroup |
| 140 wg.Add(2) // Getting log and result can happen concurrently. Wait for b oth. | 139 wg.Add(2) // Getting log and result can happen concurrently. Wait for b oth. |
| 141 | 140 |
| 142 go func() { | 141 go func() { |
| 143 defer wg.Done() | 142 defer wg.Done() |
| 144 log, errLog = getTaskOutput(sc, taskID) | 143 log, errLog = getTaskOutput(sc, taskID) |
| 145 }() | 144 }() |
| 146 go func() { | 145 go func() { |
| 147 defer wg.Done() | 146 defer wg.Done() |
| 148 sr, errRes = getSwarmingResult(sc, taskID) | 147 sr, errRes = getSwarmingResult(sc, taskID) |
| 149 }() | 148 }() |
| 150 wg.Wait() | 149 wg.Wait() |
| 151 » if errRes != nil { | 150 » return sr, log, errRes, errLog |
| 152 » » return sr, log, errRes | |
| 153 » } | |
| 154 » return sr, log, errLog | |
| 155 } | 151 } |
| 156 | 152 |
| 157 func taskProperties(sr *swarming.SwarmingRpcsTaskResult) *resp.PropertyGroup { | 153 func taskProperties(sr *swarming.SwarmingRpcsTaskResult) *resp.PropertyGroup { |
| 158 props := &resp.PropertyGroup{GroupName: "Swarming"} | 154 props := &resp.PropertyGroup{GroupName: "Swarming"} |
| 159 if len(sr.CostsUsd) == 1 { | 155 if len(sr.CostsUsd) == 1 { |
| 160 props.Property = append(props.Property, &resp.Property{ | 156 props.Property = append(props.Property, &resp.Property{ |
| 161 Key: "Cost of job (USD)", | 157 Key: "Cost of job (USD)", |
| 162 Value: fmt.Sprintf("$%.2f", sr.CostsUsd[0]), | 158 Value: fmt.Sprintf("$%.2f", sr.CostsUsd[0]), |
| 163 }) | 159 }) |
| 164 } | 160 } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 285 // goroutine safe | 281 // goroutine safe |
| 286 if err := p.RunStreams([]*annotee.Stream{&is}); err != nil { | 282 if err := p.RunStreams([]*annotee.Stream{&is}); err != nil { |
| 287 return nil, err | 283 return nil, err |
| 288 } | 284 } |
| 289 p.Finish() | 285 p.Finish() |
| 290 return c.ToLogDogStreams() | 286 return c.ToLogDogStreams() |
| 291 } | 287 } |
| 292 | 288 |
| 293 func swarmingBuildImpl(c context.Context, URL string, server string, taskID stri ng) (*resp.MiloBuild, error) { | 289 func swarmingBuildImpl(c context.Context, URL string, server string, taskID stri ng) (*resp.MiloBuild, error) { |
| 294 // Fetch the data from Swarming | 290 // Fetch the data from Swarming |
| 295 » sr, body, err := getSwarming(c, server, taskID) | 291 » sr, body, errRes, errLog := getSwarming(c, server, taskID) |
| 296 » if err != nil { | 292 » // Swarming result must come back. |
| 297 » » return nil, err | 293 » if errRes != nil { |
| 294 » » return nil, errRes | |
| 295 » } | |
| 296 » switch sr.State { | |
| 297 » case TaskCompleted, TaskRunning, TaskCanceled: | |
| 298 » » if errLog != nil { | |
| 299 » » » // If the task is completed, running, or canceled, we'd expect a log. | |
| 300 » » » // If not, we don't necessarily expect the log to come b ack. | |
|
nodir
2016/06/28 20:36:49
I think getSwarming is a better place for this log
| |
| 301 » » » return nil, errLog | |
| 302 » » } | |
| 298 } | 303 } |
| 299 | 304 |
| 300 allowMilo := false | 305 allowMilo := false |
| 301 for _, t := range sr.Tags { | 306 for _, t := range sr.Tags { |
| 302 if t == "allow_milo:1" { | 307 if t == "allow_milo:1" { |
| 303 allowMilo = true | 308 allowMilo = true |
| 304 break | 309 break |
| 305 } | 310 } |
| 306 } | 311 } |
| 307 if !allowMilo { | 312 if !allowMilo { |
| 308 return nil, fmt.Errorf("Not A Milo Job") | 313 return nil, fmt.Errorf("Not A Milo Job") |
| 309 } | 314 } |
| 310 | 315 |
| 311 build, err := taskToBuild(c, server, sr) | 316 build, err := taskToBuild(c, server, sr) |
| 312 if err != nil { | 317 if err != nil { |
| 313 return nil, err | 318 return nil, err |
| 314 } | 319 } |
| 315 | 320 |
| 316 // Decode the data using annotee. The logdog stream returned here is ass umed | 321 // Decode the data using annotee. The logdog stream returned here is ass umed |
| 317 // to be consistent, which is why the following block of code are not | 322 // to be consistent, which is why the following block of code are not |
| 318 // expected to ever err out. | 323 // expected to ever err out. |
| 319 » lds, err := streamsFromAnnotatedLog(c, body) | 324 » if errLog != nil && body != "" { |
| 320 » if err != nil { | 325 » » lds, err := streamsFromAnnotatedLog(c, body) |
| 321 » » build.Components = []*resp.BuildComponent{{ | 326 » » if err != nil { |
| 322 » » » Type: resp.Summary, | 327 » » » build.Components = []*resp.BuildComponent{{ |
| 323 » » » Label: "Milo annotation parser", | 328 » » » » Type: resp.Summary, |
| 324 » » » Text: []string{err.Error()}, | 329 » » » » Label: "Milo annotation parser", |
| 325 » » » Status: resp.InfraFailure, | 330 » » » » Text: []string{err.Error()}, |
| 326 » » » SubLink: []*resp.Link{{ | 331 » » » » Status: resp.InfraFailure, |
| 327 » » » » Label: "swarming task", | 332 » » » » SubLink: []*resp.Link{{ |
| 328 » » » » URL: taskPageURL(server, taskID), | 333 » » » » » Label: "swarming task", |
| 329 » » » }}, | 334 » » » » » URL: taskPageURL(server, taskID), |
| 330 » » }} | 335 » » » » }}, |
| 331 » } else { | 336 » » » }} |
| 332 » » logdog.AddLogDogToBuild(c, URL, lds, build) | 337 » » } else { |
| 338 » » » logdog.AddLogDogToBuild(c, URL, lds, build) | |
| 339 » » } | |
| 333 } | 340 } |
| 334 | 341 |
| 335 return build, nil | 342 return build, nil |
| 336 } | 343 } |
| 337 | 344 |
| 338 // taskPageURL returns a URL to a human-consumable page of a swarming task. | 345 // taskPageURL returns a URL to a human-consumable page of a swarming task. |
| 339 // Supports server aliases. | 346 // Supports server aliases. |
| 340 func taskPageURL(swarmingHostname, taskID string) string { | 347 func taskPageURL(swarmingHostname, taskID string) string { |
| 341 return fmt.Sprintf("https://%s/user/task/%s", resolveServer(swarmingHost name), taskID) | 348 return fmt.Sprintf("https://%s/user/task/%s", resolveServer(swarmingHost name), taskID) |
| 342 } | 349 } |
| 343 | 350 |
| 344 // botPageURL returns a URL to a human-consumable page of a swarming bot. | 351 // botPageURL returns a URL to a human-consumable page of a swarming bot. |
| 345 // Supports server aliases. | 352 // Supports server aliases. |
| 346 func botPageURL(swarmingHostname, botID string) string { | 353 func botPageURL(swarmingHostname, botID string) string { |
| 347 return fmt.Sprintf("https://%s/restricted/bot/%s", resolveServer(swarmin gHostname), botID) | 354 return fmt.Sprintf("https://%s/restricted/bot/%s", resolveServer(swarmin gHostname), botID) |
| 348 } | 355 } |
| OLD | NEW |