Extended replacement plugin with Targets field
The user can use either `target` or `targets` that is list of several `target` objects. Change-Id: I38e457842e1250a2d048f93ba2aac9258758d163
This commit is contained in:
parent
6543f63ebf
commit
10b0385691
@ -19,6 +19,33 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// These types have been changed in kustomize 4.0.5.
|
||||||
|
// Copying the version from 3.9.2
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
Targets []*ReplTarget `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 *types.Target `json:"objref,omitempty" yaml:"objref,omitempty"`
|
||||||
|
FieldRef string `json:"fieldref,omitempty" yaml:"fiedldref,omitempty"`
|
||||||
|
Value string `json:"value,omitempty" yaml:"value,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplTarget defines where a substitution is to.
|
||||||
|
type ReplTarget struct {
|
||||||
|
ObjRef *types.Selector `json:"objref,omitempty" yaml:"objref,omitempty"`
|
||||||
|
FieldRefs []string `json:"fieldrefs,omitempty" yaml:"fieldrefs,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// +kubebuilder:object:root=true
|
// +kubebuilder:object:root=true
|
||||||
|
|
||||||
// ReplacementTransformer plugin configuration for airship document model
|
// ReplacementTransformer plugin configuration for airship document model
|
||||||
@ -27,30 +54,5 @@ type ReplacementTransformer struct {
|
|||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Replacements list of source and target field to do a replacement
|
// Replacements list of source and target field to do a replacement
|
||||||
Replacements []types.Replacement `json:"replacements,omitempty" yaml:"replacements,omitempty"`
|
Replacements []Replacement `json:"replacements,omitempty" yaml:"replacements,omitempty"`
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *ReplacementTransformer) DeepCopyInto(out *ReplacementTransformer) {
|
|
||||||
*out = *in
|
|
||||||
out.TypeMeta = in.TypeMeta
|
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
|
||||||
if in.Replacements != nil {
|
|
||||||
out.Replacements = make([]types.Replacement, len(in.Replacements))
|
|
||||||
for i, repl := range in.Replacements {
|
|
||||||
out.Replacements[i] = types.Replacement{
|
|
||||||
Source: &types.ReplSource{
|
|
||||||
ObjRef: &types.Target{},
|
|
||||||
FieldRef: repl.Source.FieldRef,
|
|
||||||
Value: repl.Source.Value,
|
|
||||||
},
|
|
||||||
Target: &types.ReplTarget{
|
|
||||||
ObjRef: &types.Selector{},
|
|
||||||
FieldRefs: repl.Target.FieldRefs,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
*(out.Replacements[i].Source.ObjRef) = *(in.Replacements[i].Source.ObjRef)
|
|
||||||
*(out.Replacements[i].Target.ObjRef) = *(in.Replacements[i].Target.ObjRef)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package v1alpha1
|
|||||||
import (
|
import (
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
@ -805,6 +806,101 @@ func (in *RemoteDirectOptions) DeepCopy() *RemoteDirectOptions {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ReplSource) DeepCopyInto(out *ReplSource) {
|
||||||
|
*out = *in
|
||||||
|
if in.ObjRef != nil {
|
||||||
|
in, out := &in.ObjRef, &out.ObjRef
|
||||||
|
*out = new(types.Target)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplSource.
|
||||||
|
func (in *ReplSource) DeepCopy() *ReplSource {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ReplSource)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ReplTarget) DeepCopyInto(out *ReplTarget) {
|
||||||
|
*out = *in
|
||||||
|
if in.ObjRef != nil {
|
||||||
|
in, out := &in.ObjRef, &out.ObjRef
|
||||||
|
*out = new(types.Selector)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
|
if in.FieldRefs != nil {
|
||||||
|
in, out := &in.FieldRefs, &out.FieldRefs
|
||||||
|
*out = make([]string, len(*in))
|
||||||
|
copy(*out, *in)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplTarget.
|
||||||
|
func (in *ReplTarget) DeepCopy() *ReplTarget {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ReplTarget)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *Replacement) DeepCopyInto(out *Replacement) {
|
||||||
|
*out = *in
|
||||||
|
if in.Source != nil {
|
||||||
|
in, out := &in.Source, &out.Source
|
||||||
|
*out = new(ReplSource)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Target != nil {
|
||||||
|
in, out := &in.Target, &out.Target
|
||||||
|
*out = new(ReplTarget)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
if in.Targets != nil {
|
||||||
|
in, out := &in.Targets, &out.Targets
|
||||||
|
*out = make([]*ReplTarget, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
if (*in)[i] != nil {
|
||||||
|
in, out := &(*in)[i], &(*out)[i]
|
||||||
|
*out = new(ReplTarget)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Replacement.
|
||||||
|
func (in *Replacement) DeepCopy() *Replacement {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(Replacement)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ReplacementTransformer) DeepCopyInto(out *ReplacementTransformer) {
|
||||||
|
*out = *in
|
||||||
|
out.TypeMeta = in.TypeMeta
|
||||||
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
if in.Replacements != nil {
|
||||||
|
in, out := &in.Replacements, &out.Replacements
|
||||||
|
*out = make([]Replacement, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplacementTransformer.
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplacementTransformer.
|
||||||
func (in *ReplacementTransformer) DeepCopy() *ReplacementTransformer {
|
func (in *ReplacementTransformer) DeepCopy() *ReplacementTransformer {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
|
|
||||||
@ -57,9 +56,12 @@ func New(obj map[string]interface{}) (kio.Filter, error) {
|
|||||||
if r.Source == nil {
|
if r.Source == nil {
|
||||||
return nil, ErrBadConfiguration{Msg: "`from` must be specified in one replacement"}
|
return nil, ErrBadConfiguration{Msg: "`from` must be specified in one replacement"}
|
||||||
}
|
}
|
||||||
if r.Target == nil {
|
if r.Target == nil && r.Targets == nil {
|
||||||
return nil, ErrBadConfiguration{Msg: "`to` must be specified in one replacement"}
|
return nil, ErrBadConfiguration{Msg: "`to` must be specified in one replacement"}
|
||||||
}
|
}
|
||||||
|
if r.Target != nil && r.Targets != nil {
|
||||||
|
return nil, ErrBadConfiguration{Msg: "only target OR targets is allowed in one replacement, not both"}
|
||||||
|
}
|
||||||
if r.Source.ObjRef != nil && r.Source.Value != "" {
|
if r.Source.ObjRef != nil && r.Source.Value != "" {
|
||||||
return nil, ErrBadConfiguration{Msg: "only one of fieldref and value is allowed in one replacement"}
|
return nil, ErrBadConfiguration{Msg: "only one of fieldref and value is allowed in one replacement"}
|
||||||
}
|
}
|
||||||
@ -73,15 +75,22 @@ func (p *plugin) Filter(items []*yaml.RNode) ([]*yaml.RNode, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if r.Target != nil {
|
||||||
if err := replace(items, r.Target, val); err != nil {
|
if err := replace(items, r.Target, val); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// range handles nil case as empty list
|
||||||
|
for _, t := range r.Targets {
|
||||||
|
if err := replace(items, t, val); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getValue(items []*yaml.RNode, source *types.ReplSource) (*yaml.RNode, error) {
|
func getValue(items []*yaml.RNode, source *airshipv1.ReplSource) (*yaml.RNode, error) {
|
||||||
if source.Value != "" {
|
if source.Value != "" {
|
||||||
return yaml.NewScalarRNode(source.Value), nil
|
return yaml.NewScalarRNode(source.Value), nil
|
||||||
}
|
}
|
||||||
@ -128,7 +137,7 @@ func mutateField(rnSource *yaml.RNode) func([]*yaml.RNode) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func replace(items []*yaml.RNode, target *types.ReplTarget, value *yaml.RNode) error {
|
func replace(items []*yaml.RNode, target *airshipv1.ReplTarget, value *yaml.RNode) error {
|
||||||
targets, err := kyamlutils.DocumentSelector{}.
|
targets, err := kyamlutils.DocumentSelector{}.
|
||||||
ByGVK(target.ObjRef.Group, target.ObjRef.Version, target.ObjRef.Kind).
|
ByGVK(target.ObjRef.Group, target.ObjRef.Version, target.ObjRef.Kind).
|
||||||
ByName(target.ObjRef.Name).
|
ByName(target.ObjRef.Name).
|
||||||
|
@ -1225,6 +1225,143 @@ data:
|
|||||||
`,
|
`,
|
||||||
expectedErr: "Error while decoding base64 encoded string: abc",
|
expectedErr: "Error while decoding base64 encoded string: abc",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
cfg: `
|
||||||
|
apiVersion: airshipit.org/v1alpha1
|
||||||
|
kind: ReplacementTransformer
|
||||||
|
metadata:
|
||||||
|
name: Test_Case_25
|
||||||
|
replacements:
|
||||||
|
- source:
|
||||||
|
value: nginx:newtag
|
||||||
|
targets:
|
||||||
|
- objref:
|
||||||
|
kind: Deployment
|
||||||
|
name: deploy1
|
||||||
|
fieldrefs:
|
||||||
|
- spec.template.spec.containers[name=nginx.latest].image
|
||||||
|
- objref:
|
||||||
|
kind: Deployment
|
||||||
|
name: deploy2
|
||||||
|
fieldrefs:
|
||||||
|
- spec.template.spec.containers[name=nginx.latest].image
|
||||||
|
- source:
|
||||||
|
value: postgres:latest
|
||||||
|
targets:
|
||||||
|
- objref:
|
||||||
|
kind: Deployment
|
||||||
|
name: deploy1
|
||||||
|
fieldrefs:
|
||||||
|
- spec.template.spec.containers.3.image
|
||||||
|
- objref:
|
||||||
|
kind: Deployment
|
||||||
|
name: deploy2
|
||||||
|
fieldrefs:
|
||||||
|
- spec.template.spec.containers.3.image
|
||||||
|
`,
|
||||||
|
|
||||||
|
in: `
|
||||||
|
apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx.latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:latest
|
||||||
|
name: nginx.latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:1.8.0
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
expectedOut: `apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy1
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:newtag
|
||||||
|
name: nginx.latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:latest
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
group: apps
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: deploy2
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: nginx:1.7.9
|
||||||
|
name: nginx-tagged
|
||||||
|
- image: nginx:newtag
|
||||||
|
name: nginx.latest
|
||||||
|
- image: foobar:1
|
||||||
|
name: replaced-with-digest
|
||||||
|
- image: postgres:latest
|
||||||
|
name: postgresdb
|
||||||
|
initContainers:
|
||||||
|
- image: nginx
|
||||||
|
name: nginx-notag
|
||||||
|
- image: nginx@sha256:111111111111111111
|
||||||
|
name: nginx-sha256
|
||||||
|
- image: alpine:1.8.0
|
||||||
|
name: init-alpine
|
||||||
|
`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExec(t *testing.T) {
|
func TestExec(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user