-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add replacement filter to support replacmenttransformer
- Loading branch information
1 parent
710db98
commit 14b64b1
Showing
5 changed files
with
527 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// Package replacement contains a kio.Filter implementation of the kustomize | ||
// replacement transformer (accepts sources and looks for targets to replace | ||
// their values with values from the sources). | ||
package replacement |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright 2020 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package replacement | ||
|
||
import ( | ||
"bytes" | ||
"log" | ||
"os" | ||
|
||
"sigs.k8s.io/kustomize/kyaml/kio" | ||
"sigs.k8s.io/kustomize/kyaml/yaml" | ||
) | ||
|
||
func ExampleFilter() { | ||
f := Filter{} | ||
err := yaml.Unmarshal([]byte(` | ||
replacements: | ||
- source: | ||
value: 99 | ||
target: | ||
objref: | ||
kind: Foo | ||
fieldrefs: | ||
- spec.replicas`), &f) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
err = kio.Pipeline{ | ||
Inputs: []kio.Reader{&kio.ByteReader{Reader: bytes.NewBufferString(` | ||
apiVersion: example.com/v1 | ||
kind: Foo | ||
metadata: | ||
name: instance | ||
spec: | ||
replicas: 3 | ||
`)}}, | ||
Filters: []kio.Filter{f}, | ||
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}}, | ||
}.Execute() | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
// Output: | ||
// apiVersion: example.com/v1 | ||
// kind: Foo | ||
// metadata: | ||
// name: instance | ||
// spec: | ||
// replicas: 99 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright 2019 The Kubernetes Authors. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package replacement | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"sigs.k8s.io/kustomize/api/types" | ||
"sigs.k8s.io/kustomize/kyaml/yaml" | ||
) | ||
|
||
type Filter struct { | ||
Replacements []types.Replacement | ||
} | ||
|
||
const DefaultFieldRef = ".metadata.name" | ||
|
||
// Filter replaces values of targets with values from sources | ||
// TODO (#3492): Connect this to a replacement transformer plugin | ||
func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { | ||
for _, r := range f.Replacements { | ||
value, err := getReplacement(nodes, r.Source) | ||
if err != nil { | ||
return nil, err | ||
} | ||
nodes, err = applyReplacement(nodes, value, r.Target) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
return nodes, nil | ||
} | ||
|
||
func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, target *types.ReplTarget) ([]*yaml.RNode, error) { | ||
targets, err := getMatches(nodes, target.ObjRef) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for _, n := range targets { | ||
err := applyToNode(n, value, target) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
return nodes, nil | ||
} | ||
|
||
func applyToNode(node *yaml.RNode, value *yaml.RNode, target *types.ReplTarget) error { | ||
if len(target.FieldRefs) == 0 { | ||
target.FieldRefs = []string{DefaultFieldRef} | ||
} | ||
for i := range target.FieldRefs { | ||
fieldref := strings.Split(target.FieldRefs[i], ".") | ||
// TODO (#3492): Support using map keys in the fieldref (e.g. .spec.containers[name=nginx]) | ||
t, err := node.Pipe(yaml.Lookup(fieldref...)) | ||
if err != nil { | ||
return err | ||
} | ||
if t != nil { | ||
t.SetYNode(value.YNode()) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func getReplacement(nodes []*yaml.RNode, source *types.ReplSource) (*yaml.RNode, error) { | ||
if source.Value != "" { | ||
if source.ObjRef != nil || source.FieldRef != "" { | ||
return nil, fmt.Errorf("objref and fieldref must be empty if source value is provided") | ||
} | ||
return yaml.Parse(source.Value) | ||
} | ||
|
||
matches, err := getMatches(nodes, source.ObjRef) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(matches) > 1 { | ||
return nil, fmt.Errorf("found more than one resources matching from %v", source.ObjRef) | ||
} | ||
if len(matches) == 0 { | ||
return nil, fmt.Errorf("failed to find a resource matching from %v", source.ObjRef) | ||
} | ||
|
||
fieldRef := source.FieldRef | ||
if fieldRef == "" { | ||
fieldRef = DefaultFieldRef | ||
} | ||
fieldRefSlice := strings.Split(fieldRef, ".") | ||
|
||
// TODO (#3492): Support using map keys in the fieldref (e.g. .spec.containers[name=nginx]) | ||
rn, err := matches[0].Pipe(yaml.Lookup(fieldRefSlice...)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return rn, nil | ||
} | ||
|
||
// getMatches finds the node that matches the objRef | ||
func getMatches(nodes []*yaml.RNode, objRef *types.Target) ([]*yaml.RNode, error) { | ||
var matches []*yaml.RNode | ||
for _, n := range nodes { | ||
ns, err := n.GetNamespace() | ||
if err != nil { | ||
return nil, err | ||
} | ||
apiVersion := yaml.GetValue(n.Field(yaml.APIVersionField).Value) | ||
if (n.GetName() == objRef.Name || objRef.Name == "") && | ||
(n.GetKind() == objRef.Kind || objRef.Kind == "") && | ||
(ns == objRef.Namespace || objRef.Namespace == "") && | ||
(apiVersion == objRef.ApiVersion() || objRef.ApiVersion() == "") { | ||
matches = append(matches, n) | ||
} | ||
} | ||
return matches, nil | ||
} |
Oops, something went wrong.