...

Source file src/sigs.k8s.io/kustomize/api/types/var.go

Documentation: sigs.k8s.io/kustomize/api/types

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package types
     5  
     6  import (
     7  	"fmt"
     8  	"reflect"
     9  	"sort"
    10  	"strings"
    11  
    12  	"sigs.k8s.io/kustomize/kyaml/resid"
    13  )
    14  
    15  // Var represents a variable whose value will be sourced
    16  // from a field in a Kubernetes object.
    17  type Var struct {
    18  	// Value of identifier name e.g. FOO used in container args, annotations
    19  	// Appears in pod template as $(FOO)
    20  	Name string `json:"name" yaml:"name"`
    21  
    22  	// ObjRef must refer to a Kubernetes resource under the
    23  	// purview of this kustomization. ObjRef should use the
    24  	// raw name of the object (the name specified in its YAML,
    25  	// before addition of a namePrefix and a nameSuffix).
    26  	ObjRef Target `json:"objref" yaml:"objref"`
    27  
    28  	// FieldRef refers to the field of the object referred to by
    29  	// ObjRef whose value will be extracted for use in
    30  	// replacing $(FOO).
    31  	// If unspecified, this defaults to fieldPath: $defaultFieldPath
    32  	FieldRef FieldSelector `json:"fieldref,omitempty" yaml:"fieldref,omitempty"`
    33  }
    34  
    35  // Target refers to a kubernetes object by Group, Version, Kind and Name
    36  // gvk.Gvk contains Group, Version and Kind
    37  // APIVersion is added to keep the backward compatibility of using ObjectReference
    38  // for Var.ObjRef
    39  type Target struct {
    40  	APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
    41  	resid.Gvk  `json:",inline,omitempty" yaml:",inline,omitempty"`
    42  	Name       string `json:"name" yaml:"name"`
    43  	Namespace  string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
    44  }
    45  
    46  // GVK returns the Gvk object in Target
    47  func (t *Target) GVK() resid.Gvk {
    48  	if t.APIVersion == "" {
    49  		return t.Gvk
    50  	}
    51  	versions := strings.Split(t.APIVersion, "/")
    52  	if len(versions) == 2 {
    53  		t.Group = versions[0]
    54  		t.Version = versions[1]
    55  	}
    56  	if len(versions) == 1 {
    57  		t.Version = versions[0]
    58  	}
    59  	return t.Gvk
    60  }
    61  
    62  // FieldSelector contains the fieldPath to an object field.
    63  // This struct is added to keep the backward compatibility of using ObjectFieldSelector
    64  // for Var.FieldRef
    65  type FieldSelector struct {
    66  	FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
    67  }
    68  
    69  // defaulting sets reference to field used by default.
    70  func (v *Var) Defaulting() {
    71  	if v.FieldRef.FieldPath == "" {
    72  		v.FieldRef.FieldPath = DefaultReplacementFieldPath
    73  	}
    74  	v.ObjRef.GVK()
    75  }
    76  
    77  // DeepEqual returns true if var a and b are Equals.
    78  // Note 1: The objects are unchanged by the VarEqual
    79  // Note 2: Should be normalize be FieldPath before doing
    80  // the DeepEqual. spec.a[b] is supposed to be the same
    81  // as spec.a.b
    82  func (v Var) DeepEqual(other Var) bool {
    83  	v.Defaulting()
    84  	other.Defaulting()
    85  	return reflect.DeepEqual(v, other)
    86  }
    87  
    88  // VarSet is a set of Vars where no var.Name is repeated.
    89  type VarSet struct {
    90  	set map[string]Var
    91  }
    92  
    93  // NewVarSet returns an initialized VarSet
    94  func NewVarSet() VarSet {
    95  	return VarSet{set: map[string]Var{}}
    96  }
    97  
    98  // AsSlice returns the vars as a slice.
    99  func (vs *VarSet) AsSlice() []Var {
   100  	s := make([]Var, len(vs.set))
   101  	i := 0
   102  	for _, v := range vs.set {
   103  		s[i] = v
   104  		i++
   105  	}
   106  	sort.Sort(byName(s))
   107  	return s
   108  }
   109  
   110  // Copy returns a copy of the var set.
   111  func (vs *VarSet) Copy() VarSet {
   112  	newSet := make(map[string]Var, len(vs.set))
   113  	for k, v := range vs.set {
   114  		newSet[k] = v
   115  	}
   116  	return VarSet{set: newSet}
   117  }
   118  
   119  // MergeSet absorbs other vars with error on name collision.
   120  func (vs *VarSet) MergeSet(incoming VarSet) error {
   121  	for _, incomingVar := range incoming.set {
   122  		if err := vs.Merge(incomingVar); err != nil {
   123  			return err
   124  		}
   125  	}
   126  	return nil
   127  }
   128  
   129  // MergeSlice absorbs a Var slice with error on name collision.
   130  // Empty fields in incoming vars are defaulted.
   131  func (vs *VarSet) MergeSlice(incoming []Var) error {
   132  	for _, v := range incoming {
   133  		if err := vs.Merge(v); err != nil {
   134  			return err
   135  		}
   136  	}
   137  	return nil
   138  }
   139  
   140  // Merge absorbs another Var with error on name collision.
   141  // Empty fields in incoming Var is defaulted.
   142  func (vs *VarSet) Merge(v Var) error {
   143  	if vs.Contains(v) {
   144  		return fmt.Errorf(
   145  			"var '%s' already encountered", v.Name)
   146  	}
   147  	v.Defaulting()
   148  	vs.set[v.Name] = v
   149  	return nil
   150  }
   151  
   152  // AbsorbSet absorbs other vars with error on (name,value) collision.
   153  func (vs *VarSet) AbsorbSet(incoming VarSet) error {
   154  	for _, v := range incoming.set {
   155  		if err := vs.Absorb(v); err != nil {
   156  			return err
   157  		}
   158  	}
   159  	return nil
   160  }
   161  
   162  // AbsorbSlice absorbs a Var slice with error on (name,value) collision.
   163  // Empty fields in incoming vars are defaulted.
   164  func (vs *VarSet) AbsorbSlice(incoming []Var) error {
   165  	for _, v := range incoming {
   166  		if err := vs.Absorb(v); err != nil {
   167  			return err
   168  		}
   169  	}
   170  	return nil
   171  }
   172  
   173  // Absorb absorbs another Var with error on (name,value) collision.
   174  // Empty fields in incoming Var is defaulted.
   175  func (vs *VarSet) Absorb(v Var) error {
   176  	conflicting := vs.Get(v.Name)
   177  	if conflicting == nil {
   178  		// no conflict. The var is valid.
   179  		v.Defaulting()
   180  		vs.set[v.Name] = v
   181  		return nil
   182  	}
   183  
   184  	if !reflect.DeepEqual(v, *conflicting) {
   185  		// two vars with the same name are pointing at two
   186  		// different resources.
   187  		return fmt.Errorf(
   188  			"var '%s' already encountered", v.Name)
   189  	}
   190  	return nil
   191  }
   192  
   193  // Contains is true if the set has the other var.
   194  func (vs *VarSet) Contains(other Var) bool {
   195  	return vs.Get(other.Name) != nil
   196  }
   197  
   198  // Get returns the var with the given name, else nil.
   199  func (vs *VarSet) Get(name string) *Var {
   200  	if v, found := vs.set[name]; found {
   201  		return &v
   202  	}
   203  	return nil
   204  }
   205  
   206  // byName is a sort interface which sorts Vars by name alphabetically
   207  type byName []Var
   208  
   209  func (v byName) Len() int           { return len(v) }
   210  func (v byName) Swap(i, j int)      { v[i], v[j] = v[j], v[i] }
   211  func (v byName) Less(i, j int) bool { return v[i].Name < v[j].Name }
   212  

View as plain text