Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: milo/buildsource/buildbot/pubsub.go

Issue 2968333003: Milo: Create build summaries for buildbot in the pubsub pipeline (Closed)
Patch Set: fix Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « milo/buildsource/buildbot/build.go ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The LUCI Authors. 1 // Copyright 2016 The LUCI Authors.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 package buildbot 15 package buildbot
16 16
17 import ( 17 import (
18 "bytes" 18 "bytes"
19 "compress/gzip" 19 "compress/gzip"
20 "compress/zlib" 20 "compress/zlib"
21 "encoding/json" 21 "encoding/json"
22 "fmt" 22 "fmt"
23 "net/http" 23 "net/http"
24 "strings" 24 "strings"
25 "time" 25 "time"
26 26
27 » ds "github.com/luci/gae/service/datastore" 27 » "github.com/luci/gae/service/datastore"
28 "github.com/luci/luci-go/common/clock" 28 "github.com/luci/luci-go/common/clock"
29 "github.com/luci/luci-go/common/iotools" 29 "github.com/luci/luci-go/common/iotools"
30 "github.com/luci/luci-go/common/logging" 30 "github.com/luci/luci-go/common/logging"
31 "github.com/luci/luci-go/milo/common" 31 "github.com/luci/luci-go/milo/common"
32 "github.com/luci/luci-go/milo/common/model"
32 "github.com/luci/luci-go/server/router" 33 "github.com/luci/luci-go/server/router"
33 34
34 "golang.org/x/net/context" 35 "golang.org/x/net/context"
35 36
36 "github.com/luci/luci-go/common/tsmon/field" 37 "github.com/luci/luci-go/common/tsmon/field"
37 "github.com/luci/luci-go/common/tsmon/metric" 38 "github.com/luci/luci-go/common/tsmon/metric"
38 ) 39 )
39 40
40 var ( 41 var (
41 // Metrics 42 // Metrics
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 entry := buildbotMasterEntry{ 101 entry := buildbotMasterEntry{
101 Name: master.Name, 102 Name: master.Name,
102 Internal: internal, 103 Internal: internal,
103 Modified: clock.Now(c).UTC(), 104 Modified: clock.Now(c).UTC(),
104 } 105 }
105 toPut := []interface{}{&entry} 106 toPut := []interface{}{&entry}
106 publicTag := &buildbotMasterPublic{master.Name} 107 publicTag := &buildbotMasterPublic{master.Name}
107 if internal { 108 if internal {
108 // do the deletion immediately so that the 'public' bit is remov ed from 109 // do the deletion immediately so that the 'public' bit is remov ed from
109 // datastore before any internal details are actually written to datastore. 110 // datastore before any internal details are actually written to datastore.
110 » » if err := ds.Delete(c, publicTag); err != nil && err != ds.ErrNo SuchEntity { 111 » » if err := datastore.Delete(c, publicTag); err != nil && err != d atastore.ErrNoSuchEntity {
111 return err 112 return err
112 } 113 }
113 } else { 114 } else {
114 toPut = append(toPut, publicTag) 115 toPut = append(toPut, publicTag)
115 } 116 }
116 gzbs := bytes.Buffer{} 117 gzbs := bytes.Buffer{}
117 gsw := gzip.NewWriter(&gzbs) 118 gsw := gzip.NewWriter(&gzbs)
118 cw := iotools.CountingWriter{Writer: gsw} 119 cw := iotools.CountingWriter{Writer: gsw}
119 e := json.NewEncoder(&cw) 120 e := json.NewEncoder(&cw)
120 if err := e.Encode(master); err != nil { 121 if err := e.Encode(master); err != nil {
121 return err 122 return err
122 } 123 }
123 gsw.Close() 124 gsw.Close()
124 entry.Data = gzbs.Bytes() 125 entry.Data = gzbs.Bytes()
125 logging.Debugf(c, "Length of json data: %d", cw.Count) 126 logging.Debugf(c, "Length of json data: %d", cw.Count)
126 logging.Debugf(c, "Length of gzipped data: %d", len(entry.Data)) 127 logging.Debugf(c, "Length of gzipped data: %d", len(entry.Data))
127 » return ds.Put(c, toPut) 128 » return datastore.Put(c, toPut)
128 } 129 }
129 130
130 // unmarshal a gzipped byte stream into a list of buildbot builds and masters. 131 // unmarshal a gzipped byte stream into a list of buildbot builds and masters.
131 func unmarshal( 132 func unmarshal(
132 c context.Context, msg []byte) ([]*buildbotBuild, *buildbotMaster, error ) { 133 c context.Context, msg []byte) ([]*buildbotBuild, *buildbotMaster, error ) {
133 bm := buildMasterMsg{} 134 bm := buildMasterMsg{}
134 if len(msg) == 0 { 135 if len(msg) == 0 {
135 return bm.Builds, bm.Master, nil 136 return bm.Builds, bm.Master, nil
136 } 137 }
137 reader, err := zlib.NewReader(bytes.NewReader(msg)) 138 reader, err := zlib.NewReader(bytes.NewReader(msg))
(...skipping 26 matching lines...) Expand all
164 } 165 }
165 166
166 // getOSInfo fetches the os family and version of the slave the build was 167 // getOSInfo fetches the os family and version of the slave the build was
167 // running on from the master json on a best-effort basis. 168 // running on from the master json on a best-effort basis.
168 func getOSInfo(c context.Context, b *buildbotBuild, m *buildbotMaster) ( 169 func getOSInfo(c context.Context, b *buildbotBuild, m *buildbotMaster) (
169 family, version string) { 170 family, version string) {
170 // Fetch the master info from datastore if not provided. 171 // Fetch the master info from datastore if not provided.
171 if m.Name == "" { 172 if m.Name == "" {
172 logging.Infof(c, "Fetching info for master %s", b.Master) 173 logging.Infof(c, "Fetching info for master %s", b.Master)
173 entry := buildbotMasterEntry{Name: b.Master} 174 entry := buildbotMasterEntry{Name: b.Master}
174 » » err := ds.Get(c, &entry) 175 » » err := datastore.Get(c, &entry)
175 if err != nil { 176 if err != nil {
176 logging.WithError(err).Errorf( 177 logging.WithError(err).Errorf(
177 c, "Encountered error while fetching entry for % s", b.Master) 178 c, "Encountered error while fetching entry for % s", b.Master)
178 return 179 return
179 } 180 }
180 err = decodeMasterEntry(c, &entry, m) 181 err = decodeMasterEntry(c, &entry, m)
181 if err != nil { 182 if err != nil {
182 logging.WithError(err).Warningf( 183 logging.WithError(err).Warningf(
183 c, "Failed to decode master information for OS i nfo on master %s", b.Master) 184 c, "Failed to decode master information for OS i nfo on master %s", b.Master)
184 return 185 return
(...skipping 30 matching lines...) Expand all
215 finished := float64(clock.Now(c).Unix()) 216 finished := float64(clock.Now(c).Unix())
216 if b.TimeStamp != nil { 217 if b.TimeStamp != nil {
217 finished = float64(*b.TimeStamp) 218 finished = float64(*b.TimeStamp)
218 } 219 }
219 results := int(4) // Exception 220 results := int(4) // Exception
220 b.Times[1] = &finished 221 b.Times[1] = &finished
221 b.Finished = true 222 b.Finished = true
222 b.Results = &results 223 b.Results = &results
223 b.Currentstep = nil 224 b.Currentstep = nil
224 b.Text = append(b.Text, "Build expired on Milo") 225 b.Text = append(b.Text, "Build expired on Milo")
225 » return ds.Put(c, b) 226 » return datastore.Put(c, b)
227 }
228
229 // saveBuildSummary summerizes a build into a model.BuildSummary and then saves it.
230 func saveBuildSummary(c context.Context, b *buildbotBuild) error {
231 » resp := renderBuild(c, b)
232 » bs := model.BuildSummary{
233 » » BuildKey: datastore.KeyForObj(c, b),
234 » » BuilderID: fmt.Sprintf("buildbot/%s/%s", b.Master, b.Buildername ),
235 » }
236 » resp.SummarizeTo(&bs)
237 » return datastore.Put(c, &bs)
226 } 238 }
227 239
228 func doMaster(c context.Context, master *buildbotMaster, internal bool) int { 240 func doMaster(c context.Context, master *buildbotMaster, internal bool) int {
229 // Store the master json into the datastore. 241 // Store the master json into the datastore.
230 err := putDSMasterJSON(c, master, internal) 242 err := putDSMasterJSON(c, master, internal)
231 fullname := fmt.Sprintf("master.%s", master.Name) 243 fullname := fmt.Sprintf("master.%s", master.Name)
232 if err != nil { 244 if err != nil {
233 logging.WithError(err).Errorf( 245 logging.WithError(err).Errorf(
234 c, "Could not save master in datastore %s", err) 246 c, "Could not save master in datastore %s", err)
235 masterCounter.Add(c, 1, internal, fullname, "failure") 247 masterCounter.Add(c, 1, internal, fullname, "failure")
236 // This is transient, we do want PubSub to retry. 248 // This is transient, we do want PubSub to retry.
237 return http.StatusInternalServerError 249 return http.StatusInternalServerError
238 } 250 }
239 masterCounter.Add(c, 1, internal, fullname, "success") 251 masterCounter.Add(c, 1, internal, fullname, "success")
240 252
241 // Extract current builds data out of the master json, and use it to 253 // Extract current builds data out of the master json, and use it to
242 // clean up expired builds. 254 // clean up expired builds.
243 » q := ds.NewQuery("buildbotBuild"). 255 » q := datastore.NewQuery("buildbotBuild").
244 Eq("finished", false). 256 Eq("finished", false).
245 Eq("master", master.Name) 257 Eq("master", master.Name)
246 builds := []*buildbotBuild{} 258 builds := []*buildbotBuild{}
247 err = getBuildQueryBatcher(c).GetAll(c, q, &builds) 259 err = getBuildQueryBatcher(c).GetAll(c, q, &builds)
248 if err != nil { 260 if err != nil {
249 logging.WithError(err).Errorf(c, "Could not load current builds from master %s", 261 logging.WithError(err).Errorf(c, "Could not load current builds from master %s",
250 master.Name) 262 master.Name)
251 return http.StatusInternalServerError 263 return http.StatusInternalServerError
252 } 264 }
253 for _, b := range builds { 265 for _, b := range builds {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 if build.Master == "" { 367 if build.Master == "" {
356 logging.Errorf(c, "Invalid message, missing master name" ) 368 logging.Errorf(c, "Invalid message, missing master name" )
357 return http.StatusOK 369 return http.StatusOK
358 } 370 }
359 existingBuild := &buildbotBuild{ 371 existingBuild := &buildbotBuild{
360 Master: build.Master, 372 Master: build.Master,
361 Buildername: build.Buildername, 373 Buildername: build.Buildername,
362 Number: build.Number, 374 Number: build.Number,
363 } 375 }
364 buildExists := false 376 buildExists := false
365 » » if err := ds.Get(c, existingBuild); err == nil { 377 » » if err := datastore.Get(c, existingBuild); err == nil {
366 if existingBuild.Finished { 378 if existingBuild.Finished {
367 // Never replace a completed build. 379 // Never replace a completed build.
368 buildCounter.Add( 380 buildCounter.Add(
369 c, 1, false, build.Master, build.Builder name, false, "Rejected") 381 c, 1, false, build.Master, build.Builder name, false, "Rejected")
370 continue 382 continue
371 } 383 }
372 buildExists = true 384 buildExists = true
373 } 385 }
374 // Also set the finished, timestamp, and internal bit. 386 // Also set the finished, timestamp, and internal bit.
375 build.Finished = false 387 build.Finished = false
376 if build.TimeStamp == nil { 388 if build.TimeStamp == nil {
377 build.TimeStamp = &now 389 build.TimeStamp = &now
378 } 390 }
379 if len(build.Times) == 2 && build.Times[1] != nil { 391 if len(build.Times) == 2 && build.Times[1] != nil {
380 build.Finished = true 392 build.Finished = true
381 logging.Infof( 393 logging.Infof(
382 c, "Recording finished build %s/%s/%d", build.Ma ster, 394 c, "Recording finished build %s/%s/%d", build.Ma ster,
383 build.Buildername, build.Number) 395 build.Buildername, build.Number)
384 } 396 }
385 build.Internal = internal 397 build.Internal = internal
386 // Try to get the OS information on a best-effort basis. This a ssumes that all 398 // Try to get the OS information on a best-effort basis. This a ssumes that all
387 // builds come from one master. 399 // builds come from one master.
388 build.OSFamily, build.OSVersion = getOSInfo(c, build, &cachedMas ter) 400 build.OSFamily, build.OSVersion = getOSInfo(c, build, &cachedMas ter)
389 » » err = ds.Put(c, build) 401 » » err = datastore.Put(c, build)
390 if err != nil { 402 if err != nil {
391 if _, ok := err.(errTooBig); ok { 403 if _, ok := err.(errTooBig); ok {
392 // This will never work, we don't want PubSub to retry. 404 // This will never work, we don't want PubSub to retry.
393 logging.WithError(err).Errorf( 405 logging.WithError(err).Errorf(
394 c, "Could not save build to datastore, f ailing permanently") 406 c, "Could not save build to datastore, f ailing permanently")
395 return http.StatusOK 407 return http.StatusOK
396 } 408 }
397 // This is transient, we do want PubSub to retry. 409 // This is transient, we do want PubSub to retry.
398 logging.WithError(err).Errorf(c, "Could not save build i n datastore") 410 logging.WithError(err).Errorf(c, "Could not save build i n datastore")
399 return http.StatusInternalServerError 411 return http.StatusInternalServerError
400 } 412 }
413 err = saveBuildSummary(c, build)
414 if err != nil {
415 logging.WithError(err).Errorf(c, "could not save build s ummary into datastore")
416 return http.StatusInternalServerError
417 }
401 if buildExists { 418 if buildExists {
402 buildCounter.Add( 419 buildCounter.Add(
403 c, 1, false, build.Master, build.Buildername, bu ild.Finished, "Replaced") 420 c, 1, false, build.Master, build.Buildername, bu ild.Finished, "Replaced")
404 } else { 421 } else {
405 buildCounter.Add( 422 buildCounter.Add(
406 c, 1, false, build.Master, build.Buildername, bu ild.Finished, "New") 423 c, 1, false, build.Master, build.Buildername, bu ild.Finished, "New")
407 } 424 }
408 425
409 } 426 }
410 if master != nil { 427 if master != nil {
411 code := doMaster(c, master, internal) 428 code := doMaster(c, master, internal)
412 if code != 0 { 429 if code != 0 {
413 return code 430 return code
414 } 431 }
415 } 432 }
416 return http.StatusOK 433 return http.StatusOK
417 } 434 }
OLDNEW
« no previous file with comments | « milo/buildsource/buildbot/build.go ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698