working commit
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
)
|
||||
|
||||
type errMissingKustomization struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func (e *errMissingKustomization) Error() string {
|
||||
return fmt.Sprintf(
|
||||
"unable to find one of %v in directory '%s'",
|
||||
commaOr(quoted(konfig.RecognizedKustomizationFileNames())),
|
||||
e.path)
|
||||
}
|
||||
|
||||
func IsMissingKustomizationFileError(err error) bool {
|
||||
e := &errMissingKustomization{}
|
||||
return errors.As(err, &e)
|
||||
}
|
||||
|
||||
func NewErrMissingKustomization(p string) *errMissingKustomization {
|
||||
return &errMissingKustomization{path: p}
|
||||
}
|
||||
|
||||
func quoted(l []string) []string {
|
||||
r := make([]string, len(l))
|
||||
for i, v := range l {
|
||||
r[i] = "'" + v + "'"
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func commaOr(q []string) string {
|
||||
return strings.Join(q[:len(q)-1], ", ") + " or " + q[len(q)-1]
|
||||
}
|
||||
+593
@@ -0,0 +1,593 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/internal/accumulator"
|
||||
"sigs.k8s.io/kustomize/api/internal/builtins"
|
||||
"sigs.k8s.io/kustomize/api/internal/kusterr"
|
||||
load "sigs.k8s.io/kustomize/api/internal/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// KustTarget encapsulates the entirety of a kustomization build.
|
||||
type KustTarget struct {
|
||||
kustomization *types.Kustomization
|
||||
kustFileName string
|
||||
ldr ifc.Loader
|
||||
validator ifc.Validator
|
||||
rFactory *resmap.Factory
|
||||
pLdr *loader.Loader
|
||||
origin *resource.Origin
|
||||
helmRootNamespace string // namespace inherited from parent kustomization for HelmCharts
|
||||
}
|
||||
|
||||
// NewKustTarget returns a new instance of KustTarget.
|
||||
func NewKustTarget(
|
||||
ldr ifc.Loader,
|
||||
validator ifc.Validator,
|
||||
rFactory *resmap.Factory,
|
||||
pLdr *loader.Loader) *KustTarget {
|
||||
return &KustTarget{
|
||||
ldr: ldr,
|
||||
validator: validator,
|
||||
rFactory: rFactory,
|
||||
pLdr: pLdr.LoaderWithWorkingDir(ldr.Root()),
|
||||
}
|
||||
}
|
||||
|
||||
// Load attempts to load the target's kustomization file.
|
||||
func (kt *KustTarget) Load() error {
|
||||
content, kustFileName, err := LoadKustFile(kt.ldr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var k types.Kustomization
|
||||
if err := k.Unmarshal(content); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// show warning message when using deprecated fields.
|
||||
if warningMessages := k.CheckDeprecatedFields(); warningMessages != nil {
|
||||
for _, msg := range *warningMessages {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", msg)
|
||||
}
|
||||
}
|
||||
|
||||
k.FixKustomization()
|
||||
|
||||
// check that Kustomization is empty
|
||||
if err := k.CheckEmpty(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errs := k.EnforceFields()
|
||||
if len(errs) > 0 {
|
||||
return fmt.Errorf(
|
||||
"Failed to read kustomization file under %s:\n"+
|
||||
strings.Join(errs, "\n"), kt.ldr.Root())
|
||||
}
|
||||
kt.kustomization = &k
|
||||
kt.kustFileName = kustFileName
|
||||
return nil
|
||||
}
|
||||
|
||||
// Kustomization returns a copy of the immutable, internal kustomization object.
|
||||
func (kt *KustTarget) Kustomization() types.Kustomization {
|
||||
var result types.Kustomization
|
||||
b, _ := json.Marshal(*kt.kustomization)
|
||||
json.Unmarshal(b, &result)
|
||||
return result
|
||||
}
|
||||
|
||||
func LoadKustFile(ldr ifc.Loader) ([]byte, string, error) {
|
||||
var content []byte
|
||||
match := 0
|
||||
var kustFileName string
|
||||
for _, kf := range konfig.RecognizedKustomizationFileNames() {
|
||||
c, err := ldr.Load(kf)
|
||||
if err == nil {
|
||||
match += 1
|
||||
content = c
|
||||
kustFileName = kf
|
||||
}
|
||||
}
|
||||
switch match {
|
||||
case 0:
|
||||
return nil, "", NewErrMissingKustomization(ldr.Root())
|
||||
case 1:
|
||||
return content, kustFileName, nil
|
||||
default:
|
||||
return nil, "", fmt.Errorf(
|
||||
"Found multiple kustomization files under: %s\n", ldr.Root())
|
||||
}
|
||||
}
|
||||
|
||||
// MakeCustomizedResMap creates a fully customized ResMap
|
||||
// per the instructions contained in its kustomization instance.
|
||||
func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
|
||||
return kt.makeCustomizedResMap()
|
||||
}
|
||||
|
||||
func (kt *KustTarget) makeCustomizedResMap() (resmap.ResMap, error) {
|
||||
var origin *resource.Origin
|
||||
if len(kt.kustomization.BuildMetadata) != 0 {
|
||||
origin = &resource.Origin{}
|
||||
}
|
||||
kt.origin = origin
|
||||
ra, err := kt.AccumulateTarget()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The following steps must be done last, not as part of
|
||||
// the recursion implicit in AccumulateTarget.
|
||||
|
||||
err = kt.addHashesToNames(ra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Given that names have changed (prefixs/suffixes added),
|
||||
// fix all the back references to those names.
|
||||
err = ra.FixBackReferences()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// With all the back references fixed, it's OK to resolve Vars.
|
||||
err = ra.ResolveVars()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = kt.IgnoreLocal(ra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ra.ResMap(), nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) addHashesToNames(
|
||||
ra *accumulator.ResAccumulator) error {
|
||||
p := builtins.NewHashTransformerPlugin()
|
||||
err := kt.configureBuiltinPlugin(p, nil, builtinhelpers.HashTransformer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ra.Transform(p)
|
||||
}
|
||||
|
||||
// AccumulateTarget returns a new ResAccumulator,
|
||||
// holding customized resources and the data/rules used
|
||||
// to do so. The name back references and vars are
|
||||
// not yet fixed.
|
||||
// The origin parameter is used through the recursive calls
|
||||
// to annotate each resource with information about where
|
||||
// the resource came from, e.g. the file and/or the repository
|
||||
// it originated from.
|
||||
// As an entrypoint, one can pass an empty resource.Origin object to
|
||||
// AccumulateTarget. As AccumulateTarget moves recursively
|
||||
// through kustomization directories, it updates `origin.path`
|
||||
// accordingly. When a remote base is found, it updates `origin.repo`
|
||||
// and `origin.ref` accordingly.
|
||||
func (kt *KustTarget) AccumulateTarget() (
|
||||
ra *accumulator.ResAccumulator, err error) {
|
||||
return kt.accumulateTarget(accumulator.MakeEmptyAccumulator())
|
||||
}
|
||||
|
||||
// ra should be empty when this KustTarget is a Kustomization, or the ra of the parent if this KustTarget is a Component
|
||||
// (or empty if the Component does not have a parent).
|
||||
func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
|
||||
resRa *accumulator.ResAccumulator, err error) {
|
||||
ra, err = kt.accumulateResources(ra, kt.kustomization.Resources)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "accumulating resources")
|
||||
}
|
||||
tConfig, err := builtinconfig.MakeTransformerConfig(
|
||||
kt.ldr, kt.kustomization.Configurations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ra.MergeConfig(tConfig)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "merging config %v", tConfig)
|
||||
}
|
||||
crdTc, err := accumulator.LoadConfigFromCRDs(kt.ldr, kt.kustomization.Crds)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "loading CRDs %v", kt.kustomization.Crds)
|
||||
}
|
||||
err = ra.MergeConfig(crdTc)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "merging CRDs %v", crdTc)
|
||||
}
|
||||
err = kt.runGenerators(ra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// components are expected to execute after reading resources and adding generators ,before applying transformers and validation.
|
||||
// https://github.com/kubernetes-sigs/kustomize/pull/5170#discussion_r1212101287
|
||||
ra, err = kt.accumulateComponents(ra, kt.kustomization.Components)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "accumulating components")
|
||||
}
|
||||
|
||||
err = kt.runTransformers(ra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = kt.runValidators(ra)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ra.MergeVars(kt.kustomization.Vars)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "merging vars %v", kt.kustomization.Vars)
|
||||
}
|
||||
return ra, nil
|
||||
}
|
||||
|
||||
// IgnoreLocal drops the local resource by checking the annotation "config.kubernetes.io/local-config".
|
||||
func (kt *KustTarget) IgnoreLocal(ra *accumulator.ResAccumulator) error {
|
||||
rf := kt.rFactory.RF()
|
||||
if rf.IncludeLocalConfigs {
|
||||
return nil
|
||||
}
|
||||
remainRes, err := rf.DropLocalNodes(ra.ResMap().ToRNodeSlice())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ra.Intersection(kt.rFactory.FromResourceSlice(remainRes))
|
||||
}
|
||||
|
||||
func (kt *KustTarget) runGenerators(
|
||||
ra *accumulator.ResAccumulator) error {
|
||||
var generators []*resmap.GeneratorWithProperties
|
||||
gs, err := kt.configureBuiltinGenerators()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
generators = append(generators, gs...)
|
||||
|
||||
gs, err = kt.configureExternalGenerators()
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "loading generator plugins")
|
||||
}
|
||||
generators = append(generators, gs...)
|
||||
for i, g := range generators {
|
||||
resMap, err := g.Generate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resMap != nil {
|
||||
err = resMap.AddOriginAnnotation(generators[i].Origin)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "adding origin annotations for generator %v", g)
|
||||
}
|
||||
}
|
||||
err = ra.AbsorbAll(resMap)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "merging from generator %v", g)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureExternalGenerators() (
|
||||
[]*resmap.GeneratorWithProperties, error) {
|
||||
ra := accumulator.MakeEmptyAccumulator()
|
||||
var generatorPaths []string
|
||||
for _, p := range kt.kustomization.Generators {
|
||||
// handle inline generators
|
||||
rm, err := kt.rFactory.NewResMapFromBytes([]byte(p))
|
||||
if err != nil {
|
||||
// not an inline config
|
||||
generatorPaths = append(generatorPaths, p)
|
||||
continue
|
||||
}
|
||||
// inline config, track the origin
|
||||
if kt.origin != nil {
|
||||
resources := rm.Resources()
|
||||
for _, r := range resources {
|
||||
r.SetOrigin(kt.origin.Append(kt.kustFileName))
|
||||
rm.Replace(r)
|
||||
}
|
||||
}
|
||||
if err = ra.AppendAll(rm); err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "configuring external generator")
|
||||
}
|
||||
}
|
||||
ra, err := kt.accumulateResources(ra, generatorPaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kt.pLdr.LoadGenerators(kt.ldr, kt.validator, ra.ResMap())
|
||||
}
|
||||
|
||||
func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
|
||||
var r []*resmap.TransformerWithProperties
|
||||
tConfig := ra.GetTransformerConfig()
|
||||
lts, err := kt.configureBuiltinTransformers(tConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = append(r, lts...)
|
||||
lts, err = kt.configureExternalTransformers(kt.kustomization.Transformers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r = append(r, lts...)
|
||||
return ra.Transform(newMultiTransformer(r))
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]*resmap.TransformerWithProperties, error) {
|
||||
ra := accumulator.MakeEmptyAccumulator()
|
||||
var transformerPaths []string
|
||||
for _, p := range transformers {
|
||||
// handle inline transformers
|
||||
rm, err := kt.rFactory.NewResMapFromBytes([]byte(p))
|
||||
if err != nil {
|
||||
// not an inline config
|
||||
transformerPaths = append(transformerPaths, p)
|
||||
continue
|
||||
}
|
||||
// inline config, track the origin
|
||||
if kt.origin != nil {
|
||||
resources := rm.Resources()
|
||||
for _, r := range resources {
|
||||
r.SetOrigin(kt.origin.Append(kt.kustFileName))
|
||||
rm.Replace(r)
|
||||
}
|
||||
}
|
||||
|
||||
if err = ra.AppendAll(rm); err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "configuring external transformer")
|
||||
}
|
||||
}
|
||||
ra, err := kt.accumulateResources(ra, transformerPaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kt.pLdr.LoadTransformers(kt.ldr, kt.validator, ra.ResMap())
|
||||
}
|
||||
|
||||
func (kt *KustTarget) runValidators(ra *accumulator.ResAccumulator) error {
|
||||
validators, err := kt.configureExternalTransformers(kt.kustomization.Validators)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range validators {
|
||||
// Validators shouldn't modify the resource map
|
||||
orignal := ra.ResMap().DeepCopy()
|
||||
err = v.Transform(ra.ResMap())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMap := ra.ResMap().DeepCopy()
|
||||
if err = kt.removeValidatedByLabel(newMap); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = orignal.ErrorIfNotEqualSets(newMap); err != nil {
|
||||
return fmt.Errorf("validator shouldn't modify the resource map: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) error {
|
||||
resources := rm.Resources()
|
||||
for _, r := range resources {
|
||||
labels := r.GetLabels()
|
||||
if _, found := labels[konfig.ValidatedByLabelKey]; !found {
|
||||
continue
|
||||
}
|
||||
delete(labels, konfig.ValidatedByLabelKey)
|
||||
if err := r.SetLabels(labels); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// accumulateResources fills the given resourceAccumulator
|
||||
// with resources read from the given list of paths.
|
||||
func (kt *KustTarget) accumulateResources(
|
||||
ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) {
|
||||
for _, path := range paths {
|
||||
// try loading resource as file then as base (directory or git repository)
|
||||
if errF := kt.accumulateFile(ra, path); errF != nil {
|
||||
// not much we can do if the error is an HTTP error so we bail out
|
||||
if errors.Is(errF, load.ErrHTTP) {
|
||||
return nil, errF
|
||||
}
|
||||
ldr, err := kt.ldr.New(path)
|
||||
if err != nil {
|
||||
// If accumulateFile found malformed YAML and there was a failure
|
||||
// loading the resource as a base, then the resource is likely a
|
||||
// file. The loader failure message is unnecessary, and could be
|
||||
// confusing. Report only the file load error.
|
||||
//
|
||||
// However, a loader timeout implies there is a git repo at the
|
||||
// path. In that case, both errors could be important.
|
||||
if kusterr.IsMalformedYAMLError(errF) && !utils.IsErrTimeout(err) {
|
||||
return nil, errF
|
||||
}
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "accumulation err='%s'", errF.Error())
|
||||
}
|
||||
// store the origin, we'll need it later
|
||||
origin := kt.origin.Copy()
|
||||
if kt.origin != nil {
|
||||
kt.origin = kt.origin.Append(path)
|
||||
ra, err = kt.accumulateDirectory(ra, ldr, false)
|
||||
// after we are done recursing through the directory, reset the origin
|
||||
kt.origin = &origin
|
||||
} else {
|
||||
ra, err = kt.accumulateDirectory(ra, ldr, false)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "accumulation err='%s'", errF.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
return ra, nil
|
||||
}
|
||||
|
||||
// accumulateComponents fills the given resourceAccumulator
|
||||
// with resources read from the given list of paths.
|
||||
func (kt *KustTarget) accumulateComponents(
|
||||
ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) {
|
||||
for _, path := range paths {
|
||||
// Components always refer to directories
|
||||
ldr, errL := kt.ldr.New(path)
|
||||
if errL != nil {
|
||||
return nil, fmt.Errorf("loader.New %q", errL)
|
||||
}
|
||||
var errD error
|
||||
// store the origin, we'll need it later
|
||||
origin := kt.origin.Copy()
|
||||
if kt.origin != nil {
|
||||
kt.origin = kt.origin.Append(path)
|
||||
ra, errD = kt.accumulateDirectory(ra, ldr, true)
|
||||
// after we are done recursing through the directory, reset the origin
|
||||
kt.origin = &origin
|
||||
} else {
|
||||
ra, errD = kt.accumulateDirectory(ra, ldr, true)
|
||||
}
|
||||
if errD != nil {
|
||||
return nil, fmt.Errorf("accumulateDirectory: %q", errD)
|
||||
}
|
||||
}
|
||||
return ra, nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) accumulateDirectory(
|
||||
ra *accumulator.ResAccumulator, ldr ifc.Loader, isComponent bool) (*accumulator.ResAccumulator, error) {
|
||||
defer ldr.Cleanup()
|
||||
subKt := NewKustTarget(ldr, kt.validator, kt.rFactory, kt.pLdr)
|
||||
err := subKt.Load()
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "couldn't make target for path '%s'", ldr.Root())
|
||||
}
|
||||
subKt.kustomization.BuildMetadata = kt.kustomization.BuildMetadata
|
||||
subKt.origin = kt.origin
|
||||
// Propagate namespace to child kustomization's helmRootNamespace for HelmCharts
|
||||
// This ensures Helm charts in base kustomizations inherit namespace from overlays
|
||||
// without affecting other transformers like patches
|
||||
// Fixes https://github.com/kubernetes-sigs/kustomize/issues/6031
|
||||
// Fixes https://github.com/kubernetes-sigs/kustomize/issues/6027
|
||||
if kt.kustomization.Namespace != "" {
|
||||
subKt.helmRootNamespace = kt.kustomization.Namespace
|
||||
} else if kt.helmRootNamespace != "" {
|
||||
subKt.helmRootNamespace = kt.helmRootNamespace
|
||||
}
|
||||
var bytes []byte
|
||||
if openApiPath, exists := subKt.Kustomization().OpenAPI["path"]; exists {
|
||||
bytes, err = ldr.Load(openApiPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
err = openapi.SetSchema(subKt.Kustomization().OpenAPI, bytes, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if isComponent && subKt.kustomization.Kind != types.ComponentKind {
|
||||
return nil, fmt.Errorf(
|
||||
"expected kind '%s' for path '%s' but got '%s'", types.ComponentKind, ldr.Root(), subKt.kustomization.Kind)
|
||||
} else if !isComponent && subKt.kustomization.Kind == types.ComponentKind {
|
||||
return nil, fmt.Errorf(
|
||||
"expected kind != '%s' for path '%s'", types.ComponentKind, ldr.Root())
|
||||
}
|
||||
|
||||
var subRa *accumulator.ResAccumulator
|
||||
if isComponent {
|
||||
// Components don't create a new accumulator: the kustomization directives are added to the current accumulator
|
||||
subRa, err = subKt.accumulateTarget(ra)
|
||||
ra = accumulator.MakeEmptyAccumulator()
|
||||
} else {
|
||||
// Child Kustomizations create a new accumulator which resolves their kustomization directives, which will later
|
||||
// be merged into the current accumulator.
|
||||
subRa, err = subKt.AccumulateTarget()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "recursed accumulation of path '%s'", ldr.Root())
|
||||
}
|
||||
err = ra.MergeAccumulator(subRa)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(
|
||||
err, "recursed merging from path '%s'", ldr.Root())
|
||||
}
|
||||
return ra, nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) accumulateFile(
|
||||
ra *accumulator.ResAccumulator, path string) error {
|
||||
resources, err := kt.rFactory.FromFile(kt.ldr, path)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "accumulating resources from '%s'", path)
|
||||
}
|
||||
if kt.origin != nil {
|
||||
originAnno, err := kt.origin.Append(path).String()
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "cannot add path annotation for '%s'", path)
|
||||
}
|
||||
err = resources.AnnotateAll(utils.OriginAnnotationKey, originAnno)
|
||||
if err != nil || originAnno == "" {
|
||||
return errors.WrapPrefixf(err, "cannot add path annotation for '%s'", path)
|
||||
}
|
||||
}
|
||||
err = ra.AppendAll(resources)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(err, "merging resources from '%s'", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinPlugin(
|
||||
p resmap.Configurable, c interface{}, bpt builtinhelpers.BuiltinPluginType) (err error) {
|
||||
var y []byte
|
||||
if c != nil {
|
||||
y, err = yaml.Marshal(c)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(
|
||||
err, "builtin %s marshal", bpt)
|
||||
}
|
||||
}
|
||||
err = p.Config(
|
||||
resmap.NewPluginHelpers(
|
||||
kt.ldr, kt.validator, kt.rFactory, kt.pLdr.Config()),
|
||||
y)
|
||||
if err != nil {
|
||||
return errors.WrapPrefixf(
|
||||
err, "trouble configuring builtin %s with config: `\n%s`", bpt, string(y))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+467
@@ -0,0 +1,467 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
"sigs.k8s.io/kustomize/api/resource"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
// Functions dedicated to configuring the builtin
|
||||
// transformer and generator plugins using config data
|
||||
// read from a kustomization file and from the
|
||||
// config.TransformerConfig, whose data may be a
|
||||
// mix of hardcoded values and data read from file.
|
||||
//
|
||||
// Non-builtin plugins will get their configuration
|
||||
// from their own dedicated structs and YAML files.
|
||||
//
|
||||
// There are some loops in the functions below because
|
||||
// the kustomization file would, say, allow someone to
|
||||
// request multiple secrets be made, or run multiple
|
||||
// image tag transforms. In these cases, we'll need
|
||||
// N plugin instances with differing configurations.
|
||||
|
||||
func (kt *KustTarget) configureBuiltinGenerators() (
|
||||
result []*resmap.GeneratorWithProperties, err error) {
|
||||
for _, bpt := range []builtinhelpers.BuiltinPluginType{
|
||||
builtinhelpers.ConfigMapGenerator,
|
||||
builtinhelpers.SecretGenerator,
|
||||
builtinhelpers.HelmChartInflationGenerator,
|
||||
} {
|
||||
r, err := generatorConfigurators[bpt](
|
||||
kt, bpt, builtinhelpers.GeneratorFactories[bpt])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var generatorOrigin *resource.Origin
|
||||
if kt.origin != nil {
|
||||
generatorOrigin = &resource.Origin{
|
||||
Repo: kt.origin.Repo,
|
||||
Ref: kt.origin.Ref,
|
||||
ConfiguredIn: filepath.Join(kt.origin.Path, kt.kustFileName),
|
||||
ConfiguredBy: yaml.ResourceIdentifier{
|
||||
TypeMeta: yaml.TypeMeta{
|
||||
APIVersion: "builtin",
|
||||
Kind: bpt.String(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
for i := range r {
|
||||
result = append(result, &resmap.GeneratorWithProperties{Generator: r[i], Origin: generatorOrigin})
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (kt *KustTarget) configureBuiltinTransformers(
|
||||
tc *builtinconfig.TransformerConfig) (
|
||||
result []*resmap.TransformerWithProperties, err error) {
|
||||
for _, bpt := range []builtinhelpers.BuiltinPluginType{
|
||||
builtinhelpers.PatchStrategicMergeTransformer,
|
||||
builtinhelpers.PatchTransformer,
|
||||
builtinhelpers.NamespaceTransformer,
|
||||
builtinhelpers.PrefixTransformer,
|
||||
builtinhelpers.SuffixTransformer,
|
||||
builtinhelpers.LabelTransformer,
|
||||
builtinhelpers.AnnotationsTransformer,
|
||||
builtinhelpers.PatchJson6902Transformer,
|
||||
builtinhelpers.ReplicaCountTransformer,
|
||||
builtinhelpers.ImageTagTransformer,
|
||||
builtinhelpers.ReplacementTransformer,
|
||||
} {
|
||||
r, err := transformerConfigurators[bpt](
|
||||
kt, bpt, builtinhelpers.TransformerFactories[bpt], tc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var transformerOrigin *resource.Origin
|
||||
if kt.origin != nil {
|
||||
transformerOrigin = &resource.Origin{
|
||||
Repo: kt.origin.Repo,
|
||||
Ref: kt.origin.Ref,
|
||||
ConfiguredIn: filepath.Join(kt.origin.Path, kt.kustFileName),
|
||||
ConfiguredBy: yaml.ResourceIdentifier{
|
||||
TypeMeta: yaml.TypeMeta{
|
||||
APIVersion: "builtin",
|
||||
Kind: bpt.String(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
for i := range r {
|
||||
result = append(result, &resmap.TransformerWithProperties{Transformer: r[i], Origin: transformerOrigin})
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type gFactory func() resmap.GeneratorPlugin
|
||||
|
||||
var generatorConfigurators = map[builtinhelpers.BuiltinPluginType]func(
|
||||
kt *KustTarget,
|
||||
bpt builtinhelpers.BuiltinPluginType,
|
||||
factory gFactory) (result []resmap.Generator, err error){
|
||||
builtinhelpers.SecretGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.Generator, err error) {
|
||||
var c struct {
|
||||
types.SecretArgs
|
||||
}
|
||||
for _, args := range kt.kustomization.SecretGenerator {
|
||||
c.SecretArgs = args
|
||||
c.SecretArgs.Options = types.MergeGlobalOptionsIntoLocal(
|
||||
c.SecretArgs.Options, kt.kustomization.GeneratorOptions)
|
||||
p := f()
|
||||
err := kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
|
||||
builtinhelpers.ConfigMapGenerator: func(kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.Generator, err error) {
|
||||
var c struct {
|
||||
types.ConfigMapArgs
|
||||
}
|
||||
for _, args := range kt.kustomization.ConfigMapGenerator {
|
||||
c.ConfigMapArgs = args
|
||||
c.ConfigMapArgs.Options = types.MergeGlobalOptionsIntoLocal(
|
||||
c.ConfigMapArgs.Options, kt.kustomization.GeneratorOptions)
|
||||
p := f()
|
||||
err := kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
|
||||
builtinhelpers.HelmChartInflationGenerator: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f gFactory) (
|
||||
result []resmap.Generator, err error) {
|
||||
var c struct {
|
||||
types.HelmGlobals
|
||||
types.HelmChart
|
||||
}
|
||||
var globals types.HelmGlobals
|
||||
if kt.kustomization.HelmGlobals != nil {
|
||||
globals = *kt.kustomization.HelmGlobals
|
||||
}
|
||||
for _, chart := range kt.kustomization.HelmCharts {
|
||||
c.HelmGlobals = globals
|
||||
c.HelmChart = chart
|
||||
// Pass kustomize namespace to helm
|
||||
// Fixes https://github.com/kubernetes-sigs/kustomize/issues/5566
|
||||
// Also propagate parent namespace for multi-level kustomization hierarchies
|
||||
if c.HelmChart.Namespace == "" {
|
||||
if kt.kustomization.Namespace != "" {
|
||||
c.HelmChart.Namespace = kt.kustomization.Namespace
|
||||
} else if kt.helmRootNamespace != "" {
|
||||
c.HelmChart.Namespace = kt.helmRootNamespace
|
||||
}
|
||||
}
|
||||
p := f()
|
||||
if err = kt.configureBuiltinPlugin(p, c, bpt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
}
|
||||
|
||||
type tFactory func() resmap.TransformerPlugin
|
||||
|
||||
var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
|
||||
kt *KustTarget,
|
||||
bpt builtinhelpers.BuiltinPluginType,
|
||||
f tFactory,
|
||||
tc *builtinconfig.TransformerConfig) (result []resmap.Transformer, err error){
|
||||
builtinhelpers.NamespaceTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if kt.kustomization.Namespace == "" {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
types.ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
c.Namespace = kt.kustomization.Namespace
|
||||
c.FieldSpecs = tc.NameSpace
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
|
||||
builtinhelpers.PatchJson6902Transformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
JsonOp string `json:"jsonOp,omitempty" yaml:"jsonOp,omitempty"`
|
||||
}
|
||||
for _, args := range kt.kustomization.PatchesJson6902 {
|
||||
c.Target = args.Target
|
||||
c.Path = args.Path
|
||||
c.JsonOp = args.Patch
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
builtinhelpers.PatchStrategicMergeTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.PatchesStrategicMerge) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Paths []types.PatchStrategicMerge `json:"paths,omitempty" yaml:"paths,omitempty"`
|
||||
}
|
||||
c.Paths = kt.kustomization.PatchesStrategicMerge
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.PatchTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.Patches) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||
Options *types.PatchArgs `json:"options,omitempty" yaml:"options,omitempty"`
|
||||
}
|
||||
for _, pc := range kt.kustomization.Patches {
|
||||
c.Target = pc.Target
|
||||
c.Patch = pc.Patch
|
||||
c.Path = pc.Path
|
||||
c.Options = pc.Options
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
builtinhelpers.LabelTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.Labels) == 0 && len(kt.kustomization.CommonLabels) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
type labelStruct struct {
|
||||
Labels map[string]string
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
|
||||
for _, label := range kt.kustomization.Labels {
|
||||
var c labelStruct
|
||||
|
||||
c.Labels = label.Pairs
|
||||
fss := types.FsSlice(label.FieldSpecs)
|
||||
|
||||
// merge labels specified in the label section of transformer configs
|
||||
// these apply to selectors and templates
|
||||
fss, err := fss.MergeAll(tc.Labels)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to merge labels: %w", err)
|
||||
}
|
||||
|
||||
// merge the custom fieldSpecs with the default
|
||||
if label.IncludeSelectors {
|
||||
fss, err = fss.MergeAll(tc.CommonLabels)
|
||||
} else {
|
||||
// merge spec/template/metadata fieldSpecs if includeTemplate flag is true
|
||||
if label.IncludeTemplates {
|
||||
fss, err = fss.MergeAll(tc.TemplateLabels)
|
||||
if err != nil {
|
||||
return nil, errors.WrapPrefixf(err, "failed to merge template fieldSpec")
|
||||
}
|
||||
}
|
||||
// only add to metadata by default
|
||||
fss, err = fss.MergeOne(types.FieldSpec{Path: "metadata/labels", CreateIfNotPresent: true})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to merge labels: %w", err)
|
||||
}
|
||||
c.FieldSpecs = fss
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
|
||||
var c labelStruct
|
||||
|
||||
c.Labels = kt.kustomization.CommonLabels
|
||||
c.FieldSpecs = tc.CommonLabels
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.AnnotationsTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.CommonAnnotations) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Annotations map[string]string
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
c.Annotations = kt.kustomization.CommonAnnotations
|
||||
c.FieldSpecs = tc.CommonAnnotations
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.PrefixTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if kt.kustomization.NamePrefix == "" {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Prefix string `json:"prefix,omitempty" yaml:"prefix,omitempty"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
c.Prefix = kt.kustomization.NamePrefix
|
||||
c.FieldSpecs = tc.NamePrefix
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.SuffixTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if kt.kustomization.NameSuffix == "" {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Suffix string `json:"suffix,omitempty" yaml:"suffix,omitempty"`
|
||||
FieldSpecs []types.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||
}
|
||||
c.Suffix = kt.kustomization.NameSuffix
|
||||
c.FieldSpecs = tc.NameSuffix
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return
|
||||
},
|
||||
builtinhelpers.ImageTagTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
ImageTag types.Image
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Images {
|
||||
c.ImageTag = args
|
||||
c.FieldSpecs = tc.Images
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
builtinhelpers.ReplacementTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, _ *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
if len(kt.kustomization.Replacements) == 0 {
|
||||
return
|
||||
}
|
||||
var c struct {
|
||||
Replacements []types.ReplacementField
|
||||
}
|
||||
c.Replacements = kt.kustomization.Replacements
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
return result, nil
|
||||
},
|
||||
builtinhelpers.ReplicaCountTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
var c struct {
|
||||
Replica types.Replica
|
||||
FieldSpecs []types.FieldSpec
|
||||
}
|
||||
for _, args := range kt.kustomization.Replicas {
|
||||
c.Replica = args
|
||||
c.FieldSpecs = tc.Replicas
|
||||
p := f()
|
||||
err = kt.configureBuiltinPlugin(p, c, bpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, p)
|
||||
}
|
||||
return
|
||||
},
|
||||
// No kustomization file keyword for this yet.
|
||||
builtinhelpers.ValueAddTransformer: func(
|
||||
kt *KustTarget, bpt builtinhelpers.BuiltinPluginType, f tFactory, tc *builtinconfig.TransformerConfig) (
|
||||
result []resmap.Transformer, err error) {
|
||||
return nil, fmt.Errorf("valueadd keyword not yet defined")
|
||||
},
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package target
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/kustomize/api/resmap"
|
||||
)
|
||||
|
||||
// multiTransformer contains a list of transformers.
|
||||
type multiTransformer struct {
|
||||
transformers []*resmap.TransformerWithProperties
|
||||
}
|
||||
|
||||
var _ resmap.Transformer = &multiTransformer{}
|
||||
|
||||
// newMultiTransformer constructs a multiTransformer.
|
||||
func newMultiTransformer(t []*resmap.TransformerWithProperties) resmap.Transformer {
|
||||
r := &multiTransformer{
|
||||
transformers: make([]*resmap.TransformerWithProperties, len(t)),
|
||||
}
|
||||
copy(r.transformers, t)
|
||||
return r
|
||||
}
|
||||
|
||||
// Transform applies the member transformers in order to the resources,
|
||||
// optionally detecting and erroring on commutation conflict.
|
||||
func (o *multiTransformer) Transform(m resmap.ResMap) error {
|
||||
for _, t := range o.transformers {
|
||||
if err := t.Transform(m); err != nil {
|
||||
return err
|
||||
}
|
||||
if t.Origin != nil {
|
||||
if err := m.AddTransformerAnnotation(t.Origin); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
m.DropEmpties()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user