mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
support krm spec v1 and legacy path, index, and id annotations
This commit is contained in:
211
kyaml/kio/kio.go
211
kyaml/kio/kio.go
@@ -6,7 +6,10 @@
|
||||
package kio
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
@@ -113,6 +116,14 @@ func (p Pipeline) ExecuteWithCallback(callback PipelineExecuteCallbackFunc) erro
|
||||
// apply operations
|
||||
var err error
|
||||
for i := range p.Filters {
|
||||
// Not all RNodes passed through kio.Pipeline have metadata nor should
|
||||
// they all be required to.
|
||||
var nodeAnnos map[string]map[string]string
|
||||
nodeAnnos, err = storeInternalAnnotations(result)
|
||||
if err != nil && err != yaml.ErrMissingMetadata {
|
||||
return err
|
||||
}
|
||||
|
||||
op := p.Filters[i]
|
||||
if callback != nil {
|
||||
callback(op)
|
||||
@@ -124,6 +135,13 @@ func (p Pipeline) ExecuteWithCallback(callback PipelineExecuteCallbackFunc) erro
|
||||
if len(result) == 0 && !p.ContinueOnEmptyResult || err != nil {
|
||||
return errors.Wrap(err)
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil && err != yaml.ErrMissingMetadata {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// write to the outputs
|
||||
@@ -147,3 +165,196 @@ func FilterAll(filter yaml.Filter) Filter {
|
||||
return nodes, nil
|
||||
})
|
||||
}
|
||||
|
||||
// Store the original path, index, and id annotations so that we can reconcile
|
||||
// it 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 storeInternalAnnotations(result []*yaml.RNode) (map[string]map[string]string, error) {
|
||||
nodeAnnosMap := make(map[string]map[string]string)
|
||||
|
||||
for i := range result {
|
||||
if err := kioutil.CopyLegacyAnnotations(result[i]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meta, err := result[i].GetMeta()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := meta.Annotations[kioutil.PathAnnotation]
|
||||
index := meta.Annotations[kioutil.IndexAnnotation]
|
||||
id := meta.Annotations[kioutil.IdAnnotation]
|
||||
|
||||
if _, ok := nodeAnnosMap[path]; !ok {
|
||||
nodeAnnosMap[path] = make(map[string]string)
|
||||
}
|
||||
nodeAnnosMap[path][index] = id
|
||||
}
|
||||
return nodeAnnosMap, nil
|
||||
}
|
||||
|
||||
type nodeAnnotations struct {
|
||||
path string
|
||||
index string
|
||||
id string
|
||||
}
|
||||
|
||||
func reconcileInternalAnnotations(result []*yaml.RNode, nodeAnnosMap map[string]map[string]string) error {
|
||||
for _, node := range result {
|
||||
meta, err := node.GetMeta()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if only one annotation is set, set the other.
|
||||
err = missingInternalOrLegacyAnnotations(node, meta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// we must check to see if the function changed either the new internal annotations
|
||||
// or the old legacy annotations. If one is changed, the change must be reflected
|
||||
// in the other.
|
||||
err = checkAnnotationsAltered(node, meta, nodeAnnosMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// if the annotations are still somehow out of sync, prefer the internal annotations
|
||||
// and copy them to the legacy ones
|
||||
err = kioutil.CopyLegacyAnnotations(node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func missingInternalOrLegacyAnnotations(rn *yaml.RNode, meta yaml.ResourceMeta) error {
|
||||
if err := missingInternalOrLegacyAnnotation(rn, meta, kioutil.PathAnnotation, kioutil.LegacyPathAnnotation); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := missingInternalOrLegacyAnnotation(rn, meta, kioutil.IndexAnnotation, kioutil.LegacyIndexAnnotation); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := missingInternalOrLegacyAnnotation(rn, meta, kioutil.IdAnnotation, kioutil.LegacyIdAnnotation); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func missingInternalOrLegacyAnnotation(rn *yaml.RNode, meta yaml.ResourceMeta, newKey string, legacyKey string) error {
|
||||
value := meta.Annotations[newKey]
|
||||
legacyValue := meta.Annotations[legacyKey]
|
||||
|
||||
if value == "" && legacyValue == "" {
|
||||
// do nothing
|
||||
return nil
|
||||
}
|
||||
|
||||
if value == "" {
|
||||
// new key is not set, copy from legacy key
|
||||
if err := rn.PipeE(yaml.SetAnnotation(newKey, legacyValue)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if legacyValue == "" {
|
||||
// legacy key is not set, copy from new key
|
||||
if err := rn.PipeE(yaml.SetAnnotation(legacyKey, value)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAnnotationsAltered(rn *yaml.RNode, meta yaml.ResourceMeta, nodeAnnosMap map[string]map[string]string) error {
|
||||
// get the resource's current path, index, and ids from the new annotations
|
||||
internal := nodeAnnotations{
|
||||
path: meta.Annotations[kioutil.PathAnnotation],
|
||||
index: meta.Annotations[kioutil.IndexAnnotation],
|
||||
id: meta.Annotations[kioutil.IdAnnotation],
|
||||
}
|
||||
|
||||
// get the resource's current path, index, and ids from the legacy annotations
|
||||
legacy := nodeAnnotations{
|
||||
path: meta.Annotations[kioutil.LegacyPathAnnotation],
|
||||
index: meta.Annotations[kioutil.LegacyIndexAnnotation],
|
||||
id: meta.Annotations[kioutil.LegacyIdAnnotation],
|
||||
}
|
||||
|
||||
if internal.path == legacy.path &&
|
||||
internal.index == legacy.index &&
|
||||
internal.id == legacy.id {
|
||||
// none of the annotations differ, so no reconciliation is needed
|
||||
return nil
|
||||
}
|
||||
|
||||
// nodeAnnosMap is a map of structure path -> index -> id that stores
|
||||
// all of the resources' path/index/id annotations prior to the functions
|
||||
// being run. We use that to check whether the legacy or new internal
|
||||
// annotations have been changed, and make sure the change is reflected
|
||||
// in the other.
|
||||
|
||||
// first, check if the internal annotations are found in nodeAnnosMap
|
||||
if indexIdMap, ok := nodeAnnosMap[internal.path]; ok {
|
||||
if id, ok := indexIdMap[internal.index]; ok {
|
||||
if id == internal.id {
|
||||
// the internal annotations of the resource match the ones stored in
|
||||
// nodeAnnosMap, so we should copy the legacy annotations to the
|
||||
// internal ones
|
||||
if err := updateAnnotations(rn, meta,
|
||||
[]string{
|
||||
kioutil.PathAnnotation,
|
||||
kioutil.IndexAnnotation,
|
||||
kioutil.IdAnnotation,
|
||||
},
|
||||
[]string{
|
||||
legacy.path,
|
||||
legacy.index,
|
||||
legacy.id,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the opposite, to see if the legacy annotations are in nodeAnnosMap
|
||||
if indexIdMap, ok := nodeAnnosMap[legacy.path]; ok {
|
||||
if id, ok := indexIdMap[legacy.index]; ok {
|
||||
if id == legacy.id {
|
||||
// the legacy annotations of the resource match the ones stored in
|
||||
// nodeAnnosMap, so we should copy the internal annotations to the
|
||||
// legacy ones
|
||||
if err := updateAnnotations(rn, meta,
|
||||
[]string{
|
||||
kioutil.LegacyPathAnnotation,
|
||||
kioutil.LegacyIndexAnnotation,
|
||||
kioutil.LegacyIdAnnotation,
|
||||
},
|
||||
[]string{
|
||||
internal.path,
|
||||
internal.index,
|
||||
internal.id,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateAnnotations(rn *yaml.RNode, meta yaml.ResourceMeta, keys []string, values []string) error {
|
||||
if len(keys) != len(values) {
|
||||
return fmt.Errorf("keys is not same length as values")
|
||||
}
|
||||
for i := range keys {
|
||||
_, ok := meta.Annotations[keys[i]]
|
||||
if values[i] == "" && !ok {
|
||||
// don't set "" if annotation is not already there
|
||||
continue
|
||||
}
|
||||
if err := rn.PipeE(yaml.SetAnnotation(keys[i], values[i])); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user