github.com/SamarSidharth/kpt@v0.0.0-20231122062228-c7d747ae3ace/site/guides/value-propagation.md (about) 1 [starlark]: https://catalog.kpt.dev/starlark/v0.4/ 2 [apply-replacements]: https://catalog.kpt.dev/apply-replacements/v0.1/ 3 4 # Value propagation pattern 5 6 Generating a string value and propagating that value to another place 7 (or many other places) in your configuration is a very common pattern. 8 In this guide, we will go through the recommended technique to 9 do this value propagation using our [starlark] and [apply-replacements] 10 KRM functions. 11 12 ## String generation function 13 14 Sometimes, the value that we need to propagate is a concatenation of 15 other values that come from various other resource fields. In order 16 to generate the value we need to propagate, we can make use of the 17 [starlark] function. 18 19 For example, let's say we have a few context resources: 20 21 ```yaml 22 # gcloud-config.yaml 23 24 apiVersion: v1 25 kind: ConfigMap 26 metadata: 27 name: gcloud-config.kpt.dev 28 annotations: 29 config.kubernetes.io/local-config: "true" 30 data: 31 domain: domain 32 orgId: org-ID 33 projectID: project 34 region: region 35 zone: zone 36 ``` 37 38 ```yaml 39 # package-context.yaml 40 41 apiVersion: v1 42 kind: ConfigMap 43 metadata: 44 name: kptfile.kpt.dev 45 annotations: 46 config.kubernetes.io/local-config: "true" 47 data: 48 name: namespace 49 ``` 50 51 and a RoleBinding as follows: 52 53 ```yaml 54 # rolebinding.yaml 55 56 apiVersion: rbac.authorization.k8s.io/v1 57 kind: RoleBinding 58 metadata: 59 name: app-admin 60 namespace: myns 61 subjects: 62 - kind: Group 63 name: example-admin@example.com 64 apiGroup: rbac.authorization.k8s.io 65 roleRef: 66 kind: ClusterRole 67 name: app-admin 68 apiGroup: rbac.authorization.k8s.io 69 ``` 70 71 For this example, our goal is to change the RoleBinding's Group name 72 from `example-admin@example.com` to the value `project-namespace-role@domain`. 73 In order to generate this value, we will need to look at various fields from our 74 context resources, concatenate them together, and then store the generated value somewhere. 75 76 We can create a ConfigMap named `value-store`, which we will use to store the generated string in its 77 `data.group` field: 78 79 ```yaml 80 # value-store.yaml 81 82 apiVersion: v1 83 kind: ConfigMap 84 metadata: 85 name: value-store 86 annotations: 87 config.kubernetes.io/local-config: "true" 88 data: 89 group: example-group 90 ``` 91 92 Now we can use the [starlark] function to generate and store the desired string value. 93 This function allows you to run a Starlark script to modify or generate resources. In 94 our case, the functionConfig should look like the following: 95 96 ```yaml 97 # generate-rolebinding-group.yaml 98 99 apiVersion: fn.kpt.dev/v1alpha1 100 kind: StarlarkRun 101 metadata: 102 name: generate-rolebinding-group.yaml 103 annotations: 104 config.kubernetes.io/local-config: "true" 105 source: |- 106 load("krmfn.star", "krmfn") 107 108 def generate_group(resources, role): 109 group = "" 110 value_store = {} 111 for r in resources: 112 if krmfn.match_gvk(r, "v1", "ConfigMap") and krmfn.match_name(r, "gcloud-config.kpt.dev"): 113 project = r["data"]["projectID"] 114 domain = r["data"]["domain"] 115 if krmfn.match_gvk(r, "v1", "ConfigMap") and krmfn.match_name(r, "kptfile.kpt.dev"): 116 namespace = r["data"]["name"] 117 if krmfn.match_gvk(r, "v1", "ConfigMap") and krmfn.match_name(r, "value-store"): 118 value_store = r 119 group = project + "-" + namespace + "-" + role + "@" + domain 120 value_store["data"]["group"] = group 121 generate_group(ctx.resource_list["items"], "app-admin") 122 ``` 123 124 ## Value propagation function 125 126 Now that we have a function that can generate the desired value, we will need to 127 configure another function to propagate the value to the desired place(s). 128 129 We can achieve this with the [apply-replacements] function. The apply-replacements 130 function is a wrapper for the [kustomize replacements](https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/replacements/) 131 feature, and can be used to copy a value from a provided source to any number of specified targets. 132 In our case, the functionConfig looks like the following: 133 134 ```yaml 135 # propagate-rolebinding-group.yaml 136 137 apiVersion: fn.kpt.dev/v1alpha1 138 kind: ApplyReplacements 139 metadata: 140 name: propagate-rolebinding-group 141 annotations: 142 config.kubernetes.io/local-config: "true" 143 replacements: 144 - source: 145 kind: ConfigMap 146 name: value-store 147 fieldPath: data.group 148 targets: 149 - select: 150 kind: RoleBinding 151 name: app-admin 152 fieldPaths: 153 - subjects.[kind=Group].name 154 ``` 155 156 This functionConfig will configure [apply-replacements] to copy the value 157 we stored in `value-store` to the RoleBinding Group. 158 159 ## Running the functions 160 161 In order to run the configured functions, we can have the following pipeline in our Kptfile: 162 163 ```yaml 164 # Kptfile 165 166 apiVersion: kpt.dev/v1 167 kind: Kptfile 168 metadata: 169 name: example 170 pipeline: 171 mutators: 172 - image: gcr.io/kpt-fn/starlark:v0.4 173 configPath: generate-rolebinding-group.yaml 174 - image: gcr.io/kpt-fn/apply-replacements:v0.1 175 configPath: propagate-rolebinding-group.yaml 176 ``` 177 178 After running these two functions with `kpt fn render`, we should see the value of our 179 RoleBinding group change from `example-admin@example.com` to `project-namespace-role@domain` as desired. 180 181 ## Summary 182 183 With the above pattern and workflow, you can easily generate and propagate 184 common values to various places of your configuration.