Switch prefix transformer to kyaml.

This commit is contained in:
jregan
2020-07-17 18:01:20 -07:00
parent 45eed23b26
commit e9bc2c00c1
6 changed files with 53 additions and 112 deletions

View File

@@ -6,7 +6,8 @@ package builtins
import ( import (
"fmt" "fmt"
"sigs.k8s.io/kustomize/api/transform" "sigs.k8s.io/kustomize/api/filters/replicacount"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
@@ -30,21 +31,27 @@ func (p *ReplicaCountTransformerPlugin) Config(
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error { func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
found := false found := false
for i, replicaSpec := range p.FieldSpecs { for _, fs := range p.FieldSpecs {
matcher := p.createMatcher(i) matcher := p.createMatcher(fs)
matchOriginal := m.GetMatchingResourcesByOriginalId(matcher) matchOriginal := m.GetMatchingResourcesByOriginalId(matcher)
matchCurrent := m.GetMatchingResourcesByCurrentId(matcher) resList := append(
matchOriginal, m.GetMatchingResourcesByCurrentId(matcher)...)
for _, res := range append(matchOriginal, matchCurrent...) { if len(resList) > 0 {
found = true found = true
err := transform.MutateField( for _, r := range resList {
res.Map(), replicaSpec.PathSlice(), // There are redundant checks in the filter
replicaSpec.CreateIfNotPresent, p.addReplicas) // that we'll live with until resolution of
// https://github.com/kubernetes-sigs/kustomize/issues/2506
err := filtersutil.ApplyToJSON(replicacount.Filter{
Replica: p.Replica,
FieldSpec: fs,
}, r)
if err != nil { if err != nil {
return err return err
} }
} }
} }
}
if !found { if !found {
gvks := make([]string, len(p.FieldSpecs)) gvks := make([]string, len(p.FieldSpecs))
@@ -59,30 +66,12 @@ func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
} }
// Match Replica.Name and FieldSpec // Match Replica.Name and FieldSpec
func (p *ReplicaCountTransformerPlugin) createMatcher(i int) resmap.IdMatcher { func (p *ReplicaCountTransformerPlugin) createMatcher(fs types.FieldSpec) resmap.IdMatcher {
return func(r resid.ResId) bool { return func(r resid.ResId) bool {
return r.Name == p.Replica.Name && return r.Name == p.Replica.Name && r.Gvk.IsSelected(&fs.Gvk)
r.Gvk.IsSelected(&p.FieldSpecs[i].Gvk)
} }
} }
func (p *ReplicaCountTransformerPlugin) addReplicas(in interface{}) (interface{}, error) {
switch m := in.(type) {
case int64:
// Was already in the field.
case map[string]interface{}:
if len(m) != 0 {
// A map was already in the replicas field, don't want to
// discard this data silently.
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
}
// Just got added, default type is map, but we can return anything.
default:
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
}
return p.Replica.Count, nil
}
func NewReplicaCountTransformerPlugin() resmap.TransformerPlugin { func NewReplicaCountTransformerPlugin() resmap.TransformerPlugin {
return &ReplicaCountTransformerPlugin{} return &ReplicaCountTransformerPlugin{}
} }

View File

@@ -33,11 +33,9 @@ spec:
Count: 42, Count: 42,
Name: "instance", Name: "instance",
}, },
FsSlice: types.FsSlice{ FieldSpec: types.FieldSpec{
{
Path: "spec/template/replicas", Path: "spec/template/replicas",
}, },
},
}}, }},
Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}}, Outputs: []kio.Writer{kio.ByteWriter{Writer: os.Stdout}},
}.Execute() }.Execute()

View File

@@ -3,8 +3,8 @@ package replicacount
import ( import (
"strconv" "strconv"
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/filters/filtersutil" "sigs.k8s.io/kustomize/api/filters/filtersutil"
"sigs.k8s.io/kustomize/api/filters/fsslice"
"sigs.k8s.io/kustomize/api/types" "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"
@@ -13,9 +13,7 @@ import (
// Filter updates/sets replicas fields using the fieldSpecs // Filter updates/sets replicas fields using the fieldSpecs
type Filter struct { type Filter struct {
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"` Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
FieldSpec types.FieldSpec `json:"fieldSpec,omitempty" yaml:"fieldSpec,omitempty"`
// FsSlice contains the FieldSpecs to locate the namespace field
FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
} }
var _ kio.Filter = Filter{} var _ kio.Filter = Filter{}
@@ -24,20 +22,9 @@ func (rc Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes) return kio.FilterAll(yaml.FilterFunc(rc.run)).Filter(nodes)
} }
// run processes each node individually.
func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) { func (rc Filter) run(node *yaml.RNode) (*yaml.RNode, error) {
meta, err := node.GetMeta() err := node.PipeE(fieldspec.Filter{
if err != nil { FieldSpec: rc.FieldSpec,
return nil, err
}
// only update resources where the name matches the Replica name.
if meta.Name != rc.Replica.Name {
return node, nil
}
err = node.PipeE(fsslice.Filter{
FsSlice: rc.FsSlice,
SetValue: rc.set, SetValue: rc.set,
CreateKind: yaml.ScalarNode, // replicas is a ScalarNode CreateKind: yaml.ScalarNode, // replicas is a ScalarNode
CreateTag: yaml.IntTag, CreateTag: yaml.IntTag,

View File

@@ -5,19 +5,16 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest" filtertest_test "sigs.k8s.io/kustomize/api/testutils/filtertest"
"sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/api/types"
) )
func TestFilter(t *testing.T) { func TestFilter(t *testing.T) {
var config = builtinconfig.MakeDefaultConfig()
testCases := map[string]struct { testCases := map[string]struct {
input string input string
expected string expected string
filter Filter filter Filter
fsslice types.FsSlice
}{ }{
"update field": { "update field": {
input: ` input: `
@@ -41,11 +38,7 @@ spec:
Name: "dep", Name: "dep",
Count: 42, Count: 42,
}, },
}, FieldSpec: types.FieldSpec{Path: "spec/replicas"},
fsslice: types.FsSlice{
{
Path: "spec/replicas",
},
}, },
}, },
"add field": { "add field": {
@@ -73,9 +66,7 @@ spec:
Name: "cus", Name: "cus",
Count: 42, Count: 42,
}, },
}, FieldSpec: types.FieldSpec{
fsslice: types.FsSlice{
{
Path: "spec/template/replicas", Path: "spec/template/replicas",
CreateIfNotPresent: true, CreateIfNotPresent: true,
}, },
@@ -108,9 +99,7 @@ spec:
Name: "cus", Name: "cus",
Count: 42, Count: 42,
}, },
}, FieldSpec: types.FieldSpec{
fsslice: types.FsSlice{
{
Path: "spec/template/replicas", Path: "spec/template/replicas",
CreateIfNotPresent: true, CreateIfNotPresent: true,
}, },
@@ -140,9 +129,7 @@ spec:
Name: "cus", Name: "cus",
Count: 42, Count: 42,
}, },
}, FieldSpec: types.FieldSpec{
fsslice: types.FsSlice{
{
Path: "spec/template/replicas", Path: "spec/template/replicas",
}, },
}, },
@@ -154,7 +141,6 @@ kind: Custom
metadata: metadata:
name: cus name: cus
spec: spec:
replicas: 5
template: template:
replicas: 5 replicas: 5
`, `,
@@ -164,7 +150,6 @@ kind: Custom
metadata: metadata:
name: cus name: cus
spec: spec:
replicas: 42
template: template:
replicas: 42 replicas: 42
`, `,
@@ -173,21 +158,13 @@ spec:
Name: "cus", Name: "cus",
Count: 42, Count: 42,
}, },
}, FieldSpec: types.FieldSpec{Path: "spec/template/replicas"},
fsslice: types.FsSlice{
{
Path: "spec/template/replicas",
},
{
Path: "spec/replicas",
},
}, },
}, },
} }
for tn, tc := range testCases { for tn, tc := range testCases {
t.Run(tn, func(t *testing.T) { t.Run(tn, func(t *testing.T) {
tc.filter.FsSlice = append(config.Replicas, tc.fsslice...)
if !assert.Equal(t, if !assert.Equal(t,
strings.TrimSpace(tc.expected), strings.TrimSpace(tc.expected),
strings.TrimSpace( strings.TrimSpace(

View File

@@ -7,7 +7,8 @@ package main
import ( import (
"fmt" "fmt"
"sigs.k8s.io/kustomize/api/transform" "sigs.k8s.io/kustomize/api/filters/replicacount"
"sigs.k8s.io/kustomize/kyaml/filtersutil"
"sigs.k8s.io/kustomize/api/resid" "sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resmap"
@@ -34,21 +35,27 @@ func (p *plugin) Config(
func (p *plugin) Transform(m resmap.ResMap) error { func (p *plugin) Transform(m resmap.ResMap) error {
found := false found := false
for i, replicaSpec := range p.FieldSpecs { for _, fs := range p.FieldSpecs {
matcher := p.createMatcher(i) matcher := p.createMatcher(fs)
matchOriginal := m.GetMatchingResourcesByOriginalId(matcher) matchOriginal := m.GetMatchingResourcesByOriginalId(matcher)
matchCurrent := m.GetMatchingResourcesByCurrentId(matcher) resList := append(
matchOriginal, m.GetMatchingResourcesByCurrentId(matcher)...)
for _, res := range append(matchOriginal, matchCurrent...) { if len(resList) > 0 {
found = true found = true
err := transform.MutateField( for _, r := range resList {
res.Map(), replicaSpec.PathSlice(), // There are redundant checks in the filter
replicaSpec.CreateIfNotPresent, p.addReplicas) // that we'll live with until resolution of
// https://github.com/kubernetes-sigs/kustomize/issues/2506
err := filtersutil.ApplyToJSON(replicacount.Filter{
Replica: p.Replica,
FieldSpec: fs,
}, r)
if err != nil { if err != nil {
return err return err
} }
} }
} }
}
if !found { if !found {
gvks := make([]string, len(p.FieldSpecs)) gvks := make([]string, len(p.FieldSpecs))
@@ -63,26 +70,8 @@ func (p *plugin) Transform(m resmap.ResMap) error {
} }
// Match Replica.Name and FieldSpec // Match Replica.Name and FieldSpec
func (p *plugin) createMatcher(i int) resmap.IdMatcher { func (p *plugin) createMatcher(fs types.FieldSpec) resmap.IdMatcher {
return func(r resid.ResId) bool { return func(r resid.ResId) bool {
return r.Name == p.Replica.Name && return r.Name == p.Replica.Name && r.Gvk.IsSelected(&fs.Gvk)
r.Gvk.IsSelected(&p.FieldSpecs[i].Gvk)
} }
} }
func (p *plugin) addReplicas(in interface{}) (interface{}, error) {
switch m := in.(type) {
case int64:
// Was already in the field.
case map[string]interface{}:
if len(m) != 0 {
// A map was already in the replicas field, don't want to
// discard this data silently.
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
}
// Just got added, default type is map, but we can return anything.
default:
return nil, fmt.Errorf("%#v is expected to be %T", in, m)
}
return p.Replica.Count, nil
}

View File

@@ -4,6 +4,7 @@ go 1.14
require ( require (
sigs.k8s.io/kustomize/api v0.5.1 sigs.k8s.io/kustomize/api v0.5.1
sigs.k8s.io/kustomize/kyaml v0.4.1
sigs.k8s.io/yaml v1.2.0 sigs.k8s.io/yaml v1.2.0
) )