mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-29 09:40:49 +00:00
add replacement filter to support replacmenttransformer
This commit is contained in:
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user