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.