add replacement filter to support replacmenttransformer

This commit is contained in:
Natasha Sarkar
2021-03-17 13:51:31 -07:00
parent 710db98dbf
commit fa0b237178
14 changed files with 722 additions and 103 deletions

View File

@@ -9,13 +9,15 @@ import (
func TestPatchEquals(t *testing.T) {
selector := Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
Name: "name",
Namespace: "namespace",
},
Name: "name",
Namespace: "namespace",
LabelSelector: "selector",
AnnotationSelector: "selector",
}
@@ -38,13 +40,15 @@ func TestPatchEquals(t *testing.T) {
Path: "foo",
Patch: "bar",
Target: &Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
Name: "name",
Namespace: "namespace",
},
Name: "name",
Namespace: "namespace",
LabelSelector: "selector",
AnnotationSelector: "selector",
},
@@ -53,13 +57,15 @@ func TestPatchEquals(t *testing.T) {
Path: "foo",
Patch: "bar",
Target: &Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
Name: "name",
Namespace: "namespace",
},
Name: "name",
Namespace: "namespace",
LabelSelector: "selector",
AnnotationSelector: "selector",
},

View File

@@ -1,27 +1,62 @@
// Copyright 2019 The Kubernetes Authors.
// Copyright 2021 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package types
const DefaultReplacementFieldPath = "metadata.name"
// Replacement defines how to perform a substitution
// where it is from and where it is to.
type Replacement struct {
Source *ReplSource `json:"source" yaml:"source"`
Target *ReplTarget `json:"target" yaml:"target"`
// The source of the value.
Source *SourceSelector `json:"source" yaml:"source"`
// The N fields to write the value to.
Targets []*TargetSelector `json:"targets" yaml:"targets"`
}
// ReplSource defines where a substitution is from
// It can from two different kinds of sources
// - from a field of one resource
// - from a string
type ReplSource struct {
ObjRef *Target `json:"objref,omitempty" yaml:"objref,omitempty"`
FieldRef string `json:"fieldref,omitempty" yaml:"fiedldref,omitempty"`
Value string `json:"value,omitempty" yaml:"value,omitempty"`
// SourceSelector is the source of the replacement transformer.
type SourceSelector struct {
// A specific object to read it from.
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
// Structured field path expected in the allowed object.
FieldPath string `json:"fieldPath" yaml:"fieldPath"`
// Used to refine the interpretation of the field
Options *FieldOptions `json:"options" yaml:"options"`
}
// ReplTarget defines where a substitution is to.
type ReplTarget struct {
ObjRef *Selector `json:"objref,omitempty" yaml:"objref,omitempty"`
FieldRefs []string `json:"fieldrefs,omitempty" yaml:"fieldrefs,omitempty"`
// TargetSelector specifies fields in one or more objects.
type TargetSelector struct {
// Include objects that match this.
Select *Selector `json:"select" yaml:"select"`
// From the allowed set, remove objects that match this.
// TODO (#3492): Remove matches listed in the exclude field
// Currently this field is unused
Reject *Selector `json:"reject" yaml:"reject"`
// Structured field paths expected in each allowed object.
FieldPaths []string `json:"fieldPaths" yaml:"fieldPaths"`
// Used to refine the interpretation of the field
Options *FieldOptions `json:"options" yaml:"options"`
}
// FieldPath is a structured field path to the desired object
// TODO (#3492): Implement use of these options, they are
// currently used
type FieldOptions struct {
// Used to split/join the field.
Delimiter string `json:"delimiter" yaml:"delimiter"`
// Which position in the split to consider.
Index int `json:"index" yaml:"index"`
// None, Base64, URL, Hex, etc
Encoding string `json:"encoding" yaml:"index"`
// If field missing, add it
Create bool `json:"create" yaml:"create"`
}

View File

@@ -13,9 +13,8 @@ import (
// Any resource that matches intersection of all conditions
// is included in this set.
type Selector struct {
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// KrmId refers to a GVKN/Ns of a resource.
KrmId `json:",inline,omitempty" yaml:",inline,omitempty"`
// AnnotationSelector is a string that follows the label selection expression
// https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#api
@@ -28,6 +27,23 @@ type Selector struct {
LabelSelector string `json:"labelSelector,omitempty" yaml:"labelSelector,omitempty"`
}
// KrmId refers to a GVKN/Ns of a resource.
type KrmId struct {
resid.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
}
// Match returns true if id selects other, i.e. id's fields
// either match other's or are empty
func (id *KrmId) Match(other *KrmId) bool {
return (id.Group == "" || id.Group == other.Group) &&
(id.Version == "" || id.Version == other.Version) &&
(id.Kind == "" || id.Kind == other.Kind) &&
(id.Name == "" || id.Name == other.Name) &&
(id.Namespace == "" || id.Namespace == other.Namespace)
}
// SelectorRegex is a Selector with regex in GVK
// Any resource that matches intersection of all conditions
// is included in this set.

View File

@@ -15,10 +15,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
}{
{
S: Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
},
},
G: resid.Gvk{
@@ -30,10 +32,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
},
{
S: Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "",
Kind: "",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "group",
Version: "",
Kind: "",
},
},
},
G: resid.Gvk{
@@ -45,10 +49,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
},
{
S: Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
},
},
G: resid.Gvk{
@@ -60,10 +66,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
},
{
S: Selector{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "group",
Version: "version",
Kind: "kind",
},
},
},
G: resid.Gvk{
@@ -75,10 +83,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
},
{
S: Selector{
Gvk: resid.Gvk{
Group: "g.*",
Version: "\\d+",
Kind: ".{4}",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "g.*",
Version: "\\d+",
Kind: ".{4}",
},
},
},
G: resid.Gvk{
@@ -90,10 +100,12 @@ func TestSelectorRegexMatchGvk(t *testing.T) {
},
{
S: Selector{
Gvk: resid.Gvk{
Group: "g.*",
Version: "\\d+",
Kind: ".{4}",
KrmId: KrmId{
Gvk: resid.Gvk{
Group: "g.*",
Version: "\\d+",
Kind: ".{4}",
},
},
},
G: resid.Gvk{
@@ -125,30 +137,38 @@ func TestSelectorRegexMatchName(t *testing.T) {
}{
{
S: Selector{
Name: "foo",
Namespace: "bar",
KrmId: KrmId{
Name: "foo",
Namespace: "bar",
},
},
Name: "foo",
Expected: true,
},
{
S: Selector{
Name: "foo",
Namespace: "bar",
KrmId: KrmId{
Name: "foo",
Namespace: "bar",
},
},
Name: "bar",
Expected: false,
},
{
S: Selector{
Name: "f.*",
KrmId: KrmId{
Name: "f.*",
},
},
Name: "foo",
Expected: true,
},
{
S: Selector{
Name: "b.*",
KrmId: KrmId{
Name: "b.*",
},
},
Name: "foo",
Expected: false,
@@ -174,30 +194,38 @@ func TestSelectorRegexMatchNamespace(t *testing.T) {
}{
{
S: Selector{
Name: "bar",
Namespace: "foo",
KrmId: KrmId{
Name: "bar",
Namespace: "foo",
},
},
Namespace: "foo",
Expected: true,
},
{
S: Selector{
Name: "foo",
Namespace: "bar",
KrmId: KrmId{
Name: "foo",
Namespace: "bar",
},
},
Namespace: "foo",
Expected: false,
},
{
S: Selector{
Namespace: "f.*",
KrmId: KrmId{
Namespace: "f.*",
},
},
Namespace: "foo",
Expected: true,
},
{
S: Selector{
Namespace: "b.*",
KrmId: KrmId{
Namespace: "b.*",
},
},
Namespace: "foo",
Expected: false,

View File

@@ -12,8 +12,6 @@ import (
"sigs.k8s.io/kustomize/api/resid"
)
const defaultFieldPath = "metadata.name"
// Var represents a variable whose value will be sourced
// from a field in a Kubernetes object.
type Var struct {
@@ -71,7 +69,7 @@ type FieldSelector struct {
// defaulting sets reference to field used by default.
func (v *Var) Defaulting() {
if v.FieldRef.FieldPath == "" {
v.FieldRef.FieldPath = defaultFieldPath
v.FieldRef.FieldPath = DefaultReplacementFieldPath
}
v.ObjRef.GVK()
}

View File

@@ -69,9 +69,9 @@ func TestDefaulting(t *testing.T) {
},
}
v.Defaulting()
if v.FieldRef.FieldPath != defaultFieldPath {
if v.FieldRef.FieldPath != DefaultReplacementFieldPath {
t.Fatalf("expected %s, got %v",
defaultFieldPath, v.FieldRef.FieldPath)
DefaultReplacementFieldPath, v.FieldRef.FieldPath)
}
}
@@ -127,7 +127,7 @@ func TestVarSet(t *testing.T) {
t.Fatalf("expected var")
}
// Confirm defaulting.
if v.FieldRef.FieldPath != defaultFieldPath {
if v.FieldRef.FieldPath != DefaultReplacementFieldPath {
t.Fatalf("unexpected field path: %v", v.FieldRef.FieldPath)
}
// Confirm sorting.