diff --git a/api/internal/plugins/utils/utils.go b/api/internal/plugins/utils/utils.go index 46706627be..ffd10087aa 100644 --- a/api/internal/plugins/utils/utils.go +++ b/api/internal/plugins/utils/utils.go @@ -15,6 +15,7 @@ import ( "sigs.k8s.io/kustomize/api/konfig" "sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/resource" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/yaml" ) @@ -147,34 +148,46 @@ func GetResMapWithIDAnnotation(rm resmap.ResMap) (resmap.ResMap, error) { // UpdateResMapValues updates the Resource value in the given ResMap // with the emitted Resource values in output. func UpdateResMapValues(pluginName string, h *resmap.PluginHelpers, output []byte, rm resmap.ResMap) error { - outputRM, err := h.ResmapFactory().NewResMapFromBytes(output) + resFactory := h.ResmapFactory().RF() + resources, err := resFactory.SliceFromBytes(output) if err != nil { return err } - for _, r := range outputRM.Resources() { + for _, r := range resources { // for each emitted Resource, find the matching Resource in the original ResMap // using its id annotations := r.GetAnnotations() idString, ok := annotations[idAnnotation] + // Transformer-generated resource--add to resMap if !ok { - return fmt.Errorf("the transformer %s should not remove annotation %s", - pluginName, idAnnotation) + if err := rm.Append(r); err != nil { + return err + } + continue } + id := resid.ResId{} - err := yaml.Unmarshal([]byte(idString), &id) + err = yaml.Unmarshal([]byte(idString), &id) if err != nil { return err } + + // Outdated ID is likely a duplicated resource--add to resMap + if !id.Equals(r.CurId()) { + removeIDAnnotation(r) + if err := rm.Append(r); err != nil { + return err + } + continue + } + + // Existing resource--update in resMap + res, err := rm.GetByCurrentId(id) if err != nil { return fmt.Errorf("unable to find unique match to %s", id.String()) } - // remove the annotation set by Kustomize to track the resource - delete(annotations, idAnnotation) - if len(annotations) == 0 { - annotations = nil - } - r.SetAnnotations(annotations) + removeIDAnnotation(r) // update the resource value with the transformed object res.ResetPrimaryData(r) @@ -182,6 +195,16 @@ func UpdateResMapValues(pluginName string, h *resmap.PluginHelpers, output []byt return nil } +func removeIDAnnotation(r *resource.Resource) { + // remove the annotation set by Kustomize to track the resource + annotations := r.GetAnnotations() + delete(annotations, idAnnotation) + if len(annotations) == 0 { + annotations = nil + } + r.SetAnnotations(annotations) +} + // UpdateResourceOptions updates the generator options for each resource in the // given ResMap based on plugin provided annotations. func UpdateResourceOptions(rm resmap.ResMap) (resmap.ResMap, error) { diff --git a/plugin/someteam.example.com/v1/starlarkmixer/StarlarkMixer_test.go b/plugin/someteam.example.com/v1/starlarkmixer/StarlarkMixer_test.go index 36583095c7..4671794910 100644 --- a/plugin/someteam.example.com/v1/starlarkmixer/StarlarkMixer_test.go +++ b/plugin/someteam.example.com/v1/starlarkmixer/StarlarkMixer_test.go @@ -38,12 +38,24 @@ data: kind: ConfigMap metadata: annotations: + config.kubernetes.io/path: configmap_some-cm.yaml modified-by: mixer-instance name: some-cm --- apiVersion: v1 +data: + foo: bar +kind: ConfigMap +metadata: + annotations: + config.kubernetes.io/path: configmap_some-cm-copy.yaml + name: some-cm-copy +--- +apiVersion: v1 kind: ConfigMap metadata: + annotations: + config.kubernetes.io/path: configmap_net-new.yaml name: net-new `) } diff --git a/plugin/someteam.example.com/v1/starlarkmixer/mixer.star b/plugin/someteam.example.com/v1/starlarkmixer/mixer.star index be6e6d5a62..bf9d7e2a91 100644 --- a/plugin/someteam.example.com/v1/starlarkmixer/mixer.star +++ b/plugin/someteam.example.com/v1/starlarkmixer/mixer.star @@ -1,11 +1,27 @@ def run(r, fc): + add = [] + remove = [] for resource in r: if resource.get("metadata") == None: resource["metadata"] = {} if resource["metadata"].get("annotations") == None: resource["metadata"]["annotations"] = {} + + # Flag for deletion + if resource["metadata"]["name"] == "delete-me": + remove.append(resource) + continue + + # Deep-ish copy the resource + cp = dict(resource) + cp["metadata"] = dict(cp["metadata"]) + cp["metadata"]["annotations"] = dict(cp["metadata"]["annotations"]) + cp["metadata"]["name"] = resource["metadata"]["name"]+"-copy" + add.append(cp) + resource["metadata"]["annotations"]["modified-by"] = fc["metadata"]["name"] + # Add something new = { "kind": "ConfigMap", "apiVersion": "v1", @@ -13,6 +29,9 @@ def run(r, fc): "name": "net-new" } } + r.extend(add) r.append(new) + for resource in remove: + r.remove(resource) run(ctx.resource_list["items"], ctx.resource_list["functionConfig"])