github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/site/book/07-effective-customizations/01-single-value-replacement.md (about)

     1  ## Scenario
     2  
     3  I have a single value replacement in my package. I don’t want package consumers 
     4  to look through all the yaml files to find the value I want them to set. It 
     5  seems easier to just create a parameter for this value and have the user look 
     6  at Kptfile for inputs.
     7  
     8  Example storage bucket:
     9  
    10  ```yaml
    11  apiVersion: storage.cnrm.cloud.google.com/v1beta1
    12  kind: StorageBucket
    13  metadata:
    14    name: my-bucket # kpt-set: ${project-id}-${name}
    15    namespace: ns-test # kpt-set: ${namespace}
    16    annotations:
    17      cnrm.cloud.google.com/force-destroy: "false"
    18      cnrm.cloud.google.com/project-id: my-project # kpt-set: ${project-id}
    19  spec:
    20    storageClass: standard # kpt-set: ${storage-class}
    21    uniformBucketLevelAccess: true
    22    versioning:
    23      enabled: false
    24  ```
    25  
    26  The corresponding Kptfile:
    27  
    28  ```yaml
    29  apiVersion: kpt.dev/v1
    30  kind: Kptfile
    31  metadata:
    32    name: bucket
    33  info:
    34    description: A Google Cloud Storage bucket
    35  pipeline:
    36    mutators:
    37      - image: gcr.io/kpt-fn/apply-setters:v0.2
    38        configMap:
    39          name: todo-bucket-name
    40          namespace: todo-namespace
    41          project-id: todo-project-id
    42          storage-class: standard
    43  ```
    44  
    45  
    46  ## Problems
    47  
    48  1. With package popularity the single values inevitably expand to provide a 
    49  facade to a large portion of the data.  That defeats the purpose of minimizing 
    50  the cognitive load.  With this small example almost half of the StorageBucket configuration is now covered with parameters.
    51  1. Some values like resource names are used as references so setting them in 
    52  one place needs to trigger updates in all the places where they are referenced.
    53  1. If additional resources that have similar values are added to the package 
    54  new string replacements need to be added.  In this case everything will need
    55  to also be marked up with project ID and namespace.
    56  1. If a package is used as a sub-package the string replacement parameters need 
    57  to be surfaced to the parent package and if the parent package already expects 
    58  some values to be set and the parameters do not exist, the sub-package needs to 
    59  be updated.
    60  
    61  ## Solutions:
    62  
    63  1. kpt allows the user to edit a particular value directly in the configuration 
    64  data and will handle upstream merge.  When [editing the yaml] directly the 
    65  consumers are not confined to the parameters that the package author has 
    66  provided.  [kpt pkg update] merges the local edits made by consumer with the 
    67  changes in the upstream package made by publisher. In this case `storageClass` 
    68  can be set directly by the user.
    69  1. Attributes like resource names which are often updated by consumers to add 
    70  prefix or suffix (e.g. *-dev, *-stage, *-prod, na1-*, eu1-*) are best handled 
    71  by the [ensure-name-substring] function that will handle dependency updates as 
    72  well as capture all the resources in the package.
    73  1. Instead of setting a particular value on a resource a bulk operation can be 
    74  applied to all the resources that fit a particular interface.  This can be done 
    75  by a custom function or by [set-namespace], [search-and-replace] , [set-labels] 
    76  and [set-annotations] functions.
    77  
    78  New bucket configuration:
    79  
    80  ```yaml
    81  apiVersion: storage.cnrm.cloud.google.com/v1beta1
    82  kind: StorageBucket
    83  metadata:
    84    name: bucket
    85    annotations:
    86      cnrm.cloud.google.com/force-destroy: "false"
    87  spec:
    88    storageClass: standard
    89    uniformBucketLevelAccess: true
    90    versioning:
    91      enabled: false
    92  ```
    93  
    94  The suggested customizations are now in the Kptfile:
    95  
    96  ```yaml
    97  apiVersion: kpt.dev/v1
    98  kind: Kptfile
    99  metadata:
   100    name: bucket
   101  info:
   102    description: A Google Cloud Storage bucket
   103  pipeline:
   104    mutators:
   105      - image: gcr.io/kpt-fn/set-namespace:v0.2.0
   106        configMap:
   107          namespace: example-ns
   108      - image: gcr.io/kpt-fn/ensure-name-substring:v0.1.1
   109        configMap:
   110          prepend: project111-
   111      - image: gcr.io/kpt-fn/set-annotations:v0.1.4
   112        configMap:
   113          cnrm.cloud.google.com/project-id: project111
   114  ```
   115  
   116  The resource configuration YAML doesn't need to be marked up with where the 
   117  namespace value needs to go.  The [set-namespace] function is smart enough to 
   118  find all the appropriate resources that need the namespace.
   119  
   120  We have put in the starter name `bucket` and have an [ensure-name-substring] 
   121  that shows the package consumer that the project ID prefix is what we suggest.
   122  However if they have a different naming convention they can alter the name 
   123  prefix or suffix on all the resources in the pacakge.
   124  
   125  Since we are trying to set the annotation to the project ID we can use the 
   126  [set-annotations] function one time and the annotation are going to be set on 
   127  all the resources in the package.  If we add additional resources or whole 
   128  sub packages we will get the consistent annotations across all resources 
   129  without having to find all the places where annotations can go.
   130  
   131  [editing the yaml]: /book/03-packages/03-editing-a-package
   132  [kpt pkg update]: /book/03-packages/05-updating-a-package
   133  [ensure-name-substring]: https://catalog.kpt.dev/ensure-name-substring/v0.1/
   134  [search-and-replace]: https://catalog.kpt.dev/search-replace/v0.2/
   135  [set-labels]: https://catalog.kpt.dev/set-labels/v0.1/
   136  [set-annotations]: https://catalog.kpt.dev/set-annotations/v0.1/
   137  [set-namespace]: https://catalog.kpt.dev/set-namespace/v0.2/