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 deps | 5 package deps |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "errors" | |
| 9 "fmt" | 8 "fmt" |
| 10 | 9 |
| 11 "golang.org/x/net/context" | 10 "golang.org/x/net/context" |
| 12 "google.golang.org/grpc/codes" | 11 "google.golang.org/grpc/codes" |
| 13 | 12 |
| 14 "github.com/luci/gae/service/datastore" | 13 "github.com/luci/gae/service/datastore" |
| 15 | 14 |
| 16 "github.com/luci/luci-go/common/grpcutil" | 15 "github.com/luci/luci-go/common/grpcutil" |
| 17 "github.com/luci/luci-go/common/logging" | 16 "github.com/luci/luci-go/common/logging" |
| 18 "github.com/luci/luci-go/common/parallel" | 17 "github.com/luci/luci-go/common/parallel" |
| 19 "github.com/luci/luci-go/common/stringset" | 18 "github.com/luci/luci-go/common/stringset" |
| 20 | 19 |
| 21 » "github.com/luci/luci-go/common/api/dm/service/v1" | 20 » dm "github.com/luci/luci-go/common/api/dm/service/v1" |
| 22 "github.com/luci/luci-go/common/api/dm/template" | 21 "github.com/luci/luci-go/common/api/dm/template" |
| 23 | 22 |
| 24 "github.com/luci/luci-go/appengine/tumble" | 23 "github.com/luci/luci-go/appengine/tumble" |
| 25 | 24 |
| 25 "github.com/luci/luci-go/appengine/cmd/dm/distributor" | |
| 26 "github.com/luci/luci-go/appengine/cmd/dm/model" | 26 "github.com/luci/luci-go/appengine/cmd/dm/model" |
| 27 "github.com/luci/luci-go/appengine/cmd/dm/mutate" | 27 "github.com/luci/luci-go/appengine/cmd/dm/mutate" |
| 28 ) | 28 ) |
| 29 | 29 |
| 30 func (d *deps) runEnsureGraphDepsWalk(c context.Context, req *dm.EnsureGraphData Req, newAttempts *dm.AttemptList) (*dm.GraphData, error) { | 30 func (d *deps) runEnsureGraphDepsWalk(c context.Context, req *dm.EnsureGraphData Req, newAttempts *dm.AttemptList) (*dm.GraphData, error) { |
| 31 // first lets run a query to load all of the proposed attempts. | 31 // first lets run a query to load all of the proposed attempts. |
| 32 wgreq := &dm.WalkGraphReq{ | 32 wgreq := &dm.WalkGraphReq{ |
| 33 Query: dm.AttemptListQuery(newAttempts), | 33 Query: dm.AttemptListQuery(newAttempts), |
| 34 Limit: &dm.WalkGraphReq_Limit{ | 34 Limit: &dm.WalkGraphReq_Limit{ |
| 35 MaxDepth: 1, | 35 MaxDepth: 1, |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 214 } | 214 } |
| 215 | 215 |
| 216 // not all of the attemps exist/are finished, we have to block. | 216 // not all of the attemps exist/are finished, we have to block. |
| 217 rsp.Result = nil | 217 rsp.Result = nil |
| 218 rsp.ShouldHalt = true | 218 rsp.ShouldHalt = true |
| 219 | 219 |
| 220 return tumbleNow(c, &mutate.AddDeps{ | 220 return tumbleNow(c, &mutate.AddDeps{ |
| 221 Auth: req.ForExecution, | 221 Auth: req.ForExecution, |
| 222 Quests: newQuests, | 222 Quests: newQuests, |
| 223 // Attempts we think are missing | 223 // Attempts we think are missing |
| 224 » » Atmpts: newAttempts, | 224 » » Attempts: newAttempts, |
| 225 // Deps we think are missing (>= newAttempts) | 225 // Deps we think are missing (>= newAttempts) |
| 226 Deps: missingDeps, | 226 Deps: missingDeps, |
| 227 }) | 227 }) |
| 228 } | 228 } |
| 229 | 229 |
| 230 type templateFileKey struct { | 230 type templateFileKey struct { |
| 231 project, ref string | 231 project, ref string |
| 232 } | 232 } |
| 233 | 233 |
| 234 type templateFile struct { | 234 type templateFile struct { |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 261 if err == nil { | 261 if err == nil { |
| 262 return false | 262 return false |
| 263 } | 263 } |
| 264 if rsp.TemplateError == nil { | 264 if rsp.TemplateError == nil { |
| 265 rsp.TemplateError = make([]string, len(req.TemplateQuest )) | 265 rsp.TemplateError = make([]string, len(req.TemplateQuest )) |
| 266 } | 266 } |
| 267 rsp.TemplateError[i] = err.Error() | 267 rsp.TemplateError[i] = err.Error() |
| 268 return true | 268 return true |
| 269 } | 269 } |
| 270 | 270 |
| 271 dists := map[string]distributor.D{} | |
| 272 | |
| 271 newQuests = make(map[string]*model.Quest, len(req.Quest)+len(req.Templat eQuest)) | 273 newQuests = make(map[string]*model.Quest, len(req.Quest)+len(req.Templat eQuest)) |
| 272 newAttempts = dm.NewAttemptList(nil) | 274 newAttempts = dm.NewAttemptList(nil) |
| 273 | 275 |
| 276 reg := distributor.GetRegistry(c) | |
| 277 | |
| 274 // render all quest descriptions | 278 // render all quest descriptions |
| 275 for i, qDesc := range req.Quest { | 279 for i, qDesc := range req.Quest { |
| 276 » » var q *model.Quest | 280 » » q := model.NewQuest(c, qDesc) |
| 277 » » if q, err = model.NewQuest(c, qDesc); err != nil { | 281 |
| 278 » » » err = grpcutil.MaybeLogErr(c, err, codes.InvalidArgument , "bad quest description") | 282 » » d, ok := dists[qDesc.DistributorConfigName] |
| 283 » » if !ok { | |
| 284 » » » if d, _, err = reg.MakeDistributor(c, qDesc.DistributorC onfigName); err != nil { | |
| 285 » » » » return | |
| 286 » » » } | |
| 287 » » » dists[qDesc.DistributorConfigName] = d | |
| 288 » » } | |
| 289 | |
| 290 » » if err = d.Validate(qDesc.JsonPayload); err != nil { | |
| 291 » » » err = grpcutil.MaybeLogErr(c, err, codes.InvalidArgument , | |
| 292 » » » » "JSON payload is invalid for this distributor co nfiguration.") | |
| 279 return | 293 return |
| 280 } | 294 } |
| 281 | 295 |
| 282 // all provided quest descriptions MUST include at least one att empt | 296 // all provided quest descriptions MUST include at least one att empt |
| 283 if _, ok := req.Attempts.To[q.ID]; !ok { | 297 if _, ok := req.Attempts.To[q.ID]; !ok { |
| 284 c = logging.SetFields(c, logging.Fields{"id": q.ID, "idx ": i}) | 298 c = logging.SetFields(c, logging.Fields{"id": q.ID, "idx ": i}) |
| 285 err = grpcutil.MaybeLogErr(c, | 299 err = grpcutil.MaybeLogErr(c, |
| 286 » » » » errors.New("Quest entries must have a matching A ttempts entry"), | 300 » » » » fmt.Errorf("Quest %d:%q must have a matching Att empts entry", i, q.ID), |
|
dnj (Google)
2016/06/09 18:00:54
Maybe use annotated error?
iannucci
2016/06/15 00:45:58
I will do so in a followup for sure!
| |
| 287 codes.InvalidArgument, "no matches") | 301 codes.InvalidArgument, "no matches") |
| 288 return | 302 return |
| 289 } | 303 } |
| 290 | 304 |
| 291 if _, ok := newQuests[q.ID]; !ok { | 305 if _, ok := newQuests[q.ID]; !ok { |
| 292 newQuests[q.ID] = q | 306 newQuests[q.ID] = q |
| 293 } | 307 } |
| 294 } | 308 } |
| 295 | 309 |
| 296 // copy all normal attempt descriptions | 310 // copy all normal attempt descriptions |
| 297 for qid, nums := range req.Attempts.To { | 311 for qid, nums := range req.Attempts.To { |
| 298 newNums := &dm.AttemptList_Nums{Nums: make([]uint32, len(nums.Nu ms))} | 312 newNums := &dm.AttemptList_Nums{Nums: make([]uint32, len(nums.Nu ms))} |
| 299 copy(newNums.Nums, nums.Nums) | 313 copy(newNums.Nums, nums.Nums) |
| 300 newAttempts.To[qid] = newNums | 314 newAttempts.To[qid] = newNums |
| 301 } | 315 } |
| 302 | 316 |
| 303 // render all templates and template attempts into newQuests | 317 // render all templates and template attempts into newQuests |
| 304 templateFiles := templateFileCache{} | 318 templateFiles := templateFileCache{} |
| 305 for i := 0; i < len(req.TemplateQuest); i++ { | 319 for i := 0; i < len(req.TemplateQuest); i++ { |
| 306 inst := req.TemplateQuest[i] | 320 inst := req.TemplateQuest[i] |
| 307 | 321 |
| 308 var vers string | 322 var vers string |
| 309 var desc *dm.Quest_Desc | 323 var desc *dm.Quest_Desc |
| 310 if desc, vers, err = templateFiles.render(c, inst); setTemplateE rr(i, err) { | 324 if desc, vers, err = templateFiles.render(c, inst); setTemplateE rr(i, err) { |
| 311 continue | 325 continue |
| 312 } | 326 } |
| 313 | 327 » » if setTemplateErr(i, desc.Normalize()) { |
| 314 » » var q *model.Quest | |
| 315 » » q, err = model.NewQuest(c, desc) | |
| 316 » » if setTemplateErr(i, err) { | |
| 317 continue | 328 continue |
| 318 } | 329 } |
| 319 | 330 |
| 331 q := model.NewQuest(c, desc) | |
| 332 | |
| 320 rsp.TemplateIds = append(rsp.TemplateIds, dm.NewQuestID(q.ID)) | 333 rsp.TemplateIds = append(rsp.TemplateIds, dm.NewQuestID(q.ID)) |
| 321 | 334 |
| 322 // if we have any errors going on, might as well skip the rest | 335 // if we have any errors going on, might as well skip the rest |
| 323 if len(rsp.TemplateError) > 0 { | 336 if len(rsp.TemplateError) > 0 { |
| 324 continue | 337 continue |
| 325 } | 338 } |
| 326 | 339 |
| 327 anums := newAttempts.To[q.ID] | 340 anums := newAttempts.To[q.ID] |
| 328 anums.Nums = append(anums.Nums, req.TemplateAttempt[i].Nums...) | 341 anums.Nums = append(anums.Nums, req.TemplateAttempt[i].Nums...) |
| 329 if err := anums.Normalize(); err != nil { | 342 if err := anums.Normalize(); err != nil { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 340 Project: inst.Project, Ref: inst.Ref, Version: vers, | 353 Project: inst.Project, Ref: inst.Ref, Version: vers, |
| 341 Name: inst.Specifier.TemplateName}) | 354 Name: inst.Specifier.TemplateName}) |
| 342 } | 355 } |
| 343 | 356 |
| 344 return | 357 return |
| 345 } | 358 } |
| 346 | 359 |
| 347 func (d *deps) EnsureGraphData(c context.Context, req *dm.EnsureGraphDataReq) (r sp *dm.EnsureGraphDataRsp, err error) { | 360 func (d *deps) EnsureGraphData(c context.Context, req *dm.EnsureGraphDataReq) (r sp *dm.EnsureGraphDataRsp, err error) { |
| 348 // TODO(riannucci): real non-execution authentication | 361 // TODO(riannucci): real non-execution authentication |
| 349 if req.ForExecution != nil { | 362 if req.ForExecution != nil { |
| 363 logging.Fields{"execution": req.ForExecution.Id}.Infof(c, "on be half of") | |
| 350 _, _, err := model.AuthenticateExecution(c, req.ForExecution) | 364 _, _, err := model.AuthenticateExecution(c, req.ForExecution) |
| 351 if err != nil { | 365 if err != nil { |
| 352 return nil, grpcutil.MaybeLogErr(c, err, codes.Unauthent icated, "bad execution auth") | 366 return nil, grpcutil.MaybeLogErr(c, err, codes.Unauthent icated, "bad execution auth") |
| 353 } | 367 } |
| 354 } | 368 } |
| 355 | 369 |
| 356 // render any quest descirptions, templates and template attempts into | 370 // render any quest descirptions, templates and template attempts into |
| 357 // a single merged set of new quests and new attempts | 371 // a single merged set of new quests and new attempts |
| 358 rsp, newQuests, newAttempts, err := renderRequest(c, req) | 372 rsp, newQuests, newAttempts, err := renderRequest(c, req) |
| 359 if err != nil || len(rsp.TemplateError) > 0 { | 373 if err != nil || len(rsp.TemplateError) > 0 { |
| 360 return | 374 return |
| 361 } | 375 } |
| 362 | 376 |
| 363 newQuestList := make([]*model.Quest, 0, len(newQuests)) | 377 newQuestList := make([]*model.Quest, 0, len(newQuests)) |
| 364 for _, q := range newQuests { | 378 for _, q := range newQuests { |
| 365 newQuestList = append(newQuestList, q) | 379 newQuestList = append(newQuestList, q) |
| 366 } | 380 } |
| 367 | 381 |
| 368 err = d.ensureGraphData(c, req, newQuestList, newAttempts, rsp) | 382 err = d.ensureGraphData(c, req, newQuestList, newAttempts, rsp) |
| 369 | 383 |
| 370 return | 384 return |
| 371 } | 385 } |
| OLD | NEW |