...

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

Documentation: sigs.k8s.io/kustomize/kyaml/kio/filters

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package filters
     5  
     6  import (
     7  	"fmt"
     8  	"sort"
     9  	"strings"
    10  
    11  	"sigs.k8s.io/kustomize/kyaml/kio"
    12  	"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
    13  	"sigs.k8s.io/kustomize/kyaml/yaml"
    14  )
    15  
    16  // Filters are the list of known filters for unmarshalling a filter into a concrete
    17  // implementation.
    18  var Filters = map[string]func() kio.Filter{
    19  	"FileSetter":    func() kio.Filter { return &FileSetter{} },
    20  	"FormatFilter":  func() kio.Filter { return &FormatFilter{} },
    21  	"GrepFilter":    func() kio.Filter { return GrepFilter{} },
    22  	"MatchModifier": func() kio.Filter { return &MatchModifyFilter{} },
    23  	"Modifier":      func() kio.Filter { return &Modifier{} },
    24  }
    25  
    26  // filter wraps a kio.filter so that it can be unmarshalled from yaml.
    27  type KFilter struct {
    28  	kio.Filter
    29  }
    30  
    31  func (t KFilter) MarshalYAML() (interface{}, error) {
    32  	return t.Filter, nil
    33  }
    34  
    35  func (t *KFilter) UnmarshalYAML(unmarshal func(interface{}) error) error {
    36  	i := map[string]interface{}{}
    37  	if err := unmarshal(i); err != nil {
    38  		return err
    39  	}
    40  	meta := &yaml.ResourceMeta{}
    41  	if err := unmarshal(meta); err != nil {
    42  		return err
    43  	}
    44  	filter, found := Filters[meta.Kind]
    45  	if !found {
    46  		var knownFilters []string
    47  		for k := range Filters {
    48  			knownFilters = append(knownFilters, k)
    49  		}
    50  		sort.Strings(knownFilters)
    51  		return fmt.Errorf("unsupported filter Kind %v:  may be one of: [%s]",
    52  			meta, strings.Join(knownFilters, ","))
    53  	}
    54  	t.Filter = filter()
    55  
    56  	return unmarshal(t.Filter)
    57  }
    58  
    59  // Modifier modifies the input Resources by invoking the provided pipeline.
    60  // Modifier will return any Resources for which the pipeline does not return an error.
    61  type Modifier struct {
    62  	Kind string `yaml:"kind,omitempty"`
    63  
    64  	Filters yaml.YFilters `yaml:"pipeline,omitempty"`
    65  }
    66  
    67  var _ kio.Filter = &Modifier{}
    68  
    69  func (f Modifier) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
    70  	for i := range input {
    71  		if _, err := input[i].Pipe(f.Filters.Filters()...); err != nil {
    72  			return nil, err
    73  		}
    74  	}
    75  	return input, nil
    76  }
    77  
    78  type MatchModifyFilter struct {
    79  	Kind string `yaml:"kind,omitempty"`
    80  
    81  	MatchFilters []yaml.YFilters `yaml:"match,omitempty"`
    82  
    83  	ModifyFilters yaml.YFilters `yaml:"modify,omitempty"`
    84  }
    85  
    86  var _ kio.Filter = &MatchModifyFilter{}
    87  
    88  func (f MatchModifyFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
    89  	var matches = input
    90  	var err error
    91  	for _, filter := range f.MatchFilters {
    92  		matches, err = MatchFilter{Filters: filter}.Filter(matches)
    93  		if err != nil {
    94  			return nil, err
    95  		}
    96  	}
    97  	_, err = Modifier{Filters: f.ModifyFilters}.Filter(matches)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	return input, nil
   102  }
   103  
   104  type MatchFilter struct {
   105  	Kind string `yaml:"kind,omitempty"`
   106  
   107  	Filters yaml.YFilters `yaml:"pipeline,omitempty"`
   108  }
   109  
   110  var _ kio.Filter = &MatchFilter{}
   111  
   112  func (f MatchFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
   113  	var output []*yaml.RNode
   114  	for i := range input {
   115  		if v, err := input[i].Pipe(f.Filters.Filters()...); err != nil {
   116  			return nil, err
   117  		} else if v == nil {
   118  			continue
   119  		}
   120  		output = append(output, input[i])
   121  	}
   122  	return output, nil
   123  }
   124  
   125  type FilenameFmtVerb string
   126  
   127  const (
   128  	// KindFmt substitutes kind
   129  	KindFmt FilenameFmtVerb = "%k"
   130  
   131  	// NameFmt substitutes metadata.name
   132  	NameFmt FilenameFmtVerb = "%n"
   133  
   134  	// NamespaceFmt substitutes metdata.namespace
   135  	NamespaceFmt FilenameFmtVerb = "%s"
   136  )
   137  
   138  // FileSetter sets the file name and mode annotations on Resources.
   139  type FileSetter struct {
   140  	Kind string `yaml:"kind,omitempty"`
   141  
   142  	// FilenamePattern is the pattern to use for generating filenames.  FilenameFmtVerb
   143  	// FielnameFmtVerbs may be specified to substitute Resource metadata into the filename.
   144  	FilenamePattern string `yaml:"filenamePattern,omitempty"`
   145  
   146  	// Mode is the filemode to write.
   147  	Mode string `yaml:"mode,omitempty"`
   148  
   149  	// Override will override the existing filename if it is set on the pattern.
   150  	// Otherwise the existing filename is kept.
   151  	Override bool `yaml:"override,omitempty"`
   152  }
   153  
   154  var _ kio.Filter = &FileSetter{}
   155  
   156  const DefaultFilenamePattern = "%n_%k.yaml"
   157  
   158  func (f *FileSetter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
   159  	if f.Mode == "" {
   160  		f.Mode = fmt.Sprintf("%d", 0600)
   161  	}
   162  	if f.FilenamePattern == "" {
   163  		f.FilenamePattern = DefaultFilenamePattern
   164  	}
   165  
   166  	resources := map[string][]*yaml.RNode{}
   167  	for i := range input {
   168  		if err := kioutil.CopyLegacyAnnotations(input[i]); err != nil {
   169  			return nil, err
   170  		}
   171  
   172  		m, err := input[i].GetMeta()
   173  		if err != nil {
   174  			return nil, err
   175  		}
   176  		file := f.FilenamePattern
   177  		file = strings.ReplaceAll(file, string(KindFmt), strings.ToLower(m.Kind))
   178  		file = strings.ReplaceAll(file, string(NameFmt), strings.ToLower(m.Name))
   179  		file = strings.ReplaceAll(file, string(NamespaceFmt), strings.ToLower(m.Namespace))
   180  
   181  		if _, found := m.Annotations[kioutil.PathAnnotation]; !found || f.Override {
   182  			if _, err := input[i].Pipe(yaml.SetAnnotation(kioutil.PathAnnotation, file)); err != nil {
   183  				return nil, err
   184  			}
   185  			if _, err := input[i].Pipe(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, file)); err != nil {
   186  				return nil, err
   187  			}
   188  		}
   189  		resources[file] = append(resources[file], input[i])
   190  	}
   191  
   192  	var output []*yaml.RNode
   193  	for i := range resources {
   194  		if err := kioutil.SortNodes(resources[i]); err != nil {
   195  			return nil, err
   196  		}
   197  		for j := range resources[i] {
   198  			if _, err := resources[i][j].Pipe(
   199  				yaml.SetAnnotation(kioutil.IndexAnnotation, fmt.Sprintf("%d", j))); err != nil {
   200  				return nil, err
   201  			}
   202  			if _, err := resources[i][j].Pipe(
   203  				yaml.SetAnnotation(kioutil.LegacyIndexAnnotation, fmt.Sprintf("%d", j))); err != nil {
   204  				return nil, err
   205  			}
   206  			output = append(output, resources[i][j])
   207  		}
   208  	}
   209  	return output, nil
   210  }
   211  

View as plain text