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 |