Chromium Code Reviews| 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 "encoding/base64" | 10 "encoding/base64" |
| 11 "encoding/json" | 11 "encoding/json" |
| 12 "net/http" | |
| 13 "time" | 12 "time" |
| 14 | 13 |
| 15 "github.com/luci/gae/service/datastore" | 14 "github.com/luci/gae/service/datastore" |
| 16 "github.com/luci/luci-go/common/clock" | 15 "github.com/luci/luci-go/common/clock" |
| 17 "github.com/luci/luci-go/common/iotools" | 16 "github.com/luci/luci-go/common/iotools" |
| 18 log "github.com/luci/luci-go/common/logging" | 17 log "github.com/luci/luci-go/common/logging" |
| 18 "github.com/luci/luci-go/server/router" | |
| 19 | 19 |
| 20 "github.com/julienschmidt/httprouter" | |
| 21 "golang.org/x/net/context" | 20 "golang.org/x/net/context" |
| 22 ) | 21 ) |
| 23 | 22 |
| 24 var ( | 23 var ( |
| 25 // subName is the name of the pubsub subscription that milo is expecting . | 24 // subName is the name of the pubsub subscription that milo is expecting . |
| 26 // TODO(hinoka): This should be read from luci-config. | 25 // TODO(hinoka): This should be read from luci-config. |
| 27 subName = "projects/luci-milo/subscriptions/buildbot-public" | 26 subName = "projects/luci-milo/subscriptions/buildbot-public" |
| 28 ) | 27 ) |
| 29 | 28 |
| 30 type pubSubMessage struct { | 29 type pubSubMessage struct { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 132 bm.Builds = append(bm.Builds, build) | 131 bm.Builds = append(bm.Builds, build) |
| 133 slave.RunningbuildsMap[build.Buildername] = append( | 132 slave.RunningbuildsMap[build.Buildername] = append( |
| 134 slave.RunningbuildsMap[build.Buildername], build .Number) | 133 slave.RunningbuildsMap[build.Buildername], build .Number) |
| 135 } | 134 } |
| 136 slave.Runningbuilds = nil | 135 slave.Runningbuilds = nil |
| 137 } | 136 } |
| 138 return bm.Builds, bm.Master, nil | 137 return bm.Builds, bm.Master, nil |
| 139 } | 138 } |
| 140 | 139 |
| 141 // PubSubHandler is a webhook that stores the builds coming in from pubsub. | 140 // PubSubHandler is a webhook that stores the builds coming in from pubsub. |
| 142 func PubSubHandler( | 141 func PubSubHandler(ctx *router.Context) { |
| 143 » c context.Context, h http.ResponseWriter, r *http.Request, p httprouter. Params) { | 142 » c, h, r := ctx.Context, ctx.Writer, ctx.Request |
| 143 » defer r.Body.Close() | |
| 144 msg := pubSubSubscription{} | 144 msg := pubSubSubscription{} |
| 145 defer r.Body.Close() | |
| 146 dec := json.NewDecoder(r.Body) | 145 dec := json.NewDecoder(r.Body) |
| 147 if err := dec.Decode(&msg); err != nil { | 146 if err := dec.Decode(&msg); err != nil { |
| 148 log.WithError(err).Errorf( | 147 log.WithError(err).Errorf( |
| 149 c, "Could not decode message. %s", err) | 148 c, "Could not decode message. %s", err) |
| 150 h.WriteHeader(200) // This is a hard failure, we don't want PubS ub to retry. | 149 h.WriteHeader(200) // This is a hard failure, we don't want PubS ub to retry. |
| 150 ctx.Abort() | |
| 151 return | 151 return |
| 152 } | 152 } |
| 153 if msg.Subscription != subName { | 153 if msg.Subscription != subName { |
| 154 log.Errorf( | 154 log.Errorf( |
| 155 c, "Subscription name %s does not match %s", msg.Subscri ption, subName) | 155 c, "Subscription name %s does not match %s", msg.Subscri ption, subName) |
| 156 h.WriteHeader(200) | 156 h.WriteHeader(200) |
| 157 ctx.Abort() | |
| 157 return | 158 return |
| 158 } | 159 } |
| 159 bbMsg, err := msg.GetData() | 160 bbMsg, err := msg.GetData() |
| 160 if err != nil { | 161 if err != nil { |
| 161 log.WithError(err).Errorf(c, "Could not decode message %s", err) | 162 log.WithError(err).Errorf(c, "Could not decode message %s", err) |
| 162 h.WriteHeader(200) | 163 h.WriteHeader(200) |
| 164 ctx.Abort() | |
| 163 return | 165 return |
| 164 } | 166 } |
| 165 builds, master, err := unmarshal(c, bbMsg) | 167 builds, master, err := unmarshal(c, bbMsg) |
| 166 if err != nil { | 168 if err != nil { |
| 167 log.WithError(err).Errorf(c, "Could not unmarshal message %s", e rr) | 169 log.WithError(err).Errorf(c, "Could not unmarshal message %s", e rr) |
| 168 h.WriteHeader(200) | 170 h.WriteHeader(200) |
| 171 ctx.Abort() | |
| 169 return | 172 return |
| 170 } | 173 } |
| 171 log.Infof(c, "There are %d builds and master %s", len(builds), master.Na me) | 174 log.Infof(c, "There are %d builds and master %s", len(builds), master.Na me) |
| 172 ds := datastore.Get(c) | 175 ds := datastore.Get(c) |
| 173 // Do not use PutMulti because we might hit the 1MB limit. | 176 // Do not use PutMulti because we might hit the 1MB limit. |
| 174 for _, build := range builds { | 177 for _, build := range builds { |
| 175 log.Debugf( | 178 log.Debugf( |
| 176 c, "Checking for build %s/%s/%d", build.Master, build.Bu ildername, build.Number) | 179 c, "Checking for build %s/%s/%d", build.Master, build.Bu ildername, build.Number) |
| 177 if build.Master == "" { | 180 if build.Master == "" { |
| 178 log.Errorf(c, "Invalid message, missing master name") | 181 log.Errorf(c, "Invalid message, missing master name") |
| 179 h.WriteHeader(200) | 182 h.WriteHeader(200) |
| 183 ctx.Abort() | |
| 180 return | 184 return |
| 181 } | 185 } |
| 182 existingBuild := &buildbotBuild{ | 186 existingBuild := &buildbotBuild{ |
| 183 Master: build.Master, | 187 Master: build.Master, |
| 184 Buildername: build.Buildername, | 188 Buildername: build.Buildername, |
| 185 Number: build.Number, | 189 Number: build.Number, |
| 186 } | 190 } |
| 187 if err := ds.Get(existingBuild); err == nil { | 191 if err := ds.Get(existingBuild); err == nil { |
| 188 if existingBuild.Times[1] != nil && build.Times[1] == ni l { | 192 if existingBuild.Times[1] != nil && build.Times[1] == ni l { |
| 189 // Never replace a completed build with a pendin g build. | 193 // Never replace a completed build with a pendin g build. |
| 190 continue | 194 continue |
| 191 } | 195 } |
| 192 } | 196 } |
| 193 err = ds.Put(&build) | 197 err = ds.Put(&build) |
| 194 if err != nil { | 198 if err != nil { |
| 195 log.WithError(err).Errorf(c, "Could not save build in da tastore %s", err) | 199 log.WithError(err).Errorf(c, "Could not save build in da tastore %s", err) |
| 196 // This is transient, we do want PubSub to retry. | 200 // This is transient, we do want PubSub to retry. |
| 197 h.WriteHeader(500) | 201 h.WriteHeader(500) |
| 202 ctx.Abort() | |
| 198 return | 203 return |
| 199 } | 204 } |
| 200 } | 205 } |
| 201 if master != nil { | 206 if master != nil { |
| 202 // TODO(hinoka): Internal builds. | 207 // TODO(hinoka): Internal builds. |
| 203 err = putDSMasterJSON(c, master, false) | 208 err = putDSMasterJSON(c, master, false) |
| 204 if err != nil { | 209 if err != nil { |
| 205 log.WithError(err).Errorf( | 210 log.WithError(err).Errorf( |
| 206 c, "Could not save master in datastore %s", err) | 211 c, "Could not save master in datastore %s", err) |
| 207 // This is transient, we do want PubSub to retry. | 212 // This is transient, we do want PubSub to retry. |
| 208 h.WriteHeader(500) | 213 h.WriteHeader(500) |
| 214 ctx.Abort() | |
| 209 return | 215 return |
| 210 } | 216 } |
| 211 } | 217 } |
| 212 h.WriteHeader(200) | 218 h.WriteHeader(200) |
|
iannucci
2016/06/13 19:23:28
missed one?
| |
| 213 } | 219 } |
| OLD | NEW |