From 74ed0b30e5ba743d3fa51cd2477e401d54552636 Mon Sep 17 00:00:00 2001 From: Jeffrey Regan Date: Fri, 13 Sep 2019 14:58:36 -0700 Subject: [PATCH] Example of configuring builtin plugin. --- docs/fields.md | 331 +---------- docs/plugins/builtins.md | 683 ++++++++++++++++++++++ examples/configureBuiltinPlugin.md | 333 +++++++++++ pkg/image/image.go | 17 +- pkg/types/configmapargs.go | 10 + pkg/types/generatorargs.go | 54 ++ pkg/types/generatoroptions.go | 18 + pkg/types/kustomization.go | 136 ----- pkg/types/objectmeta.go | 11 + pkg/types/patchstrategicmerge.go | 9 + pkg/types/patchtarget.go | 13 + pkg/types/replica.go | 16 + pkg/types/secretargs.go | 19 + pkg/types/selector.go | 25 + plugin/builtin/PrefixSuffixTransformer.go | 3 + 15 files changed, 1223 insertions(+), 455 deletions(-) create mode 100644 docs/plugins/builtins.md create mode 100644 examples/configureBuiltinPlugin.md create mode 100644 pkg/types/configmapargs.go create mode 100644 pkg/types/generatorargs.go create mode 100644 pkg/types/generatoroptions.go create mode 100644 pkg/types/objectmeta.go create mode 100644 pkg/types/patchstrategicmerge.go create mode 100644 pkg/types/patchtarget.go create mode 100644 pkg/types/replica.go create mode 100644 pkg/types/secretargs.go create mode 100644 pkg/types/selector.go diff --git a/docs/fields.md b/docs/fields.md index 342fde1257..17027f55d9 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -1,5 +1,19 @@ # Kustomization File Fields +[field-name-namespace]: plugins/builtins.md#field-name-namespace +[field-name-images]: plugins/builtins.md#field-name-images +[field-name-namePrefix]: plugins/builtins.md#field-name-prefix +[field-name-nameSuffix]: plugins/builtins.md#field-name-prefix +[field-name-patches]: plugins/builtins.md#field-name-patches +[field-name-patchesStrategicMerge]: plugins/builtins.md#field-name-patchesStrategicMerge +[field-name-patchesJson6902]: plugins/builtins.md#field-name-patchesJson6902 +[field-name-replicas]: plugins/builtins.md#field-name-replicas +[field-name-secretGenerator]: plugins/builtins.md#field-name-secretGenerator +[field-name-commonLabels]: plugins/builtins.md#field-name-commonLabels +[field-name-commonAnnotations]: plugins/builtins.md#field-name-commonAnnotations +[field-name-configMapGenerator]: plugins/builtins.md#field-name-configMapGenerator + + An explanation of the fields in a [kustomization.yaml](glossary.md#kustomization) file. @@ -65,7 +79,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 ### bases -The `bases` field was deprecated in v2.1.0. +_The `bases` field was deprecated in v2.1.0._ Move entries into the [resources](#resources) field. This allows bases - which are still a @@ -73,62 +87,13 @@ field. This allows bases - which are still a ordered relative to other input resources. ### commonLabels - -Adds labels to all resources and selectors -``` -commonLabels: - someName: someValue - owner: alice - app: bingo -``` +See [field-name-commonLabels]. ### commonAnnotations - -Adds annotions (non-identifying metadata) to add -all resources. Like labels, these are key value -pairs. - -``` -commonAnnotations: - oncallPager: 800-555-1212 -``` +See [field-name-commonAnnotations]. ### configMapGenerator - -Each entry in this list results in the creation of -one ConfigMap resource (it's a generator of n maps). - -The example below creates two ConfigMaps. One with the -names and contents of the given files, the other with -key/value as data. - -Each configMapGenerator item accepts a parameter of -`behavior: [create|replace|merge]`. -This allows an overlay to modify or -replace an existing configMap from the parent. - -``` -configMapGenerator: -- name: myJavaServerProps - files: - - application.properties - - more.properties -- name: myJavaServerEnvVars - literals: - - JAVA_HOME=/opt/java/jdk - - JAVA_TOOL_OPTIONS=-agentlib:hprof -``` - -It is also possible to [define a key](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-the-key-to-use-when-creating-a-configmap-from-a-file) to set a name different than the filename. - -The example below creates a ConfigMap with the name of file as `myFileName.ini` while the _actual_ filename from which the configmap is created is `whatever.ini`. - -``` -configMapGenerator: -- name: app-whatever - files: - - myFileName.ini=whatever.ini -``` +See [field-name-configMapGenerator]. ### crds @@ -155,9 +120,7 @@ The annotations can be put into openAPI definitions are: - "x-kubernetes-object-ref-kind": "Secret", - "x-kubernetes-object-ref-name-key": "name", - ``` - crds: - crds/typeA.yaml - crds/typeB.yaml @@ -195,42 +158,7 @@ generators: ### images -Images modify the name, tags and/or digest for images without creating patches. -E.g. Given this kubernetes Deployment fragment: - -``` -containers: - - name: mypostgresdb - image: postgres:8 - - name: nginxapp - image: nginx:1.7.9 - - name: myapp - image: my-demo-app:latest - - name: alpine-app - image: alpine:3.7 -``` - -one can change the `image` in the following ways: - - - `postgres:8` to `my-registry/my-postgres:v1`, - - nginx tag `1.7.9` to `1.8.0`, - - image name `my-demo-app` to `my-app`, - - alpine's tag `3.7` to a digest value - -all with the following *kustomization*: - -``` -images: -- name: postgres - newName: my-registry/my-postgres - newTag: v1 -- name: nginx - newTag: 1.8.0 -- name: my-demo-app - newName: my-app -- name: alpine - digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3 -``` +See [field-name-images]. ### inventory @@ -244,217 +172,33 @@ If missing, this field's value defaults to kind: Kustomization ``` - ### namespace -Adds namespace to all resources - -``` -namespace: my-namespace -``` +See [field-name-namespace]. ### namePrefix -Prepends value to the names of all resources -Ex. a deployment named `wordpress` would become `alices-wordpress` - -``` -namePrefix: alices- -``` +See [field-name-namePrefix]. ### nameSuffix -The value is appended to the names of all -resources. Ex. A deployment named `wordpress` -would become `wordpress-v2`. - -The suffix is appended before content has if -resource type is ConfigMap or Secret. - -``` -nameSuffix: -v2 -``` +See [field-name-nameSuffix]. ### patches -Each entry in this list should resolve to an Patch object, -which includes a patch and a target selector. -The patch can be either a strategic merge patch or a JSON patch. -it can be either a patch file or an inline string. -The target selects -resources by group, version, kind, name, namespace, -labelSelector and annotationSelector. A resource -which matches all the specified fields is selected -to apply the patch. - -``` -patches: -- path: patch.yaml - target: - group: apps - version: v1 - kind: Deployment - name: deploy.* - labelSelector: "env=dev" - annotationSelector: "zone=west" -- patch: |- - - op: replace - path: /some/existing/path - value: new value - target: - kind: MyKind - labelSelector: "env=dev" -``` - -The `name` and `namespace` fields of the patch target selector are -automatically anchored regular expressions. This means that the value `myapp` -is equivalent to `^myapp$`. +See [field-name-patches]. ### patchesStrategicMerge -Each entry in this list should be either a relative -file path or an inline content -resolving to a partial or complete resource -definition. - -The names in these (possibly partial) resource -files must match names already loaded via the -`resources` field. These entries are used to -_patch_ (modify) the known resources. - -Small patches that do one thing are best, e.g. modify -a memory request/limit, change an env var in a -ConfigMap, etc. Small patches are easy to review and -easy to mix together in overlays. - -``` -patchesStrategicMerge: -- service_port_8888.yaml -- deployment_increase_replicas.yaml -- deployment_increase_memory.yaml -``` - -The patch content can be a inline string as well. -``` -patchesStrategicMerge: -- |- - apiVersion: apps/v1 - kind: Deployment - metadata: - name: nginx - spec: - template: - spec: - containers: - - name: nginx - image: nignx:latest -``` - -Note that kustomize does not support more than one patch -for the same object that contain a _delete_ directive. To remove -several fields / slice elements from an object create a single -patch that performs all the needed deletions. +See [field-name-patchesStrategicMerge]. ### patchesJson6902 -Each entry in this list should resolve to -a kubernetes object and a JSON patch that will be applied -to the object. -The JSON patch is documented at https://tools.ietf.org/html/rfc6902 - -target field points to a kubernetes object within the same kustomization -by the object's group, version, kind, name and namespace. -path field is a relative file path of a JSON patch file. -The content in this patch file can be either in JSON format as - -``` - [ - {"op": "add", "path": "/some/new/path", "value": "value"}, - {"op": "replace", "path": "/some/existing/path", "value": "new value"} - ] - ``` - -or in YAML format as - -``` -- op: add - path: /some/new/path - value: value -- op: replace - path: /some/existing/path - value: new value -``` - -``` -patchesJson6902: -- target: - version: v1 - kind: Deployment - name: my-deployment - path: add_init_container.yaml -- target: - version: v1 - kind: Service - name: my-service - path: add_service_annotation.yaml -``` - -The patch content can be an inline string as well: - -``` -patchesJson6902: -- target: - version: v1 - kind: Deployment - name: my-deployment - patch: |- - - op: add - path: /some/new/path - value: value - - op: replace - path: /some/existing/path - value: "new value" -``` +See [field-name-patchesJson6902]. ### replicas -Replicas modified the number of replicas for a resource. - -E.g. Given this kubernetes Deployment fragment: - -``` -kind: Deployment -metadata: - name: deployment-name -spec: - replicas: 3 -``` - -one can change the number of replicas to 5 -by adding the following to your kustomization: - -``` -replicas: -- name: deployment-name - count: 5 -``` - -This field accepts a list, so many resources can -be modified at the same time. - - -#### Limitation - -As this declaration does not take in a `kind:` nor a `group:` -it will match any `group` and `kind` that has a matching name and -that is one of: -- `Deployment` -- `ReplicationController` -- `ReplicaSet` -- `StatefulSet` - -For more complex use cases, revert to using a patch. - +See [field-name-replicas]. ### resources @@ -492,28 +236,7 @@ must contain a `kustomization.yaml` file. ### secretGenerator -Each entry in this list results in the creation of -one Secret resource (it's a generator of n secrets). - -``` -secretGenerator: -- name: app-tls - files: - - secret/tls.cert - - secret/tls.key - type: "kubernetes.io/tls" -- name: app-tls-namespaced - # you can define a namespace to generate secret in, defaults to: "default" - namespace: apps - files: - - tls.crt=catsecret/tls.cert - - tls.key=secret/tls.key - type: "kubernetes.io/tls" -- name: env_file_secret - envs: - - env.txt - type: Opaque -``` +See [field-name-secretGenerator]. ### vars diff --git a/docs/plugins/builtins.md b/docs/plugins/builtins.md new file mode 100644 index 0000000000..1e48532616 --- /dev/null +++ b/docs/plugins/builtins.md @@ -0,0 +1,683 @@ + + +# Builtin Plugins + +A list of kustomize's builtin plugins (both +generators and transformers). + +For each plugin, an example is given for + +* implicitly triggering +the plugin via a dedicated kustomization +file field (e.g. the `AnnotationsTransformer` is +triggered by the `commonAnnotations` field). + +* explicitly triggering the plugin +via the `generators` or `transformers` field +(by providing a config file specifying the +plugin). + +The former method is convenient but limited in +power as most of the plugins arguments must +be defaulted. The latter method allows for +complete plugin argument specification. + + +[types.GeneratorOptions]: ../../pkg/types/generatoroptions.go +[types.SecretArgs]: ../../pkg/types/secretargs.go +[types.ConfigMapArgs]: ../../pkg/types/configmapargs.go +[config.FieldSpec]: ../../pkg/transformers/config/fieldspec.go +[types.ObjectMeta]: ../../pkg/types/objectmeta.go +[types.Selector]: ../../pkg/types/selector.go +[types.Replica]: ../../pkg/types/replica.go +[types.PatchStrategicMerge]: ../../pkg/types/patchstrategicmerge.go +[types.PatchTarget]: ../../pkg/types/patchtarget.go +[image.Image]: ../../pkg/image/image.go + +## _AnnotationTransformer_ +### Usage via `kustomization.yaml` + +#### field name: `commonAnnotations` + +Adds annotions (non-identifying metadata) to add +all resources. Like labels, these are key value +pairs. + +``` +commonAnnotations: + oncallPager: 800-555-1212 +``` + +### Usage via plugin +#### Arguments + +> Annotations map\[string\]string +> +> FieldSpecs \[\][config.FieldSpec] + +#### Example +> ``` +> apiVersion: builtin +> kind: AnnotationsTransformer +> metadata: +> name: not-important-to-example +> annotations: +> app: myApp +> greeting/morning: a string with blanks +> fieldSpecs: +> - path: metadata/annotations +> create: true +> ``` + + + +## _ConfigMapGenerator_ + +### Usage via `kustomization.yaml` + +#### field name: `configMapGenerator` + +Each entry in this list results in the creation of +one ConfigMap resource (it's a generator of n maps). + +The example below creates two ConfigMaps. One with the +names and contents of the given files, the other with +key/value as data. + +Each configMapGenerator item accepts a parameter of +`behavior: [create|replace|merge]`. +This allows an overlay to modify or +replace an existing configMap from the parent. + +``` +configMapGenerator: +- name: my-java-server-props + files: + - application.properties + - more.properties +- name: my-java-server-env-vars + literals: + - JAVA_HOME=/opt/java/jdk + - JAVA_TOOL_OPTIONS=-agentlib:hprof +``` + +It is also possible to +[define a key](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#define-the-key-to-use-when-creating-a-configmap-from-a-file) +to set a name different than the filename. + +The example below creates a ConfigMap +with the name of file as `myFileName.ini` +while the _actual_ filename from which the +configmap is created is `whatever.ini`. + +``` +configMapGenerator: +- name: app-whatever + files: + - myFileName.ini=whatever.ini +``` + +### Usage via plugin +#### Arguments + +> [types.GeneratorOptions] +> +> [types.ConfigMapArgs] + +#### Example +> ``` +> apiVersion: builtin +> kind: ConfigMapGenerator +> metadata: +> name: mymap +> envs: +> - devops.env +> - uxteam.env +> literals: +> - FRUIT=apple +> - VEGETABLE=carrot +> ``` + + +## _ImageTagTransformer_ +### Usage via `kustomization.yaml` + +#### field name: `image` + +Images modify the name, tags and/or digest for images +without creating patches. E.g. Given this +kubernetes Deployment fragment: + +``` +containers: +- name: mypostgresdb + image: postgres:8 +- name: nginxapp + image: nginx:1.7.9 +- name: myapp + image: my-demo-app:latest +- name: alpine-app + image: alpine:3.7 +``` + +one can change the `image` in the following ways: + + - `postgres:8` to `my-registry/my-postgres:v1`, + - nginx tag `1.7.9` to `1.8.0`, + - image name `my-demo-app` to `my-app`, + - alpine's tag `3.7` to a digest value + +all with the following *kustomization*: + +``` +images: +- name: postgres + newName: my-registry/my-postgres + newTag: v1 +- name: nginx + newTag: 1.8.0 +- name: my-demo-app + newName: my-app +- name: alpine + digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3 +``` + +### Usage via plugin +#### Arguments + +> ImageTag [image.Image] +> +> FieldSpecs \[\][config.FieldSpec] + +#### Example +> ``` +> apiVersion: builtin +> kind: ImageTagTransformer +> metadata: +> name: not-important-to-example +> imageTag: +> name: nginx +> newTag: v2 +> ``` + + + +## _LabelTransformer_ +### Usage via `kustomization.yaml` + +#### field name: `commonLabels` + +Adds labels to all resources and selectors + +``` +commonLabels: + someName: someValue + owner: alice + app: bingo +``` + +### Usage via plugin +#### Arguments + +> Labels map\[string\]string +> +> FieldSpecs \[\][config.FieldSpec] + +#### Example +> ``` +> apiVersion: builtin +> kind: LabelTransformer +> metadata: +> name: not-important-to-example +> labels: +> app: myApp +> env: production +> fieldSpecs: +> - path: metadata/labels +> create: true +> ``` + + + + + + + + +## _NamespaceTransformer_ +### Usage via `kustomization.yaml` + +#### field name: `namespace` + +Adds namespace to all resources + +``` +namespace: my-namespace +``` + +### Usage via plugin +#### Arguments + +> [types.ObjectMeta] +> +> FieldSpecs \[\][config.FieldSpec] + +#### Example +> ``` +> apiVersion: builtin +> kind: NamespaceTransformer +> metadata: +> name: not-important-to-example +> namespace: test +> fieldSpecs: +> - path: metadata/namespace +> create: true +> - path: subjects +> kind: RoleBinding +> group: rbac.authorization.k8s.io +> - path: subjects +> kind: ClusterRoleBinding +> group: rbac.authorization.k8s.io +> ``` + + + + + +## _PatchesJson6902_ +### Usage via `kustomization.yaml` + +#### field name: `patchesJson6902` + +Each entry in this list should resolve to +a kubernetes object and a JSON patch that will be applied +to the object. +The JSON patch is documented at https://tools.ietf.org/html/rfc6902 + +target field points to a kubernetes object within the same kustomization +by the object's group, version, kind, name and namespace. +path field is a relative file path of a JSON patch file. +The content in this patch file can be either in JSON format as + +``` + [ + {"op": "add", "path": "/some/new/path", "value": "value"}, + {"op": "replace", "path": "/some/existing/path", "value": "new value"} + ] + ``` + +or in YAML format as + +``` +- op: add + path: /some/new/path + value: value +- op: replace + path: /some/existing/path + value: new value +``` + +``` +patchesJson6902: +- target: + version: v1 + kind: Deployment + name: my-deployment + path: add_init_container.yaml +- target: + version: v1 + kind: Service + name: my-service + path: add_service_annotation.yaml +``` + +The patch content can be an inline string as well: + +``` +patchesJson6902: +- target: + version: v1 + kind: Deployment + name: my-deployment + patch: |- + - op: add + path: /some/new/path + value: value + - op: replace + path: /some/existing/path + value: "new value" +``` + +### Usage via plugin +#### Arguments +> Target [types.PatchTarget] +> +> Path string +> +> JsonOp string + +#### Example +> ``` +> apiVersion: builtin +> kind: PatchJson6902Transformer +> metadata: +> name: not-important-to-example +> target: +> group: apps +> version: v1 +> kind: Deployment +> name: my-deploy +> path: jsonpatch.json +> ``` + + +## _PatchesStrategicMerge_ +### Usage via `kustomization.yaml` + +#### field name: `patchesStrategicMerge` + +Each entry in this list should be either a relative +file path or an inline content +resolving to a partial or complete resource +definition. + +The names in these (possibly partial) resource +files must match names already loaded via the +`resources` field. These entries are used to +_patch_ (modify) the known resources. + +Small patches that do one thing are best, e.g. modify +a memory request/limit, change an env var in a +ConfigMap, etc. Small patches are easy to review and +easy to mix together in overlays. + +``` +patchesStrategicMerge: +- service_port_8888.yaml +- deployment_increase_replicas.yaml +- deployment_increase_memory.yaml +``` + +The patch content can be a inline string as well. +``` +patchesStrategicMerge: +- |- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: nginx + spec: + template: + spec: + containers: + - name: nginx + image: nignx:latest +``` + +Note that kustomize does not support more than one patch +for the same object that contain a _delete_ directive. To remove +several fields / slice elements from an object create a single +patch that performs all the needed deletions. + +### Usage via plugin + +#### Arguments + +> Paths \[\][types.PatchStrategicMerge] +> +> Patches string + + +#### Example +> ``` +> apiVersion: builtin +> kind: PatchStrategicMergeTransformer +> metadata: +> name: not-important-to-example +> paths: +> - patch.yaml +> ``` + + +## _PatchTransformer_ +### Usage via `kustomization.yaml` + +#### field name: `patches` + +Each entry in this list should resolve to an Patch +object, which includes a patch and a target selector. +The patch can be either a strategic merge patch or a +JSON patch. it can be either a patch file or an inline +string. The target selects +resources by group, version, kind, name, namespace, +labelSelector and annotationSelector. A resource +which matches all the specified fields is selected +to apply the patch. + +``` +patches: +- path: patch.yaml + target: + group: apps + version: v1 + kind: Deployment + name: deploy.* + labelSelector: "env=dev" + annotationSelector: "zone=west" +- patch: |- + - op: replace + path: /some/existing/path + value: new value + target: + kind: MyKind + labelSelector: "env=dev" +``` + +The `name` and `namespace` fields of the patch target selector are +automatically anchored regular expressions. This means that the value `myapp` +is equivalent to `^myapp$`. + +### Usage via plugin +#### Arguments + +> Path string +> +> Patch string +> +> Target \*[types.Selector] + +#### Example +> ``` +> apiVersion: builtin +> kind: PatchTransformer +> metadata: +> name: not-important-to-example +> patch: '[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "nginx:latest"}]' +> target: +> name: .*Deploy +> kind: Deployment +> ``` + + + + +## _PrefixSuffixTransformer_ +### Usage via `kustomization.yaml` + +#### field names: `namePrefix`, `nameSuffix` + +Prepends or postfixes the value to the names +of all resources. + +E.g. a deployment named `wordpress` could +become `alices-wordpress` or `wordpress-v2` +or `alices-wordpress-v2`. + +``` +namePrefix: alices- +nameSuffix: -v2 +``` + +The suffix is appended before the content hash if +the resource type is ConfigMap or Secret. + +### Usage via plugin +#### Arguments + +> Prefix string +> +> Suffix string +> +> FieldSpecs \[\][config.FieldSpec] + +#### Example +> ``` +> apiVersion: builtin +> kind: PrefixSuffixTransformer +> metadata: +> name: not-important-to-example +> prefix: baked- +> suffix: -pie +> fieldSpecs: +> - path: metadata/name +> ``` + + + +## _ReplicaCountTransformer_ +### Usage via `kustomization.yaml` + +#### field name: `replicas` + +Replicas modified the number of replicas for a resource. + +E.g. Given this kubernetes Deployment fragment: + +``` +kind: Deployment +metadata: + name: deployment-name +spec: + replicas: 3 +``` + +one can change the number of replicas to 5 +by adding the following to your kustomization: + +``` +replicas: +- name: deployment-name + count: 5 +``` + +This field accepts a list, so many resources can +be modified at the same time. + +As this declaration does not take in a `kind:` nor a `group:` +it will match any `group` and `kind` that has a matching name and +that is one of: +- `Deployment` +- `ReplicationController` +- `ReplicaSet` +- `StatefulSet` + +For more complex use cases, revert to using a patch. + +### Usage via plugin + +#### Arguments + +> Replica [types.Replica] +> +> FieldSpecs \[\][config.FieldSpec] + +#### Example +> ``` +> apiVersion: builtin +> kind: ReplicaCountTransformer +> metadata: +> name: not-important-to-example +> replica: +> name: myapp +> count: 23 +> fieldSpecs: +> - path: spec/replicas +> create: true +> kind: Deployment +> - path: spec/replicas +> create: true +> kind: ReplicationController +> ``` + + + +## _SecretGenerator_ + +### Usage via `kustomization.yaml` + +#### field name: `secretGenerator` + +Each entry in the argument list +results in the creation of +one Secret resource +(it's a generator of n secrets). + +``` +secretGenerator: +- name: app-tls + files: + - secret/tls.cert + - secret/tls.key + type: "kubernetes.io/tls" +- name: app-tls-namespaced + # you can define a namespace to generate + # a secret in, defaults to: "default" + namespace: apps + files: + - tls.crt=catsecret/tls.cert + - tls.key=secret/tls.key + type: "kubernetes.io/tls" +- name: env_file_secret + envs: + - env.txt + type: Opaque +``` + +### Usage via plugin + +#### Arguments + +> [types.ObjectMeta] +> +> [types.GeneratorOptions] +> +> [types.SecretArgs] + +#### Example + +> ``` +> apiVersion: builtin +> kind: SecretGenerator +> metadata: +> name: my-secret +> namespace: whatever +> behavior: merge +> envs: +> - a.env +> - b.env +> files: +> - obscure=longsecret.txt +> literals: +> - FRUIT=apple +> - VEGETABLE=carrot +> ``` diff --git a/examples/configureBuiltinPlugin.md b/examples/configureBuiltinPlugin.md new file mode 100644 index 0000000000..b5f5ef1616 --- /dev/null +++ b/examples/configureBuiltinPlugin.md @@ -0,0 +1,333 @@ +[builtin operations]: ../docs/plugins/builtins.md +[builtin plugins]: ../docs/plugins/builtins.md +[plugins]: ../docs/plugins +[plugin]: ../docs/plugins +[fields]: ../docs/fields.md +[fields in a kustomization file]: ../docs/fields.md +[TransformerConfig]: ../pkg/transformers/config/transformerconfig.go +[kustomization]: ../docs/glossary.md#kustomization + +# Customizing kustomize + +The [fields in a kustomization file] allow the user to +specify which resource files to use as input, how to +_generate_ new resources, and how to _transform_ those +resources - add labels, patch them, etc. + +These fields are simple (low argument count) directives. +For example, the `commonAnnotations` field demands only a +list of _name:value_ pairs. + +If using a field triggers behavior that pleases the user, +everyone's happy. + +If not, the user can ask for new behavior to be implemented +in kustomize proper (and wait), or the user can write a +transformer or generator [plugin]. This latter option +generally means writing code; a Go plugin, a Go binary, +a C++ binary, a `bash` script - something. + +There's a third option. If one merely wants to tweak +behavior that already exists in kustomize, one may be able +to do so by just writing some YAML. + +## Configure the builtin plugins + +All of kustomize's [builtin operations] are implemented +and usable as plugins. + +Using the fields is convenient and brief, but necessarily +specifies only part of the entire plugin specification. The +unspecified part is defaulted to what are hopefully +generally appealing values. + +If, instead, one invokes the plugins directly using the +`transformers` or `generators` field, one can (indeed +_must_) specify the entire plugin configuration. + +## Example: field vs plugin + +Define a place to work: + + +``` +DEMO_HOME=$(mktemp -d) +``` + +### Using the `commonLabels` and `commonAnnotations` fields + +In this simple example, we'll use just two resources: a deployment and a service. + +Define them: + + +``` +cat <$DEMO_HOME/deployment.yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment +spec: + replicas: 10 + template: + spec: + containers: + - name: the-container + image: monopole/hello:1 +EOF +``` + + +``` +cat <$DEMO_HOME/service.yaml +apiVersion: v1 +kind: Service +metadata: + name: service +spec: + type: LoadBalancer + ports: + - protocol: TCP + port: 8666 + targetPort: 8080 +EOF +``` + +Now make a kustomization file that causes them +to be read and transformed: + + +``` +cat <<'EOF' >$DEMO_HOME/kustomization.yaml +namePrefix: hello- +commonLabels: + app: hello +commonAnnotations: + area: "51" + greeting: Take me to your leader +resources: +- deployment.yaml +- service.yaml +EOF +``` + +And run kustomize: + + +``` +kustomize build $DEMO_HOME +``` + +The output will be something like + +> ``` +> apiVersion: v1 +> kind: Service +> metadata: +> annotations: +> area: "51" +> greeting: Take me to your leader +> labels: +> app: hello +> name: hello-service +> spec: +> ports: +> - port: 8666 +> protocol: TCP +> targetPort: 8080 +> selector: +> app: hello +> type: LoadBalancer +> --- +> apiVersion: apps/v1 +> kind: Deployment +> metadata: +> annotations: +> area: "51" +> greeting: Take me to your leader +> labels: +> app: hello +> name: hello-deployment +> spec: +> replicas: 10 +> selector: +> matchLabels: +> app: hello +> template: +> metadata: +> annotations: +> area: "51" +> greeting: Take me to your leader +> labels: +> app: hello +> spec: +> containers: +> - image: monopole/hello:1 +> name: the-container +> ``` + +Let's say we are unhappy with this result. + +We only want the annotations +to be applied down in the pod templates, +and don't want to see them in the metadata +for Service or Deployment. + +We like that the label _app: hello_ ended up in + + - Service `spec.selector` + - Deployment `spec.selector.matchLabels` + - Deployment `spec.template.metadata.labels` + +as this binds the Service (load balancer) to the pods, +and the Deployment itself to its own pods - +but we again don't care to see these labels in +the metadata for the Service and the Deployment. + + +### Configuring the builtin plugins instead + +To fine tune this, invoke the same transformations +using the plugin approach. + +Change the kustomization file: + + +``` +cat <<'EOF' >$DEMO_HOME/kustomization.yaml +namePrefix: hello- +transformers: +- myAnnotator.yaml +- myLabeller.yaml +resources: +- deployment.yaml +- service.yaml +EOF +``` + +Then make the two plugin configuration files +(`myAnnotator.yaml`, `myLabeller.yaml`) +referred to by the `transformers` field above. +For details about the fields to specify, see +the documentation for the [builtin plugins]. + + +``` +cat <$DEMO_HOME/myAnnotator.yaml +apiVersion: builtin +kind: AnnotationsTransformer +metadata: + name: notImportantHere +annotations: + area: 51 + greeting: take me to your leader +fieldSpecs: +- kind: Deployment + path: spec/template/metadata/annotations + create: true +EOF +``` + + +``` +cat <$DEMO_HOME/myLabeller.yaml +apiVersion: builtin +kind: LabelTransformer +metadata: + name: notImportantHere +labels: + app: hello +fieldSpecs: +- kind: Service + path: spec/selector + create: true +- kind: Deployment + path: spec/selector/matchLabels + create: true +- kind: Deployment + path: spec/template/metadata/labels + create: true +EOF +``` + +Finally, run kustomize again: + + +``` +kustomize build $DEMO_HOME +``` + +The output should resemble the following, +with fewer labels and annotations. + +> ``` +> apiVersion: v1 +> kind: Service +> metadata: +> name: hello-service +> spec: +> ports: +> - port: 8666 +> protocol: TCP +> targetPort: 8080 +> selector: +> app: hello +> type: LoadBalancer +> --- +> apiVersion: apps/v1 +> kind: Deployment +> metadata: +> name: hello-deployment +> spec: +> replicas: 10 +> selector: +> matchLabels: +> app: hello +> template: +> metadata: +> annotations: +> area: "51" +> greeting: take me to your leader +> labels: +> app: hello +> spec: +> containers: +> - image: monopole/hello:1 +> name: the-container +> ``` + + +## The old way to do this + +The original (and still functional) way to customize +kustomize is to specify a `configurations` field in the +kustomization file. + +This field, normally omitted because it overrides hardcoded +data, accepts a list of file path arguments. The files, in +turn, specify which fields in which k8s objects should be +affected by particular builtin transformations. It's a +global configuration cutting across transformations, and +doesn't effect generators at all. + +At `build` time, the configuration files are unmarshalled +into one instance of [TransformerConfig]. This +object, _plus_ the field values for `namePrefix`, etc. are +fed into the transformation code to build the output. + +The best way to write these custom configuration files is to +generate the files from the hardcoded values built into +kustomize via these commands: + +> ``` +> mkdir /tmp/junk +> kustomize config save -d /tmp/junk +> ``` + +One can then edit those file or files, and specify the +resulting edited files in a `configurations:` +field in a kustomization file used in a `build`. + +Using plugins _completely ignores_ both hard coded +tranformer configuration, and any configuration loaded by +the `configuration` field. diff --git a/pkg/image/image.go b/pkg/image/image.go index dbe3b8b175..dbf1ab95be 100644 --- a/pkg/image/image.go +++ b/pkg/image/image.go @@ -1,18 +1,5 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 // Package image provides struct definitions and libraries // for image overwriting of names, tags and digest. diff --git a/pkg/types/configmapargs.go b/pkg/types/configmapargs.go new file mode 100644 index 0000000000..69877769fb --- /dev/null +++ b/pkg/types/configmapargs.go @@ -0,0 +1,10 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +// ConfigMapArgs contains the metadata of how to generate a configmap. +type ConfigMapArgs struct { + // GeneratorArgs for the configmap. + GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"` +} diff --git a/pkg/types/generatorargs.go b/pkg/types/generatorargs.go new file mode 100644 index 0000000000..b5fc7ec826 --- /dev/null +++ b/pkg/types/generatorargs.go @@ -0,0 +1,54 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +// GeneratorArgs contains arguments common to generators. +type GeneratorArgs struct { + // Namespace for the configmap, optional + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + + // Name - actually the partial name - of the generated resource. + // The full name ends up being something like + // NamePrefix + this.Name + hash(content of generated resource). + Name string `json:"name,omitempty" yaml:"name,omitempty"` + + // Behavior of generated resource, must be one of: + // 'create': create a new one + // 'replace': replace the existing one + // 'merge': merge with the existing one + Behavior string `json:"behavior,omitempty" yaml:"behavior,omitempty"` + + // DataSources for the generator. + DataSources `json:",inline,omitempty" yaml:",inline,omitempty"` +} + +// DataSources contains some generic sources for generators. +type DataSources struct { + // LiteralSources is a list of literal + // pair sources. Each literal source should + // be a key and literal value, e.g. `key=value` + LiteralSources []string `json:"literals,omitempty" yaml:"literals,omitempty"` + + // FileSources is a list of file "sources" to + // use in creating a list of key, value pairs. + // A source takes the form: [{key}=]{path} + // If the "key=" part is missing, the key is the + // path's basename. If they "key=" part is present, + // it becomes the key (replacing the basename). + // In either case, the value is the file contents. + // Specifying a directory will iterate each named + // file in the directory whose basename is a + // valid configmap key. + FileSources []string `json:"files,omitempty" yaml:"files,omitempty"` + + // EnvSources is a list of file paths. + // The contents of each file should be one + // key=value pair per line, e.g. a Docker + // or npm ".env" file or a ".ini" file + // (wikipedia.org/wiki/INI_file) + EnvSources []string `json:"envs,omitempty" yaml:"envs,omitempty"` + + // Deprecated. Use EnvSources instead. + EnvSource string `json:"env,omitempty" yaml:"env,omitempty"` +} diff --git a/pkg/types/generatoroptions.go b/pkg/types/generatoroptions.go new file mode 100644 index 0000000000..82778efc18 --- /dev/null +++ b/pkg/types/generatoroptions.go @@ -0,0 +1,18 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +// GeneratorOptions modify behavior of all ConfigMap and Secret generators. +type GeneratorOptions struct { + // Labels to add to all generated resources. + Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` + + // Annotations to add to all generated resources. + Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` + + // DisableNameSuffixHash if true disables the default behavior of adding a + // suffix to the names of generated resources that is a hash of the + // resource contents. + DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"` +} diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index 7104ad3351..c38e889c17 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -5,7 +5,6 @@ package types import ( - "sigs.k8s.io/kustomize/v3/pkg/gvk" "sigs.k8s.io/kustomize/v3/pkg/image" ) @@ -21,13 +20,6 @@ type TypeMeta struct { APIVersion string `json:"apiVersion,omitempty" yaml:"apiversion,omitempty"` } -// ObjectMeta partially copies apimachinery/pkg/apis/meta/v1.ObjectMeta -// No need for a direct dependence; the fields are stable. -type ObjectMeta struct { - Name string `json:"name,omitempty" yaml:"name,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` -} - // Kustomization holds the information needed to generate customized k8s api resources. type Kustomization struct { TypeMeta `json:",inline" yaml:",inline"` @@ -193,26 +185,6 @@ func (k *Kustomization) EnforceFields() []string { return errs } -// GeneratorArgs contains arguments common to generators. -type GeneratorArgs struct { - // Namespace for the configmap, optional - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - - // Name - actually the partial name - of the generated resource. - // The full name ends up being something like - // NamePrefix + this.Name + hash(content of generated resource). - Name string `json:"name,omitempty" yaml:"name,omitempty"` - - // Behavior of generated resource, must be one of: - // 'create': create a new one - // 'replace': replace the existing one - // 'merge': merge with the existing one - Behavior string `json:"behavior,omitempty" yaml:"behavior,omitempty"` - - // DataSources for the generator. - DataSources `json:",inline,omitempty" yaml:",inline,omitempty"` -} - // PluginConfig holds plugin configuration. type PluginConfig struct { // DirectoryPath is an absolute path to a @@ -225,77 +197,12 @@ type PluginConfig struct { Enabled bool } -// ConfigMapArgs contains the metadata of how to generate a configmap. -type ConfigMapArgs struct { - // GeneratorArgs for the configmap. - GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"` -} - // Pair is a key value pair. type Pair struct { Key string Value string } -// SecretArgs contains the metadata of how to generate a secret. -type SecretArgs struct { - // GeneratorArgs for the secret. - GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"` - - // Type of the secret. - // - // This is the same field as the secret type field in v1/Secret: - // It can be "Opaque" (default), or "kubernetes.io/tls". - // - // If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two - // keys: "tls.key" and "tls.crt" - Type string `json:"type,omitempty" yaml:"type,omitempty"` -} - -// DataSources contains some generic sources for configmaps. -type DataSources struct { - // LiteralSources is a list of literal - // pair sources. Each literal source should - // be a key and literal value, e.g. `key=value` - LiteralSources []string `json:"literals,omitempty" yaml:"literals,omitempty"` - - // FileSources is a list of file "sources" to - // use in creating a list of key, value pairs. - // A source takes the form: [{key}=]{path} - // If the "key=" part is missing, the key is the - // path's basename. If they "key=" part is present, - // it becomes the key (replacing the basename). - // In either case, the value is the file contents. - // Specifying a directory will iterate each named - // file in the directory whose basename is a - // valid configmap key. - FileSources []string `json:"files,omitempty" yaml:"files,omitempty"` - - // EnvSources is a list of file paths. - // The contents of each file should be one - // key=value pair per line, e.g. a Docker - // or npm ".env" file or a ".ini" file - // (wikipedia.org/wiki/INI_file) - EnvSources []string `json:"envs,omitempty" yaml:"envs,omitempty"` - - // Deprecated. Use EnvSources instead. - EnvSource string `json:"env,omitempty" yaml:"env,omitempty"` -} - -// GeneratorOptions modify behavior of all ConfigMap and Secret generators. -type GeneratorOptions struct { - // Labels to add to all generated resources. - Labels map[string]string `json:"labels,omitempty" yaml:"labels,omitempty"` - - // Annotations to add to all generated resources. - Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"` - - // DisableNameSuffixHash if true disables the default behavior of adding a - // suffix to the names of generated resources that is a hash of the - // resource contents. - DisableNameSuffixHash bool `json:"disableNameSuffixHash,omitempty" yaml:"disableNameSuffixHash,omitempty"` -} - type PluginType string func (p PluginType) IsUndefined() bool { @@ -336,30 +243,6 @@ type PatchJson6902 struct { Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` } -// PatchTarget represents the kubernetes object that the patch is applied to -type PatchTarget struct { - gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name" yaml:"name"` -} - -// PatchStrategicMerge represents a relative path to a -// stategic merge patch with the format -// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md -type PatchStrategicMerge string - -// Replica specifies a modification to a replica config. -// The number of replicas of a resource whose name matches will be set to count. -// This struct is used by the ReplicaCountTransform, and is meant to supplement -// the existing patch functionality with a simpler syntax for replica configuration. -type Replica struct { - // The name of the resource to change the replica count - Name string `json:"name,omitempty" yaml:"name,omitempty"` - - // The number of replicas required. - Count int64 `json:"count,omitempty" yaml:"count,omitempty"` -} - // Patch represent either a Strategic Merge Patch or a JSON patch // and its targets. // The content of the patch can either be from a file @@ -374,22 +257,3 @@ type Patch struct { // Target points to the resources that the patch is applied to Target *Selector `json:"target,omitempty" yaml:"target,omitempty"` } - -// Selector specifies a set of resources. -// Any resource that matches intersection of all conditions -// is included in this set. -type Selector struct { - gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - - // AnnotationSelector is a string that follows the label selection expression - // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api - // It matches with the resource annotations. - AnnotationSelector string `json:"annotationSelector,omitempty" yaml:"annotationSelector,omitempty"` - - // LabelSelector is a string that follows the label selection expression - // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api - // It matches with the resource labels. - LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"` -} diff --git a/pkg/types/objectmeta.go b/pkg/types/objectmeta.go new file mode 100644 index 0000000000..00f5333435 --- /dev/null +++ b/pkg/types/objectmeta.go @@ -0,0 +1,11 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +// ObjectMeta partially copies apimachinery/pkg/apis/meta/v1.ObjectMeta +// No need for a direct dependence; the fields are stable. +type ObjectMeta struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` +} diff --git a/pkg/types/patchstrategicmerge.go b/pkg/types/patchstrategicmerge.go new file mode 100644 index 0000000000..c5aca319e3 --- /dev/null +++ b/pkg/types/patchstrategicmerge.go @@ -0,0 +1,9 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +// PatchStrategicMerge represents a relative path to a +// stategic merge patch with the format +// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md +type PatchStrategicMerge string diff --git a/pkg/types/patchtarget.go b/pkg/types/patchtarget.go new file mode 100644 index 0000000000..b3492515c5 --- /dev/null +++ b/pkg/types/patchtarget.go @@ -0,0 +1,13 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +import "sigs.k8s.io/kustomize/v3/pkg/gvk" + +// PatchTarget represents the kubernetes object that the patch is applied to +type PatchTarget struct { + gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"` + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + Name string `json:"name" yaml:"name"` +} diff --git a/pkg/types/replica.go b/pkg/types/replica.go new file mode 100644 index 0000000000..18da6b734a --- /dev/null +++ b/pkg/types/replica.go @@ -0,0 +1,16 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +// Replica specifies a modification to a replica config. +// The number of replicas of a resource whose name matches will be set to count. +// This struct is used by the ReplicaCountTransform, and is meant to supplement +// the existing patch functionality with a simpler syntax for replica configuration. +type Replica struct { + // The name of the resource to change the replica count + Name string `json:"name,omitempty" yaml:"name,omitempty"` + + // The number of replicas required. + Count int64 `json:"count,omitempty" yaml:"count,omitempty"` +} diff --git a/pkg/types/secretargs.go b/pkg/types/secretargs.go new file mode 100644 index 0000000000..62dbe26a73 --- /dev/null +++ b/pkg/types/secretargs.go @@ -0,0 +1,19 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +// SecretArgs contains the metadata of how to generate a secret. +type SecretArgs struct { + // GeneratorArgs for the secret. + GeneratorArgs `json:",inline,omitempty" yaml:",inline,omitempty"` + + // Type of the secret. + // + // This is the same field as the secret type field in v1/Secret: + // It can be "Opaque" (default), or "kubernetes.io/tls". + // + // If type is "kubernetes.io/tls", then "literals" or "files" must have exactly two + // keys: "tls.key" and "tls.crt" + Type string `json:"type,omitempty" yaml:"type,omitempty"` +} diff --git a/pkg/types/selector.go b/pkg/types/selector.go new file mode 100644 index 0000000000..76d433e217 --- /dev/null +++ b/pkg/types/selector.go @@ -0,0 +1,25 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package types + +import "sigs.k8s.io/kustomize/v3/pkg/gvk" + +// Selector specifies a set of resources. +// Any resource that matches intersection of all conditions +// is included in this set. +type Selector struct { + gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"` + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + + // AnnotationSelector is a string that follows the label selection expression + // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + // It matches with the resource annotations. + AnnotationSelector string `json:"annotationSelector,omitempty" yaml:"annotationSelector,omitempty"` + + // LabelSelector is a string that follows the label selection expression + // https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api + // It matches with the resource labels. + LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"` +} diff --git a/plugin/builtin/PrefixSuffixTransformer.go b/plugin/builtin/PrefixSuffixTransformer.go index db4af420c4..a4a6d4325c 100644 --- a/plugin/builtin/PrefixSuffixTransformer.go +++ b/plugin/builtin/PrefixSuffixTransformer.go @@ -26,6 +26,9 @@ var prefixSuffixFieldSpecsToSkip = []config.FieldSpec{ { Gvk: gvk.Gvk{Kind: "CustomResourceDefinition"}, }, + { + Gvk: gvk.Gvk{Group: "apiregistration.k8s.io", Kind: "APIService"}, + }, } func (p *PrefixSuffixTransformerPlugin) Config(