...

Source file src/sigs.k8s.io/kustomize/kyaml/kio/filters/merge.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 merge contains libraries for merging Resources and Patches
     5  package filters
     6  
     7  import (
     8  	"sigs.k8s.io/kustomize/kyaml/kio"
     9  	"sigs.k8s.io/kustomize/kyaml/yaml"
    10  	"sigs.k8s.io/kustomize/kyaml/yaml/merge2"
    11  )
    12  
    13  // MergeFilter merges Resources with the Group/Version/Kind/Namespace/Name together using
    14  // a 2-way merge strategy.
    15  //
    16  // - Fields set to null in the source will be cleared from the destination
    17  // - Fields with matching keys will be merged recursively
    18  // - Lists with an associative key (e.g. name) will have their elements merged using the key
    19  // - List without an associative key will have the dest list replaced by the source list
    20  type MergeFilter struct {
    21  	Reverse bool
    22  }
    23  
    24  var _ kio.Filter = MergeFilter{}
    25  
    26  type mergeKey struct {
    27  	apiVersion string
    28  	kind       string
    29  	namespace  string
    30  	name       string
    31  }
    32  
    33  // MergeFilter implements kio.Filter by merging Resources with the same G/V/K/NS/N
    34  func (c MergeFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
    35  	// invert the merge precedence
    36  	if c.Reverse {
    37  		for i, j := 0, len(input)-1; i < j; i, j = i+1, j-1 {
    38  			input[i], input[j] = input[j], input[i]
    39  		}
    40  	}
    41  
    42  	// index the Resources by G/V/K/NS/N
    43  	index := map[mergeKey][]*yaml.RNode{}
    44  	// retain the original ordering
    45  	var order []mergeKey
    46  	for i := range input {
    47  		meta, err := input[i].GetMeta()
    48  		if err != nil {
    49  			return nil, err
    50  		}
    51  		key := mergeKey{
    52  			apiVersion: meta.APIVersion,
    53  			kind:       meta.Kind,
    54  			namespace:  meta.Namespace,
    55  			name:       meta.Name,
    56  		}
    57  		if _, found := index[key]; !found {
    58  			order = append(order, key)
    59  		}
    60  		index[key] = append(index[key], input[i])
    61  	}
    62  
    63  	// merge each of the G/V/K/NS/N lists
    64  	var output []*yaml.RNode
    65  	var err error
    66  	for _, k := range order {
    67  		var merged *yaml.RNode
    68  		resources := index[k]
    69  		for i := range resources {
    70  			patch := resources[i]
    71  			if merged == nil {
    72  				// first resources, don't merge it
    73  				merged = resources[i]
    74  			} else {
    75  				merged, err = merge2.Merge(patch, merged, yaml.MergeOptions{
    76  					ListIncreaseDirection: yaml.MergeOptionsListPrepend,
    77  				})
    78  				if err != nil {
    79  					return nil, err
    80  				}
    81  			}
    82  		}
    83  		output = append(output, merged)
    84  	}
    85  	return output, nil
    86  }
    87  

View as plain text