diff --git a/api/internal/konfig/builtinpluginconsts/commonlabels.go b/api/internal/konfig/builtinpluginconsts/commonlabels.go index b2a78f5681..1130b43d3e 100644 --- a/api/internal/konfig/builtinpluginconsts/commonlabels.go +++ b/api/internal/konfig/builtinpluginconsts/commonlabels.go @@ -110,4 +110,4 @@ commonLabels: create: false group: networking.k8s.io kind: NetworkPolicy -` + metadataLabelsFieldSpecs +` + metadataLabelsFieldSpecs + volumeClaimTemplatesMetadataLabels diff --git a/api/internal/konfig/builtinpluginconsts/defaultconfig.go b/api/internal/konfig/builtinpluginconsts/defaultconfig.go index 2f220cb29a..4f648c5fdf 100644 --- a/api/internal/konfig/builtinpluginconsts/defaultconfig.go +++ b/api/internal/konfig/builtinpluginconsts/defaultconfig.go @@ -14,6 +14,7 @@ func GetDefaultFieldSpecs() []byte { []byte(nameSuffixFieldSpecs), []byte(commonLabelFieldSpecs), []byte(templateLabelFieldSpecs), + []byte(volumeClaimTemplateLabelFieldSpecs), []byte(commonAnnotationFieldSpecs), []byte(namespaceFieldSpecs), []byte(varReferenceFieldSpecs), @@ -32,6 +33,7 @@ func GetDefaultFieldSpecsAsMap() map[string]string { result["namesuffix"] = nameSuffixFieldSpecs result["commonlabels"] = commonLabelFieldSpecs result["templatelabels"] = templateLabelFieldSpecs + result["volumeclaimtemplatelabels"] = volumeClaimTemplateLabelFieldSpecs result["commonannotations"] = commonAnnotationFieldSpecs result["namespace"] = namespaceFieldSpecs result["varreference"] = varReferenceFieldSpecs diff --git a/api/internal/konfig/builtinpluginconsts/metadatalabels.go b/api/internal/konfig/builtinpluginconsts/metadatalabels.go index d070cca4b8..d9d6eb0e12 100644 --- a/api/internal/konfig/builtinpluginconsts/metadatalabels.go +++ b/api/internal/konfig/builtinpluginconsts/metadatalabels.go @@ -29,11 +29,6 @@ const metadataLabelsFieldSpecs = ` group: apps kind: StatefulSet -- path: spec/volumeClaimTemplates[]/metadata/labels - create: true - group: apps - kind: StatefulSet - - path: spec/template/metadata/labels create: true group: batch diff --git a/api/internal/konfig/builtinpluginconsts/volumeclaimmetadatalabels.go b/api/internal/konfig/builtinpluginconsts/volumeclaimmetadatalabels.go new file mode 100644 index 0000000000..0a693674cc --- /dev/null +++ b/api/internal/konfig/builtinpluginconsts/volumeclaimmetadatalabels.go @@ -0,0 +1,15 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package builtinpluginconsts + +const volumeClaimTemplateLabelFieldSpecs = ` +volumeClaimTemplateLabels: +` + volumeClaimTemplatesMetadataLabels + +const volumeClaimTemplatesMetadataLabels = ` +- path: spec/volumeClaimTemplates[]/metadata/labels + create: true + group: apps + kind: StatefulSet +` diff --git a/api/internal/plugins/builtinconfig/transformerconfig.go b/api/internal/plugins/builtinconfig/transformerconfig.go index b5d4b7aec1..4390c726b7 100644 --- a/api/internal/plugins/builtinconfig/transformerconfig.go +++ b/api/internal/plugins/builtinconfig/transformerconfig.go @@ -19,17 +19,18 @@ import ( //nolint:tagalign type TransformerConfig struct { // if any fields are added, update the DeepCopy implementation - NamePrefix types.FsSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"` - 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"` - Labels types.FsSlice `json:"labels,omitempty" yaml:"labels,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"` - Images types.FsSlice `json:"images,omitempty" yaml:"images,omitempty"` - Replicas types.FsSlice `json:"replicas,omitempty" yaml:"replicas,omitempty"` + NamePrefix types.FsSlice `json:"namePrefix,omitempty" yaml:"namePrefix,omitempty"` + 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"` + Labels types.FsSlice `json:"labels,omitempty" yaml:"labels,omitempty"` + TemplateLabels types.FsSlice `json:"templateLabels,omitempty" yaml:"templateLabels,omitempty"` + VolumeClaimTemplateLabels types.FsSlice `json:"volumeClaimTemplateLabels,omitempty" yaml:"volumeClaimTemplateLabels,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"` + Images types.FsSlice `json:"images,omitempty" yaml:"images,omitempty"` + Replicas types.FsSlice `json:"replicas,omitempty" yaml:"replicas,omitempty"` } // MakeEmptyConfig returns an empty TransformerConfig object @@ -40,17 +41,18 @@ func MakeEmptyConfig() *TransformerConfig { // DeepCopy returns a new copy of TransformerConfig func (t *TransformerConfig) DeepCopy() *TransformerConfig { return &TransformerConfig{ - NamePrefix: t.NamePrefix.DeepCopy(), - NameSuffix: t.NameSuffix.DeepCopy(), - NameSpace: t.NameSpace.DeepCopy(), - CommonLabels: t.CommonLabels.DeepCopy(), - Labels: t.Labels.DeepCopy(), - TemplateLabels: t.TemplateLabels.DeepCopy(), - CommonAnnotations: t.CommonAnnotations.DeepCopy(), - NameReference: t.NameReference.DeepCopy(), - VarReference: t.VarReference.DeepCopy(), - Images: t.Images.DeepCopy(), - Replicas: t.Replicas.DeepCopy(), + NamePrefix: t.NamePrefix.DeepCopy(), + NameSuffix: t.NameSuffix.DeepCopy(), + NameSpace: t.NameSpace.DeepCopy(), + CommonLabels: t.CommonLabels.DeepCopy(), + Labels: t.Labels.DeepCopy(), + TemplateLabels: t.TemplateLabels.DeepCopy(), + VolumeClaimTemplateLabels: t.VolumeClaimTemplateLabels.DeepCopy(), + CommonAnnotations: t.CommonAnnotations.DeepCopy(), + NameReference: t.NameReference.DeepCopy(), + VarReference: t.VarReference.DeepCopy(), + Images: t.Images.DeepCopy(), + Replicas: t.Replicas.DeepCopy(), } } @@ -100,6 +102,7 @@ func (t *TransformerConfig) sortFields() { sort.Sort(t.CommonLabels) sort.Sort(t.Labels) sort.Sort(t.TemplateLabels) + sort.Sort(t.VolumeClaimTemplateLabels) sort.Sort(t.CommonAnnotations) sort.Sort(t.NameReference) sort.Sort(t.VarReference) @@ -181,6 +184,10 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) ( if err != nil { return nil, errors.WrapPrefixf(err, "failed to merge TemplateLabels fieldSpec") } + merged.VolumeClaimTemplateLabels, err = t.VolumeClaimTemplateLabels.MergeAll(input.VolumeClaimTemplateLabels) + if err != nil { + return nil, errors.WrapPrefixf(err, "failed to merge VolumeClaimTemplateLabels fieldSpec") + } merged.VarReference, err = t.VarReference.MergeAll(input.VarReference) if err != nil { return nil, errors.WrapPrefixf(err, "failed to merge VarReference fieldSpec") diff --git a/api/internal/target/kusttarget_configplugin.go b/api/internal/target/kusttarget_configplugin.go index 1ba028a36f..48101ed1d9 100644 --- a/api/internal/target/kusttarget_configplugin.go +++ b/api/internal/target/kusttarget_configplugin.go @@ -305,6 +305,13 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( return nil, errors.WrapPrefixf(err, "failed to merge template fieldSpec") } } + // merge spec/volumeClaimTemplates[]/metadata fieldSpecs if includeVolumeClaimTemplates flag is true + if label.IncludeVolumeClaimTemplates { + fss, err = fss.MergeAll(tc.VolumeClaimTemplateLabels) + if err != nil { + return nil, errors.WrapPrefixf(err, "failed to merge volumeClaimTemplate fieldSpec") + } + } // only add to metadata by default fss, err = fss.MergeOne(types.FieldSpec{Path: "metadata/labels", CreateIfNotPresent: true}) } diff --git a/api/krusty/inlinelabels_test.go b/api/krusty/inlinelabels_test.go index e5b82af160..6eb4f7a200 100644 --- a/api/krusty/inlinelabels_test.go +++ b/api/krusty/inlinelabels_test.go @@ -419,6 +419,164 @@ spec: `) } +func TestKustomizationLabelsInStatefulSetTemplateWithClaimTemplateAndIncludeVolumeClaimTemplatesFalse(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 + volumeMounts: + - mountPath: /usr/src/app/data + name: usrdata + volumeClaimTemplates: + - metadata: + name: usrdata + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +`) + th.WriteK("/app", ` +resources: +- sts.yaml + +labels: +- pairs: + foo: bar + includeSelectors: false + includeTemplates: true + includeVolumeClaimTemplates: false +`) + 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 + volumeMounts: + - mountPath: /usr/src/app/data + name: usrdata + volumeClaimTemplates: + - metadata: + name: usrdata + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +`) +} + +func TestKustomizationLabelsInStatefulSetTemplateWithClaimTemplateAndIncludeVolumeClaimTemplatesTrue(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 + volumeMounts: + - mountPath: /usr/src/app/data + name: usrdata + volumeClaimTemplates: + - metadata: + name: usrdata + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +`) + th.WriteK("/app", ` +resources: +- sts.yaml + +labels: +- pairs: + foo: bar + includeSelectors: false + includeTemplates: true + includeVolumeClaimTemplates: 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 + volumeMounts: + - mountPath: /usr/src/app/data + name: usrdata + volumeClaimTemplates: + - metadata: + labels: + foo: bar + name: usrdata + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi +`) +} + func TestKustomizationLabelsInCronJobTemplate(t *testing.T) { th := kusttest_test.MakeHarness(t) th.WriteF("app/cjob.yaml", ` diff --git a/api/types/labels.go b/api/types/labels.go index 35f7fb2a5b..25ed9ee8bb 100644 --- a/api/types/labels.go +++ b/api/types/labels.go @@ -15,8 +15,13 @@ type Label struct { // spec/template/metadata fieldSpec. Custom fieldSpecs specified by // FieldSpecs will be merged with spec/template/metadata fieldSpec if this // is true. If IncludeSelectors is true, IncludeTemplates is not needed. - IncludeTemplates bool `json:"includeTemplates,omitempty" yaml:"includeTemplates,omitempty"` - FieldSpecs []FieldSpec `json:"fields,omitempty" yaml:"fields,omitempty"` + IncludeTemplates bool `json:"includeTemplates,omitempty" yaml:"includeTemplates,omitempty"` + // IncludeVolumeClaimTemplates indicates whether the transformer should include the + // spec/volumeClaimTemplates[]/metadata fieldSpec. Custom fieldSpecs specified by + // FieldSpecs will be merged with spec/volumeClaimTemplates[]/metadata fieldSpec if this + // is true. If IncludeSelectors is true, IncludeVolumeClaimTemplates is not needed. + IncludeVolumeClaimTemplates bool `json:"includeVolumeClaimTemplates,omitempty" yaml:"includeVolumeClaimTemplates,omitempty"` + FieldSpecs []FieldSpec `json:"fields,omitempty" yaml:"fields,omitempty"` } func labelFromCommonLabels(commonLabels map[string]string) *Label {