diff --git a/cmd/config/internal/commands/e2e/e2e_test.go b/cmd/config/internal/commands/e2e/e2e_test.go index 54749ed9f2b..d0bf7d09271 100644 --- a/cmd/config/internal/commands/e2e/e2e_test.go +++ b/cmd/config/internal/commands/e2e/e2e_test.go @@ -293,6 +293,8 @@ apiVersion: apps/v1 kind: Deployment metadata: name: foo + annotations: + internal.config.k8s.io/annotations-migration-resource-id: '1' `, } }, diff --git a/kyaml/fn/framework/framework.go b/kyaml/fn/framework/framework.go index 2f7983dcf59..d37c88f8ad4 100644 --- a/kyaml/fn/framework/framework.go +++ b/kyaml/fn/framework/framework.go @@ -117,7 +117,7 @@ func Execute(p ResourceListProcessor, rlSource *kio.ByteReadWriter) error { rl.FunctionConfig = rlSource.FunctionConfig // We store the original - nodeAnnos, err := kio.GetInternalAnnotationsFromResourceList(rl.Items) + nodeAnnos, err := kio.PreprocessResourcesForInternalAnnotationMigration(rl.Items) if err != nil { return err } diff --git a/kyaml/kio/kio.go b/kyaml/kio/kio.go index d3c017ff09f..46047152a32 100644 --- a/kyaml/kio/kio.go +++ b/kyaml/kio/kio.go @@ -7,12 +7,17 @@ package kio import ( "fmt" + "strconv" "sigs.k8s.io/kustomize/kyaml/errors" "sigs.k8s.io/kustomize/kyaml/kio/kioutil" "sigs.k8s.io/kustomize/kyaml/yaml" ) +// resourceIDAnnotation is used to uniquely identify the resource during round trip +// to and from a function execution. +const resourceIDAnnotation = "internal.config.k8s.io/annotations-migration-resource-id" + // Reader reads ResourceNodes. Analogous to io.Reader. type Reader interface { Read() ([]*yaml.RNode, error) @@ -117,7 +122,7 @@ func (p Pipeline) ExecuteWithCallback(callback PipelineExecuteCallbackFunc) erro for i := range p.Filters { // Not all RNodes passed through kio.Pipeline have metadata nor should // they all be required to. - nodeAnnos, err := GetInternalAnnotationsFromResourceList(result) + nodeAnnos, err := PreprocessResourcesForInternalAnnotationMigration(result) if err != nil { return err } @@ -136,7 +141,7 @@ func (p Pipeline) ExecuteWithCallback(callback PipelineExecuteCallbackFunc) erro // If either the internal annotations for path, index, and id OR the legacy // annotations for path, index, and id are changed, we have to update the other. - err = reconcileInternalAnnotations(result, nodeAnnos, false) + err = ReconcileInternalAnnotations(result, nodeAnnos) if err != nil { return err } @@ -164,31 +169,29 @@ func FilterAll(filter yaml.Filter) Filter { }) } -// GetInternalAnnotationsFromResourceList stores the original path, index, and id annotations so that we can reconcile -// it later. This is necessary because currently both internal-prefixed annotations +// PreprocessResourcesForInternalAnnotationMigration returns a mapping from id to all +// internal annotations, so that we can use it to reconcile the annotations +// later. This is necessary because currently both internal-prefixed annotations // and legacy annotations are currently supported, and a change to one must be -// reflected in the other. -func GetInternalAnnotationsFromResourceList(result []*yaml.RNode) (map[nodeAnnotations]map[string]string, error) { - nodeAnnosMap := make(map[nodeAnnotations]map[string]string) - +// reflected in the other if needed. +func PreprocessResourcesForInternalAnnotationMigration(result []*yaml.RNode) (map[string]map[string]string, error) { + idToAnnosMap := make(map[string]map[string]string) for i := range result { - id := kioutil.GetIdAnnotation(result[i]) - path, index, _ := kioutil.GetFileAnnotations(result[i]) - annoKey := nodeAnnotations{ - path: path, - index: index, - id: id, + idStr := strconv.Itoa(i) + err := result[i].PipeE(yaml.SetAnnotation(resourceIDAnnotation, idStr)) + if err != nil { + return nil, err } - nodeAnnosMap[annoKey] = kioutil.GetInternalAnnotations(result[i]) - if err := kioutil.CopyLegacyAnnotations(result[i]); err != nil { + idToAnnosMap[idStr] = kioutil.GetInternalAnnotations(result[i]) + if err = kioutil.CopyLegacyAnnotations(result[i]); err != nil { return nil, err } - - if err := checkMismatchedAnnos(result[i].GetAnnotations()); err != nil { + meta, _ := result[i].GetMeta() + if err = checkMismatchedAnnos(meta.Annotations); err != nil { return nil, err } } - return nodeAnnosMap, nil + return idToAnnosMap, nil } func checkMismatchedAnnos(annotations map[string]string) error { @@ -221,26 +224,17 @@ type nodeAnnotations struct { } // ReconcileInternalAnnotations reconciles the annotation format for path, index and id annotations. -func ReconcileInternalAnnotations(result []*yaml.RNode, nodeAnnosMap map[nodeAnnotations]map[string]string) error { - return reconcileInternalAnnotations(result, nodeAnnosMap, true) -} - -// reconcileInternalAnnotations reconciles the annotation format for path, index and id annotations. -// If formatAnnotations is true, we will ensure the output annotation format matches the format -// in the input. e.g. if the input format uses the legacy format and the output will be converted to -// the legacy format if it's not. -func reconcileInternalAnnotations(result []*yaml.RNode, nodeAnnosMap map[nodeAnnotations]map[string]string, formatAnnotations bool) error { - var useInternal, useLegacy bool - var err error - if formatAnnotations { - if useInternal, useLegacy, err = determineAnnotationsFormat(nodeAnnosMap); err != nil { - return err - } +// It will ensure the output annotation format matches the format in the input. e.g. if the input +// format uses the legacy format and the output will be converted to the legacy format if it's not. +func ReconcileInternalAnnotations(result []*yaml.RNode, nodeAnnosMap map[string]map[string]string) error { + useInternal, useLegacy, err := determineAnnotationsFormat(nodeAnnosMap) + if err != nil { + return err } for i := range result { // if only one annotation is set, set the other. - err := missingInternalOrLegacyAnnotations(result[i]) + err = missingInternalOrLegacyAnnotations(result[i]) if err != nil { return err } @@ -251,26 +245,29 @@ func reconcileInternalAnnotations(result []*yaml.RNode, nodeAnnosMap map[nodeAnn if err != nil { return err } - if formatAnnotations { - // We invoke determineAnnotationsFormat to find out if the original annotations - // use the internal or (and) the legacy format. We format the resources to - // make them consistent with original format. - err = formatInternalAnnotations(result[i], useInternal, useLegacy) - if err != nil { - return err - } + // We invoke determineAnnotationsFormat to find out if the original annotations + // use the internal or (and) the legacy format. We format the resources to + // make them consistent with original format. + err = formatInternalAnnotations(result[i], useInternal, useLegacy) + if err != nil { + return err } // if the annotations are still somehow out of sync, throw an error - err = checkMismatchedAnnos(result[i].GetAnnotations()) + meta, _ := result[i].GetMeta() + err = checkMismatchedAnnos(meta.Annotations) if err != nil { return err } + + if _, err = result[i].Pipe(yaml.ClearAnnotation(resourceIDAnnotation)); err != nil { + return err + } } return nil } // determineAnnotationsFormat determines if the resources are using one of the internal and legacy annotation format or both of them. -func determineAnnotationsFormat(nodeAnnosMap map[nodeAnnotations]map[string]string) (useInternal, useLegacy bool, err error) { +func determineAnnotationsFormat(nodeAnnosMap map[string]map[string]string) (useInternal, useLegacy bool, err error) { if len(nodeAnnosMap) == 0 { return true, true, nil } @@ -280,24 +277,31 @@ func determineAnnotationsFormat(nodeAnnosMap map[nodeAnnotations]map[string]stri _, foundPath := annos[kioutil.PathAnnotation] _, foundIndex := annos[kioutil.IndexAnnotation] _, foundId := annos[kioutil.IdAnnotation] + _, foundLegacyPath := annos[kioutil.LegacyPathAnnotation] + _, foundLegacyIndex := annos[kioutil.LegacyIndexAnnotation] + _, foundLegacyId := annos[kioutil.LegacyIdAnnotation] + + if !(foundPath || foundIndex || foundId || foundLegacyPath || foundLegacyIndex || foundLegacyId) { + continue + } + foundOneOf := foundPath || foundIndex || foundId if internal == nil { - internal = &foundOneOf + f := foundOneOf + internal = &f } if (foundOneOf && !*internal) || (!foundOneOf && *internal) { - err = fmt.Errorf("the formatting in the input resources is not consistent") + err = fmt.Errorf("the annotation formatting in the input resources is not consistent") return } - _, foundPath = annos[kioutil.LegacyPathAnnotation] - _, foundIndex = annos[kioutil.LegacyIndexAnnotation] - _, foundId = annos[kioutil.LegacyIdAnnotation] - foundOneOf = foundPath || foundIndex || foundId + foundOneOf = foundLegacyPath || foundLegacyIndex || foundLegacyId if legacy == nil { - legacy = &foundOneOf + f := foundOneOf + legacy = &f } if (foundOneOf && !*legacy) || (!foundOneOf && *legacy) { - err = fmt.Errorf("the formatting in the input resources is not consistent") + err = fmt.Errorf("the annotation formatting in the input resources is not consistent") return } } @@ -324,8 +328,10 @@ func missingInternalOrLegacyAnnotations(rn *yaml.RNode) error { } func missingInternalOrLegacyAnnotation(rn *yaml.RNode, newKey string, legacyKey string) error { - value := rn.GetAnnotations()[newKey] - legacyValue := rn.GetAnnotations()[legacyKey] + meta, _ := rn.GetMeta() + annotations := meta.Annotations + value := annotations[newKey] + legacyValue := annotations[legacyKey] if value == "" && legacyValue == "" { // do nothing @@ -346,8 +352,9 @@ func missingInternalOrLegacyAnnotation(rn *yaml.RNode, newKey string, legacyKey return nil } -func checkAnnotationsAltered(rn *yaml.RNode, nodeAnnosMap map[nodeAnnotations]map[string]string) error { - annotations := rn.GetAnnotations() +func checkAnnotationsAltered(rn *yaml.RNode, nodeAnnosMap map[string]map[string]string) error { + meta, _ := rn.GetMeta() + annotations := meta.Annotations // get the resource's current path, index, and ids from the new annotations internal := nodeAnnotations{ path: annotations[kioutil.PathAnnotation], @@ -362,16 +369,19 @@ func checkAnnotationsAltered(rn *yaml.RNode, nodeAnnosMap map[nodeAnnotations]ma id: annotations[kioutil.LegacyIdAnnotation], } - originalAnnotations, found := nodeAnnosMap[internal] + rid := annotations[resourceIDAnnotation] + originalAnnotations, found := nodeAnnosMap[rid] if !found { - originalAnnotations, found = nodeAnnosMap[legacy] + return nil } originalPath, found := originalAnnotations[kioutil.PathAnnotation] if !found { originalPath = originalAnnotations[kioutil.LegacyPathAnnotation] } if originalPath != "" { - if originalPath != internal.path { + if originalPath != internal.path && originalPath != legacy.path && internal.path != legacy.path { + return fmt.Errorf("resource input to function has mismatched legacy and internal path annotations") + } else if originalPath != internal.path { if _, err := rn.Pipe(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, internal.path)); err != nil { return err } @@ -387,7 +397,9 @@ func checkAnnotationsAltered(rn *yaml.RNode, nodeAnnosMap map[nodeAnnotations]ma originalIndex = originalAnnotations[kioutil.LegacyIndexAnnotation] } if originalIndex != "" { - if originalIndex != internal.index { + if originalIndex != internal.index && originalIndex != legacy.index && internal.index != legacy.index { + return fmt.Errorf("resource input to function has mismatched legacy and internal index annotations") + } else if originalIndex != internal.index { if _, err := rn.Pipe(yaml.SetAnnotation(kioutil.LegacyIndexAnnotation, internal.index)); err != nil { return err } diff --git a/kyaml/kio/kio_test.go b/kyaml/kio/kio_test.go index b63b59b01c0..e7e5d046a97 100644 --- a/kyaml/kio/kio_test.go +++ b/kyaml/kio/kio_test.go @@ -217,9 +217,9 @@ func TestLegacyAnnotationReconciliation(t *testing.T) { } return nodes, nil } - changeBothPathAnnos := func(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + changeBothPathAnnosMatch := func(nodes []*yaml.RNode) ([]*yaml.RNode, error) { for _, rn := range nodes { - if err := rn.PipeE(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, "legacy")); err != nil { + if err := rn.PipeE(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, "new")); err != nil { return nil, err } if err := rn.PipeE(yaml.SetAnnotation(kioutil.PathAnnotation, "new")); err != nil { @@ -228,6 +228,17 @@ func TestLegacyAnnotationReconciliation(t *testing.T) { } return nodes, nil } + changeBothPathAnnosMismatch := func(nodes []*yaml.RNode) ([]*yaml.RNode, error) { + for _, rn := range nodes { + if err := rn.PipeE(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, "foo")); err != nil { + return nil, err + } + if err := rn.PipeE(yaml.SetAnnotation(kioutil.PathAnnotation, "bar")); err != nil { + return nil, err + } + } + return nodes, nil + } noops := []Filter{ FilterFunc(noopFilter1), @@ -235,7 +246,8 @@ func TestLegacyAnnotationReconciliation(t *testing.T) { } internal := []Filter{FilterFunc(changeInternalAnnos)} legacy := []Filter{FilterFunc(changeLegacyAnnos)} - changeBoth := []Filter{FilterFunc(changeBothPathAnnos), FilterFunc(noopFilter1)} + changeBothMatch := []Filter{FilterFunc(changeBothPathAnnosMatch), FilterFunc(noopFilter1)} + changeBothMismatch := []Filter{FilterFunc(changeBothPathAnnosMismatch), FilterFunc(noopFilter1)} testCases := map[string]struct { input string @@ -274,8 +286,6 @@ metadata: annotations: config.kubernetes.io/path: 'configmap.yaml' config.kubernetes.io/index: '0' - internal.config.kubernetes.io/path: 'configmap.yaml' - internal.config.kubernetes.io/index: '0' data: grpcPort: 8080 --- @@ -286,8 +296,6 @@ metadata: annotations: config.kubernetes.io/path: "configmap.yaml" config.kubernetes.io/index: '1' - internal.config.kubernetes.io/path: 'configmap.yaml' - internal.config.kubernetes.io/index: '1' data: grpcPort: 8081 `, @@ -323,6 +331,28 @@ metadata: annotations: internal.config.kubernetes.io/path: 'configmap.yaml' internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + }, + // the orchestrator should detect that the legacy annotations + // have been changed by the function + "change only legacy annotations": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: config.kubernetes.io/path: 'configmap.yaml' config.kubernetes.io/index: '0' data: @@ -330,21 +360,174 @@ data: --- apiVersion: v1 kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "configmap.yaml" + config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: legacy, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + config.kubernetes.io/path: 'new' + config.kubernetes.io/index: 'new' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "new" + config.kubernetes.io/index: 'new' +data: + grpcPort: 8081 +`, + }, + // the orchestrator should detect that the new internal annotations + // have been changed by the function + "change only internal annotations": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + internal.config.kubernetes.io/path: 'configmap.yaml' + internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap metadata: name: ports-to annotations: internal.config.kubernetes.io/path: "configmap.yaml" internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: internal, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + internal.config.kubernetes.io/path: 'new' + internal.config.kubernetes.io/index: 'new' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + internal.config.kubernetes.io/path: "new" + internal.config.kubernetes.io/index: 'new' +data: + grpcPort: 8081 +`, + }, + // the orchestrator should detect that the legacy annotations + // have been changed by the function + "change only internal annotations while input is legacy annotations": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: config.kubernetes.io/path: 'configmap.yaml' + config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "configmap.yaml" config.kubernetes.io/index: '1' data: grpcPort: 8081 +`, + filters: internal, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + config.kubernetes.io/path: 'new' + config.kubernetes.io/index: 'new' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "new" + config.kubernetes.io/index: 'new' +data: + grpcPort: 8081 +`, + }, + // the orchestrator should detect that the new internal annotations + // have been changed by the function + "change only legacy annotations while input is internal annotations": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + internal.config.kubernetes.io/path: 'configmap.yaml' + internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: legacy, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + internal.config.kubernetes.io/path: 'new' + internal.config.kubernetes.io/index: 'new' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + internal.config.kubernetes.io/path: "new" + internal.config.kubernetes.io/index: 'new' +data: + grpcPort: 8081 `, }, // the orchestrator should detect that the legacy annotations - // have been changed by the function, and should update the - // new internal annotations to reflect the same change - "change only legacy annotations": { + // have been changed by the function + "change only legacy annotations while input has both": { input: `apiVersion: v1 kind: ConfigMap metadata: @@ -352,6 +535,8 @@ metadata: annotations: config.kubernetes.io/path: 'configmap.yaml' config.kubernetes.io/index: '0' + internal.config.kubernetes.io/path: 'configmap.yaml' + internal.config.kubernetes.io/index: '0' data: grpcPort: 8080 --- @@ -362,6 +547,8 @@ metadata: annotations: config.kubernetes.io/path: "configmap.yaml" config.kubernetes.io/index: '1' + internal.config.kubernetes.io/path: 'configmap.yaml' + internal.config.kubernetes.io/index: '1' data: grpcPort: 8081 `, @@ -392,16 +579,17 @@ data: `, }, // the orchestrator should detect that the new internal annotations - // have been changed by the function, and should update the - // legacy annotations to reflect the same change - "change only internal annotations": { + // have been changed by the function + "change only internal annotations while input has both": { input: `apiVersion: v1 kind: ConfigMap metadata: name: ports-from annotations: - config.kubernetes.io/path: 'configmap.yaml' + config.kubernetes.io/path: "configmap.yaml" config.kubernetes.io/index: '0' + internal.config.kubernetes.io/path: 'configmap.yaml' + internal.config.kubernetes.io/index: '0' data: grpcPort: 8080 --- @@ -412,6 +600,8 @@ metadata: annotations: config.kubernetes.io/path: "configmap.yaml" config.kubernetes.io/index: '1' + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '1' data: grpcPort: 8081 `, @@ -421,7 +611,7 @@ kind: ConfigMap metadata: name: ports-from annotations: - config.kubernetes.io/path: 'new' + config.kubernetes.io/path: "new" config.kubernetes.io/index: 'new' internal.config.kubernetes.io/path: 'new' internal.config.kubernetes.io/index: 'new' @@ -435,22 +625,220 @@ metadata: annotations: config.kubernetes.io/path: "new" config.kubernetes.io/index: 'new' - internal.config.kubernetes.io/path: 'new' + internal.config.kubernetes.io/path: "new" internal.config.kubernetes.io/index: 'new' data: grpcPort: 8081 `, }, - // the function changes both the legacy and new path annotation, + // the orchestrator should detect that the new internal annotations + // have been changed by the function + "change both to matching value while input has both": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + config.kubernetes.io/path: "configmap.yaml" + config.kubernetes.io/index: '0' + internal.config.kubernetes.io/path: 'configmap.yaml' + internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "configmap.yaml" + config.kubernetes.io/index: '1' + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: changeBothMatch, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + config.kubernetes.io/path: "new" + config.kubernetes.io/index: '0' + internal.config.kubernetes.io/path: 'new' + internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "new" + config.kubernetes.io/index: '1' + internal.config.kubernetes.io/path: "new" + internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + }, + // the orchestrator should detect that the new internal annotations + // have been changed by the function + "change both to matching value while input is legacy": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + config.kubernetes.io/path: "configmap.yaml" + config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "configmap.yaml" + config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: changeBothMatch, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + config.kubernetes.io/path: "new" + config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "new" + config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + }, + // the orchestrator should detect that the new internal annotations + // have been changed by the function + "change both to matching value while input is internal": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + internal.config.kubernetes.io/path: 'configmap.yaml' + internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: changeBothMatch, + expected: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + internal.config.kubernetes.io/path: 'new' + internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + internal.config.kubernetes.io/path: "new" + internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + }, + // the function changes both the legacy and new path annotation, and they mismatch, + // so we should get an error + "change both but mismatch while input is legacy": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + config.kubernetes.io/path: 'configmap.yaml' + config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + config.kubernetes.io/path: "configmap.yaml" + config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: changeBothMismatch, + expectedErr: "resource input to function has mismatched legacy and internal path annotations", + }, + // the function changes both the legacy and new path annotation, and they mismatch, // so we should get an error - "change both": { + "change both but mismatch while input is internal": { + input: `apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-from + annotations: + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '0' +data: + grpcPort: 8080 +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: ports-to + annotations: + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '1' +data: + grpcPort: 8081 +`, + filters: changeBothMismatch, + expectedErr: "resource input to function has mismatched legacy and internal path annotations", + }, + // the function changes both the legacy and new path annotation, and they mismatch, + // so we should get an error + "change both but mismatch while input has both": { input: `apiVersion: v1 kind: ConfigMap metadata: name: ports-from annotations: config.kubernetes.io/path: 'configmap.yaml' - internal.kubernetes.io/path: 'configmap.yaml' + config.kubernetes.io/index: '0' + config.k8s.io/id: '1' + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '0' data: grpcPort: 8080 --- @@ -461,10 +849,13 @@ metadata: annotations: config.kubernetes.io/path: "configmap.yaml" config.kubernetes.io/index: '1' + config.k8s.io/id: '2' + internal.config.kubernetes.io/path: "configmap.yaml" + internal.config.kubernetes.io/index: '1' data: grpcPort: 8081 `, - filters: changeBoth, + filters: changeBothMismatch, expectedErr: "resource input to function has mismatched legacy and internal path annotations", }, } diff --git a/kyaml/kio/kioutil/kioutil.go b/kyaml/kio/kioutil/kioutil.go index 800dcfe4549..9f117e95a20 100644 --- a/kyaml/kio/kioutil/kioutil.go +++ b/kyaml/kio/kioutil/kioutil.go @@ -44,7 +44,8 @@ const ( ) func GetFileAnnotations(rn *yaml.RNode) (string, string, error) { - annotations := rn.GetAnnotations() + rm, _ := rn.GetMeta() + annotations := rm.Annotations path, found := annotations[PathAnnotation] if !found { path = annotations[LegacyPathAnnotation] @@ -57,7 +58,8 @@ func GetFileAnnotations(rn *yaml.RNode) (string, string, error) { } func GetIdAnnotation(rn *yaml.RNode) string { - annotations := rn.GetAnnotations() + rm, _ := rn.GetMeta() + annotations := rm.Annotations id, found := annotations[IdAnnotation] if !found { id = annotations[LegacyIdAnnotation] @@ -391,7 +393,8 @@ func ConfirmInternalAnnotationUnchanged(r1 *yaml.RNode, r2 *yaml.RNode, exclusio // `internal.config.kubernetes.io` 2) is one of `config.kubernetes.io/path`, // `config.kubernetes.io/index` and `config.k8s.io/id`. func GetInternalAnnotations(rn *yaml.RNode) map[string]string { - annotations := rn.GetAnnotations() + meta, _ := rn.GetMeta() + annotations := meta.Annotations result := make(map[string]string) for k, v := range annotations { if strings.HasPrefix(k, internalPrefix) || k == LegacyPathAnnotation || k == LegacyIndexAnnotation || k == LegacyIdAnnotation {