...

Source file src/sigs.k8s.io/kustomize/kyaml/yaml/filters.go

Documentation: sigs.k8s.io/kustomize/kyaml/yaml

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package yaml
     5  
     6  import (
     7  	"fmt"
     8  	"regexp"
     9  	"sort"
    10  	"strings"
    11  )
    12  
    13  // Filters is the list of serializable Pipeline Filters
    14  var Filters = map[string]func() Filter{
    15  	"AnnotationClearer": func() Filter { return &AnnotationClearer{} },
    16  	"AnnotationGetter":  func() Filter { return &AnnotationGetter{} },
    17  	"AnnotationSetter":  func() Filter { return &AnnotationSetter{} },
    18  	"LabelSetter":       func() Filter { return &LabelSetter{} },
    19  	"ElementAppender":   func() Filter { return &ElementAppender{} },
    20  	"ElementMatcher":    func() Filter { return &ElementMatcher{} },
    21  	"FieldClearer":      func() Filter { return &FieldClearer{} },
    22  	"FilterMatcher":     func() Filter { return &FilterMatcher{} },
    23  	"FieldMatcher":      func() Filter { return &FieldMatcher{} },
    24  	"FieldSetter":       func() Filter { return &FieldSetter{} },
    25  	"PathGetter":        func() Filter { return &PathGetter{} },
    26  	"PathMatcher":       func() Filter { return &PathMatcher{} },
    27  	"Parser":            func() Filter { return &Parser{} },
    28  	"PrefixSetter":      func() Filter { return &PrefixSetter{} },
    29  	"ValueReplacer":     func() Filter { return &ValueReplacer{} },
    30  	"SuffixSetter":      func() Filter { return &SuffixSetter{} },
    31  	"TeePiper":          func() Filter { return &TeePiper{} },
    32  }
    33  
    34  // YFilter wraps the Filter interface so the filter can be represented as
    35  // data and can be unmarshalled into a struct from a yaml config file.
    36  // This allows Pipelines to be expressed as data rather than code.
    37  type YFilter struct {
    38  	Filter
    39  }
    40  
    41  func (y YFilter) MarshalYAML() (interface{}, error) {
    42  	return y.Filter, nil
    43  }
    44  
    45  func (y *YFilter) UnmarshalYAML(unmarshal func(interface{}) error) error {
    46  	meta := &ResourceMeta{}
    47  	if err := unmarshal(meta); err != nil {
    48  		return err
    49  	}
    50  	filter, found := Filters[meta.Kind]
    51  	if !found {
    52  		var knownFilters []string
    53  		for k := range Filters {
    54  			knownFilters = append(knownFilters, k)
    55  		}
    56  		sort.Strings(knownFilters)
    57  		return fmt.Errorf("unsupported Filter Kind %s:  may be one of: [%s]",
    58  			meta.Kind, strings.Join(knownFilters, ","))
    59  	}
    60  	y.Filter = filter()
    61  
    62  	if err := unmarshal(y.Filter); err != nil {
    63  		return err
    64  	}
    65  	return nil
    66  }
    67  
    68  type YFilters []YFilter
    69  
    70  func (y YFilters) Filters() []Filter {
    71  	f := make([]Filter, 0, len(y))
    72  	for i := range y {
    73  		f = append(f, y[i].Filter)
    74  	}
    75  	return f
    76  }
    77  
    78  type FilterMatcher struct {
    79  	Kind string `yaml:"kind"`
    80  
    81  	// Filters are the set of Filters run by TeePiper.
    82  	Filters YFilters `yaml:"pipeline,omitempty"`
    83  }
    84  
    85  func (t FilterMatcher) Filter(rn *RNode) (*RNode, error) {
    86  	v, err := rn.Pipe(t.Filters.Filters()...)
    87  	if v == nil || err != nil {
    88  		return nil, err
    89  	}
    90  	// return the original input if the pipeline resolves to true
    91  	return rn, err
    92  }
    93  
    94  type ValueReplacer struct {
    95  	Kind string `yaml:"kind"`
    96  
    97  	StringMatch string `yaml:"stringMatch"`
    98  	RegexMatch  string `yaml:"regexMatch"`
    99  	Replace     string `yaml:"replace"`
   100  	Count       int    `yaml:"count"`
   101  }
   102  
   103  func (s ValueReplacer) Filter(object *RNode) (*RNode, error) {
   104  	if s.Count == 0 {
   105  		s.Count = -1
   106  	}
   107  	switch {
   108  	case s.StringMatch != "":
   109  		object.value.Value = strings.Replace(object.value.Value, s.StringMatch, s.Replace, s.Count)
   110  	case s.RegexMatch != "":
   111  		r, err := regexp.Compile(s.RegexMatch)
   112  		if err != nil {
   113  			return nil, fmt.Errorf("ValueReplacer RegexMatch does not compile: %v", err)
   114  		}
   115  		object.value.Value = r.ReplaceAllString(object.value.Value, s.Replace)
   116  	default:
   117  		return nil, fmt.Errorf("ValueReplacer missing StringMatch and RegexMatch")
   118  	}
   119  	return object, nil
   120  }
   121  
   122  type PrefixSetter struct {
   123  	Kind string `yaml:"kind"`
   124  
   125  	Value string `yaml:"value"`
   126  }
   127  
   128  func (s PrefixSetter) Filter(object *RNode) (*RNode, error) {
   129  	if !strings.HasPrefix(object.value.Value, s.Value) {
   130  		object.value.Value = s.Value + object.value.Value
   131  	}
   132  	return object, nil
   133  }
   134  
   135  type SuffixSetter struct {
   136  	Kind string `yaml:"kind"`
   137  
   138  	Value string `yaml:"value"`
   139  }
   140  
   141  func (s SuffixSetter) Filter(object *RNode) (*RNode, error) {
   142  	if !strings.HasSuffix(object.value.Value, s.Value) {
   143  		object.value.Value += s.Value
   144  	}
   145  	return object, nil
   146  }
   147  

View as plain text