go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/starlark/stdlib/internal/luci/rules/bucket_constraints.star (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 """Defines luci.bucket_constraints(...) rule.""" 16 17 load("@stdlib//internal/graph.star", "graph") 18 load("@stdlib//internal/luci/common.star", "keys", "kinds") 19 load("@stdlib//internal/luci/rules/binding.star", "binding") 20 load("@stdlib//internal/lucicfg.star", "lucicfg") 21 load("@stdlib//internal/validate.star", "validate") 22 23 def _bucket_constraints( 24 ctx, # @unused 25 bucket = None, 26 pools = None, 27 service_accounts = None): 28 """Adds constraints to a bucket. 29 30 `service_accounts` added as the bucket's constraints will also be granted 31 `role/buildbucket.builderServiceAccount` role. 32 33 Used inline in luci.bucket(...) declarations to provide `pools` and 34 `service_accounts` constraints for a bucket. `bucket` argument can be 35 omitted in this case: 36 37 luci.bucket( 38 name = 'try.shadow', 39 shadows ='try', 40 ... 41 constraints = luci.bucket_constraints( 42 pools = ['luci.project.shadow'], 43 service_accounts = [`shadow@chops-service-account.com`], 44 ), 45 ) 46 47 luci.builder function implicitly populates the constraints to the 48 builder’s bucket. I.e. 49 50 luci.builder( 51 'builder', 52 bucket = 'ci', 53 service_account = 'ci-sa@service-account.com', 54 ) 55 56 adds 'ci-sa@service-account.com' to bucket ci’s constraints. 57 58 Can also be used to add constraints to a bucket outside of 59 the bucket declaration. For example: 60 61 luci.bucket(name = 'ci') 62 luci.bucket(name = 'ci.shadow', shadows = 'ci') 63 luci.bucket_constraints(bucket = 'ci.shadow', pools = [shadow_pool]) 64 65 Args: 66 ctx: the implicit rule context, see lucicfg.rule(...). 67 bucket: name of the bucket to add the constrains. 68 pools: list of allowed swarming pools to add to the bucket's constraints. 69 service_accounts: list of allowed service accounts to add to the bucket's 70 constraints. 71 """ 72 pools = validate.str_list("pools", pools, required = False) 73 service_accounts = validate.str_list("service_accounts", service_accounts, required = False) 74 75 # This will be attached to the realm that has this constraint. 76 binding_key = None 77 if service_accounts: 78 binding_key = binding( 79 roles = "role/buildbucket.builderServiceAccount", 80 users = service_accounts, 81 ).get(kinds.BINDING) 82 83 # Note: name of this node is important only for error messages. It isn't 84 # showing up in any generated files and by construction it can't 85 # accidentally collide with some other name. 86 if bucket == None: 87 key = keys.unique(kinds.BUCKET_CONSTRAINTS, "") 88 else: 89 key = keys.unique(kinds.BUCKET_CONSTRAINTS, keys.bucket(bucket).id) 90 91 graph.add_node(key, props = { 92 "pools": pools, 93 "service_accounts": service_accounts, 94 }) 95 if bucket != None: 96 graph.add_edge(parent = keys.bucket(bucket), child = key) 97 if binding_key: 98 graph.add_edge(parent = keys.realm(bucket), child = binding_key) 99 100 # This is used to detect bucket_constraints nodes that aren't connected to 101 # any bucket. Such orphan nodes aren't allowed. 102 graph.add_node(keys.bucket_constraints_root(), idempotent = True) 103 graph.add_edge(parent = keys.bucket_constraints_root(), child = key) 104 105 keyset = [key] 106 if binding_key: 107 keyset.append(binding_key) 108 return graph.keyset(*keyset) 109 110 bucket_constraints = lucicfg.rule(impl = _bucket_constraints)