diff --git a/api/builtins/PatchTransformer.go b/api/builtins/PatchTransformer.go index 0696f3e1a6..99f48e7489 100644 --- a/api/builtins/PatchTransformer.go +++ b/api/builtins/PatchTransformer.go @@ -21,6 +21,7 @@ type PatchTransformerPlugin struct { Path string `json:"path,omitempty" yaml:"path,omitempty"` Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"` + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"` } func (p *PatchTransformerPlugin) Config( @@ -60,6 +61,12 @@ func (p *PatchTransformerPlugin) Config( } if errSM == nil { p.loadedPatch = patchSM + if p.Options["allowNameChange"] { + p.loadedPatch.SetAllowNameChange("true") + } + if p.Options["allowKindChange"] { + p.loadedPatch.SetAllowKindChange("true") + } } else { p.decodedPatch = patchJson } diff --git a/api/internal/accumulator/resaccumulator_test.go b/api/internal/accumulator/resaccumulator_test.go index 26000ff661..0c7bf521a5 100644 --- a/api/internal/accumulator/resaccumulator_test.go +++ b/api/internal/accumulator/resaccumulator_test.go @@ -352,6 +352,7 @@ func TestResolveVarsWithNoambiguation(t *testing.T) { "metadata": map[string]interface{}{ "name": "sub-backendOne", "annotations": map[string]interface{}{ + "config.kubernetes.io/previousKinds": "Service", "config.kubernetes.io/previousNames": "backendOne", "config.kubernetes.io/previousNamespaces": "default", "config.kubernetes.io/prefixes": "sub-", diff --git a/api/internal/target/kusttarget_configplugin.go b/api/internal/target/kusttarget_configplugin.go index 640cc742ad..0cf629b82b 100644 --- a/api/internal/target/kusttarget_configplugin.go +++ b/api/internal/target/kusttarget_configplugin.go @@ -201,14 +201,16 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func( return } var c struct { - Path string `json:"path,omitempty" yaml:"path,omitempty"` - Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` - Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty"` + Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` + Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"` + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"` } for _, pc := range kt.kustomization.Patches { c.Target = pc.Target c.Patch = pc.Patch c.Path = pc.Path + c.Options = pc.Options p := f() err = kt.configureBuiltinPlugin(p, c, bpt) if err != nil { diff --git a/api/krusty/gvknpatch_test.go b/api/krusty/gvknpatch_test.go index 970c7535e7..763d885864 100644 --- a/api/krusty/gvknpatch_test.go +++ b/api/krusty/gvknpatch_test.go @@ -14,7 +14,6 @@ import ( // GVKN shouldn't change with default options func TestKeepOriginalGVKN(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -27,14 +26,12 @@ spec: - name: nginx image: nginx `) - th.WriteF("patch.yaml", ` apiVersion: v1 kind: StatefulSet metadata: name: new-name `) - th.WriteK(".", ` resources: - deployment.yaml @@ -44,7 +41,6 @@ patches: target: kind: Deployment `) - m := th.Run(".", th.MakeDefaultOptions()) th.AssertActualEqualsExpected(m, ` apiVersion: v1 @@ -64,7 +60,6 @@ spec: // These tests document behavior that will change func TestChangeName(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -77,14 +72,12 @@ spec: - name: nginx image: nginx `) - th.WriteF("patch.yaml", ` apiVersion: v1 kind: Deployment metadata: name: new-name `) - th.WriteK(".", ` resources: - deployment.yaml @@ -93,18 +86,16 @@ patches: - path: patch.yaml target: kind: Deployment + options: + allowNameChange: true `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - - // name should become `new-name` m := th.Run(".", options) th.AssertActualEqualsExpected(m, ` apiVersion: v1 kind: Deployment metadata: - name: old-name + name: new-name spec: template: spec: @@ -116,7 +107,6 @@ spec: func TestChangeKind(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -129,32 +119,27 @@ spec: - name: nginx image: nginx `) - th.WriteF("patch.yaml", ` apiVersion: v1 kind: StatefulSet metadata: name: old-name `) - th.WriteK(".", ` resources: - deployment.yaml - patches: - path: patch.yaml target: kind: Deployment + options: + allowKindChange: true `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - - // kind should become `StatefulSet` m := th.Run(".", options) th.AssertActualEqualsExpected(m, ` apiVersion: v1 -kind: Deployment +kind: StatefulSet metadata: name: old-name spec: @@ -168,7 +153,6 @@ spec: func TestChangeNameAndKind(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -181,35 +165,30 @@ spec: - name: nginx image: nginx `) - th.WriteF("patch.yaml", ` apiVersion: v1 kind: StatefulSet metadata: name: new-name `) - th.WriteK(".", ` resources: - deployment.yaml - patches: - path: patch.yaml target: kind: Deployment + options: + allowNameChange: true + allowKindChange: true `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - - // kind should become `StatefulSet` - // name should become `new-name` m := th.Run(".", options) th.AssertActualEqualsExpected(m, ` apiVersion: v1 -kind: Deployment +kind: StatefulSet metadata: - name: old-name + name: new-name spec: template: spec: @@ -219,12 +198,10 @@ spec: `) } -// https://github.com/kubernetes-sigs/kustomize/issues/3280 // Should be able to refer to a resource with either its // original GVKN or its current one func TestPatchOriginalName(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("base/deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -246,13 +223,13 @@ metadata: th.WriteK("base", ` resources: - deployment.yaml - patches: - path: patch.yaml target: kind: Deployment + options: + allowNameChange: true `) - th.WriteK("overlay", ` resources: - ../base @@ -267,17 +244,13 @@ metadata: spec: replicas: 999 `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - - // name should become `new-name` m := th.Run("overlay", options) th.AssertActualEqualsExpected(m, ` apiVersion: v1 kind: Deployment metadata: - name: old-name + name: new-name spec: replicas: 999 template: @@ -290,7 +263,6 @@ spec: func TestPatchNewName(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("base/deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -312,13 +284,13 @@ metadata: th.WriteK("base", ` resources: - deployment.yaml - patches: - path: patch.yaml target: kind: Deployment + options: + allowNameChange: true `) - th.WriteK("overlay", ` resources: - ../base @@ -333,18 +305,25 @@ metadata: spec: replicas: 999 `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - - // depPatch cannot find target with the name `new-name` - // because base/patch.yaml can't yet edit the name - assert.Error(t, th.RunWithErr("overlay", options)) + m := th.Run("overlay", options) + th.AssertActualEqualsExpected(m, ` +apiVersion: v1 +kind: Deployment +metadata: + name: new-name +spec: + replicas: 999 + template: + spec: + containers: + - image: nginx + name: nginx +`) } func TestPatchOriginalNameAndKind(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("base/deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -366,13 +345,14 @@ metadata: th.WriteK("base", ` resources: - deployment.yaml - patches: - path: patch.yaml target: kind: Deployment + options: + allowNameChange: true + allowKindChange: true `) - th.WriteK("overlay", ` resources: - ../base @@ -387,18 +367,13 @@ metadata: spec: replicas: 999 `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - - // kind should become `StatefulSet` - // name should become `new-name` m := th.Run("overlay", options) th.AssertActualEqualsExpected(m, ` apiVersion: v1 -kind: Deployment +kind: StatefulSet metadata: - name: old-name + name: new-name spec: replicas: 999 template: @@ -411,7 +386,6 @@ spec: func TestPatchNewNameAndKind(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("base/deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -433,13 +407,14 @@ metadata: th.WriteK("base", ` resources: - deployment.yaml - patches: - path: patch.yaml target: kind: Deployment + options: + allowNameChange: true + allowKindChange: true `) - th.WriteK("overlay", ` resources: - ../base @@ -454,20 +429,27 @@ metadata: spec: replicas: 999 `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - - // depPatch cannot find target with kind `StatefulSet` and name `new-name` - // because base/patch.yaml can't yet edit the kind or name - assert.Error(t, th.RunWithErr("overlay", options)) + m := th.Run("overlay", options) + th.AssertActualEqualsExpected(m, ` +apiVersion: v1 +kind: StatefulSet +metadata: + name: new-name +spec: + replicas: 999 + template: + spec: + containers: + - image: nginx + name: nginx +`) } // Use original name, but new kind // Should fail, even after #3280 is done, because this ID is invalid func TestPatchOriginalNameAndNewKind(t *testing.T) { th := kusttest_test.MakeHarness(t) - th.WriteF("base/deployment.yaml", ` apiVersion: v1 kind: Deployment @@ -489,13 +471,14 @@ metadata: th.WriteK("base", ` resources: - deployment.yaml - patches: - path: patch.yaml target: kind: Deployment + options: + allowNameChange: true + allowKindChange: true `) - th.WriteK("overlay", ` resources: - ../base @@ -510,10 +493,7 @@ metadata: spec: replicas: 999 `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true - // depPatch cannot find target with kind `Deployment` and name `new-name` // because the resource never had this GVKN assert.Error(t, th.RunWithErr("overlay", options)) @@ -552,12 +532,11 @@ spec: func TestBaseReuseNameAndKindConflict(t *testing.T) { th := kusttest_test.MakeHarness(t) - - th.WriteK("/app/shared", ` + th.WriteK("shared", ` resources: - deployment.yaml `) - th.WriteF("/app/shared/deployment.yaml", ` + th.WriteF("shared/deployment.yaml", ` apiVersion: v1 kind: Deployment metadata: @@ -570,53 +549,139 @@ spec: image: nginx `) - th.WriteK("/app/component1/base", ` + th.WriteK("component1/base", ` resources: - ../../shared `) - th.WriteK("/app/component1/overlay", ` + th.WriteK("component1/overlay", ` resources: - ../base - namePrefix: overlay- `) - th.WriteK("/app/component2/base", ` + th.WriteK("component2/base", ` resources: - ../../shared - patches: - path: patch.yaml target: kind: Deployment name: my-deploy + options: + allowNameChange: true + allowKindChange: true `) - th.WriteF("/app/component2/base/patch.yaml", ` + th.WriteF("component2/base/patch.yaml", ` apiVersion: v1 kind: StatefulSet metadata: name: my-stateful-set `) - th.WriteK("/app/component2/overlay", ` + th.WriteK("component2/overlay", ` resources: - ../base - namePrefix: overlay- `) - th.WriteK("/app", ` + th.WriteK(".", ` resources: - component1/overlay - component2/overlay `) - options := th.MakeDefaultOptions() - options.AllowResourceIdChanges = true + m := th.Run(".", options) + th.AssertActualEqualsExpected(m, ` +apiVersion: v1 +kind: Deployment +metadata: + name: overlay-my-deploy +spec: + template: + spec: + containers: + - image: nginx + name: nginx +--- +apiVersion: v1 +kind: StatefulSet +metadata: + name: overlay-my-stateful-set +spec: + template: + spec: + containers: + - image: nginx + name: nginx +`) +} - // Error occurs when app/component2/base tries to load the shared resources - // because the kind is not (yet) allowed to change yet - // so it loads a second Deployment with the name my-deploy - // instead of a StatefulSet as specified by the patch. - // Will be fixed by #3280. - assert.Error(t, th.RunWithErr("overlay", options)) +func TestNameReferenceAfterGvknChange(t *testing.T) { + th := kusttest_test.MakeHarness(t) + th.WriteF("configMap.yaml", ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: old-name +`) + th.WriteF("patch.yaml", ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: new-name +`) + th.WriteF("deployment.yaml", ` +apiVersion: v1 +kind: Deployment +metadata: + name: deploy +spec: + template: + spec: + containers: + - env: + - valueFrom: + configMapKeyRef: + name: old-name + key: somekey + envFrom: + - configMapRef: + name: old-name + key: somekey +`) + th.WriteK(".", ` +resources: +- configMap.yaml +- deployment.yaml +patches: +- path: patch.yaml + target: + kind: ConfigMap + options: + allowNameChange: true +`) + m := th.Run(".", th.MakeDefaultOptions()) + th.AssertActualEqualsExpected(m, ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: new-name +--- +apiVersion: v1 +kind: Deployment +metadata: + name: deploy +spec: + template: + spec: + containers: + - env: + - valueFrom: + configMapKeyRef: + key: somekey + name: new-name + envFrom: + - configMapRef: + key: somekey + name: new-name +`) } diff --git a/api/krusty/options.go b/api/krusty/options.go index a7229fee21..91fd707a9f 100644 --- a/api/krusty/options.go +++ b/api/krusty/options.go @@ -33,21 +33,16 @@ type Options struct { // Options related to kustomize plugins. PluginConfig *types.PluginConfig - - // When true, allow name and kind changing via a patch - // When false, patch name/kind don't overwrite target name/kind - AllowResourceIdChanges bool } // MakeDefaultOptions returns a default instance of Options. func MakeDefaultOptions() *Options { return &Options{ - DoLegacyResourceSort: false, - AddManagedbyLabel: false, - LoadRestrictions: types.LoadRestrictionsRootOnly, - DoPrune: false, - PluginConfig: konfig.DisabledPluginConfig(), - AllowResourceIdChanges: false, + DoLegacyResourceSort: false, + AddManagedbyLabel: false, + LoadRestrictions: types.LoadRestrictionsRootOnly, + DoPrune: false, + PluginConfig: konfig.DisabledPluginConfig(), } } diff --git a/api/resmap/reswrangler.go b/api/resmap/reswrangler.go index f76276c481..478b67e1b9 100644 --- a/api/resmap/reswrangler.go +++ b/api/resmap/reswrangler.go @@ -596,6 +596,7 @@ func (m *resWrangler) ApplySmPatch( patchCopy := patch.DeepCopy() patchCopy.CopyMergeMetaDataFieldsFrom(patch) patchCopy.SetGvk(res.GetGvk()) + patchCopy.SetKind(patch.GetKind()) err := res.ApplySmPatch(patchCopy) if err != nil { // Check for an error string from UnmarshalJSON that's indicative diff --git a/api/resmap/reswrangler_test.go b/api/resmap/reswrangler_test.go index 6b3d8c387d..e6bce67a80 100644 --- a/api/resmap/reswrangler_test.go +++ b/api/resmap/reswrangler_test.go @@ -339,6 +339,7 @@ func TestGetMatchingResourcesByAnyId(t *testing.T) { "metadata": map[string]interface{}{ "name": "new-alice", "annotations": map[string]interface{}{ + "config.kubernetes.io/previousKinds": "ConfigMap", "config.kubernetes.io/previousNames": "alice", "config.kubernetes.io/previousNamespaces": "default", }, @@ -351,6 +352,7 @@ func TestGetMatchingResourcesByAnyId(t *testing.T) { "metadata": map[string]interface{}{ "name": "new-bob", "annotations": map[string]interface{}{ + "config.kubernetes.io/previousKinds": "ConfigMap,ConfigMap", "config.kubernetes.io/previousNames": "bob,bob2", "config.kubernetes.io/previousNamespaces": "default,default", }, @@ -364,6 +366,7 @@ func TestGetMatchingResourcesByAnyId(t *testing.T) { "name": "new-bob", "namespace": "new-happy", "annotations": map[string]interface{}{ + "config.kubernetes.io/previousKinds": "ConfigMap", "config.kubernetes.io/previousNames": "bob", "config.kubernetes.io/previousNamespaces": "happy", }, @@ -377,6 +380,7 @@ func TestGetMatchingResourcesByAnyId(t *testing.T) { "name": "charlie", "namespace": "happy", "annotations": map[string]interface{}{ + "config.kubernetes.io/previousKinds": "ConfigMap", "config.kubernetes.io/previousNames": "charlie", "config.kubernetes.io/previousNamespaces": "default", }, diff --git a/api/resource/factory.go b/api/resource/factory.go index df08c5dbf5..b04b3ef3b2 100644 --- a/api/resource/factory.go +++ b/api/resource/factory.go @@ -41,7 +41,8 @@ func (rf *Factory) FromMapWithName(n string, m map[string]interface{}) *Resource // FromMapWithNamespaceAndName returns a new instance with the given "original" namespace. func (rf *Factory) FromMapWithNamespaceAndName(ns string, n string, m map[string]interface{}) *Resource { - return rf.makeOne(rf.kf.FromMap(m), nil).setPreviousNamespaceAndName(ns, n) + r := rf.makeOne(rf.kf.FromMap(m), nil) + return r.setPreviousId(ns, n, r.GetKind()) } // FromMapAndOption returns a new instance of Resource with given options. @@ -157,7 +158,7 @@ func (rf *Factory) SliceFromBytesWithNames(names []string, in []byte) ([]*Resour return nil, fmt.Errorf("number of names doesn't match number of resources") } for i, res := range result { - res.setPreviousNamespaceAndName(resid.DefaultNamespace, names[i]) + res.setPreviousId(resid.DefaultNamespace, names[i], res.GetKind()) } return result, nil } diff --git a/api/resource/resource.go b/api/resource/resource.go index d9f2b107b0..71aafd7a2a 100644 --- a/api/resource/resource.go +++ b/api/resource/resource.go @@ -33,17 +33,26 @@ type Resource struct { } const ( + buildAnnotationPreviousKinds = konfig.ConfigAnnoDomain + "/previousKinds" buildAnnotationPreviousNames = konfig.ConfigAnnoDomain + "/previousNames" buildAnnotationPrefixes = konfig.ConfigAnnoDomain + "/prefixes" buildAnnotationSuffixes = konfig.ConfigAnnoDomain + "/suffixes" buildAnnotationPreviousNamespaces = konfig.ConfigAnnoDomain + "/previousNamespaces" + + // the following are only for patches, to specify whether they can change names + // and kinds of their targets + buildAnnotationAllowNameChange = konfig.ConfigAnnoDomain + "/allowNameChange" + buildAnnotationAllowKindChange = konfig.ConfigAnnoDomain + "/allowKindChange" ) var buildAnnotations = []string{ + buildAnnotationPreviousKinds, buildAnnotationPreviousNames, buildAnnotationPrefixes, buildAnnotationSuffixes, buildAnnotationPreviousNamespaces, + buildAnnotationAllowNameChange, + buildAnnotationAllowKindChange, } func (r *Resource) ResetPrimaryData(incoming *Resource) { @@ -157,6 +166,12 @@ func (r *Resource) SetNamespace(n string) { r.kunStr.SetNamespace(n) } +func (r *Resource) SetKind(k string) { + gvk := r.GetGvk() + gvk.Kind = k + r.SetGvk(gvk) +} + func (r *Resource) UnmarshalJSON(s []byte) error { return r.kunStr.UnmarshalJSON(s) } @@ -351,12 +366,41 @@ func (r *Resource) RemoveBuildAnnotations() { r.SetAnnotations(annotations) } -func (r *Resource) setPreviousNamespaceAndName(ns string, n string) *Resource { +func (r *Resource) setPreviousId(ns string, n string, k string) *Resource { r.appendCsvAnnotation(buildAnnotationPreviousNames, n) r.appendCsvAnnotation(buildAnnotationPreviousNamespaces, ns) + r.appendCsvAnnotation(buildAnnotationPreviousKinds, k) return r } +func (r *Resource) SetAllowNameChange(value string) { + annotations := r.GetAnnotations() + annotations[buildAnnotationAllowNameChange] = value + r.SetAnnotations(annotations) +} + +func (r *Resource) NameChangeAllowed() bool { + annotations := r.GetAnnotations() + if allowed, set := annotations[buildAnnotationAllowNameChange]; set && allowed == "true" { + return true + } + return false +} + +func (r *Resource) SetAllowKindChange(value string) { + annotations := r.GetAnnotations() + annotations[buildAnnotationAllowKindChange] = value + r.SetAnnotations(annotations) +} + +func (r *Resource) KindChangeAllowed() bool { + annotations := r.GetAnnotations() + if allowed, set := annotations[buildAnnotationAllowKindChange]; set && allowed == "true" { + return true + } + return false +} + // String returns resource as JSON. func (r *Resource) String() string { bs, err := r.MarshalJSON() @@ -430,14 +474,19 @@ func (r *Resource) PrevIds() []resid.ResId { // pairs on one annotation so there is no chance of error names := r.getCsvAnnotation(buildAnnotationPreviousNames) ns := r.getCsvAnnotation(buildAnnotationPreviousNamespaces) - if len(names) != len(ns) { + kinds := r.getCsvAnnotation(buildAnnotationPreviousKinds) + if len(names) != len(ns) || len(names) != len(kinds) { panic(errors.New( - "number of previous names not equal to " + - "number of previous namespaces")) + "number of previous names, " + + "number of previous namespaces, " + + "number of previous kinds not equal")) } for i := range names { + k := kinds[i] + gvk := r.GetGvk() + gvk.Kind = k ids = append(ids, resid.NewResIdWithNamespace( - r.GetGvk(), names[i], ns[i])) + gvk, names[i], ns[i])) } return ids } @@ -445,7 +494,7 @@ func (r *Resource) PrevIds() []resid.ResId { // StorePreviousId stores the resource's current ID via build annotations. func (r *Resource) StorePreviousId() { id := r.CurId() - r.setPreviousNamespaceAndName(id.EffectiveNamespace(), id.Name) + r.setPreviousId(id.EffectiveNamespace(), id.Name, id.Kind) } // CurId returns a ResId for the resource using the @@ -482,7 +531,10 @@ func (r *Resource) ApplySmPatch(patch *Resource) error { if err != nil { return err } - n, ns := r.GetName(), r.GetNamespace() + n, ns, k := r.GetName(), r.GetNamespace(), r.GetKind() + if patch.NameChangeAllowed() || patch.KindChangeAllowed() { + r.StorePreviousId() + } err = r.ApplyFilter(patchstrategicmerge.Filter{ Patch: node, }) @@ -493,11 +545,17 @@ func (r *Resource) ApplySmPatch(patch *Resource) error { if err != nil { return err } - if !empty { + if empty { + return nil + } + if !patch.KindChangeAllowed() { + r.SetKind(k) + } + if !patch.NameChangeAllowed() { r.SetName(n) - r.SetNamespace(ns) } - return err + r.SetNamespace(ns) + return nil } func (r *Resource) ApplyFilter(f kio.Filter) error { diff --git a/api/resource/resource_test.go b/api/resource/resource_test.go index 7329bf5593..660cc6245d 100644 --- a/api/resource/resource_test.go +++ b/api/resource/resource_test.go @@ -714,6 +714,7 @@ metadata: kind: Secret metadata: annotations: + config.kubernetes.io/previousKinds: Secret config.kubernetes.io/previousNames: oldName config.kubernetes.io/previousNamespaces: default name: newName @@ -725,6 +726,7 @@ metadata: kind: Secret metadata: annotations: + config.kubernetes.io/previousKinds: Secret config.kubernetes.io/previousNames: oldName config.kubernetes.io/previousNamespaces: default name: oldName2 @@ -735,6 +737,7 @@ metadata: kind: Secret metadata: annotations: + config.kubernetes.io/previousKinds: Secret,Secret config.kubernetes.io/previousNames: oldName,oldName2 config.kubernetes.io/previousNamespaces: default,default name: newName @@ -746,6 +749,7 @@ metadata: kind: Secret metadata: annotations: + config.kubernetes.io/previousKinds: Secret config.kubernetes.io/previousNames: oldName config.kubernetes.io/previousNamespaces: default name: oldName2 @@ -757,6 +761,7 @@ metadata: kind: Secret metadata: annotations: + config.kubernetes.io/previousKinds: Secret,Secret config.kubernetes.io/previousNames: oldName,oldName2 config.kubernetes.io/previousNamespaces: default,oldNamespace name: newName @@ -806,6 +811,7 @@ metadata: kind: Secret metadata: annotations: + config.kubernetes.io/previousKinds: Secret config.kubernetes.io/previousNames: oldName config.kubernetes.io/previousNamespaces: default name: newName @@ -824,6 +830,7 @@ metadata: kind: Secret metadata: annotations: + config.kubernetes.io/previousKinds: Secret,Secret config.kubernetes.io/previousNames: oldName,oldName2 config.kubernetes.io/previousNamespaces: default,oldNamespace name: newName diff --git a/api/types/patch.go b/api/types/patch.go index 48b521d7e8..5310a6e66d 100644 --- a/api/types/patch.go +++ b/api/types/patch.go @@ -3,6 +3,8 @@ package types +import "reflect" + // Patch represent either a Strategic Merge Patch or a JSON patch // and its targets. // The content of the patch can either be from a file @@ -16,6 +18,9 @@ type Patch struct { // Target points to the resources that the patch is applied to Target *Selector `json:"target,omitempty" yaml:"target,omitempty"` + + // Options is a list of options for the patch + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"` } // Equals return true if p equals o. @@ -24,5 +29,6 @@ func (p *Patch) Equals(o Patch) bool { (p.Target != nil && o.Target != nil && *p.Target == *o.Target) return p.Path == o.Path && p.Patch == o.Patch && - targetEqual + targetEqual && + reflect.DeepEqual(p.Options, o.Options) } diff --git a/kustomize/commands/build/build.go b/kustomize/commands/build/build.go index 0fa5177fd1..c7069bfe2c 100644 --- a/kustomize/commands/build/build.go +++ b/kustomize/commands/build/build.go @@ -22,9 +22,8 @@ var theArgs struct { var theFlags struct { outputPath string enable struct { - resourceIdChanges bool - plugins bool - managedByLabel bool + plugins bool + managedByLabel bool } loadRestrictor string reorderOutput string @@ -104,7 +103,6 @@ func NewCmdBuild( AddFlagEnablePlugins(cmd.Flags()) AddFlagReorderOutput(cmd.Flags()) AddFlagEnableManagedbyLabel(cmd.Flags()) - AddFlagAllowResourceIdChanges(cmd.Flags()) return cmd } @@ -140,6 +138,5 @@ func HonorKustomizeFlags(kOpts *krusty.Options) *krusty.Options { kOpts.PluginConfig = c } kOpts.AddManagedbyLabel = isManagedByLabelEnabled() - kOpts.AllowResourceIdChanges = theFlags.enable.resourceIdChanges return kOpts } diff --git a/kustomize/commands/build/flagallowresourceidchanges.go b/kustomize/commands/build/flagallowresourceidchanges.go deleted file mode 100644 index c05aa5b769..0000000000 --- a/kustomize/commands/build/flagallowresourceidchanges.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2019 The Kubernetes Authors. -// SPDX-License-Identifier: Apache-2.0 - -package build - -import ( - "github.com/spf13/pflag" -) - -func AddFlagAllowResourceIdChanges(set *pflag.FlagSet) { - set.BoolVar( - &theFlags.enable.resourceIdChanges, - "allow-id-changes", - false, - `enable changes to a resourceId`) -} diff --git a/kustomize/commands/edit/remove/removepatch.go b/kustomize/commands/edit/remove/removepatch.go index f136d7d701..52b9921929 100644 --- a/kustomize/commands/edit/remove/removepatch.go +++ b/kustomize/commands/edit/remove/removepatch.go @@ -85,7 +85,7 @@ func (o *removePatchOptions) RunRemovePatch(fSys filesys.FileSystem) error { } } if len(patches) == len(m.Patches) { - log.Printf("patch %s doesn't exist in kustomization file", o.Patch) + log.Printf("patch %s doesn't exist in kustomization file", o.Patch.Patch) return nil } m.Patches = patches diff --git a/plugin/builtin/patchtransformer/PatchTransformer.go b/plugin/builtin/patchtransformer/PatchTransformer.go index 1da970b70d..1e26128727 100644 --- a/plugin/builtin/patchtransformer/PatchTransformer.go +++ b/plugin/builtin/patchtransformer/PatchTransformer.go @@ -22,6 +22,7 @@ type plugin struct { Path string `json:"path,omitempty" yaml:"path,omitempty"` Patch string `json:"patch,omitempty" yaml:"patch,omitempty"` Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"` + Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"` } //noinspection GoUnusedGlobalVariable @@ -64,6 +65,12 @@ func (p *plugin) Config( } if errSM == nil { p.loadedPatch = patchSM + if p.Options["allowNameChange"] { + p.loadedPatch.SetAllowNameChange("true") + } + if p.Options["allowKindChange"] { + p.loadedPatch.SetAllowKindChange("true") + } } else { p.decodedPatch = patchJson } diff --git a/plugin/builtin/patchtransformer/PatchTransformer_test.go b/plugin/builtin/patchtransformer/PatchTransformer_test.go index 846e3e3324..9f94263d62 100644 --- a/plugin/builtin/patchtransformer/PatchTransformer_test.go +++ b/plugin/builtin/patchtransformer/PatchTransformer_test.go @@ -296,7 +296,6 @@ spec: - proxy - sidecar `) - rm := th.LoadAndRunTransformer(` apiVersion: builtin kind: PatchTransformer @@ -364,6 +363,8 @@ spec: - sidecar image: docker.io/istio/proxyv2 name: istio-proxy + - image: nginx + name: nginx `) } diff --git a/plugin/builtin/prefixsuffixtransformer/PrefixSuffixTransformer_test.go b/plugin/builtin/prefixsuffixtransformer/PrefixSuffixTransformer_test.go index 192183991f..777ace1336 100644 --- a/plugin/builtin/prefixsuffixtransformer/PrefixSuffixTransformer_test.go +++ b/plugin/builtin/prefixsuffixtransformer/PrefixSuffixTransformer_test.go @@ -64,6 +64,7 @@ kind: Service metadata: annotations: config.kubernetes.io/prefixes: baked- + config.kubernetes.io/previousKinds: Service config.kubernetes.io/previousNames: apple config.kubernetes.io/previousNamespaces: default config.kubernetes.io/suffixes: -pie @@ -87,6 +88,7 @@ kind: ConfigMap metadata: annotations: config.kubernetes.io/prefixes: baked- + config.kubernetes.io/previousKinds: ConfigMap config.kubernetes.io/previousNames: cm config.kubernetes.io/previousNamespaces: default config.kubernetes.io/suffixes: -pie @@ -138,6 +140,7 @@ kind: Deployment metadata: annotations: config.kubernetes.io/prefixes: test- + config.kubernetes.io/previousKinds: Deployment config.kubernetes.io/previousNames: deployment config.kubernetes.io/previousNamespaces: default name: test-deployment