kyaml setters: support full and partial field replacement

This commit is contained in:
Phillip Wittrock
2020-01-02 14:00:43 -08:00
parent 3577a7e174
commit ac9b0a3e9e
6 changed files with 76 additions and 34 deletions

View File

@@ -34,6 +34,8 @@ func NewCreateSetterRunner(parent string) *CreateSetterRunner {
"kind of the Resource on which to create the setter.") "kind of the Resource on which to create the setter.")
set.Flags().StringVar(&r.Set.SetPartialField.Type, "type", "", set.Flags().StringVar(&r.Set.SetPartialField.Type, "type", "",
"valid OpenAPI field type -- e.g. integer,boolean,string.") "valid OpenAPI field type -- e.g. integer,boolean,string.")
set.Flags().BoolVar(&r.Set.SetPartialField.Partial, "partial", false,
"create a partial setter for only part of the field value.")
fixDocs(parent, set) fixDocs(parent, set)
set.MarkFlagRequired("type") set.MarkFlagRequired("type")
set.MarkFlagRequired("field") set.MarkFlagRequired("field")

View File

@@ -22,7 +22,8 @@ type FieldMeta struct {
type XKustomize struct { type XKustomize struct {
SetBy string `yaml:"setBy,omitempty" json:"setBy,omitempty"` SetBy string `yaml:"setBy,omitempty" json:"setBy,omitempty"`
PartialFieldSetters []PartialFieldSetter `yaml:"partialFieldSetters" json:"partialFieldSetters"` PartialFieldSetters []PartialFieldSetter `yaml:"partialSetters,omitempty" json:"partialSetters,omitempty"`
FieldSetter *PartialFieldSetter `yaml:"setter,omitempty" json:"setter,omitempty"`
} }
// PartialFieldSetter defines how to set part of a field rather than the full field // PartialFieldSetter defines how to set part of a field rather than the full field

View File

@@ -29,6 +29,9 @@ type customFieldSetter struct {
Type string Type string
// Partial will create a partial setter if set to true
Partial bool
// currentFieldName is the name of the current field being processed // currentFieldName is the name of the current field being processed
currentFieldName string currentFieldName string
} }
@@ -66,11 +69,6 @@ func (m *customFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) {
} }
func (m *customFieldSetter) create(field *yaml.RNode) error { func (m *customFieldSetter) create(field *yaml.RNode) error {
// doesn't match the supplied value
if !strings.Contains(field.YNode().Value, m.Setter.Value) {
return nil
}
fm := fieldmeta.FieldMeta{} fm := fieldmeta.FieldMeta{}
if err := fm.Read(field); err != nil { if err := fm.Read(field); err != nil {
return errors.Wrap(err) return errors.Wrap(err)
@@ -83,6 +81,19 @@ func (m *customFieldSetter) create(field *yaml.RNode) error {
fm.Extensions.SetBy = m.SetBy fm.Extensions.SetBy = m.SetBy
fm.Schema.Type = []string{m.Type} fm.Schema.Type = []string{m.Type}
if !m.Partial {
// doesn't match the supplied value
if field.YNode().Value != m.Setter.Value {
return nil
}
// full setter
fm.Extensions.FieldSetter = &m.Setter
fm.Extensions.PartialFieldSetters = nil
} else {
// doesn't match the supplied value
if !strings.Contains(field.YNode().Value, m.Setter.Value) {
return nil
}
found := false found := false
for i := range fm.Extensions.PartialFieldSetters { for i := range fm.Extensions.PartialFieldSetters {
s := fm.Extensions.PartialFieldSetters[i] s := fm.Extensions.PartialFieldSetters[i]
@@ -97,6 +108,8 @@ func (m *customFieldSetter) create(field *yaml.RNode) error {
// add the setter if it wasn't found // add the setter if it wasn't found
fm.Extensions.PartialFieldSetters = append(fm.Extensions.PartialFieldSetters, m.Setter) fm.Extensions.PartialFieldSetters = append(fm.Extensions.PartialFieldSetters, m.Setter)
} }
}
if err := fm.Write(field); err != nil { if err := fm.Write(field); err != nil {
return errors.Wrap(err) return errors.Wrap(err)
} }

View File

@@ -30,7 +30,7 @@ type PerformSetters struct {
func (s *PerformSetters) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { func (s *PerformSetters) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
for i := range input { for i := range input {
p := &partialFieldSetter{ p := &fieldSetter{
Name: s.Name, Name: s.Name,
Value: s.Value, Value: s.Value,
Description: s.Description, Description: s.Description,

View File

@@ -11,10 +11,10 @@ import (
"sigs.k8s.io/kustomize/kyaml/yaml" "sigs.k8s.io/kustomize/kyaml/yaml"
) )
var _ yaml.Filter = &partialFieldSetter{} var _ yaml.Filter = &fieldSetter{}
// partialFieldSetter sets part of a field value. // fieldSetter sets part or all of a field value.
type partialFieldSetter struct { type fieldSetter struct {
// Name is the name of the setter to perform. // Name is the name of the setter to perform.
Name string Name string
@@ -32,7 +32,7 @@ type partialFieldSetter struct {
} }
// Filter implements yaml.Filter // Filter implements yaml.Filter
func (fs *partialFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) { func (fs *fieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) {
switch object.YNode().Kind { switch object.YNode().Kind {
case yaml.DocumentNode: case yaml.DocumentNode:
// Document is the root of the object and always contains 1 node // Document is the root of the object and always contains 1 node
@@ -49,7 +49,7 @@ func (fs *partialFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) {
}) })
case yaml.ScalarNode: case yaml.ScalarNode:
// Check if there is a setter matching the name // Check if there is a setter matching the name
s, f, err := fs.findPartialSetter(object) s, f, partial, err := fs.findSetter(object)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -58,19 +58,19 @@ func (fs *partialFieldSetter) Filter(object *yaml.RNode) (*yaml.RNode, error) {
return object, nil return object, nil
} }
// set the field value // set the field value
return object, fs.set(object, s, f) return object, fs.set(object, s, f, partial)
default: default:
return object, nil return object, nil
} }
} }
// findPartialSetter finds the setter matching the name if one exists // findPartialSetter finds the setter matching the name if one exists
func (fs *partialFieldSetter) findPartialSetter(field *yaml.RNode) ( func (fs *fieldSetter) findSetter(field *yaml.RNode) (
*fieldmeta.PartialFieldSetter, *fieldmeta.FieldMeta, error) { *fieldmeta.PartialFieldSetter, *fieldmeta.FieldMeta, bool, error) {
// check if there are any substitutions for this field // check if there are any substitutions for this field
var fm = &fieldmeta.FieldMeta{} var fm = &fieldmeta.FieldMeta{}
if err := fm.Read(field); err != nil { if err := fm.Read(field); err != nil {
return nil, nil, err return nil, nil, false, err
} }
if fs.SetBy != "" { if fs.SetBy != "" {
fm.Extensions.SetBy = fs.SetBy fm.Extensions.SetBy = fs.SetBy
@@ -79,18 +79,23 @@ func (fs *partialFieldSetter) findPartialSetter(field *yaml.RNode) (
fm.Schema.Description = fs.Description fm.Schema.Description = fs.Description
} }
if fm.Extensions.FieldSetter != nil && fm.Extensions.FieldSetter.Name == fs.Name {
return fm.Extensions.FieldSetter, fm, false, nil
}
// check if there is a matching substitution // check if there is a matching substitution
for i := range fm.Extensions.PartialFieldSetters { for i := range fm.Extensions.PartialFieldSetters {
if fm.Extensions.PartialFieldSetters[i].Name == fs.Name { if fm.Extensions.PartialFieldSetters[i].Name == fs.Name {
return &fm.Extensions.PartialFieldSetters[i], fm, nil return &fm.Extensions.PartialFieldSetters[i], fm, true, nil
} }
} }
return nil, nil, nil return nil, nil, false, nil
} }
// set performs the substitution for the given field, substitution, and metadata // set performs the substitution for the given field, substitution, and metadata
func (fs *partialFieldSetter) set( func (fs *fieldSetter) set(
field *yaml.RNode, s *fieldmeta.PartialFieldSetter, f *fieldmeta.FieldMeta) error { field *yaml.RNode, s *fieldmeta.PartialFieldSetter,
f *fieldmeta.FieldMeta, partial bool) error {
if s.Value == fs.Value || !strings.Contains(field.YNode().Value, s.Value) { if s.Value == fs.Value || !strings.Contains(field.YNode().Value, s.Value) {
// no substitutions necessary -- already substituted or doesn't have the set value // no substitutions necessary -- already substituted or doesn't have the set value
// which acts as a marker // which acts as a marker
@@ -100,8 +105,13 @@ func (fs *partialFieldSetter) set(
// record that the config has been modified // record that the config has been modified
fs.Count++ fs.Count++
if !partial {
// full setter
field.YNode().Value = fs.Value
} else {
// replace the current value with the new value // replace the current value with the new value
field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Value, fs.Value) field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Value, fs.Value)
}
// be sure to set the tag to the matching type so the yaml doesn't incorrectly quote // be sure to set the tag to the matching type so the yaml doesn't incorrectly quote
//integers or booleans as strings //integers or booleans as strings

View File

@@ -54,6 +54,22 @@ func (ls *lookupSetters) lookup(field *yaml.RNode) error {
return err return err
} }
if fm.Extensions.FieldSetter != nil {
if ls.Name != "" && ls.Name != fm.Extensions.FieldSetter.Name {
// skip this setter, it doesn't match the specified setter
return nil
}
// full setter
ls.Setters = append(ls.Setters, setter{
PartialFieldSetter: *fm.Extensions.FieldSetter,
Description: fm.Schema.Description,
Type: fm.Schema.Type[0],
SetBy: fm.Extensions.SetBy,
})
return nil
}
// partial setters
for i := range fm.Extensions.PartialFieldSetters { for i := range fm.Extensions.PartialFieldSetters {
if ls.Name != "" && ls.Name != fm.Extensions.PartialFieldSetters[i].Name { if ls.Name != "" && ls.Name != fm.Extensions.PartialFieldSetters[i].Name {
// skip this setter // skip this setter