...

Source file src/sigs.k8s.io/kustomize/api/resmap/resmap.go

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

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  // Package resmap implements a map from ResId to Resource that
     5  // tracks all resources in a kustomization.
     6  package resmap
     7  
     8  import (
     9  	"sigs.k8s.io/kustomize/api/ifc"
    10  	"sigs.k8s.io/kustomize/api/resource"
    11  	"sigs.k8s.io/kustomize/api/types"
    12  	"sigs.k8s.io/kustomize/kyaml/kio"
    13  	"sigs.k8s.io/kustomize/kyaml/resid"
    14  	"sigs.k8s.io/kustomize/kyaml/yaml"
    15  )
    16  
    17  // A Transformer modifies an instance of ResMap.
    18  type Transformer interface {
    19  	// Transform modifies data in the argument,
    20  	// e.g. adding labels to resources that can be labelled.
    21  	Transform(m ResMap) error
    22  }
    23  
    24  // A TransformerWithProperties contains a Transformer and stores
    25  // some of its properties
    26  type TransformerWithProperties struct {
    27  	Transformer
    28  	Origin *resource.Origin
    29  }
    30  
    31  // A Generator creates an instance of ResMap.
    32  type Generator interface {
    33  	Generate() (ResMap, error)
    34  }
    35  
    36  // A GeneratorWithProperties contains a Generator and stores
    37  // some of its properties
    38  type GeneratorWithProperties struct {
    39  	Generator
    40  	Origin *resource.Origin
    41  }
    42  
    43  // Something that's configurable accepts an
    44  // instance of PluginHelpers and a raw config
    45  // object (YAML in []byte form).
    46  type Configurable interface {
    47  	Config(h *PluginHelpers, config []byte) error
    48  }
    49  
    50  // NewPluginHelpers makes an instance of PluginHelpers.
    51  func NewPluginHelpers(
    52  	ldr ifc.Loader, v ifc.Validator, rf *Factory,
    53  	pc *types.PluginConfig) *PluginHelpers {
    54  	return &PluginHelpers{ldr: ldr, v: v, rf: rf, pc: pc}
    55  }
    56  
    57  // PluginHelpers holds things that any or all plugins might need.
    58  // This should be available to each plugin, in addition to
    59  // any plugin-specific configuration.
    60  type PluginHelpers struct {
    61  	ldr ifc.Loader
    62  	v   ifc.Validator
    63  	rf  *Factory
    64  	pc  *types.PluginConfig
    65  }
    66  
    67  func (c *PluginHelpers) GeneralConfig() *types.PluginConfig {
    68  	return c.pc
    69  }
    70  
    71  func (c *PluginHelpers) Loader() ifc.Loader {
    72  	return c.ldr
    73  }
    74  
    75  func (c *PluginHelpers) ResmapFactory() *Factory {
    76  	return c.rf
    77  }
    78  
    79  func (c *PluginHelpers) Validator() ifc.Validator {
    80  	return c.v
    81  }
    82  
    83  type GeneratorPlugin interface {
    84  	Generator
    85  	Configurable
    86  }
    87  
    88  type TransformerPlugin interface {
    89  	Transformer
    90  	Configurable
    91  }
    92  
    93  // ResMap is an interface describing operations on the
    94  // core kustomize data structure, a list of Resources.
    95  //
    96  // Every Resource has two ResIds: OrgId and CurId.
    97  //
    98  // In a ResMap, no two resources may have the same CurId,
    99  // but they may have the same OrgId.  The latter can happen
   100  // when mixing two or more different overlays apply different
   101  // transformations to a common base.  When looking for a
   102  // resource to transform, try the OrgId first, and if this
   103  // fails or finds too many, it might make sense to then try
   104  // the CurrId.  Depends on the situation.
   105  //
   106  // TODO: get rid of this interface (use bare resWrangler).
   107  // There aren't multiple implementations any more.
   108  type ResMap interface {
   109  	// Size reports the number of resources.
   110  	Size() int
   111  
   112  	// Resources provides a discardable slice
   113  	// of resource pointers, returned in the order
   114  	// as appended.
   115  	Resources() []*resource.Resource
   116  
   117  	// Append adds a Resource. Error on CurId collision.
   118  	//
   119  	// A class invariant of ResMap is that all of its
   120  	// resources must differ in their value of
   121  	// CurId(), aka current Id.  The Id is the tuple
   122  	// of {namespace, group, version, kind, name}
   123  	// (see ResId).
   124  	//
   125  	// This invariant reflects the invariant of a
   126  	// kubernetes cluster, where if one tries to add
   127  	// a resource to the cluster whose Id matches
   128  	// that of a resource already in the cluster,
   129  	// only two outcomes are allowed.  Either the
   130  	// incoming resource is _merged_ into the existing
   131  	// one, or the incoming resource is rejected.
   132  	// One cannot end up with two resources
   133  	// in the cluster with the same Id.
   134  	Append(*resource.Resource) error
   135  
   136  	// AppendAll appends another ResMap to self,
   137  	// failing on any CurId collision.
   138  	AppendAll(ResMap) error
   139  
   140  	// AbsorbAll appends, replaces or merges the contents
   141  	// of another ResMap into self,
   142  	// allowing and sometimes demanding ID collisions.
   143  	// A collision would be demanded, say, when a generated
   144  	// ConfigMap has the "replace" option in its generation
   145  	// instructions, meaning it _must_ replace
   146  	// something in the known set of resources.
   147  	// If a resource id for resource X is found to already
   148  	// be in self, then the behavior field for X must
   149  	// be BehaviorMerge or BehaviorReplace. If X is not in
   150  	// self, then its behavior _cannot_ be merge or replace.
   151  	AbsorbAll(ResMap) error
   152  
   153  	// AddOriginAnnotation will add the provided origin as
   154  	// an origin annotation to all resources in the ResMap, if
   155  	// the origin is not nil.
   156  	AddOriginAnnotation(origin *resource.Origin) error
   157  
   158  	// RemoveOriginAnnotation will remove the origin annotation
   159  	// from all resources in the ResMap
   160  	RemoveOriginAnnotations() error
   161  
   162  	// AddTransformerAnnotation will add the provided origin as
   163  	// an origin annotation if the resource doesn't have one; a
   164  	// transformer annotation otherwise; to all resources in
   165  	// ResMap
   166  	AddTransformerAnnotation(origin *resource.Origin) error
   167  
   168  	// RemoveTransformerAnnotation will remove the transformer annotation
   169  	// from all resources in the ResMap
   170  	RemoveTransformerAnnotations() error
   171  
   172  	// AnnotateAll annotates all resources in the ResMap with
   173  	// the provided key value pair.
   174  	AnnotateAll(key string, value string) error
   175  
   176  	// AsYaml returns the yaml form of resources.
   177  	AsYaml() ([]byte, error)
   178  
   179  	// GetByIndex returns a resource at the given index,
   180  	// nil if out of range.
   181  	GetByIndex(int) *resource.Resource
   182  
   183  	// GetIndexOfCurrentId returns the index of the resource
   184  	// with the given CurId.
   185  	// Returns error if there is more than one match.
   186  	// Returns (-1, nil) if there is no match.
   187  	GetIndexOfCurrentId(id resid.ResId) (int, error)
   188  
   189  	// GetMatchingResourcesByCurrentId returns the resources
   190  	// who's CurId is matched by the argument.
   191  	GetMatchingResourcesByCurrentId(matches IdMatcher) []*resource.Resource
   192  
   193  	// GetMatchingResourcesByAnyId returns the resources
   194  	// who's current or previous IDs is matched by the argument.
   195  	GetMatchingResourcesByAnyId(matches IdMatcher) []*resource.Resource
   196  
   197  	// GetByCurrentId is shorthand for calling
   198  	// GetMatchingResourcesByCurrentId with a matcher requiring
   199  	// an exact match, returning an error on multiple or no matches.
   200  	GetByCurrentId(resid.ResId) (*resource.Resource, error)
   201  
   202  	// GetById is shorthand for calling
   203  	// GetMatchingResourcesByAnyId with a matcher requiring
   204  	// an exact match, returning an error on multiple or no matches.
   205  	GetById(resid.ResId) (*resource.Resource, error)
   206  
   207  	// GroupedByCurrentNamespace returns a map of namespace
   208  	// to a slice of *Resource in that namespace.
   209  	// Cluster-scoped Resources are not included (see ClusterScoped).
   210  	// Resources with an empty namespace are placed
   211  	// in the resid.DefaultNamespace entry.
   212  	GroupedByCurrentNamespace() map[string][]*resource.Resource
   213  
   214  	// GroupedByOriginalNamespace performs as GroupByNamespace
   215  	// but use the original namespace instead of the current
   216  	// one to perform the grouping.
   217  	GroupedByOriginalNamespace() map[string][]*resource.Resource
   218  
   219  	// ClusterScoped returns a slice of resources that
   220  	// cannot be placed in a namespace, e.g.
   221  	// Node, ClusterRole, Namespace itself, etc.
   222  	ClusterScoped() []*resource.Resource
   223  
   224  	// AllIds returns all CurrentIds.
   225  	AllIds() []resid.ResId
   226  
   227  	// Replace replaces the resource with the matching CurId.
   228  	// Error if there's no match or more than one match.
   229  	// Returns the index where the replacement happened.
   230  	Replace(*resource.Resource) (int, error)
   231  
   232  	// Remove removes the resource whose CurId matches the argument.
   233  	// Error if not found.
   234  	Remove(resid.ResId) error
   235  
   236  	// Clear removes all resources and Ids.
   237  	Clear()
   238  
   239  	// DropEmpties drops empty resources from the ResMap.
   240  	DropEmpties()
   241  
   242  	// SubsetThatCouldBeReferencedByResource returns a ResMap subset
   243  	// of self with resources that could be referenced by the
   244  	// resource argument.
   245  	// This is a filter; it excludes things that cannot be
   246  	// referenced by the resource, e.g. objects in other
   247  	// namespaces. Cluster wide objects are never excluded.
   248  	SubsetThatCouldBeReferencedByResource(*resource.Resource) (ResMap, error)
   249  
   250  	// DeAnchor replaces YAML aliases with structured data copied from anchors.
   251  	// This cannot be undone; if desired, call DeepCopy first.
   252  	// Subsequent marshalling to YAML will no longer have anchor
   253  	// definitions ('&') or aliases ('*').
   254  	//
   255  	// Anchors are not expected to work across YAML 'documents'.
   256  	// If three resources are loaded from one file containing three YAML docs:
   257  	//
   258  	//   {resourceA}
   259  	//   ---
   260  	//   {resourceB}
   261  	//   ---
   262  	//   {resourceC}
   263  	//
   264  	// then anchors defined in A cannot be seen from B and C and vice versa.
   265  	// OTOH, cross-resource links (a field in B referencing fields in A) will
   266  	// work if the resources are gathered in a ResourceList:
   267  	//
   268  	//   apiVersion: config.kubernetes.io/v1
   269  	//   kind: ResourceList
   270  	//   metadata:
   271  	//     name: someList
   272  	//   items:
   273  	//   - {resourceA}
   274  	//   - {resourceB}
   275  	//   - {resourceC}
   276  	//
   277  	DeAnchor() error
   278  
   279  	// DeepCopy copies the ResMap and underlying resources.
   280  	DeepCopy() ResMap
   281  
   282  	// ShallowCopy copies the ResMap but
   283  	// not the underlying resources.
   284  	ShallowCopy() ResMap
   285  
   286  	// ErrorIfNotEqualSets returns an error if the
   287  	// argument doesn't have the same resources as self.
   288  	// Ordering is _not_ taken into account,
   289  	// as this function was solely used in tests written
   290  	// before internal resource order was maintained,
   291  	// and those tests are initialized with maps which
   292  	// by definition have random ordering, and will
   293  	// fail spuriously.
   294  	// TODO: modify tests to not use resmap.FromMap,
   295  	// TODO: - and replace this with a stricter equals.
   296  	ErrorIfNotEqualSets(ResMap) error
   297  
   298  	// ErrorIfNotEqualLists returns an error if the
   299  	// argument doesn't have the resource objects
   300  	// data as self, in the same order.
   301  	// Meta information is ignored; this is similar
   302  	// to comparing the AsYaml() strings, but allows
   303  	// for more informed errors on not equals.
   304  	ErrorIfNotEqualLists(ResMap) error
   305  
   306  	// Debug prints the ResMap.
   307  	Debug(title string)
   308  
   309  	// Select returns a list of resources that
   310  	// are selected by a Selector
   311  	Select(types.Selector) ([]*resource.Resource, error)
   312  
   313  	// ToRNodeSlice returns a copy of the resources as RNodes.
   314  	ToRNodeSlice() []*yaml.RNode
   315  
   316  	// ApplySmPatch applies a strategic-merge patch to the
   317  	// selected set of resources.
   318  	ApplySmPatch(
   319  		selectedSet *resource.IdSet, patch *resource.Resource) error
   320  
   321  	// RemoveBuildAnnotations removes annotations created by the build process.
   322  	RemoveBuildAnnotations()
   323  
   324  	// ApplyFilter applies an RNode filter to all Resources in the ResMap.
   325  	// TODO: Send/recover ancillary Resource data to/from subprocesses.
   326  	// Assure that the ancillary data in Resource (everything not in the RNode)
   327  	// is sent to and re-captured from transformer subprocess (as the process
   328  	// might edit that information).  One way to do this would be to solely use
   329  	// RNode metadata annotation reading and writing instead of using Resource
   330  	// struct data members, i.e. the Resource struct is replaced by RNode
   331  	// and use of (slow) k8s metadata annotations inside the RNode.
   332  	ApplyFilter(f kio.Filter) error
   333  }
   334  

View as plain text