github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/docs/design-docs/05-kpt-fn-exclude.md (about)

     1  # Title
     2  
     3  * Author(s): Natasha Sarkar, natasha41575
     4  * Approver: Sunil Arora, droot
     5  
     6  ## Why
     7  
     8  `kpt fn render` and `kpt fn eval` now include meta resources (functionConfigs and the Kptfile), 
     9  a breaking change from previous behavior. Users who use functions such as set-labels and set-namespace
    10  will now see their KRM functions acting on resources that were previously excluded by default. 
    11  For these users, we need to provide a way to preserve old behavior by introducing a mechanism to 
    12  exclude certain resources, such as resources of a certain GVK or local configuration resources, from 
    13  being acted on by kpt functions during `kpt fn render` and `kpt fn eval`.
    14  
    15  ### Background
    16  
    17  Open source issue: https://github.com/GoogleContainerTools/kpt/issues/2930
    18  
    19  #### Redefining and inclusion of meta resources
    20  
    21  Previously, `kpt fn render` and `kpt fn eval` excluded functionConfigs and the Kptfile. A user could include t
    22  hese "meta resources'' by setting the `--include-meta-resources` flag. There is a separate discussion 
    23  and PR (https://github.com/GoogleContainerTools/kpt/pull/2894) with the following changes:
    24  
    25  - The definition of meta-resources. Kpt no longer considers functionConfigs as meta resources; they are KRM 
    26  resources like any other, and the fact that they are used to configure a KRM function does not mean they should be 
    27  treated specially. With this change, "meta-resources" only includes the Kptfile.
    28  - The `--include-meta-resources` flag is going away, and meta resources are processed by all kpt functions by default. 
    29  With this change, there is no mechanism for users to exclude the Kptfile.
    30  
    31  #### `kpt fn` selectors
    32  
    33  kpt fn render and kpt fn eval currently support selector-based mechanisms to target certain resources.
    34  
    35  Imperatively:
    36  
    37  ```shell
    38  $ kpt fn eval [PKG_DIR] -i set-labels:v0.1.5 --match-kind Deployment
    39  ```
    40  
    41  Declaratively:
    42  
    43  ```yaml
    44  # pipeline of Kptfile
    45  pipeline:
    46    mutators:
    47    - image: set-labels:v0.1.5
    48      selectors:
    49      - kind: Deployment
    50  ```
    51  
    52  These selectors only allow you to list out which resources you want to include. There is no current mechanism to exclude a certain kind of resource. 
    53  For example, the user may want to exclude the Kptfile.
    54  
    55  #### Prior art in kustomize
    56  The kustomize `replacements` feature (used in our new apply-replacements function), allows a mechanism to exclude certain resources from being modified. 
    57  `replacements` is one of the most popular among kustomize users.
    58  
    59  Kustomize has also had a few requests (such as this one: https://github.com/kubernetes/enhancements/pull/1232) to allow transformers to skip resources of a 
    60  certain GVK, which gives us confidence that a similar feature in kpt would be welcome.
    61  
    62  ## Design
    63  
    64  ### A new `exclude` option inline with selectors
    65  
    66  We can extend the current selector mechanism to allow exclusions. This can be achieved by new exclude flags for imperative workflow and a new exclude field in the 
    67  Kptfile pipeline for declarative workflow. These correspond to the imperative match flags and declarative selectors field.
    68  
    69  A few reasons in favor of this design:
    70  - Flexible and powerful
    71  - Allows users very explicit control of which resources are included at a per-function level
    72  - It is consistent with our current selector mechanism.
    73  - It is consistent with the syntax of kustomize replacements (used in our new apply-replacements function), which is popular and heavily used among the kubernetes community
    74  - It is consistent with a highly requested feature in kustomize to allow transformers to exclude resources of a certain GVK.
    75  
    76  #### Example: Exclude all resources of kind "Deployment"
    77  
    78  ```shell
    79  $ kpt fn eval [PKG_DIR] -i set-labels:v0.1.5 --exclude-kind Deployment
    80  ```
    81  
    82  ```yaml
    83  # pipeline of Kptfile
    84  pipeline:
    85    mutators:
    86    - image: set-labels:v0.1.5
    87      exclude:
    88      - kind: Deployment
    89  ```
    90  
    91  #### Example: Exclude all resources that have both group "apps" and kind "Deployment"
    92  
    93  ```shell
    94  $ kpt fn eval [PKG_DIR] -i set-labels:v0.1.5 --exclude-kind Deployment --exclude-group apps
    95  ```
    96  ```yaml
    97  # pipeline of Kptfile
    98  pipeline:
    99    mutators:
   100    - image: set-labels:v0.1.5
   101      exclude:
   102      - kind: Deployment
   103        group: apps
   104  ```
   105  
   106  #### Example: Exclude all resources that have either group "apps" or kind "Deployment"
   107  
   108  ```yaml
   109  # pipeline of Kptfile
   110  pipeline:
   111    mutators:
   112    - image: set-labels:v0.1.5
   113      exclude:
   114      - kind: Deployment
   115      - group: apps
   116  ```
   117  
   118  With the current proposal, this is not possible imperatively with kpt fn eval.
   119  
   120  #### Example: Select all resources that have group "apps", but do NOT have kind "Deployment"
   121  
   122  ```shell
   123  $ kpt fn eval [PKG_DIR] -i set-labels:v0.1.5 --match-group apps --exclude-kind Deployment
   124  ```
   125  ```yaml
   126  # pipeline of Kptfile
   127  pipeline:
   128    mutators:
   129    - image: set-labels:v0.1.5
   130      selectors:
   131        group: apps
   132      exclude:
   133      - kind: Deployment
   134  ``` 
   135  
   136  ### Selecting by labels or annotations
   137  
   138  We will support selection and exclusion with annotation and label selectors.
   139  
   140  ```shell
   141  $ kpt fn eval [PKG_DIR] -i set-labels:v0.1.5 --match-annotation foo=bar --exclude-annotation config.kubernetes.io/local-config=true
   142  ```
   143  
   144  ```yaml
   145  # pipeline of Kptfile
   146  pipeline:
   147    mutators:
   148    - image: set-labels:v0.1.5
   149      selectors:
   150      - annotations:
   151          foo: bar
   152      exclude:
   153      - annotations:
   154          config.kubernetes.io/local-config: "true"
   155  ```
   156  
   157  ## Open Issues/Questions
   158  
   159  ### How should kpt functions handle meta resources?
   160  
   161  One concern about this approach is that in order to exclude the Kptfile from being modified by horizontal
   162  transformations like set-namespace and set-labels, the user will have to write an exclusion field for each function.
   163  Arguably, the user shouldn't have to provide any special syntax for the Kptfile at all, because kpt and 
   164  kpt functions should be able to handle it correctly. A mitigation for this is that our own horizontal kpt functions
   165  can exclude the Kptfile within the function logic itself, and there will be no special handling logic in kpt. 
   166  
   167  ## Alternatives Considered
   168  
   169  ### A new annotation to decide if a kpt function should modify it
   170  
   171  We can introduce a new annotation that determines if functions should modify it.
   172  
   173  ```yaml
   174  apiVersion: kpt.dev/v1
   175  kind: Kptfile
   176  metadata:
   177    name: example
   178    annotations:
   179      config.kubernetes.io/hydration-override: false
   180  ```
   181  
   182  If kpt sees `config.kubernetes.io/hydration-override: false`, it won't allow the functions to modify the resource. The user can add 
   183  this annotation to every resource that they don't want functions to modify.
   184  
   185  Pros:
   186  - The user would not need to write an exclusion field for each function.
   187  
   188  Cons:
   189  - It will not be possible to control at a function level. If users want some functions to modify the Kptfile/meta resources, and others not to touch it, 
   190  they will have to re-organize their package.
   191  
   192  
   193  ### Use the existing selector mechanism
   194  
   195  We can recommend that users use the existing selectors to exclude the Kptfile and functionConfigs if they don't want functions to run on them. 
   196  Here is an example: https://github.com/natasha41575/kpt-exclude-kptfile/blob/main/Kptfile. The Kptfile looks like:
   197  
   198  ```yaml
   199  apiVersion: kpt.dev/v1
   200  kind: Kptfile
   201  metadata:
   202    name: example
   203  pipeline:
   204    mutators:
   205    - image: gcr.io/kpt-fn/set-labels:unstable
   206      configPath: functionconfig.yaml
   207      selectors:
   208      - apiVersion: "batch/v1"
   209      - apiVersion: "apps/v1"
   210      - apiVersion: "v1"
   211      - apiVersion: "example.com/v1"
   212  ```
   213  
   214  Some problems with this approach:
   215  - It is verbose.
   216  - Verbosity increases if the user has more resources in the package.
   217  - The user will have to keep track of an exhaustive list of all their resources in their package just to exclude the Kptfile.
   218  - kpt and kpt functions should already know about the Kptfile, so this overhead on the user's side is unnecessary.
   219  
   220  ### Rely on the existing annotation config.kubernetes.io/local-config
   221  
   222  We can exclude all local-config resources (i.e. resources with the annotation `config.kubernetes.io/local-config: true`) from functions. This annotation is 
   223  currently used by kpt live apply to determine whether to apply the resource to the cluster. However, users may have some resources that they want kpt to modify or be 
   224  available as function inputs, but that they don't want to be applied to the cluster. In these cases, overloading the annotation in this way will
   225  break some functions.
   226  
   227  ### Mark meta resources with an annotation
   228  Kpt can add the annotation config.kubernetes.io/meta-resource: true to all meta resources, to allow users to easily target the Kptfile and functionConfigs. 
   229  Users can then use the annotation selector mechanism to target meta resources if desired.
   230  
   231  However, because most meta resources already have the `config.kubernetes.io/local-config: true` annotation, a new meta resource annotation is not necessary. 
   232  With the proposed `exclude` mechanism, users can filter out local-config easily, and in other cases, Kind- based exclusion is good enough.
   233