go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/led/job/buildbucket.go (about) 1 // Copyright 2020 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 job 16 17 import ( 18 "github.com/golang/protobuf/proto" 19 "google.golang.org/protobuf/types/known/structpb" 20 21 "go.chromium.org/luci/buildbucket" 22 bbpb "go.chromium.org/luci/buildbucket/proto" 23 "go.chromium.org/luci/buildbucket/protoutil" 24 "go.chromium.org/luci/common/data/stringset" 25 "go.chromium.org/luci/common/errors" 26 "go.chromium.org/luci/luciexe/exe" 27 swarmingpb "go.chromium.org/luci/swarming/proto/api_v2" 28 ) 29 30 // WriteProperties writes an input property on this Buildbucket message. 31 func (b *Buildbucket) WriteProperties(inputs map[string]any) { 32 b.EnsureBasics() 33 34 if err := exe.WriteProperties(b.BbagentArgs.Build.Input.Properties, inputs); err != nil { 35 panic(errors.Annotate(err, "impossible").Err()) 36 } 37 } 38 39 // EnsureBasics ensures that the following fields are non-nil: 40 // 41 // b.BbagentArgs 42 // b.BbagentArgs.Build 43 // b.BbagentArgs.Build.Exe 44 // b.BbagentArgs.Build.Infra 45 // b.BbagentArgs.Build.Infra.Buildbucket 46 // b.BbagentArgs.Build.Infra.Logdog 47 // b.BbagentArgs.Build.Input 48 // b.BbagentArgs.Build.Input.Properties 49 // 50 // b.BbagentArgs.Build.Infra.Swarming is also ensured in the case that 51 // b.BbagentArgs.Build.Infra.Backend is nil. 52 func (b *Buildbucket) EnsureBasics() { 53 proto.Merge(b, &Buildbucket{BbagentArgs: &bbpb.BBAgentArgs{Build: &bbpb.Build{ 54 Exe: &bbpb.Executable{}, 55 Input: &bbpb.Build_Input{ 56 Properties: &structpb.Struct{}, 57 }, 58 Infra: &bbpb.BuildInfra{ 59 Buildbucket: &bbpb.BuildInfra_Buildbucket{}, 60 Logdog: &bbpb.BuildInfra_LogDog{}, 61 }, 62 }}}) 63 64 if b.BbagentArgs.Build.Infra.Swarming == nil && b.BbagentArgs.Build.Infra.Backend == nil { 65 b.BbagentArgs.Build.Infra.Swarming = &bbpb.BuildInfra_Swarming{} 66 } 67 } 68 69 // UpdateBuildbucketAgent updates or populates b.BbagentArgs.Build.Infra.Buildbucket.Agent. 70 func (b *Buildbucket) UpdateBuildbucketAgent(updates *bbpb.BuildInfra_Buildbucket_Agent) { 71 if b.BbagentArgs.Build.Infra.Buildbucket.GetAgent() == nil { 72 b.BbagentArgs.Build.Infra.Buildbucket.Agent = &bbpb.BuildInfra_Buildbucket_Agent{} 73 } 74 proto.Merge(b.BbagentArgs.Build.Infra.Buildbucket.Agent, updates) 75 } 76 77 func (b *Buildbucket) updateBuildbucketAgentPayloadPath(newPath string) { 78 for p, purpose := range b.BbagentArgs.Build.Infra.Buildbucket.GetAgent().GetPurposes() { 79 if purpose == bbpb.BuildInfra_Buildbucket_Agent_PURPOSE_EXE_PAYLOAD { 80 delete(b.BbagentArgs.Build.Infra.Buildbucket.Agent.Purposes, p) 81 } 82 } 83 b.UpdateBuildbucketAgent(&bbpb.BuildInfra_Buildbucket_Agent{ 84 Purposes: map[string]bbpb.BuildInfra_Buildbucket_Agent_Purpose{ 85 newPath: bbpb.BuildInfra_Buildbucket_Agent_PURPOSE_EXE_PAYLOAD, 86 }, 87 }) 88 } 89 90 // UpdateBuildFromBbagentArgs populates fields in b.BbagentArgs.Build 91 // from b.BbagentArgs. 92 func (b *Buildbucket) UpdateBuildFromBbagentArgs() { 93 b.EnsureBasics() 94 95 if b.BbagentArgs.Build.Infra.GetBbagent() == nil { 96 b.BbagentArgs.Build.Infra.Bbagent = &bbpb.BuildInfra_BBAgent{ 97 PayloadPath: b.BbagentArgs.PayloadPath, 98 CacheDir: b.BbagentArgs.CacheDir, 99 } 100 } 101 102 b.BbagentArgs.Build.Infra.Buildbucket.KnownPublicGerritHosts = b.BbagentArgs.KnownPublicGerritHosts 103 b.updateBuildbucketAgentPayloadPath(b.BbagentArgs.PayloadPath) 104 } 105 106 // UpdatePayloadPath updates the payload path of the led build. 107 func (b *Buildbucket) UpdatePayloadPath(newPath string) { 108 b.BbagentArgs.PayloadPath = newPath 109 if b.BbagentArgs.Build.Infra.GetBbagent() == nil { 110 b.BbagentArgs.Build.Infra.Bbagent = &bbpb.BuildInfra_BBAgent{} 111 } 112 b.BbagentArgs.Build.Infra.Bbagent.PayloadPath = newPath 113 b.updateBuildbucketAgentPayloadPath(newPath) 114 } 115 116 // PayloadPath returns the payload path of the led build. 117 func (b *Buildbucket) PayloadPath() string { 118 return protoutil.ExePayloadPath(b.BbagentArgs.GetBuild()) 119 } 120 121 func (b *Buildbucket) Payload() (*bbpb.InputDataRef_CAS, *bbpb.InputDataRef_CIPD) { 122 payloadPath := b.PayloadPath() 123 inputData := b.BbagentArgs.GetBuild().GetInfra().GetBuildbucket().GetAgent().GetInput().GetData() 124 if inputData == nil { 125 return nil, nil 126 } 127 if ref, ok := inputData[payloadPath]; ok { 128 return ref.GetCas(), ref.GetCipd() 129 } 130 return nil, nil 131 } 132 133 func (b *Buildbucket) CacheDir() string { 134 return protoutil.CacheDir(b.BbagentArgs.GetBuild()) 135 } 136 137 // BbagentDownloadCIPDPkgs returns a bool on whether bbagent is responsible for 138 // downloading CIPD packages. 139 func (b *Buildbucket) BbagentDownloadCIPDPkgs() bool { 140 return !b.LegacyKitchen && stringset.NewFromSlice(b.GetBbagentArgs().GetBuild().GetInput().GetExperiments()...).Has(buildbucket.ExperimentBBAgentDownloadCipd) 141 } 142 143 func (b *Buildbucket) UpdateLedProperties() error { 144 curLedProps := &ledProperties{} 145 err := exe.ParseProperties(b.GetBbagentArgs().GetBuild().GetInput().GetProperties(), map[string]any{ 146 "$recipe_engine/led": curLedProps, 147 }) 148 if err != nil { 149 return errors.Annotate(err, `failed to parse input property "$recipe_engine/led"`).Err() 150 } 151 props := &ledProperties{ 152 ShadowedBucket: curLedProps.ShadowedBucket, 153 } 154 155 cas, cipd := b.Payload() 156 switch { 157 case len(cipd.GetSpecs()) > 0: 158 props.CIPDInput = &cipdInput{ 159 Package: cipd.Specs[0].GetPackage(), 160 Version: cipd.Specs[0].GetVersion(), 161 } 162 case cas != nil: 163 props.RbeCasInput = &swarmingpb.CASReference{ 164 CasInstance: cas.GetCasInstance(), 165 Digest: &swarmingpb.Digest{ 166 Hash: cas.GetDigest().GetHash(), 167 SizeBytes: cas.GetDigest().GetSizeBytes(), 168 }, 169 } 170 } 171 172 b.WriteProperties(map[string]any{ 173 "$recipe_engine/led": nil, 174 }) 175 b.WriteProperties(map[string]any{ 176 "$recipe_engine/led": props, 177 }) 178 return nil 179 }