From 7b82154c4c2915b9b91512ca4b426aa8181e45d3 Mon Sep 17 00:00:00 2001 From: Karen Bradshaw Date: Thu, 7 Mar 2019 10:14:07 -0500 Subject: [PATCH 01/10] correct spelling, minor word ordering --- examples/transformerconfigs/README.md | 63 ++++++++++++++++----------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/examples/transformerconfigs/README.md b/examples/transformerconfigs/README.md index 292cc3e4b..ab93ab595 100644 --- a/examples/transformerconfigs/README.md +++ b/examples/transformerconfigs/README.md @@ -1,6 +1,7 @@ # Transformer Configurations -Kustomize computes the resources by applying a series of transformers: +Kustomize computes the configuration of a resource by applying a series of transformers: + - namespace transformer - prefix/suffix transformer - label transformer @@ -8,30 +9,36 @@ Kustomize computes the resources by applying a series of transformers: - name reference transformer - variable reference transformer -Each transformer takes a list of resources and modifies certain fields. The modification is based on the transformer's rule. -The fields to update is the transformer's configuration, which is a list of filedspec that can be represented in YAML format. +Each transformer takes a list of resources and modifies certain fields in the resource based upon the transformer's configuration. A transformer's configuration is a list of `fieldSpec`, represented in YAML format. -## fieldSpec -FieldSpec is a type to represent a path to a field in one kind of resources. It has following format -``` +## FieldSpec + +FieldSpec is a type that represents a path to a field in a resource such as `Job`. Here is the `fieldSpec` format: + +```yaml group: some-group version: some-version kind: some-kind path: path/to/the/field create: false ``` -If `create` is set to true, it indicates the transformer to create the path if it is not found in the resources. This is most useful for label and annotation transformers, where the path for labels or annotations may not be set before the transformation. -## prefix/suffix transformer -Name prefix suffix transformer adds prefix and suffix to the `metadata/name` field for all resources with following configuration: -``` +If `create` is set to `true`, the transformer creates the path to the field in the resource if the path is not already found. This is most useful for label and annotation transformers, where the path for labels or annotations may not be set before the transformation. + +## Prefix/suffix transformer + +The prefix/suffix transformer adds a prefix/suffix to the `metadata/name` field for all resources. Here is an example of a prefix transformer configuration: + +```yaml namePrefix: - path: metadata/name ``` -## label transformer -Label transformer adds labels to `metadata/labels` field for all resources. It also adds labels to `spec/selector` field in all Service and to `spec/selector/matchLabels` field in all Deployment. -``` +## Label transformer + +The label transformer adds labels to the `metadata/labels` field for all resources. It also adds labels to the `spec/selector` field in all Service resources as well as the `spec/selector/matchLabels` field in all Deployment resources. + +```yaml commonLabels: - path: metadata/labels create: true @@ -44,15 +51,17 @@ commonLabels: - path: spec/selector/matchLabels create: true kind: Deployment - (etc.) +# add additional paths to resource fields ``` -## name reference transformer -Name reference transformer's configuration is different from all other transformers. It contains a list of namebackreferences, which represented all the possible fields that a type could be used as a reference in other types of resources. A namebackreference contains a type such as ConfigMap as well as a list of FieldSpecs where ConfigMap is referenced. Here is an example. -``` +## Name reference transformer + +Name reference transformer's configuration is different from all other transformers. It contains a list of `nameReferences`, which represent all of the possible fields that a type could be used as a reference in other types of resources. A `nameReference` contains a type such as ConfigMap as well as a list of `fieldSpecs` where ConfigMap is referenced in other resources. Here is an example. + +```yaml kind: ConfigMap version: v1 -FieldSpecs: +fieldSpecs: - kind: Pod version: v1 path: spec/volumes/configMap/name @@ -60,10 +69,12 @@ FieldSpecs: path: spec/template/spec/volumes/configMap/name - kind: Job path: spec/template/spec/volumes/configMap/name - (etc.) -``` -Name reference transformer configuration contains a list of such namebackreferences for ConfigMap, Secret, Service, Role, ServiceAccount and so on. +# add additional paths to resource fields ``` + +Name reference transformer's configuration contains a list of `nameReferences` for resources such as ConfigMap, Secret, Service, Role, and ServiceAccount. Here is an example configuration: + +```yaml nameReference: - kind: ConfigMap version: v1 @@ -74,7 +85,7 @@ nameReference: - path: spec/containers/env/valueFrom/configMapKeyRef/name version: v1 kind: Pod - (etc.) + # add additional paths to resource fields - kind: Secret version: v1 fieldSpecs: @@ -84,12 +95,14 @@ nameReference: - path: spec/containers/env/valueFrom/secretKeyRef/name version: v1 kind: Pod - (etc.) + # add additional paths to resource fields ``` -## customizing transformer configurations +## Customizing transformer configurations + +Kustomize has a default set of transformer configurations. You can save the default transformer configurations +to a local directory by calling `kustomize config save -d`. Kustomize allows modifying those configuration files and using them in a kustomization.yaml file. This tutorial shows how to customize those configurations to: -Kustomize has a default set of configurations. They can be saved to local directory through `kustomize config save -d`. Kustomize allows modifying those configuration files and using them in kustomization.yaml file. This tutorial shows how to customize those configurations to - [support a CRD type](crd/README.md) - add extra fields for variable substitution - add extra fields for name reference From 942e36e19f8c1ef310f60135a843f4fb9c98f109 Mon Sep 17 00:00:00 2001 From: Karen Bradshaw Date: Tue, 12 Mar 2019 21:18:18 -0400 Subject: [PATCH 02/10] a few more changes --- examples/transformerconfigs/README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/transformerconfigs/README.md b/examples/transformerconfigs/README.md index ab93ab595..536978aaf 100644 --- a/examples/transformerconfigs/README.md +++ b/examples/transformerconfigs/README.md @@ -13,7 +13,7 @@ Each transformer takes a list of resources and modifies certain fields in the re ## FieldSpec -FieldSpec is a type that represents a path to a field in a resource such as `Job`. Here is the `fieldSpec` format: +FieldSpec is a type that represents a path to a field in one kind of resource, such as `Job`. ```yaml group: some-group @@ -27,7 +27,7 @@ If `create` is set to `true`, the transformer creates the path to the field in t ## Prefix/suffix transformer -The prefix/suffix transformer adds a prefix/suffix to the `metadata/name` field for all resources. Here is an example of a prefix transformer configuration: +The prefix/suffix transformer adds a prefix/suffix to the `metadata/name` field for all resources. Here is the default prefix transformer configuration: ```yaml namePrefix: @@ -51,7 +51,6 @@ commonLabels: - path: spec/selector/matchLabels create: true kind: Deployment -# add additional paths to resource fields ``` ## Name reference transformer @@ -69,7 +68,6 @@ fieldSpecs: path: spec/template/spec/volumes/configMap/name - kind: Job path: spec/template/spec/volumes/configMap/name -# add additional paths to resource fields ``` Name reference transformer's configuration contains a list of `nameReferences` for resources such as ConfigMap, Secret, Service, Role, and ServiceAccount. Here is an example configuration: @@ -95,13 +93,13 @@ nameReference: - path: spec/containers/env/valueFrom/secretKeyRef/name version: v1 kind: Pod - # add additional paths to resource fields ``` ## Customizing transformer configurations -Kustomize has a default set of transformer configurations. You can save the default transformer configurations -to a local directory by calling `kustomize config save -d`. Kustomize allows modifying those configuration files and using them in a kustomization.yaml file. This tutorial shows how to customize those configurations to: +Kustomize has a default set of transformer configurations. You can view the default transformer configurations by saving them to a local directory by calling kustomize config save -d. + +Kustomize also supports adding extra transformer configurations by adding configuration files in the kustomization.yaml file. This tutorial shows how to customize those configurations to: - [support a CRD type](crd/README.md) - add extra fields for variable substitution From 65886f12581c106b20a8ffc7c0401b19e5b4e829 Mon Sep 17 00:00:00 2001 From: Karen Bradshaw Date: Fri, 15 Mar 2019 16:34:47 -0400 Subject: [PATCH 03/10] address comments --- examples/transformerconfigs/README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/examples/transformerconfigs/README.md b/examples/transformerconfigs/README.md index 536978aaf..293ae7332 100644 --- a/examples/transformerconfigs/README.md +++ b/examples/transformerconfigs/README.md @@ -1,19 +1,21 @@ # Transformer Configurations -Kustomize computes the configuration of a resource by applying a series of transformers: +Kustomize creates new resources by applying a series of transformations to an original +set of resources. Kustomize provides the following default transformers: -- namespace transformer -- prefix/suffix transformer -- label transformer -- annotation transformer -- name reference transformer -- variable reference transformer +- namespace +- prefix/suffix +- label +- annotation +- name reference +- variable reference -Each transformer takes a list of resources and modifies certain fields in the resource based upon the transformer's configuration. A transformer's configuration is a list of `fieldSpec`, represented in YAML format. +A `fieldSpec` list, in a transformer's configuration, determines which resource types and which fields +within those types the transformer can modify. ## FieldSpec -FieldSpec is a type that represents a path to a field in one kind of resource, such as `Job`. +FieldSpec is a type that represents a path to a field in one kind of resource. ```yaml group: some-group @@ -97,10 +99,8 @@ nameReference: ## Customizing transformer configurations -Kustomize has a default set of transformer configurations. You can view the default transformer configurations by saving them to a local directory by calling kustomize config save -d. - -Kustomize also supports adding extra transformer configurations by adding configuration files in the kustomization.yaml file. This tutorial shows how to customize those configurations to: +Kustomize has a default set of transformer configurations. You can save the default transformer configurations to a local directory by calling `kustomize config save -d`, and then modify and use these configurations. Kustomize also supports adding new transformer configurations to kustomization.yaml. This tutorial shows how to customize those configurations to: - [support a CRD type](crd/README.md) - add extra fields for variable substitution -- add extra fields for name reference +- add extra fields for name reference \ No newline at end of file From f850ca63f4311712a1b7f1d39dd7ccfefaa2c139 Mon Sep 17 00:00:00 2001 From: Karen Bradshaw Date: Sat, 16 Mar 2019 16:49:16 -0400 Subject: [PATCH 04/10] remove extra comment --- examples/transformerconfigs/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/transformerconfigs/README.md b/examples/transformerconfigs/README.md index 293ae7332..dcab70902 100644 --- a/examples/transformerconfigs/README.md +++ b/examples/transformerconfigs/README.md @@ -57,7 +57,7 @@ commonLabels: ## Name reference transformer -Name reference transformer's configuration is different from all other transformers. It contains a list of `nameReferences`, which represent all of the possible fields that a type could be used as a reference in other types of resources. A `nameReference` contains a type such as ConfigMap as well as a list of `fieldSpecs` where ConfigMap is referenced in other resources. Here is an example. +Name reference transformer's configuration is different from all other transformers. It contains a list of `nameReferences`, which represent all of the possible fields that a type could be used as a reference in other types of resources. A `nameReference` contains a type such as ConfigMap as well as a list of `fieldSpecs` where ConfigMap is referenced in other resources. Here is an example: ```yaml kind: ConfigMap @@ -85,7 +85,7 @@ nameReference: - path: spec/containers/env/valueFrom/configMapKeyRef/name version: v1 kind: Pod - # add additional paths to resource fields + # ... - kind: Secret version: v1 fieldSpecs: @@ -99,7 +99,7 @@ nameReference: ## Customizing transformer configurations -Kustomize has a default set of transformer configurations. You can save the default transformer configurations to a local directory by calling `kustomize config save -d`, and then modify and use these configurations. Kustomize also supports adding new transformer configurations to kustomization.yaml. This tutorial shows how to customize those configurations to: +Kustomize has a default set of transformer configurations. You can save the default transformer configurations to a local directory by calling `kustomize config save -d`, and modify and use these configurations. Kustomize also supports adding new transformer configurations to kustomization.yaml. This tutorial shows how to customize those configurations to: - [support a CRD type](crd/README.md) - add extra fields for variable substitution From 5c4719651ef39f94452ebf10283daf0dd2cf368e Mon Sep 17 00:00:00 2001 From: Seth Pollack Date: Sat, 16 Mar 2019 20:46:37 -0400 Subject: [PATCH 05/10] honor XDG_CONFIG_HOME --- k8sdeps/kv/plugin/goplugin.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/k8sdeps/kv/plugin/goplugin.go b/k8sdeps/kv/plugin/goplugin.go index d316a76cd..09351fa1a 100644 --- a/k8sdeps/kv/plugin/goplugin.go +++ b/k8sdeps/kv/plugin/goplugin.go @@ -25,7 +25,7 @@ import ( var _ Factory = &goFactory{} const ( - dir = "$HOME/.config/kustomize/plugins/kvsource" + pluginDir = "kustomize/plugins/kvsource" ) func newGoFactory() *goFactory { @@ -38,12 +38,20 @@ type goFactory struct { plugins map[string]KVSource } +func configDir() string { + xdghome := os.Getenv("XDG_CONFIG_HOME") + if len(xdghome) == 0 { + return os.ExpandEnv("$HOME/.config") + } + return xdghome +} + func (p *goFactory) load(name string) (KVSource, error) { if plug, ok := p.plugins[name]; ok { return plug, nil } - goPlugin, err := plugin.Open(fmt.Sprintf("%s/kustomize-%s.so", os.ExpandEnv(dir), name)) + goPlugin, err := plugin.Open(fmt.Sprintf("%s/%s/kustomize-%s.so", configDir(), pluginDir, name)) if err != nil { return nil, err } From 3011f18047210dd4668517780f5279ad46289090 Mon Sep 17 00:00:00 2001 From: Jesse Dubay Date: Sat, 16 Mar 2019 19:11:42 -0700 Subject: [PATCH 06/10] Sort default varReference config by kind, path --- .../config/defaultconfig/varreference.go | 200 +++++++++--------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/pkg/transformers/config/defaultconfig/varreference.go b/pkg/transformers/config/defaultconfig/varreference.go index 77bffbeda..cead95708 100644 --- a/pkg/transformers/config/defaultconfig/varreference.go +++ b/pkg/transformers/config/defaultconfig/varreference.go @@ -19,98 +19,68 @@ package defaultconfig const ( varReferenceFieldSpecs = ` varReference: -- path: spec/template/spec/initContainers/command - kind: StatefulSet - -- path: spec/template/spec/containers/command - kind: StatefulSet - -- path: spec/template/spec/initContainers/command - kind: Deployment - -- path: spec/template/spec/containers/command - kind: Deployment - -- path: spec/template/spec/initContainers/command - kind: DaemonSet - -- path: spec/template/spec/containers/command - kind: DaemonSet - -- path: spec/template/spec/containers/command - kind: Job +- path: spec/jobTemplate/spec/template/spec/containers/args + kind: CronJob - path: spec/jobTemplate/spec/template/spec/containers/command kind: CronJob -- path: spec/template/spec/initContainers/args - kind: StatefulSet - -- path: spec/template/spec/containers/args - kind: StatefulSet - -- path: spec/template/spec/initContainers/args - kind: Deployment - -- path: spec/template/spec/containers/args - kind: Deployment - -- path: spec/template/spec/initContainers/args - kind: DaemonSet - -- path: spec/template/spec/containers/args - kind: DaemonSet - -- path: spec/template/spec/containers/args - kind: Job - -- path: spec/jobTemplate/spec/template/spec/containers/args - kind: CronJob - -- path: spec/template/spec/initContainers/env/value - kind: StatefulSet - -- path: spec/template/spec/containers/env/value - kind: StatefulSet - -- path: spec/template/spec/initContainers/env/value - kind: Deployment - -- path: spec/template/spec/containers/env/value - kind: Deployment - -- path: spec/template/spec/initContainers/env/value - kind: DaemonSet - -- path: spec/template/spec/containers/env/value - kind: DaemonSet - -- path: spec/template/spec/containers/env/value - kind: Job - -- path: spec/template/spec/initContainers/env/value - kind: Job - - path: spec/jobTemplate/spec/template/spec/containers/env/value kind: CronJob -- path: spec/containers/command - kind: Pod +- path: spec/template/spec/containers/volumeMounts/mountPath + kind: CronJob -- path: spec/containers/args - kind: Pod +- path: spec/template/spec/initContainers/volumeMounts/mountPath + kind: CronJob -- path: spec/containers/env/value - kind: Pod +- path: spec/template/spec/containers/args + kind: DaemonSet -- path: spec/initContainers/command - kind: Pod +- path: spec/template/spec/containers/command + kind: DaemonSet -- path: spec/initContainers/args - kind: Pod +- path: spec/template/spec/containers/env/value + kind: DaemonSet -- path: spec/initContainers/env/value - kind: Pod +- path: spec/template/spec/containers/volumeMounts/mountPath + kind: DaemonSet + +- path: spec/template/spec/initContainers/args + kind: DaemonSet + +- path: spec/template/spec/initContainers/command + kind: DaemonSet + +- path: spec/template/spec/initContainers/env/value + kind: DaemonSet + +- path: spec/template/spec/initContainers/volumeMounts/mountPath + kind: DaemonSet + +- path: spec/template/spec/containers/args + kind: Deployment + +- path: spec/template/spec/containers/command + kind: Deployment + +- path: spec/template/spec/containers/env/value + kind: Deployment + +- path: spec/template/spec/containers/volumeMounts/mountPath + kind: Deployment + +- path: spec/template/spec/initContainers/args + kind: Deployment + +- path: spec/template/spec/initContainers/command + kind: Deployment + +- path: spec/template/spec/initContainers/env/value + kind: Deployment + +- path: spec/template/spec/initContainers/volumeMounts/mountPath + kind: Deployment - path: spec/rules/host kind: Ingress @@ -118,15 +88,45 @@ varReference: - path: spec/tls/hosts kind: Ingress +- path: spec/template/spec/containers/args + kind: Job + +- path: spec/template/spec/containers/command + kind: Job + +- path: spec/template/spec/containers/env/value + kind: Job + - path: spec/template/spec/containers/volumeMounts/mountPath - kind: StatefulSet + kind: Job + +- path: spec/template/spec/initContainers/env/value + kind: Job - path: spec/template/spec/initContainers/volumeMounts/mountPath - kind: StatefulSet + kind: Job + +- path: spec/containers/args + kind: Pod + +- path: spec/containers/command + kind: Pod + +- path: spec/containers/env/value + kind: Pod - path: spec/containers/volumeMounts/mountPath kind: Pod +- path: spec/initContainers/args + kind: Pod + +- path: spec/initContainers/command + kind: Pod + +- path: spec/initContainers/env/value + kind: Pod + - path: spec/initContainers/volumeMounts/mountPath kind: Pod @@ -136,29 +136,29 @@ varReference: - path: spec/template/spec/initContainers/volumeMounts/mountPath kind: ReplicaSet -- path: spec/template/spec/containers/volumeMounts/mountPath - kind: Job +- path: spec/template/spec/containers/args + kind: StatefulSet -- path: spec/template/spec/initContainers/volumeMounts/mountPath - kind: Job +- path: spec/template/spec/containers/command + kind: StatefulSet + +- path: spec/template/spec/containers/env/value + kind: StatefulSet - path: spec/template/spec/containers/volumeMounts/mountPath - kind: CronJob + kind: StatefulSet + +- path: spec/template/spec/initContainers/args + kind: StatefulSet + +- path: spec/template/spec/initContainers/command + kind: StatefulSet + +- path: spec/template/spec/initContainers/env/value + kind: StatefulSet - path: spec/template/spec/initContainers/volumeMounts/mountPath - kind: CronJob - -- path: spec/template/spec/containers/volumeMounts/mountPath - kind: DaemonSet - -- path: spec/template/spec/initContainers/volumeMounts/mountPath - kind: DaemonSet - -- path: spec/template/spec/containers/volumeMounts/mountPath - kind: Deployment - -- path: spec/template/spec/initContainers/volumeMounts/mountPath - kind: Deployment + kind: StatefulSet - path: metadata/labels ` From e207ae4c01aef23e099a4e7732bc46488fd3fdcc Mon Sep 17 00:00:00 2001 From: Jesse Dubay Date: Sat, 16 Mar 2019 19:12:58 -0700 Subject: [PATCH 07/10] Fix incorrect default varrefs for CronJob volumeMounts --- pkg/transformers/config/defaultconfig/varreference.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/transformers/config/defaultconfig/varreference.go b/pkg/transformers/config/defaultconfig/varreference.go index cead95708..9314eb7db 100644 --- a/pkg/transformers/config/defaultconfig/varreference.go +++ b/pkg/transformers/config/defaultconfig/varreference.go @@ -28,10 +28,10 @@ varReference: - path: spec/jobTemplate/spec/template/spec/containers/env/value kind: CronJob -- path: spec/template/spec/containers/volumeMounts/mountPath +- path: spec/jobTemplate/spec/template/spec/containers/volumeMounts/mountPath kind: CronJob -- path: spec/template/spec/initContainers/volumeMounts/mountPath +- path: spec/jobTemplate/spec/template/spec/initContainers/volumeMounts/mountPath kind: CronJob - path: spec/template/spec/containers/args From 31091a8df2004786697e708770d28b5658de5b09 Mon Sep 17 00:00:00 2001 From: Jesse Dubay Date: Sat, 16 Mar 2019 19:15:56 -0700 Subject: [PATCH 08/10] Fix missing varrefs for CronJob, Job, ReplicaSet --- .../config/defaultconfig/varreference.go | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pkg/transformers/config/defaultconfig/varreference.go b/pkg/transformers/config/defaultconfig/varreference.go index 9314eb7db..5f89dfd4f 100644 --- a/pkg/transformers/config/defaultconfig/varreference.go +++ b/pkg/transformers/config/defaultconfig/varreference.go @@ -31,6 +31,15 @@ varReference: - path: spec/jobTemplate/spec/template/spec/containers/volumeMounts/mountPath kind: CronJob +- path: spec/jobTemplate/spec/template/spec/initContainers/args + kind: CronJob + +- path: spec/jobTemplate/spec/template/spec/initContainers/command + kind: CronJob + +- path: spec/jobTemplate/spec/template/spec/initContainers/env/value + kind: CronJob + - path: spec/jobTemplate/spec/template/spec/initContainers/volumeMounts/mountPath kind: CronJob @@ -100,6 +109,12 @@ varReference: - path: spec/template/spec/containers/volumeMounts/mountPath kind: Job +- path: spec/template/spec/initContainers/args + kind: Job + +- path: spec/template/spec/initContainers/command + kind: Job + - path: spec/template/spec/initContainers/env/value kind: Job @@ -130,9 +145,27 @@ varReference: - path: spec/initContainers/volumeMounts/mountPath kind: Pod +- path: spec/template/spec/containers/args + kind: ReplicaSet + +- path: spec/template/spec/containers/command + kind: ReplicaSet + +- path: spec/template/spec/containers/env/value + kind: ReplicaSet + - path: spec/template/spec/containers/volumeMounts/mountPath kind: ReplicaSet +- path: spec/template/spec/initContainers/args + kind: ReplicaSet + +- path: spec/template/spec/initContainers/command + kind: ReplicaSet + +- path: spec/template/spec/initContainers/env/value + kind: ReplicaSet + - path: spec/template/spec/initContainers/volumeMounts/mountPath kind: ReplicaSet From d0cf0473815db1d2e99aacd7468114e26c652fde Mon Sep 17 00:00:00 2001 From: Yujun Zhang Date: Sun, 17 Mar 2019 16:18:46 +0800 Subject: [PATCH 09/10] Convert image transformer test to a more readable format --- pkg/target/transformersimage_test.go | 170 +++++++++++++++++ pkg/transformers/image_test.go | 266 --------------------------- 2 files changed, 170 insertions(+), 266 deletions(-) create mode 100644 pkg/target/transformersimage_test.go delete mode 100644 pkg/transformers/image_test.go diff --git a/pkg/target/transformersimage_test.go b/pkg/target/transformersimage_test.go new file mode 100644 index 000000000..7d09bdf49 --- /dev/null +++ b/pkg/target/transformersimage_test.go @@ -0,0 +1,170 @@ +/* +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. +*/ + +package target_test + +import ( + "testing" +) + +func makeTransfomersImageBase(th *KustTestHarness) { + th.writeK("/app/base", ` +resources: +- deploy1.yaml +- random.yaml +images: +- name: nginx + newTag: v2 +- name: my-nginx + newTag: previous +- name: myprivaterepohostname:1234/my/image + newTag: v1.0.1 +- name: foobar + digest: sha256:24a0c4b4 +- name: alpine + newName: myprivaterepohostname:1234/my/cool-alpine +- name: gcr.io:8080/my-project/my-cool-app + newName: my-cool-app +- name: postgres + newName: my-postgres + newTag: v3 +- name: docker + newName: my-docker + digest: sha256:25a0d4b4 +`) + th.writeF("/app/base/deploy1.yaml", ` +group: apps +apiVersion: v1 +kind: Deployment +metadata: + name: deploy1 +spec: + template: + spec: + initContainers: + - name: nginx2 + image: my-nginx:1.8.0 + - name: init-alpine + image: alpine:1.8.0 + containers: + - name: ngnix + image: nginx:1.7.9 + - name: repliaced-with-digest + image: foobar:1 + - name: postgresdb + image: postgres:1.8.0 +`) + th.writeF("/app/base/random.yaml", ` +kind: randomKind +metadata: + name: random +spec: + template: + spec: + containers: + - name: ngnix1 + image: nginx +spec2: + template: + spec: + containers: + - name: nginx3 + image: nginx:v1 + - name: nginx4 + image: my-nginx:latest +spec3: + template: + spec: + initContainers: + - name: postgresdb + image: postgres:alpine-9 + - name: init-docker + image: docker:17-git + - name: myImage + image: myprivaterepohostname:1234/my/image:latest + - name: myImage2 + image: myprivaterepohostname:1234/my/image + - name: my-app + image: my-app-image:v1 + - name: my-cool-app + image: gcr.io:8080/my-project/my-cool-app:latest +`) +} + +func TestTransfomersImageDefaultConfig(t *testing.T) { + th := NewKustTestHarness(t, "/app/base") + makeTransfomersImageBase(th) + m, err := th.makeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.assertActualEqualsExpected(m, ` +apiVersion: v1 +group: apps +kind: Deployment +metadata: + name: deploy1 +spec: + template: + spec: + containers: + - image: nginx:v2 + name: ngnix + - image: foobar@sha256:24a0c4b4 + name: repliaced-with-digest + - image: my-postgres:v3 + name: postgresdb + initContainers: + - image: my-nginx:previous + name: nginx2 + - image: myprivaterepohostname:1234/my/cool-alpine:1.8.0 + name: init-alpine +--- +kind: randomKind +metadata: + name: random +spec: + template: + spec: + containers: + - image: nginx:v2 + name: ngnix1 +spec2: + template: + spec: + containers: + - image: nginx:v2 + name: nginx3 + - image: my-nginx:previous + name: nginx4 +spec3: + template: + spec: + initContainers: + - image: my-postgres:v3 + name: postgresdb + - image: my-docker@sha256:25a0d4b4 + name: init-docker + - image: myprivaterepohostname:1234/my/image:v1.0.1 + name: myImage + - image: myprivaterepohostname:1234/my/image:v1.0.1 + name: myImage2 + - image: my-app-image:v1 + name: my-app + - image: my-cool-app:latest + name: my-cool-app +`) +} diff --git a/pkg/transformers/image_test.go b/pkg/transformers/image_test.go deleted file mode 100644 index c62ba3432..000000000 --- a/pkg/transformers/image_test.go +++ /dev/null @@ -1,266 +0,0 @@ -/* -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. -*/ - -package transformers - -import ( - "reflect" - "testing" - - "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - "sigs.k8s.io/kustomize/pkg/gvk" - "sigs.k8s.io/kustomize/pkg/image" - "sigs.k8s.io/kustomize/pkg/resid" - "sigs.k8s.io/kustomize/pkg/resmap" - "sigs.k8s.io/kustomize/pkg/resource" -) - -func TestImageTransformer(t *testing.T) { - var rf = resource.NewFactory( - kunstruct.NewKunstructuredFactoryImpl()) - - m := resmap.ResMap{ - resid.NewResId(deploy, "deploy1"): rf.FromMap( - map[string]interface{}{ - "group": "apps", - "apiVersion": "v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "deploy1", - }, - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "initContainers": []interface{}{ - map[string]interface{}{ - "name": "nginx2", - "image": "my-nginx:1.8.0", - }, - map[string]interface{}{ - "name": "init-alpine", - "image": "alpine:1.8.0", - }, - }, - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "image": "nginx:1.7.9", - }, - map[string]interface{}{ - "name": "replaced-with-digest", - "image": "foobar:1", - }, - map[string]interface{}{ - "name": "postgresdb", - "image": "postgres:1.8.0", - }, - }, - }, - }, - }, - }), - resid.NewResId(gvk.Gvk{Kind: "randomKind"}, "random"): rf.FromMap( - map[string]interface{}{ - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx1", - "image": "nginx", - }, - }, - }, - }, - }, - "spec2": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx3", - "image": "nginx:v1", - }, - map[string]interface{}{ - "name": "nginx4", - "image": "my-nginx:latest", - }, - }, - }, - }, - }, - "spec3": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "initContainers": []interface{}{ - map[string]interface{}{ - "name": "postgresdb", - "image": "postgres:alpine-9", - }, - map[string]interface{}{ - "name": "init-docker", - "image": "docker:17-git", - }, - map[string]interface{}{ - "name": "myimage", - "image": "myprivaterepohostname:1234/my/image:latest", - }, - map[string]interface{}{ - "name": "myimage2", - "image": "myprivaterepohostname:1234/my/image", - }, - map[string]interface{}{ - "name": "my-app", - "image": "my-app-image:v1", - }, - map[string]interface{}{ - "name": "my-cool-app", - "image": "gcr.io:8080/my-project/my-cool-app:latest", - }, - }, - }, - }, - }, - }), - } - expected := resmap.ResMap{ - resid.NewResId(deploy, "deploy1"): rf.FromMap( - map[string]interface{}{ - "group": "apps", - "apiVersion": "v1", - "kind": "Deployment", - "metadata": map[string]interface{}{ - "name": "deploy1", - }, - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "initContainers": []interface{}{ - map[string]interface{}{ - "name": "nginx2", - "image": "my-nginx:previous", - }, - map[string]interface{}{ - "name": "init-alpine", - "image": "myprivaterepohostname:1234/my/cool-alpine:1.8.0", - }, - }, - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx", - "image": "nginx:v2", - }, - map[string]interface{}{ - "name": "replaced-with-digest", - "image": "foobar@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3", - }, - map[string]interface{}{ - "name": "postgresdb", - "image": "my-postgres:v3", - }, - }, - }, - }, - }, - }), - resid.NewResId(gvk.Gvk{Kind: "randomKind"}, "random"): rf.FromMap( - map[string]interface{}{ - "spec": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx1", - "image": "nginx:v2", - }, - }, - }, - }, - }, - "spec2": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "containers": []interface{}{ - map[string]interface{}{ - "name": "nginx3", - "image": "nginx:v2", - }, - map[string]interface{}{ - "name": "nginx4", - "image": "my-nginx:previous", - }, - }, - }, - }, - }, - "spec3": map[string]interface{}{ - "template": map[string]interface{}{ - "spec": map[string]interface{}{ - "initContainers": []interface{}{ - map[string]interface{}{ - "name": "postgresdb", - "image": "my-postgres:v3", - }, - map[string]interface{}{ - "name": "init-docker", - "image": "my-docker@sha256:25a0d4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3", - }, - map[string]interface{}{ - "name": "myimage", - "image": "myprivaterepohostname:1234/my/image:v1.0.1", - }, - map[string]interface{}{ - "name": "myimage2", - "image": "myprivaterepohostname:1234/my/image:v1.0.1", - }, - map[string]interface{}{ - "name": "my-app", - "image": "gcr.io/my-project/my-app-image:v1", - }, - map[string]interface{}{ - "name": "my-cool-app", - "image": "my-cool-app:latest", - }, - }, - }, - }, - }, - }), - } - - it, err := NewImageTransformer([]image.Image{ - {Name: "nginx", NewTag: "v2"}, - {Name: "my-nginx", NewTag: "previous"}, - {Name: "myprivaterepohostname:1234/my/image", NewTag: "v1.0.1"}, - {Name: "foobar", Digest: "sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"}, - {Name: "alpine", NewName: "myprivaterepohostname:1234/my/cool-alpine"}, - {Name: "my-app-image", NewName: "gcr.io/my-project/my-app-image"}, - {Name: "gcr.io:8080/my-project/my-cool-app", NewName: "my-cool-app"}, - {Name: "postgres", NewName: "my-postgres", NewTag: "v3"}, - {Name: "docker", NewName: "my-docker", Digest: "sha256:25a0d4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"}, - }) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - err = it.Transform(m) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !reflect.DeepEqual(m, expected) { - err = expected.ErrorIfNotEqual(m) - t.Fatalf("actual doesn't match expected: %v. Actual %+v", err, m) - } -} From 103c1b3a4fd10c7afa2b3447cf5fe93027770ba3 Mon Sep 17 00:00:00 2001 From: jregan Date: Sun, 17 Mar 2019 07:18:42 -0700 Subject: [PATCH 10/10] Put goplugins behind flag. --- .../configmapandsecret/configmapfactory.go | 9 ++- k8sdeps/factory.go | 34 ----------- k8sdeps/kunstruct/factory.go | 20 ++++++- k8sdeps/kv/plugin/goplugin.go | 50 +++++++++++++---- k8sdeps/kv/plugin/registry.go | 29 ++++++++-- kustomize.go | 3 +- pkg/commands/build/build.go | 6 +- pkg/commands/build/build_test.go | 4 +- pkg/commands/commands.go | 44 +++++++++++---- pkg/commands/edit/add/addmetadata.go | 6 +- pkg/commands/kustfile/kustomizationfile.go | 6 +- .../kustfile/kustomizationfile_test.go | 6 +- pkg/factory/factory.go | 39 ------------- pkg/fs/fakefs.go | 6 +- pkg/loader/fileloader_test.go | 4 +- pkg/pgmconfig/config.go | 54 ++++++++++++++++++ pkg/pgmconfig/config_test.go | 56 +++++++++++++++++++ pkg/{constants => pgmconfig}/constants.go | 14 +++-- pkg/target/generatoroptions_test.go | 47 ++++++++++++++++ pkg/target/kusttarget.go | 6 +- pkg/target/kusttestharness_test.go | 15 ++++- pkg/types/kustomization.go | 19 +++++++ 22 files changed, 337 insertions(+), 140 deletions(-) delete mode 100644 k8sdeps/factory.go delete mode 100644 pkg/factory/factory.go create mode 100644 pkg/pgmconfig/config.go create mode 100644 pkg/pgmconfig/config_test.go rename pkg/{constants => pgmconfig}/constants.go (76%) diff --git a/k8sdeps/configmapandsecret/configmapfactory.go b/k8sdeps/configmapandsecret/configmapfactory.go index a40792258..27897c705 100644 --- a/k8sdeps/configmapandsecret/configmapfactory.go +++ b/k8sdeps/configmapandsecret/configmapfactory.go @@ -21,8 +21,7 @@ import ( "fmt" "unicode/utf8" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/types" @@ -40,8 +39,8 @@ func NewFactory( } func makeFreshConfigMap( - args *types.ConfigMapArgs) *corev1.ConfigMap { - cm := &corev1.ConfigMap{} + args *types.ConfigMapArgs) *v1.ConfigMap { + cm := &v1.ConfigMap{} cm.APIVersion = "v1" cm.Kind = "ConfigMap" cm.Name = args.Name @@ -52,7 +51,7 @@ func makeFreshConfigMap( // MakeConfigMap returns a new ConfigMap, or nil and an error. func (f *Factory) MakeConfigMap( - args *types.ConfigMapArgs) (*corev1.ConfigMap, error) { + args *types.ConfigMapArgs) (*v1.ConfigMap, error) { all, err := f.loadKvPairs(args.GeneratorArgs) if err != nil { return nil, err diff --git a/k8sdeps/factory.go b/k8sdeps/factory.go deleted file mode 100644 index a422b25a4..000000000 --- a/k8sdeps/factory.go +++ /dev/null @@ -1,34 +0,0 @@ -/* -Copyright 2018 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. -*/ - -// Package k8sdeps provides kustomize factory with k8s dependencies -package k8sdeps - -import ( - "sigs.k8s.io/kustomize/k8sdeps/kunstruct" - "sigs.k8s.io/kustomize/k8sdeps/transformer" - "sigs.k8s.io/kustomize/k8sdeps/validator" - "sigs.k8s.io/kustomize/pkg/factory" -) - -// NewFactory creates an instance of KustFactory using k8sdeps factories -func NewFactory() *factory.KustFactory { - return factory.NewKustFactory( - kunstruct.NewKunstructuredFactoryImpl(), - validator.NewKustValidator(), - transformer.NewFactoryImpl(), - ) -} diff --git a/k8sdeps/kunstruct/factory.go b/k8sdeps/kunstruct/factory.go index 3c3644c3f..ef40209b9 100644 --- a/k8sdeps/kunstruct/factory.go +++ b/k8sdeps/kunstruct/factory.go @@ -32,13 +32,21 @@ import ( // KunstructuredFactoryImpl hides construction using apimachinery types. type KunstructuredFactoryImpl struct { + generatorMetaArgs *types.GeneratorMetaArgs } var _ ifc.KunstructuredFactory = &KunstructuredFactoryImpl{} // NewKunstructuredFactoryImpl returns a factory. func NewKunstructuredFactoryImpl() ifc.KunstructuredFactory { - return &KunstructuredFactoryImpl{} + return NewKunstructuredFactoryWithGeneratorArgs( + &types.GeneratorMetaArgs{}) +} + +// NewKunstructuredFactoryWithGeneratorArgs returns a factory. +func NewKunstructuredFactoryWithGeneratorArgs( + gma *types.GeneratorMetaArgs) ifc.KunstructuredFactory { + return &KunstructuredFactoryImpl{gma} } // SliceFromBytes returns a slice of Kunstructured. @@ -82,7 +90,10 @@ func (kf *KunstructuredFactoryImpl) MakeConfigMap( ldr ifc.Loader, options *types.GeneratorOptions, args *types.ConfigMapArgs) (ifc.Kunstructured, error) { - o, err := configmapandsecret.NewFactory(ldr, options, plugin.NewRegistry(ldr)).MakeConfigMap(args) + o, err := configmapandsecret.NewFactory( + ldr, options, + plugin.NewConfiguredRegistry( + ldr, &kf.generatorMetaArgs.PluginConfig)).MakeConfigMap(args) if err != nil { return nil, err } @@ -94,7 +105,10 @@ func (kf *KunstructuredFactoryImpl) MakeSecret( ldr ifc.Loader, options *types.GeneratorOptions, args *types.SecretArgs) (ifc.Kunstructured, error) { - o, err := configmapandsecret.NewFactory(ldr, options, plugin.NewRegistry(ldr)).MakeSecret(args) + o, err := configmapandsecret.NewFactory( + ldr, options, + plugin.NewConfiguredRegistry( + ldr, &kf.generatorMetaArgs.PluginConfig)).MakeSecret(args) if err != nil { return nil, err } diff --git a/k8sdeps/kv/plugin/goplugin.go b/k8sdeps/kv/plugin/goplugin.go index 09351fa1a..4b67f9dd2 100644 --- a/k8sdeps/kv/plugin/goplugin.go +++ b/k8sdeps/kv/plugin/goplugin.go @@ -18,40 +18,66 @@ package plugin import ( "fmt" - "os" + "path/filepath" "plugin" + + "sigs.k8s.io/kustomize/pkg/types" ) var _ Factory = &goFactory{} const ( - pluginDir = "kustomize/plugins/kvsource" + kvSourcesDir = "kvSources" + EnableGoPluginsFlagName = "enable_alpha_goplugins_accept_panic_risk" + EnableGoPluginsFlagHelp = ` +Warning: the main program may panic and exit on an +attempt to use a goplugin that was compiled under +conditions differing from the those in effect when +main was compiled. It's safest to use this flag in +the context of a container image holding both the +main and the goplugins it needs, all built on the +same machine, with the same transitive libs and +the same compiler version. +` + errorFmt = ` +enable go plugins by specifying flag + --%s +Place .so files in + %s +%s +` ) -func newGoFactory() *goFactory { +func newGoFactory(c *types.PluginConfig) *goFactory { return &goFactory{ + config: c, plugins: make(map[string]KVSource), } } type goFactory struct { + config *types.PluginConfig plugins map[string]KVSource } -func configDir() string { - xdghome := os.Getenv("XDG_CONFIG_HOME") - if len(xdghome) == 0 { - return os.ExpandEnv("$HOME/.config") - } - return xdghome -} - func (p *goFactory) load(name string) (KVSource, error) { if plug, ok := p.plugins[name]; ok { return plug, nil } - goPlugin, err := plugin.Open(fmt.Sprintf("%s/%s/kustomize-%s.so", configDir(), pluginDir, name)) + dir := filepath.Join( + p.config.DirectoryPath, + kvSourcesDir) + if !p.config.GoEnabled { + return nil, fmt.Errorf( + errorFmt, + EnableGoPluginsFlagName, + dir, + EnableGoPluginsFlagHelp) + } + + goPlugin, err := plugin.Open( + filepath.Join(dir, name+".so")) if err != nil { return nil, err } diff --git a/k8sdeps/kv/plugin/registry.go b/k8sdeps/kv/plugin/registry.go index bf6c8ae0a..9e7447f29 100644 --- a/k8sdeps/kv/plugin/registry.go +++ b/k8sdeps/kv/plugin/registry.go @@ -18,8 +18,10 @@ package plugin import ( "fmt" - + "path/filepath" "sigs.k8s.io/kustomize/pkg/ifc" + "sigs.k8s.io/kustomize/pkg/pgmconfig" + "sigs.k8s.io/kustomize/pkg/types" ) // Registry holds all the plugin factories. @@ -28,17 +30,36 @@ type Registry struct { ldr ifc.Loader } -// NewRegistry returns a new Registry loaded with all the factories. -func NewRegistry(ldr ifc.Loader) Registry { +const ( + PluginsDir = "plugins" +) + +func DefaultPluginConfig() types.PluginConfig { + return types.PluginConfig{ + GoEnabled: false, + DirectoryPath: filepath.Join( + pgmconfig.ConfigRoot(), PluginsDir), + } +} + +// NewConfiguredRegistry returns a new Registry loaded +// with all the factories and a custom PluginConfig. +func NewConfiguredRegistry( + ldr ifc.Loader, pc *types.PluginConfig) Registry { return Registry{ ldr: ldr, factories: map[string]Factory{ - "go": newGoFactory(), + "go": newGoFactory(pc), "testonly": newTestonlyFactory(), }, } } +// NewRegistry returns a new Registry with default config. +func NewRegistry(ldr ifc.Loader) Registry { + return NewConfiguredRegistry(ldr, &types.PluginConfig{}) +} + // Load returns a plugin by type and name, func (r *Registry) Load(pluginType, name string) (KVSource, error) { factory, exists := r.factories[pluginType] diff --git a/kustomize.go b/kustomize.go index e17481de9..584b559e8 100644 --- a/kustomize.go +++ b/kustomize.go @@ -19,12 +19,11 @@ package main import ( "os" - "sigs.k8s.io/kustomize/k8sdeps" "sigs.k8s.io/kustomize/pkg/commands" ) func main() { - if err := commands.NewDefaultCommand(k8sdeps.NewFactory()).Execute(); err != nil { + if err := commands.NewDefaultCommand().Execute(); err != nil { os.Exit(1) } os.Exit(0) diff --git a/pkg/commands/build/build.go b/pkg/commands/build/build.go index e62747e32..1176f25b1 100644 --- a/pkg/commands/build/build.go +++ b/pkg/commands/build/build.go @@ -21,10 +21,10 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc/transformer" "sigs.k8s.io/kustomize/pkg/loader" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/target" ) @@ -67,7 +67,7 @@ func NewCmdBuild( cmd := &cobra.Command{ Use: "build [path]", - Short: "Print current configuration per contents of " + constants.KustomizationFileNames[0], + Short: "Print current configuration per contents of " + pgmconfig.KustomizationFileNames[0], Example: examples, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { @@ -88,7 +88,7 @@ func NewCmdBuild( // Validate validates build command. func (o *Options) Validate(args []string) error { if len(args) > 1 { - return errors.New("specify one path to " + constants.KustomizationFileNames[0]) + return errors.New("specify one path to " + pgmconfig.KustomizationFileNames[0]) } if len(args) == 0 { o.kustomizationPath = "./" diff --git a/pkg/commands/build/build_test.go b/pkg/commands/build/build_test.go index b06ccdea2..792d95aac 100644 --- a/pkg/commands/build/build_test.go +++ b/pkg/commands/build/build_test.go @@ -19,7 +19,7 @@ package build import ( "testing" - "sigs.k8s.io/kustomize/pkg/constants" + "sigs.k8s.io/kustomize/pkg/pgmconfig" ) func TestNewOptionsToSilenceCodeInspectionError(t *testing.T) { @@ -39,7 +39,7 @@ func TestBuildValidate(t *testing.T) { {"file", []string{"beans"}, "beans", ""}, {"path", []string{"a/b/c"}, "a/b/c", ""}, {"path", []string{"too", "many"}, - "", "specify one path to " + constants.KustomizationFileNames[0]}, + "", "specify one path to " + pgmconfig.KustomizationFileNames[0]}, } for _, mycase := range cases { opts := Options{} diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index 3651ae6cf..5a4ff0d05 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -20,35 +20,57 @@ package commands import ( "flag" "os" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/k8sdeps/kunstruct" + "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" + "sigs.k8s.io/kustomize/k8sdeps/transformer" + "sigs.k8s.io/kustomize/k8sdeps/validator" "sigs.k8s.io/kustomize/pkg/commands/build" "sigs.k8s.io/kustomize/pkg/commands/edit" "sigs.k8s.io/kustomize/pkg/commands/misc" - "sigs.k8s.io/kustomize/pkg/factory" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/resource" + "sigs.k8s.io/kustomize/pkg/types" ) // NewDefaultCommand returns the default (aka root) command for kustomize command. -func NewDefaultCommand(f *factory.KustFactory) *cobra.Command { - fsys := fs.MakeRealFS() +func NewDefaultCommand() *cobra.Command { + fSys := fs.MakeRealFS() stdOut := os.Stdout c := &cobra.Command{ - Use: "kustomize", - Short: "kustomize manages declarative configuration of Kubernetes", + Use: pgmconfig.PgmName, + Short: "Manages declarative configuration of Kubernetes", Long: ` -kustomize manages declarative configuration of Kubernetes. - +Manages declarative configuration of Kubernetes. See https://sigs.k8s.io/kustomize `, } + // Configuration for ConfigMap and Secret generators. + genMetaArgs := types.GeneratorMetaArgs{ + PluginConfig: plugin.DefaultPluginConfig(), + } + + c.Flags().BoolVar( + &genMetaArgs.PluginConfig.GoEnabled, + plugin.EnableGoPluginsFlagName, + false, plugin.EnableGoPluginsFlagHelp) + // Not advertising this alpha feature. + c.Flags().MarkHidden(plugin.EnableGoPluginsFlagName) + + uf := kunstruct.NewKunstructuredFactoryWithGeneratorArgs(&genMetaArgs) + c.AddCommand( - // TODO: Make consistent API for newCmd* functions. - build.NewCmdBuild(stdOut, fsys, f.ResmapF, f.TransformerF), - edit.NewCmdEdit(fsys, f.ValidatorF, f.UnstructF), - misc.NewCmdConfig(fsys), + build.NewCmdBuild( + stdOut, fSys, + resmap.NewFactory(resource.NewFactory(uf)), + transformer.NewFactoryImpl()), + edit.NewCmdEdit(fSys, validator.NewKustValidator(), uf), + misc.NewCmdConfig(fSys), misc.NewCmdVersion(stdOut), ) c.PersistentFlags().AddGoFlagSet(flag.CommandLine) diff --git a/pkg/commands/edit/add/addmetadata.go b/pkg/commands/edit/add/addmetadata.go index d9104f35d..b4e14f34e 100644 --- a/pkg/commands/edit/add/addmetadata.go +++ b/pkg/commands/edit/add/addmetadata.go @@ -22,8 +22,8 @@ import ( "github.com/spf13/cobra" "sigs.k8s.io/kustomize/pkg/commands/kustfile" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/types" ) @@ -59,7 +59,7 @@ func newCmdAddAnnotation(fSys fs.FileSystem, v func(map[string]string) error) *c o.mapValidator = v cmd := &cobra.Command{ Use: "annotation", - Short: "Adds one or more commonAnnotations to " + constants.KustomizationFileNames[0], + Short: "Adds one or more commonAnnotations to " + pgmconfig.KustomizationFileNames[0], Example: ` add annotation {annotationKey1:annotationValue1},{annotationKey2:annotationValue2}`, RunE: func(cmd *cobra.Command, args []string) error { @@ -76,7 +76,7 @@ func newCmdAddLabel(fSys fs.FileSystem, v func(map[string]string) error) *cobra. o.mapValidator = v cmd := &cobra.Command{ Use: "label", - Short: "Adds one or more commonLabels to " + constants.KustomizationFileNames[0], + Short: "Adds one or more commonLabels to " + pgmconfig.KustomizationFileNames[0], Example: ` add label {labelKey1:labelValue1},{labelKey2:labelValue2}`, RunE: func(cmd *cobra.Command, args []string) error { diff --git a/pkg/commands/kustfile/kustomizationfile.go b/pkg/commands/kustfile/kustomizationfile.go index cf66745ec..42b93d789 100644 --- a/pkg/commands/kustfile/kustomizationfile.go +++ b/pkg/commands/kustfile/kustomizationfile.go @@ -27,8 +27,8 @@ import ( "strings" "github.com/ghodss/yaml" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/types" ) @@ -129,7 +129,7 @@ func NewKustomizationFile(fSys fs.FileSystem) (*kustomizationFile, error) { // n func (mf *kustomizationFile) validate() error { match := 0 var path []string - for _, kfilename := range constants.KustomizationFileNames { + for _, kfilename := range pgmconfig.KustomizationFileNames { if mf.fSys.Exists(kfilename) { match += 1 path = append(path, kfilename) @@ -138,7 +138,7 @@ func (mf *kustomizationFile) validate() error { switch match { case 0: - return fmt.Errorf("Missing kustomization file '%s'.\n", constants.KustomizationFileNames[0]) + return fmt.Errorf("Missing kustomization file '%s'.\n", pgmconfig.KustomizationFileNames[0]) case 1: mf.path = path[0] default: diff --git a/pkg/commands/kustfile/kustomizationfile_test.go b/pkg/commands/kustfile/kustomizationfile_test.go index 79e3a5da3..0795986c3 100644 --- a/pkg/commands/kustfile/kustomizationfile_test.go +++ b/pkg/commands/kustfile/kustomizationfile_test.go @@ -21,8 +21,8 @@ import ( "strings" "testing" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/fs" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/types" ) @@ -112,12 +112,12 @@ configMapGenerator: name: my-configmap ` fakeFS := fs.MakeFakeFS() - fakeFS.WriteFile(constants.KustomizationFileNames[1], []byte(kcontent)) + fakeFS.WriteFile(pgmconfig.KustomizationFileNames[1], []byte(kcontent)) k, err := NewKustomizationFile(fakeFS) if err != nil { t.Fatalf("Unexpected Error: %v", err) } - if k.path != constants.KustomizationFileNames[1] { + if k.path != pgmconfig.KustomizationFileNames[1] { t.Fatalf("Load incorrect file path %s", k.path) } } diff --git a/pkg/factory/factory.go b/pkg/factory/factory.go deleted file mode 100644 index e71669a87..000000000 --- a/pkg/factory/factory.go +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2018 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. -*/ -// Package factory provides factories for kustomize. -package factory - -import ( - "sigs.k8s.io/kustomize/pkg/ifc" - "sigs.k8s.io/kustomize/pkg/ifc/transformer" - "sigs.k8s.io/kustomize/pkg/resmap" - "sigs.k8s.io/kustomize/pkg/resource" -) - -// KustFactory provides different factories for kustomize -type KustFactory struct { - ResmapF *resmap.Factory - TransformerF transformer.Factory - ValidatorF ifc.Validator - UnstructF ifc.KunstructuredFactory -} - -// NewKustFactory creats a KustFactory instance -func NewKustFactory(u ifc.KunstructuredFactory, v ifc.Validator, t transformer.Factory) *KustFactory { - return &KustFactory{ - ResmapF: resmap.NewFactory(resource.NewFactory(u)), - TransformerF: t, - ValidatorF: v, - UnstructF: u, - } -} diff --git a/pkg/fs/fakefs.go b/pkg/fs/fakefs.go index 59c0966b2..0f2a4eedf 100644 --- a/pkg/fs/fakefs.go +++ b/pkg/fs/fakefs.go @@ -22,7 +22,7 @@ import ( "sort" "strings" - "sigs.k8s.io/kustomize/pkg/constants" + "sigs.k8s.io/kustomize/pkg/pgmconfig" ) var _ FileSystem = &fakeFs{} @@ -158,7 +158,7 @@ func (fs *fakeFs) ReadFile(name string) ([]byte, error) { } func (fs *fakeFs) ReadTestKustomization() ([]byte, error) { - return fs.ReadFile(constants.KustomizationFileNames[0]) + return fs.ReadFile(pgmconfig.KustomizationFileNames[0]) } // WriteFile always succeeds and does nothing. @@ -176,7 +176,7 @@ func (fs *fakeFs) WriteTestKustomization() { // WriteTestKustomizationWith writes a standard test file. func (fs *fakeFs) WriteTestKustomizationWith(bytes []byte) { - fs.WriteFile(constants.KustomizationFileNames[0], bytes) + fs.WriteFile(pgmconfig.KustomizationFileNames[0], bytes) } func (fs *fakeFs) pathMatch(path, pattern string) bool { diff --git a/pkg/loader/fileloader_test.go b/pkg/loader/fileloader_test.go index b8affe10e..68114f368 100644 --- a/pkg/loader/fileloader_test.go +++ b/pkg/loader/fileloader_test.go @@ -25,8 +25,8 @@ import ( "strings" "testing" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/git" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/fs" "sigs.k8s.io/kustomize/pkg/ifc" @@ -341,7 +341,7 @@ func TestNewLoaderAtGitClone(t *testing.T) { fSys.MkdirAll(coRoot) fSys.MkdirAll(coRoot + "/" + pathInRepo) fSys.WriteFile( - coRoot+"/"+pathInRepo+"/"+constants.KustomizationFileNames[0], + coRoot+"/"+pathInRepo+"/"+pgmconfig.KustomizationFileNames[0], []byte(` whatever `)) diff --git a/pkg/pgmconfig/config.go b/pkg/pgmconfig/config.go new file mode 100644 index 000000000..d7a27422a --- /dev/null +++ b/pkg/pgmconfig/config.go @@ -0,0 +1,54 @@ +/* +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. +*/ + +// Package commands holds the CLI glue mapping textual commands/args to method calls. +package pgmconfig + +import ( + "os" + "path/filepath" + "runtime" +) + +const ( + XDG_CONFIG_HOME = "XDG_CONFIG_HOME" + defaultConfigSubdir = ".config" +) + +// Use https://github.com/kirsle/configdir instead? +func ConfigRoot() string { + dir := os.Getenv(XDG_CONFIG_HOME) + if len(dir) == 0 { + dir = filepath.Join( + homeDir(), defaultConfigSubdir) + } + return filepath.Join(dir, PgmName) +} + +func homeDir() string { + home := os.Getenv(homeEnv()) + if len(home) > 0 { + return home + } + return "~" +} + +func homeEnv() string { + if runtime.GOOS == "windows" { + return "USERPROFILE" + } + return "HOME" +} diff --git a/pkg/pgmconfig/config_test.go b/pkg/pgmconfig/config_test.go new file mode 100644 index 000000000..2833afea7 --- /dev/null +++ b/pkg/pgmconfig/config_test.go @@ -0,0 +1,56 @@ +/* +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. +*/ + +package pgmconfig + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestConfigDirNoXdg(t *testing.T) { + xdg, isSet := os.LookupEnv(XDG_CONFIG_HOME) + if isSet { + os.Unsetenv(XDG_CONFIG_HOME) + } + s := ConfigRoot() + if isSet { + os.Setenv(XDG_CONFIG_HOME, xdg) + } + if !strings.HasSuffix( + s, + rootedPath(defaultConfigSubdir, PgmName)) { + t.Fatalf("unexpected config dir: %s", s) + } +} + +func rootedPath(elem ...string) string { + return string(filepath.Separator) + filepath.Join(elem...) +} + +func TestConfigDirWithXdg(t *testing.T) { + xdg, isSet := os.LookupEnv(XDG_CONFIG_HOME) + os.Setenv(XDG_CONFIG_HOME, rootedPath("blah")) + s := ConfigRoot() + if isSet { + os.Setenv(XDG_CONFIG_HOME, xdg) + } + if s != rootedPath("blah", PgmName) { + t.Fatalf("unexpected config dir: %s", s) + } +} diff --git a/pkg/constants/constants.go b/pkg/pgmconfig/constants.go similarity index 76% rename from pkg/constants/constants.go rename to pkg/pgmconfig/constants.go index dd50230fb..008b69da9 100644 --- a/pkg/constants/constants.go +++ b/pkg/pgmconfig/constants.go @@ -15,14 +15,18 @@ limitations under the License. */ // Package constants holds global constants for the kustomize tool. -package constants +package pgmconfig -// KustomizationFileNames is a list of filenames that can be recognized and consumbed -// by Kustomize. -// In each directory, Kustomize searches for file with the name in this list. -// Only one match is allowed. +// KustomizationFileNames is a list of filenames +// that kustomize recognizes. +// To avoid ambiguity, a directory cannot contain +// more than one match to this list. var KustomizationFileNames = []string{ "kustomization.yaml", "kustomization.yml", "Kustomization", } + +const ( + PgmName = "kustomize" +) diff --git a/pkg/target/generatoroptions_test.go b/pkg/target/generatoroptions_test.go index 4dbdbb588..fc1bd792e 100644 --- a/pkg/target/generatoroptions_test.go +++ b/pkg/target/generatoroptions_test.go @@ -14,6 +14,9 @@ limitations under the License. package target_test import ( + "path/filepath" + "sigs.k8s.io/kustomize/pkg/types" + "strings" "testing" ) @@ -69,3 +72,47 @@ metadata: name: shouldNotHaveHash `) } + +func TestGoPluginNotEnabled(t *testing.T) { + th := NewKustTestHarness(t, "/app") + th.writeK("/app", ` +secretGenerator: +- name: attemptGoPlugin + kvSources: + - name: foo + pluginType: go + args: + - someArg + - someOtherArg +`) + _, err := th.makeKustTarget().MakeCustomizedResMap() + if err == nil { + t.Fatalf("expected error") + } + if !strings.Contains(err.Error(), "enable go plugins by ") { + t.Fatalf("unexpected err: %v", err) + } +} + +func TestGoPluginDoesNotExist(t *testing.T) { + th := NewKustTestHarnessWithPluginConfig( + t, "/app", types.PluginConfig{GoEnabled: true}) + th.writeK("/app", ` +secretGenerator: +- name: attemptGoPlugin + kvSources: + - name: foo + pluginType: go + args: + - someArg + - someOtherArg +`) + _, err := th.makeKustTarget().MakeCustomizedResMap() + if err == nil { + t.Fatalf("expected error") + } + if !strings.Contains(err.Error(), + filepath.Join("kvSources", "foo.so")) { + t.Fatalf("unexpected err: %v", err) + } +} diff --git a/pkg/target/kusttarget.go b/pkg/target/kusttarget.go index 5bbd2198c..6a6eb952b 100644 --- a/pkg/target/kusttarget.go +++ b/pkg/target/kusttarget.go @@ -25,11 +25,11 @@ import ( "github.com/ghodss/yaml" "github.com/pkg/errors" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/ifc" "sigs.k8s.io/kustomize/pkg/ifc/transformer" interror "sigs.k8s.io/kustomize/pkg/internal/error" patchtransformer "sigs.k8s.io/kustomize/pkg/patch/transformer" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" "sigs.k8s.io/kustomize/pkg/transformers" @@ -89,7 +89,7 @@ func commaOr(q []string) string { func loadKustFile(ldr ifc.Loader) ([]byte, error) { var content []byte match := 0 - for _, kf := range constants.KustomizationFileNames { + for _, kf := range pgmconfig.KustomizationFileNames { c, err := ldr.Load(kf) if err == nil { match += 1 @@ -100,7 +100,7 @@ func loadKustFile(ldr ifc.Loader) ([]byte, error) { case 0: return nil, fmt.Errorf( "unable to find one of %v in directory '%s'", - commaOr(quoted(constants.KustomizationFileNames)), ldr.Root()) + commaOr(quoted(pgmconfig.KustomizationFileNames)), ldr.Root()) case 1: return content, nil default: diff --git a/pkg/target/kusttestharness_test.go b/pkg/target/kusttestharness_test.go index 74cbab348..ea3b712bd 100644 --- a/pkg/target/kusttestharness_test.go +++ b/pkg/target/kusttestharness_test.go @@ -21,13 +21,14 @@ package target_test import ( "fmt" "path/filepath" + "sigs.k8s.io/kustomize/k8sdeps/kv/plugin" "strings" "testing" "sigs.k8s.io/kustomize/k8sdeps/kunstruct" "sigs.k8s.io/kustomize/k8sdeps/transformer" - "sigs.k8s.io/kustomize/pkg/constants" "sigs.k8s.io/kustomize/pkg/internal/loadertest" + "sigs.k8s.io/kustomize/pkg/pgmconfig" "sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resource" . "sigs.k8s.io/kustomize/pkg/target" @@ -42,10 +43,18 @@ type KustTestHarness struct { } func NewKustTestHarness(t *testing.T, path string) *KustTestHarness { + return NewKustTestHarnessWithPluginConfig( + t, path, plugin.DefaultPluginConfig()) +} + +func NewKustTestHarnessWithPluginConfig( + t *testing.T, path string, + config types.PluginConfig) *KustTestHarness { return &KustTestHarness{ t: t, rf: resmap.NewFactory(resource.NewFactory( - kunstruct.NewKunstructuredFactoryImpl())), + kunstruct.NewKunstructuredFactoryWithGeneratorArgs( + &types.GeneratorMetaArgs{PluginConfig: config}))), ldr: loadertest.NewFakeLoader(path)} } @@ -66,7 +75,7 @@ func (th *KustTestHarness) writeF(dir string, content string) { } func (th *KustTestHarness) writeK(dir string, content string) { - th.writeF(filepath.Join(dir, constants.KustomizationFileNames[0]), ` + th.writeF(filepath.Join(dir, pgmconfig.KustomizationFileNames[0]), ` apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization `+content) diff --git a/pkg/types/kustomization.go b/pkg/types/kustomization.go index c92867422..39a08700d 100644 --- a/pkg/types/kustomization.go +++ b/pkg/types/kustomization.go @@ -194,6 +194,25 @@ type GeneratorArgs struct { KVSources []KVSource `json:",inline,omitempty" yaml:",inline,omitempty"` } +// GeneratorMetaArgs contains arguments common to generators +// that come from somewhere other than a kustomization file. +type GeneratorMetaArgs struct { + PluginConfig PluginConfig +} + +// PluginConfig holds plugin configuration. +type PluginConfig struct { + // DirectoryPath is an absolute path to a + // directory containing kustomize plugins. + // This directory may contain subdirectories + // further categorizing plugins. + DirectoryPath string + + // GoEnabled is true if goplugins are enabled. + // See https://golang.org/pkg/plugin + GoEnabled bool +} + // ConfigMapArgs contains the metadata of how to generate a configmap. type ConfigMapArgs struct { // GeneratorArgs for the configmap.