mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-10 16:42:51 +00:00
Resources annotated as "local-config" are expected to be ignored. This skip local resource happens in "accumulateResources" which happens before any transformation operations. However, the local resource may be needed in transformations. Thus, this change removes the "drop local resource" logic from accumulateResources and removes these local resource after all transformation operations and var operations are done. Note: None of the existing ResMap functions can drop the resource slice easily: "Clear" will ruin the resource order, "AppendAll" only adds non-existing resource, "AbsorbAll" only add or modify but not delete. Thus, we introduce a new func "Intersection" for resourceAccumulator that specificaly removes the resource by ID and keep the original order.
191 lines
5.2 KiB
Go
191 lines
5.2 KiB
Go
// Copyright 2019 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package accumulator
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
|
|
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
|
"sigs.k8s.io/kustomize/api/resmap"
|
|
"sigs.k8s.io/kustomize/api/types"
|
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
|
)
|
|
|
|
// ResAccumulator accumulates resources and the rules
|
|
// used to customize those resources. It's a ResMap
|
|
// plus stuff needed to modify the ResMap.
|
|
type ResAccumulator struct {
|
|
resMap resmap.ResMap
|
|
tConfig *builtinconfig.TransformerConfig
|
|
varSet types.VarSet
|
|
}
|
|
|
|
func MakeEmptyAccumulator() *ResAccumulator {
|
|
ra := &ResAccumulator{}
|
|
ra.resMap = resmap.New()
|
|
ra.tConfig = &builtinconfig.TransformerConfig{}
|
|
ra.varSet = types.NewVarSet()
|
|
return ra
|
|
}
|
|
|
|
// ResMap returns a copy of the internal resMap.
|
|
func (ra *ResAccumulator) ResMap() resmap.ResMap {
|
|
return ra.resMap.ShallowCopy()
|
|
}
|
|
|
|
// Vars returns a copy of underlying vars.
|
|
func (ra *ResAccumulator) Vars() []types.Var {
|
|
return ra.varSet.AsSlice()
|
|
}
|
|
|
|
func (ra *ResAccumulator) AppendAll(resources resmap.ResMap) error {
|
|
return ra.resMap.AppendAll(resources)
|
|
}
|
|
|
|
func (ra *ResAccumulator) AbsorbAll(resources resmap.ResMap) error {
|
|
return ra.resMap.AbsorbAll(resources)
|
|
}
|
|
|
|
func (ra *ResAccumulator) MergeConfig(
|
|
tConfig *builtinconfig.TransformerConfig) (err error) {
|
|
ra.tConfig, err = ra.tConfig.Merge(tConfig)
|
|
return err
|
|
}
|
|
|
|
func (ra *ResAccumulator) GetTransformerConfig() *builtinconfig.TransformerConfig {
|
|
return ra.tConfig
|
|
}
|
|
|
|
// MergeVars accumulates vars into ResAccumulator.
|
|
// A Var is a tuple of name, object reference and field reference.
|
|
// This func takes a list of vars from the current kustomization file and
|
|
// annotates the accumulated resources with the names of the vars that match
|
|
// those resources. E.g. if there's a var named "sam" that wants to get
|
|
// its data from a ConfigMap named "james", and the resource list contains a
|
|
// ConfigMap named "james", then that ConfigMap will be annotated with the
|
|
// var name "sam". Later this annotation is used to find the data for "sam"
|
|
// by digging into a particular fieldpath of "james".
|
|
func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
|
for _, v := range incoming {
|
|
targetId := resid.NewResIdWithNamespace(v.ObjRef.GVK(), v.ObjRef.Name, v.ObjRef.Namespace)
|
|
idMatcher := targetId.GvknEquals
|
|
if targetId.Namespace != "" || targetId.IsClusterScoped() {
|
|
// Preserve backward compatibility. An empty namespace means
|
|
// wildcard search on the namespace hence we still use GvknEquals
|
|
idMatcher = targetId.Equals
|
|
}
|
|
matched := ra.resMap.GetMatchingResourcesByAnyId(idMatcher)
|
|
if len(matched) > 1 {
|
|
return fmt.Errorf(
|
|
"found %d resId matches for var %s "+
|
|
"(unable to disambiguate)",
|
|
len(matched), v)
|
|
}
|
|
if len(matched) == 1 {
|
|
matched[0].AppendRefVarName(v)
|
|
}
|
|
}
|
|
return ra.varSet.MergeSlice(incoming)
|
|
}
|
|
|
|
func (ra *ResAccumulator) MergeAccumulator(other *ResAccumulator) (err error) {
|
|
err = ra.AppendAll(other.resMap)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = ra.MergeConfig(other.tConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return ra.varSet.MergeSet(other.varSet)
|
|
}
|
|
|
|
func (ra *ResAccumulator) findVarValueFromResources(v types.Var) (interface{}, error) {
|
|
for _, res := range ra.resMap.Resources() {
|
|
for _, varName := range res.GetRefVarNames() {
|
|
if varName == v.Name {
|
|
//nolint: staticcheck
|
|
s, err := res.GetFieldValue(v.FieldRef.FieldPath)
|
|
if err != nil {
|
|
return "", fmt.Errorf(
|
|
"field specified in var '%v' "+
|
|
"not found in corresponding resource", v)
|
|
}
|
|
return s, nil
|
|
}
|
|
}
|
|
}
|
|
return "", fmt.Errorf(
|
|
"var '%v' cannot be mapped to a field "+
|
|
"in the set of known resources", v)
|
|
}
|
|
|
|
// makeVarReplacementMap returns a map of Var names to
|
|
// their final values. The values are strings intended
|
|
// for substitution wherever the $(var.Name) occurs.
|
|
func (ra *ResAccumulator) makeVarReplacementMap() (map[string]interface{}, error) {
|
|
result := map[string]interface{}{}
|
|
for _, v := range ra.Vars() {
|
|
s, err := ra.findVarValueFromResources(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result[v.Name] = s
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (ra *ResAccumulator) Transform(t resmap.Transformer) error {
|
|
return t.Transform(ra.resMap)
|
|
}
|
|
|
|
func (ra *ResAccumulator) ResolveVars() error {
|
|
replacementMap, err := ra.makeVarReplacementMap()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(replacementMap) == 0 {
|
|
return nil
|
|
}
|
|
t := newRefVarTransformer(
|
|
replacementMap, ra.tConfig.VarReference)
|
|
err = ra.Transform(t)
|
|
if len(t.UnusedVars()) > 0 {
|
|
log.Printf(
|
|
"well-defined vars that were never replaced: %s\n",
|
|
strings.Join(t.UnusedVars(), ","))
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (ra *ResAccumulator) FixBackReferences() (err error) {
|
|
if ra.tConfig.NameReference == nil {
|
|
return nil
|
|
}
|
|
return ra.Transform(
|
|
newNameReferenceTransformer(ra.tConfig.NameReference))
|
|
}
|
|
|
|
// Intersection drops the resources which "other" does not have.
|
|
func (ra *ResAccumulator) Intersection(other resmap.ResMap) error {
|
|
for _, curId := range ra.resMap.AllIds() {
|
|
toDelete := true
|
|
for _, otherId := range other.AllIds() {
|
|
if otherId == curId {
|
|
toDelete = false
|
|
break
|
|
}
|
|
}
|
|
if toDelete {
|
|
err := ra.resMap.Remove(curId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|