Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 The LUCI Authors. All rights reserved. | |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | |
| 3 // that can be found in the LICENSE file. | |
| 4 | |
| 5 package swarming | |
| 6 | |
| 7 import ( | |
| 8 "strings" | |
| 9 | |
| 10 swarming "github.com/luci/luci-go/common/api/swarming/swarming/v1" | |
| 11 "github.com/luci/luci-go/common/logging" | |
| 12 miloProto "github.com/luci/luci-go/common/proto/milo" | |
| 13 "github.com/luci/luci-go/grpc/grpcutil" | |
| 14 "github.com/luci/luci-go/logdog/client/coordinator" | |
| 15 "github.com/luci/luci-go/logdog/common/types" | |
| 16 "github.com/luci/luci-go/luci_config/common/cfgtypes" | |
| 17 milo "github.com/luci/luci-go/milo/api/proto" | |
| 18 "github.com/luci/luci-go/milo/appengine/logdog" | |
| 19 | |
| 20 "golang.org/x/net/context" | |
| 21 ) | |
| 22 | |
| 23 // BuildInfoProvider is a configuration that provides build information. | |
|
hinoka
2017/02/07 20:07:24
s/configuration/service/ ?
dnj
2017/02/07 23:06:09
Done.
| |
| 24 // | |
| 25 // In a production system, this will be completely defaults. For testing, the | |
| 26 // various services and data sources may be substituted for testing stubs. | |
| 27 type BuildInfoProvider struct { | |
| 28 // LogdogClientFunc returns a coordinator Client instance for the suppli ed | |
| 29 // parameters. | |
| 30 // | |
| 31 // If nil, a production client will be generated. | |
| 32 LogdogClientFunc func(c context.Context) (*coordinator.Client, error) | |
| 33 | |
| 34 // swarmingServiceFunc returns a swarmingService instance for the suppli ed | |
| 35 // parameters. | |
| 36 // | |
| 37 // If nil, a production fetcher will be generated. | |
| 38 swarmingServiceFunc func(c context.Context, host string) (swarmingServic e, error) | |
| 39 } | |
| 40 | |
| 41 func (p *BuildInfoProvider) newLogdogClient(c context.Context) (*coordinator.Cli ent, error) { | |
| 42 if p.LogdogClientFunc != nil { | |
| 43 return p.LogdogClientFunc(c) | |
| 44 } | |
| 45 return logdog.NewClient(c, "") | |
| 46 } | |
| 47 | |
| 48 func (p *BuildInfoProvider) newSwarmingService(c context.Context, host string) ( swarmingService, error) { | |
| 49 fn := p.swarmingServiceFunc | |
| 50 if fn == nil { | |
| 51 fn = getSwarmingService | |
| 52 } | |
| 53 return fn(c, host) | |
| 54 } | |
| 55 | |
| 56 // GetBuildInfo resolves a Milo protobuf Step for a given Swarming task. | |
| 57 func (p *BuildInfoProvider) GetBuildInfo(c context.Context, req *milo.BuildInfoR equest_Swarming, | |
| 58 projectHint cfgtypes.ProjectName) (*milo.BuildInfoResponse, error) { | |
| 59 | |
| 60 // Load the Swarming task (no log content). | |
| 61 sf, err := p.newSwarmingService(c, req.Host) | |
| 62 if err != nil { | |
| 63 logging.WithError(err).Errorf(c, "Failed to create Swarming fetc her.") | |
| 64 return nil, grpcutil.Internal | |
| 65 } | |
| 66 | |
| 67 // Use default Swarming host. | |
| 68 host := sf.getHost() | |
| 69 logging.Infof(c, "Loading build info for Swarming host %s, task %s.", ho st, req.Task) | |
| 70 | |
| 71 fetchParams := swarmingFetchParams{ | |
| 72 fetchReq: true, | |
| 73 fetchRes: true, | |
| 74 } | |
| 75 fr, err := swarmingFetch(c, sf, req.Task, fetchParams) | |
| 76 if err != nil { | |
| 77 if err == errNotMiloJob { | |
| 78 logging.Warningf(c, "User requested non-Milo task.") | |
| 79 return nil, grpcutil.NotFound | |
| 80 } | |
| 81 | |
| 82 logging.WithError(err).Errorf(c, "Failed to load Swarming task." ) | |
| 83 return nil, grpcutil.Internal | |
| 84 } | |
| 85 | |
| 86 // Determine the LogDog annotation stream path for this Swarming task. | |
| 87 // | |
| 88 // On failure, will return a gRPC error. | |
| 89 as, err := getLogDogAnnotations(c, fr.req, projectHint, host, req.Task) | |
| 90 if err != nil { | |
| 91 logging.WithError(err).Warningf(c, "Failed to get annotation str eam parameters.") | |
| 92 return nil, err | |
| 93 } | |
| 94 if err := as.Normalize(); err != nil { | |
| 95 logging.WithError(err).Warningf(c, "Failed to normalize annotati on stream parameters.") | |
| 96 return nil, grpcutil.Internal | |
| 97 } | |
| 98 | |
| 99 client, err := p.newLogdogClient(c) | |
| 100 if err != nil { | |
| 101 logging.WithError(err).Errorf(c, "Failed to create LogDog client .") | |
| 102 return nil, grpcutil.Internal | |
| 103 } | |
| 104 | |
| 105 as.Client = client | |
| 106 step, err := as.Load(c) | |
|
hinoka
2017/02/07 20:07:24
This is an RPC call right? Add a comment here deno
dnj
2017/02/07 23:06:09
Done.
| |
| 107 if err != nil { | |
| 108 logging.WithError(err).Warningf(c, "Failed to load annotation st ream.") | |
| 109 return nil, grpcutil.Internal | |
| 110 } | |
| 111 | |
| 112 // Add Swarming task parameters to the Milo step. | |
| 113 if err := addTaskToMiloStep(c, sf.getHost(), fr.res, step); err != nil { | |
| 114 return nil, err | |
| 115 } | |
| 116 | |
| 117 prefix, name := as.Path.Split() | |
| 118 return &milo.BuildInfoResponse{ | |
| 119 Project: string(as.Project), | |
| 120 Step: step, | |
| 121 AnnotationStream: &miloProto.LogdogStream{ | |
| 122 Server: client.Host, | |
| 123 Prefix: string(prefix), | |
| 124 Name: string(name), | |
| 125 }, | |
| 126 }, nil | |
| 127 } | |
| 128 | |
| 129 // getLogDogAnnotations returns a configured AnnotationStream given the input | |
| 130 // parameters. | |
| 131 // | |
| 132 // This will return a gRPC error on failure. | |
| 133 // | |
| 134 // This function is messy and implementation-specific. That's the point of this | |
| 135 // endpoint, though. All of the nastiness here should be replaced with something | |
| 136 // more elegant once that becomes available. In the meantime... | |
| 137 func getLogDogAnnotations(c context.Context, sr *swarming.SwarmingRpcsTaskReques t, projectHint cfgtypes.ProjectName, | |
|
hinoka
2017/02/07 20:07:24
I think "resolveLogDogAnnotations" is clearer
dnj
2017/02/07 23:06:09
Done.
| |
| 138 host, taskID string) (*logdog.AnnotationStream, error) { | |
| 139 | |
| 140 // If this is a Kitchen command, maybe we can infer our LogDog project f rom | |
| 141 // the command-line. | |
| 142 var as logdog.AnnotationStream | |
| 143 if sr.Properties == nil { | |
| 144 logging.Warningf(c, "No request properties, can't infer annotati on stream path.") | |
| 145 return nil, grpcutil.NotFound | |
| 146 } | |
| 147 | |
| 148 var isKitchen bool | |
| 149 if as.Project, isKitchen = getLogDogProjectFromKitchen(sr.Properties.Com mand); !isKitchen { | |
| 150 logging.Warningf(c, "Not a Kitchen CLI, can't infer annotation s tream path.") | |
| 151 return nil, grpcutil.NotFound | |
| 152 } | |
| 153 | |
| 154 if as.Project == "" { | |
| 155 as.Project = projectHint | |
| 156 } | |
| 157 if as.Project == "" { | |
| 158 logging.Warningf(c, "Don't know how to get annotation stream pat h.") | |
| 159 return nil, grpcutil.NotFound | |
| 160 } | |
| 161 | |
| 162 // This is a Kitchen run, and it has a project! Construct the annotation | |
| 163 // stream path. | |
| 164 // | |
| 165 // This is an implementation of: | |
| 166 // https://chromium.googlesource.com/infra/infra/+/a7032e3e240d4b81a1912 bfaf29a20d02f665cc1/go/src/infra/tools/kitchen/cook_logdog.go#129 | |
| 167 prefix, err := types.MakeStreamName("", "swarm", host, taskID) | |
| 168 if err != nil { | |
| 169 logging.WithError(err).Errorf(c, "Failed to generate Swarming pr efix.") | |
| 170 return nil, grpcutil.Internal | |
| 171 } | |
| 172 as.Path = prefix.Join("annotations") | |
| 173 return &as, nil | |
| 174 } | |
| 175 | |
| 176 func getLogDogProjectFromKitchen(cmd []string) (proj cfgtypes.ProjectName, isKit chen bool) { | |
| 177 // Is this a Kitchen command? | |
| 178 switch { | |
| 179 case len(cmd) == 0: | |
| 180 return | |
| 181 case !strings.HasPrefix(cmd[0], "kitchen"): | |
| 182 return | |
| 183 } | |
| 184 isKitchen = true | |
| 185 cmd = cmd[1:] | |
| 186 | |
| 187 // Scan through for the "-logdog-project" argument. | |
| 188 for i, arg := range cmd { | |
| 189 if arg == "-logdog-project" { | |
| 190 if i < len(cmd)-2 { | |
| 191 proj = cfgtypes.ProjectName(cmd[i+1]) | |
| 192 return | |
| 193 } | |
| 194 break | |
| 195 } | |
| 196 } | |
| 197 return | |
| 198 } | |
| OLD | NEW |