| OLD | NEW |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 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 buildbot | 5 package buildbot |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "compress/gzip" | 9 "compress/gzip" |
| 10 "compress/zlib" | 10 "compress/zlib" |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 // Internal | 68 // Internal |
| 69 Internal bool | 69 Internal bool |
| 70 // Data is the json serialzed and gzipped blob of the master data. | 70 // Data is the json serialzed and gzipped blob of the master data. |
| 71 Data []byte `gae:",noindex"` | 71 Data []byte `gae:",noindex"` |
| 72 // Modified is when this entry was last modified. | 72 // Modified is when this entry was last modified. |
| 73 Modified time.Time | 73 Modified time.Time |
| 74 } | 74 } |
| 75 | 75 |
| 76 func putDSMasterJSON( | 76 func putDSMasterJSON( |
| 77 c context.Context, master *buildbotMaster, internal bool) error { | 77 c context.Context, master *buildbotMaster, internal bool) error { |
| 78 // Trim pending build states. These things are large and we can't reall
y | |
| 79 // store more than 25 of them. If this becomes an issue again, we'll ha
ve | |
| 80 // to trim out things from the pending build state such as the changed | |
| 81 // file list, commit comments, etc. | |
| 82 for _, builder := range master.Builders { | 78 for _, builder := range master.Builders { |
| 83 » » if len(builder.PendingBuildStates) > 25 { | 79 » » // Trim out extra info in the "Changes" portion of the pending b
uild state, |
| 84 » » » builder.PendingBuildStates = builder.PendingBuildStates[
0:25] | 80 » » // we don't actually need comments, files, and properties |
| 81 » » for _, pbs := range builder.PendingBuildStates { |
| 82 » » » for i := range pbs.Source.Changes { |
| 83 » » » » pbs.Source.Changes[i].Comments = "" |
| 84 » » » » pbs.Source.Changes[i].Files = nil |
| 85 » » » » pbs.Source.Changes[i].Properties = nil |
| 86 » » » } |
| 85 } | 87 } |
| 86 } | 88 } |
| 87 entry := buildbotMasterEntry{ | 89 entry := buildbotMasterEntry{ |
| 88 Name: master.Name, | 90 Name: master.Name, |
| 89 Internal: internal, | 91 Internal: internal, |
| 90 Modified: clock.Now(c).UTC(), | 92 Modified: clock.Now(c).UTC(), |
| 91 } | 93 } |
| 92 gzbs := bytes.Buffer{} | 94 gzbs := bytes.Buffer{} |
| 93 gsw := gzip.NewWriter(&gzbs) | 95 gsw := gzip.NewWriter(&gzbs) |
| 94 cw := iotools.CountingWriter{Writer: gsw} | 96 cw := iotools.CountingWriter{Writer: gsw} |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 230 builder, ok := master.Builders[b.Buildername] | 232 builder, ok := master.Builders[b.Buildername] |
| 231 if !ok { | 233 if !ok { |
| 232 // Mark this build due to builder being removed. | 234 // Mark this build due to builder being removed. |
| 233 logging.Infof(c, "Expiring %s/%s/%d due to builder being
removed", | 235 logging.Infof(c, "Expiring %s/%s/%d due to builder being
removed", |
| 234 master.Name, b.Buildername, b.Number) | 236 master.Name, b.Buildername, b.Number) |
| 235 err = expireBuild(c, b) | 237 err = expireBuild(c, b) |
| 236 if err != nil { | 238 if err != nil { |
| 237 logging.WithError(err).Errorf(c, "Could not expi
re build") | 239 logging.WithError(err).Errorf(c, "Could not expi
re build") |
| 238 return 500 | 240 return 500 |
| 239 } | 241 } |
| 242 continue |
| 240 } | 243 } |
| 241 | 244 |
| 242 found := false | 245 found := false |
| 243 for _, bnum := range builder.CurrentBuilds { | 246 for _, bnum := range builder.CurrentBuilds { |
| 244 if b.Number == bnum { | 247 if b.Number == bnum { |
| 245 found = true | 248 found = true |
| 246 break | 249 break |
| 247 } | 250 } |
| 248 } | 251 } |
| 249 if !found { | 252 if !found { |
| 250 // Mark this build due to build not current anymore. | 253 // Mark this build due to build not current anymore. |
| 251 logging.Infof(c, "Expiring %s/%s/%d due to build not cur
rent", | 254 logging.Infof(c, "Expiring %s/%s/%d due to build not cur
rent", |
| 252 master.Name, b.Buildername, b.Number) | 255 master.Name, b.Buildername, b.Number) |
| 253 err = expireBuild(c, b) | 256 err = expireBuild(c, b) |
| 254 if err != nil { | 257 if err != nil { |
| 255 logging.WithError(err).Errorf(c, "Could not expi
re build") | 258 logging.WithError(err).Errorf(c, "Could not expi
re build") |
| 256 return 500 | 259 return 500 |
| 257 } | 260 } |
| 258 } | 261 } |
| 259 } | 262 } |
| 260 return 0 | 263 return 0 |
| 261 } | 264 } |
| 262 | 265 |
| 263 // PubSubHandler is a webhook that stores the builds coming in from pubsub. | 266 // PubSubHandler is a webhook that stores the builds coming in from pubsub. |
| 264 func PubSubHandler(ctx *router.Context) { | 267 func PubSubHandler(ctx *router.Context) { |
| 265 c, h, r := ctx.Context, ctx.Writer, ctx.Request | 268 c, h, r := ctx.Context, ctx.Writer, ctx.Request |
| 266 | 269 |
| 267 msg := pubSubSubscription{} | 270 msg := pubSubSubscription{} |
| 268 defer r.Body.Close() | 271 defer r.Body.Close() |
| 272 logging.Infof(c, "Message is %d bytes long", r.ContentLength) |
| 269 dec := json.NewDecoder(r.Body) | 273 dec := json.NewDecoder(r.Body) |
| 270 if err := dec.Decode(&msg); err != nil { | 274 if err := dec.Decode(&msg); err != nil { |
| 271 logging.WithError(err).Errorf( | 275 logging.WithError(err).Errorf( |
| 272 c, "Could not decode message. %s", err) | 276 c, "Could not decode message. %s", err) |
| 273 h.WriteHeader(200) // This is a hard failure, we don't want PubS
ub to retry. | 277 h.WriteHeader(200) // This is a hard failure, we don't want PubS
ub to retry. |
| 274 return | 278 return |
| 275 } | 279 } |
| 276 internal := true | 280 internal := true |
| 277 switch msg.Subscription { | 281 switch msg.Subscription { |
| 278 case publicSubName: | 282 case publicSubName: |
| (...skipping 22 matching lines...) Expand all Loading... |
| 301 logging.Infof(c, "There are %d builds", len(builds)) | 305 logging.Infof(c, "There are %d builds", len(builds)) |
| 302 if master != nil { | 306 if master != nil { |
| 303 logging.Infof(c, "The master name is %s", master.Name) | 307 logging.Infof(c, "The master name is %s", master.Name) |
| 304 } else { | 308 } else { |
| 305 logging.Infof(c, "No master in this message") | 309 logging.Infof(c, "No master in this message") |
| 306 } | 310 } |
| 307 // This is used to cache the master used for extracting OS information. | 311 // This is used to cache the master used for extracting OS information. |
| 308 cachedMaster := buildbotMaster{} | 312 cachedMaster := buildbotMaster{} |
| 309 // Do not use PutMulti because we might hit the 1MB limit. | 313 // Do not use PutMulti because we might hit the 1MB limit. |
| 310 for _, build := range builds { | 314 for _, build := range builds { |
| 311 logging.Debugf( | |
| 312 c, "Checking for build %s/%s/%d", build.Master, build.Bu
ildername, build.Number) | |
| 313 if build.Master == "" { | 315 if build.Master == "" { |
| 314 logging.Errorf(c, "Invalid message, missing master name"
) | 316 logging.Errorf(c, "Invalid message, missing master name"
) |
| 315 h.WriteHeader(200) | 317 h.WriteHeader(200) |
| 316 return | 318 return |
| 317 } | 319 } |
| 318 existingBuild := &buildbotBuild{ | 320 existingBuild := &buildbotBuild{ |
| 319 Master: build.Master, | 321 Master: build.Master, |
| 320 Buildername: build.Buildername, | 322 Buildername: build.Buildername, |
| 321 Number: build.Number, | 323 Number: build.Number, |
| 322 } | 324 } |
| 323 buildExists := false | 325 buildExists := false |
| 324 if err := ds.Get(c, existingBuild); err == nil { | 326 if err := ds.Get(c, existingBuild); err == nil { |
| 325 if existingBuild.Finished { | 327 if existingBuild.Finished { |
| 326 // Never replace a completed build. | 328 // Never replace a completed build. |
| 327 buildCounter.Add( | 329 buildCounter.Add( |
| 328 c, 1, false, build.Master, build.Builder
name, false, "Rejected") | 330 c, 1, false, build.Master, build.Builder
name, false, "Rejected") |
| 329 logging.Debugf( | |
| 330 c, "Found build %s/%s/%d and it's finish
ed, skipping", build.Master, build.Buildername, build.Number) | |
| 331 continue | 331 continue |
| 332 } | 332 } |
| 333 buildExists = true | 333 buildExists = true |
| 334 } | 334 } |
| 335 // Also set the finished and internal bit. | 335 // Also set the finished and internal bit. |
| 336 build.Finished = false | 336 build.Finished = false |
| 337 if len(build.Times) == 2 && build.Times[1] != nil { | 337 if len(build.Times) == 2 && build.Times[1] != nil { |
| 338 build.Finished = true | 338 build.Finished = true |
| 339 } | 339 } |
| 340 build.Internal = internal | 340 build.Internal = internal |
| 341 // Try to get the OS information on a best-effort basis. This a
ssumes that all | 341 // Try to get the OS information on a best-effort basis. This a
ssumes that all |
| 342 // builds come from one master. | 342 // builds come from one master. |
| 343 build.OSFamily, build.OSVersion = getOSInfo(c, build, &cachedMas
ter) | 343 build.OSFamily, build.OSVersion = getOSInfo(c, build, &cachedMas
ter) |
| 344 err = ds.Put(c, build) | 344 err = ds.Put(c, build) |
| 345 if err != nil { | 345 if err != nil { |
| 346 if _, ok := err.(errTooBig); ok { | 346 if _, ok := err.(errTooBig); ok { |
| 347 // This will never work, we don't want PubSub to
retry. | 347 // This will never work, we don't want PubSub to
retry. |
| 348 logging.WithError(err).Errorf( | 348 logging.WithError(err).Errorf( |
| 349 c, "Could not save build to datastore, f
ailing permanently") | 349 c, "Could not save build to datastore, f
ailing permanently") |
| 350 h.WriteHeader(200) | 350 h.WriteHeader(200) |
| 351 } else { | 351 } else { |
| 352 // This is transient, we do want PubSub to retry
. | 352 // This is transient, we do want PubSub to retry
. |
| 353 logging.WithError(err).Errorf(c, "Could not save
build in datastore") | 353 logging.WithError(err).Errorf(c, "Could not save
build in datastore") |
| 354 h.WriteHeader(500) | 354 h.WriteHeader(500) |
| 355 } | 355 } |
| 356 return | 356 return |
| 357 } | 357 } |
| 358 logging.Debugf( | |
| 359 c, "Saved build %s/%s/%d, it is %s", | |
| 360 build.Master, build.Buildername, build.Number, build.Fin
ished) | |
| 361 if buildExists { | 358 if buildExists { |
| 362 buildCounter.Add( | 359 buildCounter.Add( |
| 363 c, 1, false, build.Master, build.Buildername, bu
ild.Finished, "Replaced") | 360 c, 1, false, build.Master, build.Buildername, bu
ild.Finished, "Replaced") |
| 364 } else { | 361 } else { |
| 365 buildCounter.Add( | 362 buildCounter.Add( |
| 366 c, 1, false, build.Master, build.Buildername, bu
ild.Finished, "New") | 363 c, 1, false, build.Master, build.Buildername, bu
ild.Finished, "New") |
| 367 } | 364 } |
| 368 | 365 |
| 369 } | 366 } |
| 370 if master != nil { | 367 if master != nil { |
| 371 code := doMaster(c, master, internal) | 368 code := doMaster(c, master, internal) |
| 372 if code != 0 { | 369 if code != 0 { |
| 373 h.WriteHeader(code) | 370 h.WriteHeader(code) |
| 374 return | 371 return |
| 375 } | 372 } |
| 376 } | 373 } |
| 377 h.WriteHeader(200) | 374 h.WriteHeader(200) |
| 378 } | 375 } |
| OLD | NEW |