| 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/json" | 10 "encoding/json" |
| 11 | 11 |
| 12 "golang.org/x/net/context" |
| 12 "google.golang.org/grpc" | 13 "google.golang.org/grpc" |
| 13 "google.golang.org/grpc/codes" | 14 "google.golang.org/grpc/codes" |
| 14 | 15 |
| 15 "github.com/golang/protobuf/ptypes/timestamp" | 16 "github.com/golang/protobuf/ptypes/timestamp" |
| 16 ds "github.com/luci/gae/service/datastore" | 17 ds "github.com/luci/gae/service/datastore" |
| 17 "github.com/luci/luci-go/common/iotools" | 18 "github.com/luci/luci-go/common/iotools" |
| 18 "github.com/luci/luci-go/common/logging" | 19 "github.com/luci/luci-go/common/logging" |
| 19 milo "github.com/luci/luci-go/milo/api/proto" | 20 milo "github.com/luci/luci-go/milo/api/proto" |
| 20 "github.com/luci/luci-go/server/auth" | 21 "github.com/luci/luci-go/server/auth" |
| 21 "golang.org/x/net/context" | |
| 22 ) | 22 ) |
| 23 | 23 |
| 24 // Service is a service implementation that displays BuildBot builds. | 24 // Service is a service implementation that displays BuildBot builds. |
| 25 type Service struct{} | 25 type Service struct{} |
| 26 | 26 |
| 27 var errNotFoundGRPC = grpc.Errorf(codes.NotFound, "Master Not Found") | 27 var errNotFoundGRPC = grpc.Errorf(codes.NotFound, "Master Not Found") |
| 28 | 28 |
| 29 // GetBuildbotBuildJSON implements milo.BuildbotServer. | 29 // GetBuildbotBuildJSON implements milo.BuildbotServer. |
| 30 func (s *Service) GetBuildbotBuildJSON( | 30 func (s *Service) GetBuildbotBuildJSON(c context.Context, req *milo.BuildbotBuil
dRequest) ( |
| 31 » c context.Context, req *milo.BuildbotBuildRequest) ( | |
| 32 *milo.BuildbotBuildJSON, error) { | 31 *milo.BuildbotBuildJSON, error) { |
| 33 | 32 |
| 34 if req.Master == "" { | 33 if req.Master == "" { |
| 35 return nil, grpc.Errorf(codes.InvalidArgument, "No master specif
ied") | 34 return nil, grpc.Errorf(codes.InvalidArgument, "No master specif
ied") |
| 36 } | 35 } |
| 37 if req.Builder == "" { | 36 if req.Builder == "" { |
| 38 return nil, grpc.Errorf(codes.InvalidArgument, "No builder speci
fied") | 37 return nil, grpc.Errorf(codes.InvalidArgument, "No builder speci
fied") |
| 39 } | 38 } |
| 40 | 39 |
| 41 cu := auth.CurrentUser(c) | 40 cu := auth.CurrentUser(c) |
| 42 logging.Debugf(c, "%s is requesting %s/%s/%d", | 41 logging.Debugf(c, "%s is requesting %s/%s/%d", |
| 43 cu.Identity, req.Master, req.Builder, req.BuildNum) | 42 cu.Identity, req.Master, req.Builder, req.BuildNum) |
| 44 | 43 |
| 45 b, err := getBuild(c, req.Master, req.Builder, int(req.BuildNum)) | 44 b, err := getBuild(c, req.Master, req.Builder, int(req.BuildNum)) |
| 46 switch { | 45 switch { |
| 47 case err == errBuildNotFound: | 46 case err == errBuildNotFound: |
| 48 return nil, grpc.Errorf(codes.NotFound, "Build not found") | 47 return nil, grpc.Errorf(codes.NotFound, "Build not found") |
| 49 case err == errNotAuth: | 48 case err == errNotAuth: |
| 50 return nil, grpc.Errorf(codes.Unauthenticated, "Unauthenticated
request") | 49 return nil, grpc.Errorf(codes.Unauthenticated, "Unauthenticated
request") |
| 51 case err != nil: | 50 case err != nil: |
| 52 return nil, err | 51 return nil, err |
| 53 } | 52 } |
| 54 | 53 |
| 54 updatePostProcessBuild(b) |
| 55 bs, err := json.Marshal(b) | 55 bs, err := json.Marshal(b) |
| 56 if err != nil { | 56 if err != nil { |
| 57 return nil, err | 57 return nil, err |
| 58 } | 58 } |
| 59 | 59 |
| 60 // Marshal the build back into JSON format. | 60 // Marshal the build back into JSON format. |
| 61 return &milo.BuildbotBuildJSON{Data: bs}, nil | 61 return &milo.BuildbotBuildJSON{Data: bs}, nil |
| 62 } | 62 } |
| 63 | 63 |
| 64 // GetBuildbotBuildsJSON implements milo.BuildbotServer. | 64 // GetBuildbotBuildsJSON implements milo.BuildbotServer. |
| 65 func (s *Service) GetBuildbotBuildsJSON( | 65 func (s *Service) GetBuildbotBuildsJSON(c context.Context, req *milo.BuildbotBui
ldsRequest) ( |
| 66 » c context.Context, req *milo.BuildbotBuildsRequest) ( | |
| 67 *milo.BuildbotBuildsJSON, error) { | 66 *milo.BuildbotBuildsJSON, error) { |
| 68 | 67 |
| 69 if req.Master == "" { | 68 if req.Master == "" { |
| 70 return nil, grpc.Errorf(codes.InvalidArgument, "No master specif
ied") | 69 return nil, grpc.Errorf(codes.InvalidArgument, "No master specif
ied") |
| 71 } | 70 } |
| 72 if req.Builder == "" { | 71 if req.Builder == "" { |
| 73 return nil, grpc.Errorf(codes.InvalidArgument, "No builder speci
fied") | 72 return nil, grpc.Errorf(codes.InvalidArgument, "No builder speci
fied") |
| 74 } | 73 } |
| 75 | 74 |
| 76 limit := req.Limit | 75 limit := req.Limit |
| (...skipping 25 matching lines...) Expand all Loading... |
| 102 q = q.Eq("finished", true) | 101 q = q.Eq("finished", true) |
| 103 } | 102 } |
| 104 builds := []*buildbotBuild{} | 103 builds := []*buildbotBuild{} |
| 105 err = getBuildQueryBatcher(c).GetAll(c, q, &builds) | 104 err = getBuildQueryBatcher(c).GetAll(c, q, &builds) |
| 106 if err != nil { | 105 if err != nil { |
| 107 return nil, err | 106 return nil, err |
| 108 } | 107 } |
| 109 | 108 |
| 110 results := make([]*milo.BuildbotBuildJSON, len(builds)) | 109 results := make([]*milo.BuildbotBuildJSON, len(builds)) |
| 111 for i, b := range builds { | 110 for i, b := range builds { |
| 111 updatePostProcessBuild(b) |
| 112 |
| 112 // In theory we could do this in parallel, but it doesn't actual
ly go faster | 113 // In theory we could do this in parallel, but it doesn't actual
ly go faster |
| 113 // since AppEngine is single-cored. | 114 // since AppEngine is single-cored. |
| 114 bs, err := json.Marshal(b) | 115 bs, err := json.Marshal(b) |
| 115 if err != nil { | 116 if err != nil { |
| 116 return nil, err | 117 return nil, err |
| 117 } | 118 } |
| 118 results[i] = &milo.BuildbotBuildJSON{Data: bs} | 119 results[i] = &milo.BuildbotBuildJSON{Data: bs} |
| 119 } | 120 } |
| 120 return &milo.BuildbotBuildsJSON{ | 121 return &milo.BuildbotBuildsJSON{ |
| 121 Builds: results, | 122 Builds: results, |
| 122 }, nil | 123 }, nil |
| 123 } | 124 } |
| 124 | 125 |
| 125 // GetCompressedMasterJSON assembles a CompressedMasterJSON object from the | 126 // GetCompressedMasterJSON assembles a CompressedMasterJSON object from the |
| 126 // provided MasterRequest. | 127 // provided MasterRequest. |
| 127 func (s *Service) GetCompressedMasterJSON( | 128 func (s *Service) GetCompressedMasterJSON(c context.Context, req *milo.MasterReq
uest) ( |
| 128 » c context.Context, req *milo.MasterRequest) (*milo.CompressedMasterJSON,
error) { | 129 » *milo.CompressedMasterJSON, error) { |
| 129 | 130 |
| 130 if req.Name == "" { | 131 if req.Name == "" { |
| 131 return nil, grpc.Errorf(codes.InvalidArgument, "No master specif
ied") | 132 return nil, grpc.Errorf(codes.InvalidArgument, "No master specif
ied") |
| 132 } | 133 } |
| 133 | 134 |
| 134 cu := auth.CurrentUser(c) | 135 cu := auth.CurrentUser(c) |
| 135 logging.Debugf(c, "%s is making a master request for %s", cu.Identity, r
eq.Name) | 136 logging.Debugf(c, "%s is making a master request for %s", cu.Identity, r
eq.Name) |
| 136 | 137 |
| 137 entry, err := getMasterEntry(c, req.Name) | 138 entry, err := getMasterEntry(c, req.Name) |
| 138 switch { | 139 switch { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 162 Number: buildNum, | 163 Number: buildNum, |
| 163 }) | 164 }) |
| 164 } | 165 } |
| 165 } | 166 } |
| 166 if err := ds.Get(c, slave.Runningbuilds); err != nil { | 167 if err := ds.Get(c, slave.Runningbuilds); err != nil { |
| 167 logging.WithError(err).Errorf(c, | 168 logging.WithError(err).Errorf(c, |
| 168 "Encountered error while trying to fetch running
builds for %s: %v", | 169 "Encountered error while trying to fetch running
builds for %s: %v", |
| 169 master.Name, slave.Runningbuilds) | 170 master.Name, slave.Runningbuilds) |
| 170 return nil, err | 171 return nil, err |
| 171 } | 172 } |
| 173 |
| 174 for _, b := range slave.Runningbuilds { |
| 175 updatePostProcessBuild(b) |
| 176 } |
| 172 } | 177 } |
| 173 | 178 |
| 174 // Also inject cached builds information. | 179 // Also inject cached builds information. |
| 175 for builderName, builder := range master.Builders { | 180 for builderName, builder := range master.Builders { |
| 176 // Get the most recent 50 buildNums on the builder to simulate w
hat the | 181 // Get the most recent 50 buildNums on the builder to simulate w
hat the |
| 177 // cachedBuilds field looks like from the real buildbot master j
son. | 182 // cachedBuilds field looks like from the real buildbot master j
son. |
| 178 q := ds.NewQuery("buildbotBuild"). | 183 q := ds.NewQuery("buildbotBuild"). |
| 179 Eq("finished", true). | 184 Eq("finished", true). |
| 180 Eq("master", req.Name). | 185 Eq("master", req.Name). |
| 181 Eq("builder", builderName). | 186 Eq("builder", builderName). |
| (...skipping 26 matching lines...) Expand all Loading... |
| 208 | 213 |
| 209 return &milo.CompressedMasterJSON{ | 214 return &milo.CompressedMasterJSON{ |
| 210 Internal: entry.Internal, | 215 Internal: entry.Internal, |
| 211 Modified: ×tamp.Timestamp{ | 216 Modified: ×tamp.Timestamp{ |
| 212 Seconds: entry.Modified.Unix(), | 217 Seconds: entry.Modified.Unix(), |
| 213 Nanos: int32(entry.Modified.Nanosecond()), | 218 Nanos: int32(entry.Modified.Nanosecond()), |
| 214 }, | 219 }, |
| 215 Data: gzbs.Bytes(), | 220 Data: gzbs.Bytes(), |
| 216 }, nil | 221 }, nil |
| 217 } | 222 } |
| OLD | NEW |