mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-11 00:52:55 +00:00
fix bug with migrating annotations
This commit is contained in:
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user