go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/buildbucket/cmd/bbagent/context.go (about) 1 // Copyright 2022 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (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 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "context" 19 "fmt" 20 "io" 21 "os" 22 23 "google.golang.org/protobuf/encoding/protojson" 24 25 "go.chromium.org/luci/auth" 26 "go.chromium.org/luci/auth/authctx" 27 bbpb "go.chromium.org/luci/buildbucket/proto" 28 "go.chromium.org/luci/common/errors" 29 "go.chromium.org/luci/common/logging" 30 "go.chromium.org/luci/lucictx" 31 ) 32 33 func setResultDBContext(ctx context.Context, buildProto *bbpb.Build, secrets *bbpb.BuildSecrets) context.Context { 34 if invocation := buildProto.GetInfra().GetResultdb().GetInvocation(); invocation != "" { 35 // For buildbucket builds, buildbucket creates the invocations and saves the 36 // info in build proto. 37 // Then bbagent uses the info from build proto to set resultdb 38 // parameters in the luci context. 39 return lucictx.SetResultDB(ctx, &lucictx.ResultDB{ 40 Hostname: buildProto.Infra.Resultdb.Hostname, 41 CurrentInvocation: &lucictx.ResultDBInvocation{ 42 Name: invocation, 43 UpdateToken: secrets.ResultdbInvocationUpdateToken, 44 }, 45 }) 46 } else if resultDBCtx := lucictx.GetResultDB(ctx); resultDBCtx != nil { 47 // For led builds, swarming creates the invocations and sets resultdb 48 // parameters in luci context. 49 // Then bbagent gets the parameters from luci context and updates build proto. 50 buildProto.Infra.Resultdb = &bbpb.BuildInfra_ResultDB{ 51 Hostname: resultDBCtx.Hostname, 52 Invocation: resultDBCtx.CurrentInvocation.Name, 53 } 54 return ctx 55 } 56 return ctx 57 } 58 59 func setBuildbucketContext(ctx context.Context, hostname *string, secrets *bbpb.BuildSecrets) context.Context { 60 // Set `buildbucket` in the context. 61 bbCtx := lucictx.GetBuildbucket(ctx) 62 if bbCtx == nil || bbCtx.Hostname != *hostname || bbCtx.ScheduleBuildToken != secrets.BuildToken { 63 ctx = lucictx.SetBuildbucket(ctx, &lucictx.Buildbucket{ 64 Hostname: *hostname, 65 ScheduleBuildToken: secrets.BuildToken, 66 }) 67 if bbCtx != nil { 68 logging.Warningf(ctx, "buildbucket context is overwritten.") 69 } 70 } 71 return ctx 72 } 73 74 func setRealmContext(ctx context.Context, input *bbpb.BBAgentArgs) context.Context { 75 // Populate `realm` in the context based on the build's bucket if there's no 76 // realm there already. 77 if lucictx.GetRealm(ctx).GetName() == "" { 78 project := input.Build.Builder.Project 79 bucket := input.Build.Builder.Bucket 80 if project != "" && bucket != "" { 81 ctx = lucictx.SetRealm(ctx, &lucictx.Realm{ 82 Name: fmt.Sprintf("%s:%s", project, bucket), 83 }) 84 } else { 85 logging.Warningf(ctx, "Bad BuilderID in the build proto: %s", input.Build.Builder) 86 } 87 } 88 return ctx 89 } 90 91 func setLocalAuth(ctx context.Context) context.Context { 92 // If asked to use the GCE account, create a new local auth context so it 93 // can be properly picked through out the rest of bbagent process tree. Use 94 // it as the default task account and as a "system" account (so it is used 95 // for things like Logdog PubSub calls). 96 authCtx := authctx.Context{ 97 ID: "bbagent", 98 Options: auth.Options{Method: auth.GCEMetadataMethod}, 99 ExposeSystemAccount: true, 100 } 101 err := authCtx.Launch(ctx, "") 102 check(ctx, errors.Annotate(err, "failed launch the local LUCI auth context").Err()) 103 defer authCtx.Close(ctx) 104 105 // Switch the default auth in the context to the one we just setup. 106 return authCtx.SetLocalAuth(ctx) 107 } 108 109 // getContextFromFile gets BuildbucketAgentContext from a json context file. 110 func getContextFromFile(ctx context.Context, contextFile string) (*bbpb.BuildbucketAgentContext, error) { 111 bbagentCtx := &bbpb.BuildbucketAgentContext{} 112 file, err := os.Open(contextFile) 113 defer file.Close() 114 if err != nil { 115 return nil, err 116 } 117 contents, err := io.ReadAll(file) 118 if err != nil { 119 return nil, err 120 } 121 err = protojson.Unmarshal(contents, bbagentCtx) 122 if err != nil { 123 return nil, err 124 } 125 return bbagentCtx, nil 126 } 127 128 // getContextFromLuciContext generates BuildbucketAgentContext from Lucictx. 129 func getContextFromLuciContext(ctx context.Context) (*bbpb.BuildbucketAgentContext, error) { 130 bbagentCtx := &bbpb.BuildbucketAgentContext{} 131 bbagentCtx.TaskId = retrieveTaskIDFromContext(ctx) 132 secrets, err := readBuildSecrets(ctx) 133 if err != nil { 134 return nil, err 135 } 136 bbagentCtx.Secrets = secrets 137 return bbagentCtx, nil 138 } 139 140 // getBuildbucketAgentContext retrieves the bbpb.BuildbucketAgentContext from 141 // the contextFile path provided as a bbagent arg. 142 // 143 // Since we are mid migration from hard coded swarming to task backend, it also 144 // takes the current LUCI_CONTEXT env and turns it into a 145 // bbpb.BuildbucketAgentContext for use by bbagent. 146 // 147 // (TODO: randymaldonado) Have this function only pull from context file once the task backend migration is over. 148 func getBuildbucketAgentContext(ctx context.Context, contextFile string) (*bbpb.BuildbucketAgentContext, error) { 149 if contextFile != "" { 150 return getContextFromFile(ctx, contextFile) 151 } 152 return getContextFromLuciContext(ctx) 153 }