diff --git a/api/internal/plugins/builtinconfig/transformerconfig.go b/api/internal/plugins/builtinconfig/transformerconfig.go index a28627a13..50f162f99 100644 --- a/api/internal/plugins/builtinconfig/transformerconfig.go +++ b/api/internal/plugins/builtinconfig/transformerconfig.go @@ -10,6 +10,7 @@ import ( "sigs.k8s.io/kustomize/api/ifc" "sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts" "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/errors" ) // TransformerConfig holds the data needed to perform transformations. @@ -18,6 +19,7 @@ type TransformerConfig struct { NameSuffix types.FsSlice `json:"nameSuffix,omitempty" yaml:"nameSuffix,omitempty"` NameSpace types.FsSlice `json:"namespace,omitempty" yaml:"namespace,omitempty"` CommonLabels types.FsSlice `json:"commonLabels,omitempty" yaml:"commonLabels,omitempty"` + TemplateLabels types.FsSlice `json:"templateLabels,omitempty" yaml:"templateLabels,omitempty"` CommonAnnotations types.FsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"` NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"` VarReference types.FsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"` @@ -60,6 +62,7 @@ func (t *TransformerConfig) sortFields() { sort.Sort(t.NamePrefix) sort.Sort(t.NameSpace) sort.Sort(t.CommonLabels) + sort.Sort(t.TemplateLabels) sort.Sort(t.CommonAnnotations) sort.Sort(t.NameReference) sort.Sort(t.VarReference) @@ -108,40 +111,44 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) ( merged = &TransformerConfig{} merged.NamePrefix, err = t.NamePrefix.MergeAll(input.NamePrefix) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge NamePrefix fieldSpec") } merged.NameSuffix, err = t.NameSuffix.MergeAll(input.NameSuffix) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge NameSuffix fieldSpec") } merged.NameSpace, err = t.NameSpace.MergeAll(input.NameSpace) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge NameSpace fieldSpec") } merged.CommonAnnotations, err = t.CommonAnnotations.MergeAll( input.CommonAnnotations) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge CommonAnnotations fieldSpec") } merged.CommonLabels, err = t.CommonLabels.MergeAll(input.CommonLabels) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge CommonLabels fieldSpec") + } + merged.TemplateLabels, err = t.TemplateLabels.MergeAll(input.TemplateLabels) + if err != nil { + return nil, errors.WrapPrefixf(err, "failed to merge TemplateLabels fieldSpec") } merged.VarReference, err = t.VarReference.MergeAll(input.VarReference) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge VarReference fieldSpec") } merged.NameReference, err = t.NameReference.mergeAll(input.NameReference) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge NameReference fieldSpec") } merged.Images, err = t.Images.MergeAll(input.Images) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge Images fieldSpec") } merged.Replicas, err = t.Replicas.MergeAll(input.Replicas) if err != nil { - return nil, err + return nil, errors.WrapPrefixf(err, "failed to merge Replicas fieldSpec") } merged.sortFields() return merged, nil diff --git a/api/internal/target/kusttarget_configplugin.go b/api/internal/target/kusttarget_configplugin.go index 0991c5fac..9a3c63086 100644 --- a/api/internal/target/kusttarget_configplugin.go +++ b/api/internal/target/kusttarget_configplugin.go @@ -286,9 +286,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( if label.IncludeSelectors { fss, err = fss.MergeAll(tc.CommonLabels) } else { - // merge spec/template/metadata fieldSpec if includeTemplate flag is true + // merge spec/template/metadata fieldSpecs if includeTemplate flag is true if label.IncludeTemplates { - fss, err = fss.MergeOne(types.FieldSpec{Path: "spec/template/metadata/labels", CreateIfNotPresent: false}) + fss, err = fss.MergeAll(tc.TemplateLabels) if err != nil { return nil, errors.Wrap(err, "failed to merge template fieldSpec") } diff --git a/api/konfig/builtinpluginconsts/commonlabels.go b/api/konfig/builtinpluginconsts/commonlabels.go index 7775a544f..b2a78f568 100644 --- a/api/konfig/builtinpluginconsts/commonlabels.go +++ b/api/konfig/builtinpluginconsts/commonlabels.go @@ -5,9 +5,6 @@ package builtinpluginconsts const commonLabelFieldSpecs = ` commonLabels: -- path: metadata/labels - create: true - - path: spec/selector create: true version: v1 @@ -17,20 +14,10 @@ commonLabels: create: true version: v1 kind: ReplicationController - -- path: spec/template/metadata/labels - create: true - version: v1 - kind: ReplicationController - - path: spec/selector/matchLabels create: true kind: Deployment -- path: spec/template/metadata/labels - create: true - kind: Deployment - - path: spec/template/spec/affinity/podAffinity/preferredDuringSchedulingIgnoredDuringExecution/podAffinityTerm/labelSelector/matchLabels create: false group: apps @@ -60,28 +47,15 @@ commonLabels: create: true kind: ReplicaSet -- path: spec/template/metadata/labels - create: true - kind: ReplicaSet - - path: spec/selector/matchLabels create: true kind: DaemonSet -- path: spec/template/metadata/labels - create: true - kind: DaemonSet - - path: spec/selector/matchLabels create: true group: apps kind: StatefulSet -- path: spec/template/metadata/labels - create: true - group: apps - kind: StatefulSet - - path: spec/template/spec/affinity/podAffinity/preferredDuringSchedulingIgnoredDuringExecution/podAffinityTerm/labelSelector/matchLabels create: false group: apps @@ -107,36 +81,16 @@ commonLabels: group: apps kind: StatefulSet -- path: spec/volumeClaimTemplates[]/metadata/labels - create: true - group: apps - kind: StatefulSet - - path: spec/selector/matchLabels create: false group: batch kind: Job -- path: spec/template/metadata/labels - create: true - group: batch - kind: Job - - path: spec/jobTemplate/spec/selector/matchLabels create: false group: batch kind: CronJob -- path: spec/jobTemplate/metadata/labels - create: true - group: batch - kind: CronJob - -- path: spec/jobTemplate/spec/template/metadata/labels - create: true - group: batch - kind: CronJob - - path: spec/selector/matchLabels create: false group: policy @@ -156,4 +110,4 @@ commonLabels: create: false group: networking.k8s.io kind: NetworkPolicy -` +` + metadataLabelsFieldSpecs diff --git a/api/konfig/builtinpluginconsts/defaultconfig.go b/api/konfig/builtinpluginconsts/defaultconfig.go index 29673d76a..2f220cb29 100644 --- a/api/konfig/builtinpluginconsts/defaultconfig.go +++ b/api/konfig/builtinpluginconsts/defaultconfig.go @@ -13,6 +13,7 @@ func GetDefaultFieldSpecs() []byte { []byte(namePrefixFieldSpecs), []byte(nameSuffixFieldSpecs), []byte(commonLabelFieldSpecs), + []byte(templateLabelFieldSpecs), []byte(commonAnnotationFieldSpecs), []byte(namespaceFieldSpecs), []byte(varReferenceFieldSpecs), @@ -30,6 +31,7 @@ func GetDefaultFieldSpecsAsMap() map[string]string { result["nameprefix"] = namePrefixFieldSpecs result["namesuffix"] = nameSuffixFieldSpecs result["commonlabels"] = commonLabelFieldSpecs + result["templatelabels"] = templateLabelFieldSpecs result["commonannotations"] = commonAnnotationFieldSpecs result["namespace"] = namespaceFieldSpecs result["varreference"] = varReferenceFieldSpecs diff --git a/api/konfig/builtinpluginconsts/metadatalabels.go b/api/konfig/builtinpluginconsts/metadatalabels.go new file mode 100644 index 000000000..d070cca4b --- /dev/null +++ b/api/konfig/builtinpluginconsts/metadatalabels.go @@ -0,0 +1,51 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package builtinpluginconsts + +const metadataLabelsFieldSpecs = ` +- path: metadata/labels + create: true + +- path: spec/template/metadata/labels + create: true + version: v1 + kind: ReplicationController + +- path: spec/template/metadata/labels + create: true + kind: Deployment + +- path: spec/template/metadata/labels + create: true + kind: ReplicaSet + +- path: spec/template/metadata/labels + create: true + kind: DaemonSet + +- path: spec/template/metadata/labels + create: true + group: apps + kind: StatefulSet + +- path: spec/volumeClaimTemplates[]/metadata/labels + create: true + group: apps + kind: StatefulSet + +- path: spec/template/metadata/labels + create: true + group: batch + kind: Job + +- path: spec/jobTemplate/metadata/labels + create: true + group: batch + kind: CronJob + +- path: spec/jobTemplate/spec/template/metadata/labels + create: true + group: batch + kind: CronJob +` diff --git a/api/konfig/builtinpluginconsts/templatelabels.go b/api/konfig/builtinpluginconsts/templatelabels.go new file mode 100644 index 000000000..5d3c9c195 --- /dev/null +++ b/api/konfig/builtinpluginconsts/templatelabels.go @@ -0,0 +1,8 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package builtinpluginconsts + +const templateLabelFieldSpecs = ` +templateLabels: +` + metadataLabelsFieldSpecs diff --git a/api/krusty/inlinelabels_test.go b/api/krusty/inlinelabels_test.go index 2979c27e4..e5b82af16 100644 --- a/api/krusty/inlinelabels_test.go +++ b/api/krusty/inlinelabels_test.go @@ -92,7 +92,7 @@ spec: `) } -func TestKustomizationLabelsInTemplate(t *testing.T) { +func TestKustomizationLabelsInDeploymentTemplate(t *testing.T) { th := kusttest_test.MakeHarness(t) th.WriteF("app/deployment.yaml", ` apiVersion: apps/v1 @@ -160,3 +160,368 @@ spec: foo: bar `) } + +func TestKustomizationLabelsInTemplateWhenLabelsIsNil(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteF("app/deployment.yaml", ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment +spec: + replicas: 1 + template: + spec: + containers: + - name: test-server + image: test-server +`) + th.WriteK("/app", ` +resources: +- deployment.yaml + +commonLabels: + app: test-server + +labels: +- pairs: + app.kubernetes.io/component: a + app.kubernetes.io/instance: b + app.kubernetes.io/name: c + app.kubernetes.io/part-of: d + includeSelectors: false + includeTemplates: true +`) + m := th.Run("/app", th.MakeDefaultOptions()) + th.AssertActualEqualsExpected(m, ` +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: test-server + app.kubernetes.io/component: a + app.kubernetes.io/instance: b + app.kubernetes.io/name: c + app.kubernetes.io/part-of: d + name: deployment +spec: + replicas: 1 + selector: + matchLabels: + app: test-server + template: + metadata: + labels: + app: test-server + app.kubernetes.io/component: a + app.kubernetes.io/instance: b + app.kubernetes.io/name: c + app.kubernetes.io/part-of: d + spec: + containers: + - image: test-server + name: test-server +`) +} + +func TestKustomizationLabelsDoesNotCreateInvalidTemplatePaths(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteF("app/deployment.yaml", ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment +spec: + replicas: 1 + template: + spec: + containers: + - name: test-server + image: test-server +`) + th.WriteF("app/service.yaml", ` +apiVersion: v1 +kind: Service +metadata: + name: service +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 9376 +`) + th.WriteK("/app", ` +resources: +- deployment.yaml +- service.yaml + +commonLabels: + app: test-server + +labels: +- pairs: + app.kubernetes.io/component: a + app.kubernetes.io/instance: b + app.kubernetes.io/name: c + app.kubernetes.io/part-of: d + includeSelectors: false + includeTemplates: true +`) + m := th.Run("/app", th.MakeDefaultOptions()) + th.AssertActualEqualsExpected(m, ` +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: test-server + app.kubernetes.io/component: a + app.kubernetes.io/instance: b + app.kubernetes.io/name: c + app.kubernetes.io/part-of: d + name: deployment +spec: + replicas: 1 + selector: + matchLabels: + app: test-server + template: + metadata: + labels: + app: test-server + app.kubernetes.io/component: a + app.kubernetes.io/instance: b + app.kubernetes.io/name: c + app.kubernetes.io/part-of: d + spec: + containers: + - image: test-server + name: test-server +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: test-server + app.kubernetes.io/component: a + app.kubernetes.io/instance: b + app.kubernetes.io/name: c + app.kubernetes.io/part-of: d + name: service +spec: + ports: + - port: 80 + protocol: TCP + targetPort: 9376 + selector: + app: test-server +`) +} + +func TestKustomizationLabelsInDaemonSetTemplate(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteF("app/ds.yaml", ` +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + app.kubernetes.io/name: daemon + name: daemon +spec: + selector: + matchLabels: + app.kubernetes.io/name: daemon + template: + metadata: + labels: + app.kubernetes.io/name: daemon +`) + th.WriteK("/app", ` +resources: +- ds.yaml + +labels: +- pairs: + foo: bar + includeSelectors: false + includeTemplates: true +`) + m := th.Run("/app", th.MakeDefaultOptions()) + th.AssertActualEqualsExpected(m, ` +apiVersion: apps/v1 +kind: DaemonSet +metadata: + labels: + app.kubernetes.io/name: daemon + foo: bar + name: daemon +spec: + selector: + matchLabels: + app.kubernetes.io/name: daemon + template: + metadata: + labels: + app.kubernetes.io/name: daemon + foo: bar +`) +} + +func TestKustomizationLabelsInStatefulSetTemplate(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteF("app/sts.yaml", ` +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app.kubernetes.io/name: set + name: set +spec: + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: set + serviceName: set + template: + metadata: + labels: + app.kubernetes.io/name: set +`) + th.WriteK("/app", ` +resources: +- sts.yaml + +labels: +- pairs: + foo: bar + includeSelectors: false + includeTemplates: true +`) + m := th.Run("/app", th.MakeDefaultOptions()) + th.AssertActualEqualsExpected(m, ` +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app.kubernetes.io/name: set + foo: bar + name: set +spec: + replicas: 3 + selector: + matchLabels: + app.kubernetes.io/name: set + serviceName: set + template: + metadata: + labels: + app.kubernetes.io/name: set + foo: bar +`) +} + +func TestKustomizationLabelsInCronJobTemplate(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteF("app/cjob.yaml", ` +apiVersion: batch/v1 +kind: CronJob +metadata: + labels: + app.kubernetes.io/name: job + name: job +spec: + jobTemplate: + spec: + backoffLimit: 4 + template: + metadata: + labels: + app.kubernetes.io/name: job + spec: + restartPolicy: Never + schedule: '* * * * *' +`) + th.WriteK("/app", ` +resources: +- cjob.yaml + +labels: +- pairs: + foo: bar + includeSelectors: false + includeTemplates: true +`) + m := th.Run("/app", th.MakeDefaultOptions()) + th.AssertActualEqualsExpected(m, ` +apiVersion: batch/v1 +kind: CronJob +metadata: + labels: + app.kubernetes.io/name: job + foo: bar + name: job +spec: + jobTemplate: + metadata: + labels: + foo: bar + spec: + backoffLimit: 4 + template: + metadata: + labels: + app.kubernetes.io/name: job + foo: bar + spec: + restartPolicy: Never + schedule: '* * * * *' +`) +} + +func TestKustomizationLabelsInJobTemplate(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteF("app/job.yaml", ` +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app.kubernetes.io/name: job + name: job +spec: + backoffLimit: 4 + template: + metadata: + labels: + app.kubernetes.io/name: job + spec: + restartPolicy: Never +`) + th.WriteK("/app", ` +resources: +- job.yaml + +labels: +- pairs: + foo: bar + includeSelectors: false + includeTemplates: true +`) + m := th.Run("/app", th.MakeDefaultOptions()) + th.AssertActualEqualsExpected(m, ` +apiVersion: batch/v1 +kind: Job +metadata: + labels: + app.kubernetes.io/name: job + foo: bar + name: job +spec: + backoffLimit: 4 + template: + metadata: + labels: + app.kubernetes.io/name: job + foo: bar + spec: + restartPolicy: Never +`) +}