fix bug with migrating annotations

This commit is contained in:
natasha41575
2021-10-12 10:59:41 -07:00
parent 67c58ad4f4
commit 55ac9ca88d
6 changed files with 182 additions and 18 deletions

View File

@@ -316,6 +316,10 @@ func (r *ByteReader) decode(originalYAML string, index int, decoder *yaml.Decode
r.SetAnnotations = map[string]string{} r.SetAnnotations = map[string]string{}
} }
if !r.OmitReaderAnnotations { if !r.OmitReaderAnnotations {
err := kioutil.CopyLegacyAnnotations(n)
if err != nil {
return nil, err
}
r.SetAnnotations[kioutil.IndexAnnotation] = fmt.Sprintf("%d", index) r.SetAnnotations[kioutil.IndexAnnotation] = fmt.Sprintf("%d", index)
r.SetAnnotations[kioutil.LegacyIndexAnnotation] = fmt.Sprintf("%d", index) r.SetAnnotations[kioutil.LegacyIndexAnnotation] = fmt.Sprintf("%d", index)

View File

@@ -299,7 +299,13 @@ g:
`, `,
}, },
expectedOutput: `a: b #first expectedOutput: `e: f
g:
h:
- i # has a list
- j
---
a: b #first
metadata: metadata:
annotations: annotations:
internal.config.kubernetes.io/path: "a/b/a_test.yaml" internal.config.kubernetes.io/path: "a/b/a_test.yaml"
@@ -310,12 +316,6 @@ metadata:
annotations: annotations:
internal.config.kubernetes.io/path: "a/b/a_test.yaml" internal.config.kubernetes.io/path: "a/b/a_test.yaml"
config.kubernetes.io/path: 'a/b/a_test.yaml' config.kubernetes.io/path: 'a/b/a_test.yaml'
---
e: f
g:
h:
- i # has a list
- j
`, `,
}, },

View File

@@ -181,6 +181,10 @@ func storeInternalAnnotations(result []*yaml.RNode) (map[string]map[string]strin
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := checkMismatchedAnnos(meta); err != nil {
return nil, err
}
path := meta.Annotations[kioutil.PathAnnotation] path := meta.Annotations[kioutil.PathAnnotation]
index := meta.Annotations[kioutil.IndexAnnotation] index := meta.Annotations[kioutil.IndexAnnotation]
id := meta.Annotations[kioutil.IdAnnotation] id := meta.Annotations[kioutil.IdAnnotation]
@@ -193,6 +197,29 @@ func storeInternalAnnotations(result []*yaml.RNode) (map[string]map[string]strin
return nodeAnnosMap, nil return nodeAnnosMap, nil
} }
func checkMismatchedAnnos(meta yaml.ResourceMeta) error {
path := meta.Annotations[kioutil.PathAnnotation]
index := meta.Annotations[kioutil.IndexAnnotation]
id := meta.Annotations[kioutil.IdAnnotation]
legacyPath := meta.Annotations[kioutil.LegacyPathAnnotation]
legacyIndex := meta.Annotations[kioutil.LegacyIndexAnnotation]
legacyId := meta.Annotations[kioutil.LegacyIdAnnotation]
// if prior to running the functions, the legacy and internal annotations differ,
// throw an error as we cannot infer the user's intent.
if path != legacyPath {
return fmt.Errorf("resource input to function has mismatched legacy and internal path annotations")
}
if index != legacyIndex {
return fmt.Errorf("resource input to function has mismatched legacy and internal index annotations")
}
if id != legacyId {
return fmt.Errorf("resource input to function has mismatched legacy and internal id annotations")
}
return nil
}
type nodeAnnotations struct { type nodeAnnotations struct {
path string path string
index string index string
@@ -217,9 +244,12 @@ func reconcileInternalAnnotations(result []*yaml.RNode, nodeAnnosMap map[string]
if err != nil { if err != nil {
return err return err
} }
// if the annotations are still somehow out of sync, prefer the internal annotations // if the annotations are still somehow out of sync, throw an error
// and copy them to the legacy ones meta, err = node.GetMeta()
err = kioutil.CopyLegacyAnnotations(node) if err != nil {
return err
}
err = checkMismatchedAnnos(meta)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -233,6 +233,17 @@ func TestLegacyAnnotationReconciliation(t *testing.T) {
} }
return nodes, nil return nodes, nil
} }
changeBothPathAnnos := func(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
for _, rn := range nodes {
if err := rn.PipeE(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, "legacy")); err != nil {
return nil, err
}
if err := rn.PipeE(yaml.SetAnnotation(kioutil.PathAnnotation, "new")); err != nil {
return nil, err
}
}
return nodes, nil
}
noops := []Filter{ noops := []Filter{
FilterFunc(noopFilter1), FilterFunc(noopFilter1),
@@ -242,11 +253,13 @@ func TestLegacyAnnotationReconciliation(t *testing.T) {
legacy := []Filter{FilterFunc(changeLegacyAnnos)} legacy := []Filter{FilterFunc(changeLegacyAnnos)}
legacyId := []Filter{FilterFunc(changeLegacyId)} legacyId := []Filter{FilterFunc(changeLegacyId)}
internalId := []Filter{FilterFunc(changeInternalId)} internalId := []Filter{FilterFunc(changeInternalId)}
changeBoth := []Filter{FilterFunc(changeBothPathAnnos), FilterFunc(noopFilter1)}
testCases := map[string]struct { testCases := map[string]struct {
input string input string
filters []Filter filters []Filter
expected string expected string
expectedErr string
}{ }{
// the orchestrator should copy the legacy annotations to the new // the orchestrator should copy the legacy annotations to the new
// annotations // annotations
@@ -510,6 +523,32 @@ data:
grpcPort: 8080 grpcPort: 8080
`, `,
}, },
// the function changes both the legacy and new path annotation,
// so we should get an error
"change both": {
input: `apiVersion: v1
kind: ConfigMap
metadata:
name: ports-from
annotations:
config.kubernetes.io/path: 'configmap.yaml'
internal.kubernetes.io/path: 'configmap.yaml'
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: changeBoth,
expectedErr: "resource input to function has mismatched legacy and internal path annotations",
},
} }
for tn, tc := range testCases { for tn, tc := range testCases {
@@ -526,8 +565,16 @@ data:
Filters: tc.filters, Filters: tc.filters,
Outputs: []Writer{&input}, Outputs: []Writer{&input},
} }
assert.NoError(t, p.Execute())
assert.Equal(t, tc.expected, out.String()) err := p.Execute()
if tc.expectedErr == "" {
assert.NoError(t, err)
assert.Equal(t, tc.expected, out.String())
} else {
assert.Error(t, err)
assert.Equal(t, tc.expectedErr, err.Error())
}
}) })
} }
} }

View File

@@ -55,6 +55,10 @@ func GetFileAnnotations(rn *yaml.RNode) (string, string, error) {
func CopyLegacyAnnotations(rn *yaml.RNode) error { func CopyLegacyAnnotations(rn *yaml.RNode) error {
meta, err := rn.GetMeta() meta, err := rn.GetMeta()
if err != nil { if err != nil {
if err == yaml.ErrMissingMetadata {
// resource has no metadata, this should be a no-op
return nil
}
return err return err
} }
if err := copyAnnotations(meta, rn, LegacyPathAnnotation, PathAnnotation); err != nil { if err := copyAnnotations(meta, rn, LegacyPathAnnotation, PathAnnotation); err != nil {
@@ -71,12 +75,14 @@ func CopyLegacyAnnotations(rn *yaml.RNode) error {
func copyAnnotations(meta yaml.ResourceMeta, rn *yaml.RNode, legacyKey string, newKey string) error { func copyAnnotations(meta yaml.ResourceMeta, rn *yaml.RNode, legacyKey string, newKey string) error {
newValue := meta.Annotations[newKey] newValue := meta.Annotations[newKey]
legacyValue := meta.Annotations[legacyKey]
if newValue != "" { if newValue != "" {
if err := rn.PipeE(yaml.SetAnnotation(legacyKey, newValue)); err != nil { if legacyValue == "" {
return err if err := rn.PipeE(yaml.SetAnnotation(legacyKey, newValue)); err != nil {
return err
}
} }
} else { } else {
legacyValue := meta.Annotations[legacyKey]
if legacyValue != "" { if legacyValue != "" {
if err := rn.PipeE(yaml.SetAnnotation(newKey, legacyValue)); err != nil { if err := rn.PipeE(yaml.SetAnnotation(newKey, legacyValue)); err != nil {
return err return err

View File

@@ -374,3 +374,80 @@ func TestCreatePathAnnotationValue(t *testing.T) {
} }
} }
} }
func TestCopyLegacyAnnotations(t *testing.T) {
var tests = []struct {
input string
expected string
}{
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/index: '5'
`,
expected: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/index: '5'
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
`,
expected: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
internal.config.kubernetes.io/index: '5'
config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/index: '5'
`,
},
{
input: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/path: 'c/d.yaml'
`,
expected: `apiVersion: v1
kind: Foo
metadata:
name: foobar
annotations:
internal.config.kubernetes.io/path: 'a/b.yaml'
config.kubernetes.io/path: 'c/d.yaml'
`,
},
}
for _, tc := range tests {
rw := kio.ByteReadWriter{
Reader: bytes.NewBufferString(tc.input),
OmitReaderAnnotations: true,
}
nodes, err := rw.Read()
assert.NoError(t, err)
assert.NoError(t, kioutil.CopyLegacyAnnotations(nodes[0]))
assert.Equal(t, tc.expected, nodes[0].MustString())
}
}