mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 09:24:23 +00:00
Introduce ResAccumulator.
This commit is contained in:
@@ -211,6 +211,9 @@ spec:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
|
// TODO(#669): The name of the patched Deployment is
|
||||||
|
// test-infra-baseprefix-mungebot, retaining the base
|
||||||
|
// prefix (example of correct behavior).
|
||||||
th.assertActualEqualsExpected(m, `
|
th.assertActualEqualsExpected(m, `
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
|
|||||||
@@ -136,6 +136,9 @@ spec:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
|
// TODO(#669): The name of the patched Deployment is
|
||||||
|
// b-a-myDeployment, retaining the base prefix
|
||||||
|
// (example of correct behavior).
|
||||||
th.assertActualEqualsExpected(m, `
|
th.assertActualEqualsExpected(m, `
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ spec:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
// TODO(#605): Some output here is wrong due to #605
|
// TODO(#669): Bee's name should be "prod-x-bee", not "prod-bee".
|
||||||
th.assertActualEqualsExpected(m, `
|
th.assertActualEqualsExpected(m, `
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
@@ -308,9 +308,9 @@ metadata:
|
|||||||
name: prod-x-mykind
|
name: prod-x-mykind
|
||||||
spec:
|
spec:
|
||||||
beeRef:
|
beeRef:
|
||||||
name: bee
|
name: prod-bee
|
||||||
secretRef:
|
secretRef:
|
||||||
name: crdsecret
|
name: prod-x-crdsecret
|
||||||
---
|
---
|
||||||
apiVersion: v1beta1
|
apiVersion: v1beta1
|
||||||
kind: Bee
|
kind: Bee
|
||||||
|
|||||||
@@ -221,9 +221,7 @@ spec:
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test demonstrates bug #605.
|
func TestFixedBug605_BaseCustomizationAvailableInOverlay(t *testing.T) {
|
||||||
// The customization supplied in a base isn't available to the overlay.
|
|
||||||
func TestBug605(t *testing.T) {
|
|
||||||
th := NewKustTestHarness(t, "/app/overlay")
|
th := NewKustTestHarness(t, "/app/overlay")
|
||||||
makeBaseReferencingCustomConfig(th)
|
makeBaseReferencingCustomConfig(th)
|
||||||
th.writeDefaultConfigs("/app/base/config/defaults.yaml")
|
th.writeDefaultConfigs("/app/base/config/defaults.yaml")
|
||||||
@@ -274,13 +272,8 @@ spec:
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
// Problems in the expected result:
|
// TODO(#669): The name of AnimalPark should be x-o-sandiego,
|
||||||
// - The variables are not replaced in the "food" fields.
|
// not o-sandiego, since AnimalPark appears in the base.
|
||||||
// - The name of the AnimalPark should be x-o-sandiego, since
|
|
||||||
// AnimalPark appears in the base.
|
|
||||||
// - The giraffe and gorilla name are incorrect in AnimalPark;
|
|
||||||
// they should be o-x-april and o-ursus respectively. The
|
|
||||||
// Gorilla ursus doesn't get an x because it's not in the base.
|
|
||||||
th.assertActualEqualsExpected(m, `
|
th.assertActualEqualsExpected(m, `
|
||||||
kind: AnimalPark
|
kind: AnimalPark
|
||||||
metadata:
|
metadata:
|
||||||
@@ -290,12 +283,12 @@ metadata:
|
|||||||
name: o-sandiego
|
name: o-sandiego
|
||||||
spec:
|
spec:
|
||||||
food:
|
food:
|
||||||
- $(APRIL_DIET)
|
- mimosa
|
||||||
- $(KOKO_DIET)
|
- bambooshoots
|
||||||
giraffeRef:
|
giraffeRef:
|
||||||
name: april
|
name: o-x-april
|
||||||
gorillaRef:
|
gorillaRef:
|
||||||
name: ursus
|
name: o-ursus
|
||||||
---
|
---
|
||||||
kind: Giraffe
|
kind: Giraffe
|
||||||
metadata:
|
metadata:
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/ifc/transformer"
|
"sigs.k8s.io/kustomize/pkg/ifc/transformer"
|
||||||
interror "sigs.k8s.io/kustomize/pkg/internal/error"
|
interror "sigs.k8s.io/kustomize/pkg/internal/error"
|
||||||
patchtransformer "sigs.k8s.io/kustomize/pkg/patch/transformer"
|
patchtransformer "sigs.k8s.io/kustomize/pkg/patch/transformer"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||||
@@ -46,7 +45,6 @@ type KustTarget struct {
|
|||||||
ldr ifc.Loader
|
ldr ifc.Loader
|
||||||
fSys fs.FileSystem
|
fSys fs.FileSystem
|
||||||
rFactory *resmap.Factory
|
rFactory *resmap.Factory
|
||||||
tConfig *config.TransformerConfig
|
|
||||||
tFactory transformer.Factory
|
tFactory transformer.Factory
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,16 +71,11 @@ func NewKustTarget(
|
|||||||
if len(msgs) > 0 {
|
if len(msgs) > 0 {
|
||||||
log.Printf(strings.Join(msgs, "\n"))
|
log.Printf(strings.Join(msgs, "\n"))
|
||||||
}
|
}
|
||||||
tConfig, err := makeTransformerConfig(ldr, k.Configurations)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &KustTarget{
|
return &KustTarget{
|
||||||
kustomization: &k,
|
kustomization: &k,
|
||||||
ldr: ldr,
|
ldr: ldr,
|
||||||
fSys: fSys,
|
fSys: fSys,
|
||||||
rFactory: rFactory,
|
rFactory: rFactory,
|
||||||
tConfig: tConfig,
|
|
||||||
tFactory: tFactory,
|
tFactory: tFactory,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -141,7 +134,7 @@ func mergeCustomConfigWithDefaults(
|
|||||||
// MakeCustomizedResMap creates a ResMap per kustomization instructions.
|
// MakeCustomizedResMap creates a ResMap per kustomization instructions.
|
||||||
// The Resources in the returned ResMap are fully customized.
|
// The Resources in the returned ResMap are fully customized.
|
||||||
func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
|
func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
|
||||||
m, err := kt.loadCustomizedResMap()
|
ra, err := kt.accumulateTarget()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -150,23 +143,20 @@ func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
|
|||||||
// It changes only the Name field in the
|
// It changes only the Name field in the
|
||||||
// resource held in the ResMap's value, not
|
// resource held in the ResMap's value, not
|
||||||
// the Name in the key in the ResMap.
|
// the Name in the key in the ResMap.
|
||||||
err := kt.tFactory.MakeHashTransformer().Transform(m)
|
err := ra.Transform(kt.tFactory.MakeHashTransformer())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Given that names have changed (prefixs/suffixes added),
|
// Given that names have changed (prefixs/suffixes added),
|
||||||
// fix all the back references to those names.
|
// fix all the back references to those names.
|
||||||
if kt.tConfig.NameReference != nil {
|
err = ra.FixBackReferences()
|
||||||
err = transformers.NewNameReferenceTransformer(
|
if err != nil {
|
||||||
kt.tConfig.NameReference).Transform(m)
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// With all the back references fixed, it's OK to resolve Vars.
|
// With all the back references fixed, it's OK to resolve Vars.
|
||||||
err = kt.doVarReplacement(m)
|
err = ra.ResolveVars()
|
||||||
return m, err
|
return ra.ResMap(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kt *KustTarget) shouldAddHashSuffixesToGeneratedResources() bool {
|
func (kt *KustTarget) shouldAddHashSuffixesToGeneratedResources() bool {
|
||||||
@@ -174,31 +164,46 @@ func (kt *KustTarget) shouldAddHashSuffixesToGeneratedResources() bool {
|
|||||||
!kt.kustomization.GeneratorOptions.DisableNameSuffixHash
|
!kt.kustomization.GeneratorOptions.DisableNameSuffixHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kt *KustTarget) doVarReplacement(m resmap.ResMap) error {
|
// accumulateTarget returns a new ResAccumulator,
|
||||||
vars, err := kt.getAllVars()
|
// holding customized resources and the data/rules used
|
||||||
if err != nil {
|
// to do so. The name back references and vars are
|
||||||
return err
|
// not yet fixed.
|
||||||
}
|
func (kt *KustTarget) accumulateTarget() (
|
||||||
varMap, err := kt.resolveVars(m, vars)
|
ra *ResAccumulator, err error) {
|
||||||
if err != nil {
|
// TODO(monopole): Get rid of the KustomizationErrors accumulator.
|
||||||
return err
|
// It's not consistently used, and complicates tests.
|
||||||
}
|
|
||||||
return transformers.NewRefVarTransformer(
|
|
||||||
varMap, kt.tConfig.VarReference).Transform(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadCustomizedResMap loads and customizes resources to build a ResMap.
|
|
||||||
func (kt *KustTarget) loadCustomizedResMap() (resmap.ResMap, error) {
|
|
||||||
errs := &interror.KustomizationErrors{}
|
errs := &interror.KustomizationErrors{}
|
||||||
result, err := kt.loadResMapFromBasesAndResources()
|
ra, errs = kt.accumulateBases()
|
||||||
|
resources, err := kt.rFactory.FromFiles(
|
||||||
|
kt.ldr, kt.kustomization.Resources)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(errors.Wrap(err, "loadResMapFromBasesAndResources"))
|
errs.Append(errors.Wrap(err, "rawResources failed to read Resources"))
|
||||||
|
}
|
||||||
|
if len(errs.Get()) > 0 {
|
||||||
|
return ra, errs
|
||||||
|
}
|
||||||
|
err = ra.MergeResourcesWithErrorOnIdCollision(resources)
|
||||||
|
if err != nil {
|
||||||
|
errs.Append(errors.Wrap(err, "MergeResourcesWithErrorOnIdCollision"))
|
||||||
|
}
|
||||||
|
tConfig, err := makeTransformerConfig(
|
||||||
|
kt.ldr, kt.kustomization.Configurations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = ra.MergeConfig(tConfig)
|
||||||
|
if err != nil {
|
||||||
|
errs.Append(errors.Wrap(err, "MergeConfig"))
|
||||||
|
}
|
||||||
|
err = ra.MergeVars(kt.kustomization.Vars)
|
||||||
|
if err != nil {
|
||||||
|
errs.Append(errors.Wrap(err, "MergeVars"))
|
||||||
}
|
}
|
||||||
crdTc, err := config.NewFactory(kt.ldr).LoadCRDs(kt.kustomization.Crds)
|
crdTc, err := config.NewFactory(kt.ldr).LoadCRDs(kt.kustomization.Crds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(errors.Wrap(err, "LoadCRDs"))
|
errs.Append(errors.Wrap(err, "LoadCRDs"))
|
||||||
}
|
}
|
||||||
kt.tConfig, err = kt.tConfig.Merge(crdTc)
|
err = ra.MergeConfig(crdTc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(errors.Wrap(err, "merge CRDs"))
|
errs.Append(errors.Wrap(err, "merge CRDs"))
|
||||||
}
|
}
|
||||||
@@ -206,11 +211,10 @@ func (kt *KustTarget) loadCustomizedResMap() (resmap.ResMap, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(errors.Wrap(err, "generateConfigMapsAndSecrets"))
|
errs.Append(errors.Wrap(err, "generateConfigMapsAndSecrets"))
|
||||||
}
|
}
|
||||||
result, err = resmap.MergeWithOverride(result, resMap)
|
err = ra.MergeResourcesWithOverride(resMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
patches, err := kt.rFactory.RF().SliceFromPatches(
|
patches, err := kt.rFactory.RF().SliceFromPatches(
|
||||||
kt.ldr, kt.kustomization.PatchesStrategicMerge)
|
kt.ldr, kt.kustomization.PatchesStrategicMerge)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -219,30 +223,15 @@ func (kt *KustTarget) loadCustomizedResMap() (resmap.ResMap, error) {
|
|||||||
if len(errs.Get()) > 0 {
|
if len(errs.Get()) > 0 {
|
||||||
return nil, errs
|
return nil, errs
|
||||||
}
|
}
|
||||||
|
t, err := kt.newTransformer(patches, ra.tConfig)
|
||||||
var r []transformers.Transformer
|
|
||||||
t, err := kt.newTransformer(patches)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r = append(r, t)
|
err = ra.Transform(t)
|
||||||
t, err = patchtransformer.NewPatchJson6902Factory(kt.ldr).
|
|
||||||
MakePatchJson6902Transformer(kt.kustomization.PatchesJson6902)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r = append(r, t)
|
return ra, nil
|
||||||
t, err = transformers.NewImageTagTransformer(kt.kustomization.ImageTags)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
r = append(r, t)
|
|
||||||
|
|
||||||
err = transformers.NewMultiTransformer(r).Transform(result)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kt *KustTarget) generateConfigMapsAndSecrets(
|
func (kt *KustTarget) generateConfigMapsAndSecrets(
|
||||||
@@ -261,75 +250,48 @@ func (kt *KustTarget) generateConfigMapsAndSecrets(
|
|||||||
return resmap.MergeWithErrorOnIdCollision(cms, secrets)
|
return resmap.MergeWithErrorOnIdCollision(cms, secrets)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets Bases and Resources as advertised.
|
// accumulateBases returns a new ResAccumulator
|
||||||
func (kt *KustTarget) loadResMapFromBasesAndResources() (resmap.ResMap, error) {
|
// holding customized resources and the data/rules
|
||||||
bases, errs := kt.loadCustomizedBases()
|
// used to customized them from only the _bases_
|
||||||
resources, err := kt.rFactory.FromFiles(
|
// of this KustTarget.
|
||||||
kt.ldr, kt.kustomization.Resources)
|
func (kt *KustTarget) accumulateBases() (
|
||||||
if err != nil {
|
ra *ResAccumulator, errs *interror.KustomizationErrors) {
|
||||||
errs.Append(errors.Wrap(err, "rawResources failed to read Resources"))
|
errs = &interror.KustomizationErrors{}
|
||||||
}
|
ra = MakeEmptyAccumulator()
|
||||||
if len(errs.Get()) > 0 {
|
|
||||||
return nil, errs
|
|
||||||
}
|
|
||||||
return resmap.MergeWithErrorOnIdCollision(resources, bases)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through the Bases of this kustomization recursively loading resources.
|
|
||||||
// Combine into one ResMap, demanding unique Ids for each resource.
|
|
||||||
func (kt *KustTarget) loadCustomizedBases() (
|
|
||||||
resmap.ResMap, *interror.KustomizationErrors) {
|
|
||||||
var list []resmap.ResMap
|
|
||||||
errs := &interror.KustomizationErrors{}
|
|
||||||
for _, path := range kt.kustomization.Bases {
|
for _, path := range kt.kustomization.Bases {
|
||||||
ldr, err := kt.ldr.New(path)
|
ldr, err := kt.ldr.New(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(errors.Wrap(err, "couldn't make loader for "+path))
|
errs.Append(errors.Wrap(err, "couldn't make loader for "+path))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
target, err := NewKustTarget(
|
subKt, err := NewKustTarget(
|
||||||
ldr, kt.fSys,
|
|
||||||
kt.rFactory, kt.tFactory)
|
|
||||||
if err != nil {
|
|
||||||
errs.Append(errors.Wrap(err, "couldn't make target for "+path))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resMap, err := target.loadCustomizedResMap()
|
|
||||||
if err != nil {
|
|
||||||
errs.Append(errors.Wrap(err, "SemiResources"))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ldr.Cleanup()
|
|
||||||
list = append(list, resMap)
|
|
||||||
}
|
|
||||||
result, err := resmap.MergeWithErrorOnIdCollision(list...)
|
|
||||||
if err != nil {
|
|
||||||
errs.Append(errors.Wrap(err, "Merge failed"))
|
|
||||||
}
|
|
||||||
return result, errs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kt *KustTarget) loadBasesAsKustTargets() ([]*KustTarget, error) {
|
|
||||||
var result []*KustTarget
|
|
||||||
for _, path := range kt.kustomization.Bases {
|
|
||||||
ldr, err := kt.ldr.New(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
target, err := NewKustTarget(
|
|
||||||
ldr, kt.fSys, kt.rFactory, kt.tFactory)
|
ldr, kt.fSys, kt.rFactory, kt.tFactory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
errs.Append(errors.Wrap(err, "couldn't make target for "+path))
|
||||||
|
ldr.Cleanup()
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
result = append(result, target)
|
subRa, err := subKt.accumulateTarget()
|
||||||
|
if err != nil {
|
||||||
|
errs.Append(errors.Wrap(err, "accumulateTarget"))
|
||||||
|
ldr.Cleanup()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = ra.MergeAccumulator(subRa)
|
||||||
|
if err != nil {
|
||||||
|
errs.Append(errors.Wrap(err, path))
|
||||||
|
}
|
||||||
|
ldr.Cleanup()
|
||||||
}
|
}
|
||||||
return result, nil
|
return ra, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTransformer makes a Transformer that does a collection
|
// newTransformer makes a Transformer that does a collection
|
||||||
// of object transformations.
|
// of object transformations.
|
||||||
func (kt *KustTarget) newTransformer(
|
func (kt *KustTarget) newTransformer(
|
||||||
patches []*resource.Resource) (transformers.Transformer, error) {
|
patches []*resource.Resource, tConfig *config.TransformerConfig) (
|
||||||
|
transformers.Transformer, error) {
|
||||||
var r []transformers.Transformer
|
var r []transformers.Transformer
|
||||||
t, err := kt.tFactory.MakePatchTransformer(patches, kt.rFactory.RF())
|
t, err := kt.tFactory.MakePatchTransformer(patches, kt.rFactory.RF())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -337,24 +299,35 @@ func (kt *KustTarget) newTransformer(
|
|||||||
}
|
}
|
||||||
r = append(r, t)
|
r = append(r, t)
|
||||||
r = append(r, transformers.NewNamespaceTransformer(
|
r = append(r, transformers.NewNamespaceTransformer(
|
||||||
string(kt.kustomization.Namespace), kt.tConfig.NameSpace))
|
string(kt.kustomization.Namespace), tConfig.NameSpace))
|
||||||
t, err = transformers.NewNamePrefixSuffixTransformer(
|
t, err = transformers.NewNamePrefixSuffixTransformer(
|
||||||
string(kt.kustomization.NamePrefix),
|
string(kt.kustomization.NamePrefix),
|
||||||
string(kt.kustomization.NameSuffix),
|
string(kt.kustomization.NameSuffix),
|
||||||
kt.tConfig.NamePrefix,
|
tConfig.NamePrefix,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r = append(r, t)
|
r = append(r, t)
|
||||||
t, err = transformers.NewLabelsMapTransformer(
|
t, err = transformers.NewLabelsMapTransformer(
|
||||||
kt.kustomization.CommonLabels, kt.tConfig.CommonLabels)
|
kt.kustomization.CommonLabels, tConfig.CommonLabels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
r = append(r, t)
|
r = append(r, t)
|
||||||
t, err = transformers.NewAnnotationsMapTransformer(
|
t, err = transformers.NewAnnotationsMapTransformer(
|
||||||
kt.kustomization.CommonAnnotations, kt.tConfig.CommonAnnotations)
|
kt.kustomization.CommonAnnotations, tConfig.CommonAnnotations)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r = append(r, t)
|
||||||
|
t, err = patchtransformer.NewPatchJson6902Factory(kt.ldr).
|
||||||
|
MakePatchJson6902Transformer(kt.kustomization.PatchesJson6902)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r = append(r, t)
|
||||||
|
t, err = transformers.NewImageTagTransformer(kt.kustomization.ImageTags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -362,78 +335,6 @@ func (kt *KustTarget) newTransformer(
|
|||||||
return transformers.NewMultiTransformer(r), nil
|
return transformers.NewMultiTransformer(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveVars returns a map of Var names to their final values.
|
|
||||||
// The values are strings intended for substitution wherever
|
|
||||||
// the $(var.Name) occurs.
|
|
||||||
func (kt *KustTarget) resolveVars(
|
|
||||||
m resmap.ResMap, vars map[string]types.Var) (map[string]string, error) {
|
|
||||||
result := map[string]string{}
|
|
||||||
for _, v := range vars {
|
|
||||||
id := resid.NewResId(v.ObjRef.GVK(), v.ObjRef.Name)
|
|
||||||
if r, found := m.DemandOneMatchForId(id); found {
|
|
||||||
s, err := r.GetFieldValue(v.FieldRef.FieldPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("field path err for var: %+v", v)
|
|
||||||
}
|
|
||||||
result[v.Name] = s
|
|
||||||
} else {
|
|
||||||
log.Printf("couldn't resolve var: %v", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ErrVarCollision struct {
|
|
||||||
name string
|
|
||||||
path string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e ErrVarCollision) Error() string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"var %s in %s defined in some other kustomization",
|
|
||||||
e.name, e.path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getAllVars returns a map of Var names to Var instances, pulled from
|
|
||||||
// this kustomization and the kustomizations it depends on.
|
|
||||||
// An error is returned on Var name collision.
|
|
||||||
func (kt *KustTarget) getAllVars() (map[string]types.Var, error) {
|
|
||||||
result, err := kt.getVarsFromBases()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, v := range kt.kustomization.Vars {
|
|
||||||
v.Defaulting()
|
|
||||||
if _, oops := result[v.Name]; oops {
|
|
||||||
return nil, ErrVarCollision{v.Name, kt.ldr.Root()}
|
|
||||||
}
|
|
||||||
result[v.Name] = v
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (kt *KustTarget) getVarsFromBases() (map[string]types.Var, error) {
|
|
||||||
targets, err := kt.loadBasesAsKustTargets()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result := make(map[string]types.Var)
|
|
||||||
for _, subKt := range targets {
|
|
||||||
vars, err := subKt.getAllVars()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
subKt.ldr.Cleanup()
|
|
||||||
for k, v := range vars {
|
|
||||||
if _, oops := result[k]; oops {
|
|
||||||
return nil, ErrVarCollision{v.Name, subKt.ldr.Root()}
|
|
||||||
}
|
|
||||||
result[k] = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadKustFile(ldr ifc.Loader) ([]byte, error) {
|
func loadKustFile(ldr ifc.Loader) ([]byte, error) {
|
||||||
for _, kf := range []string{
|
for _, kf := range []string{
|
||||||
constants.KustomizationFileName,
|
constants.KustomizationFileName,
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ package target
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -346,28 +346,21 @@ vars:
|
|||||||
name: heron
|
name: heron
|
||||||
apiVersion: v300
|
apiVersion: v300
|
||||||
`)
|
`)
|
||||||
vars, err := th.makeKustTarget().getAllVars()
|
ra, err := th.makeKustTarget().accumulateTarget()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
|
vars := ra.varSet.Set()
|
||||||
if len(vars) != 2 {
|
if len(vars) != 2 {
|
||||||
t.Fatalf("unexpected size %d", len(vars))
|
t.Fatalf("unexpected size %d", len(vars))
|
||||||
}
|
}
|
||||||
for i, k := range sortedKeys(vars)[:2] {
|
for i := range vars[:2] {
|
||||||
if !reflect.DeepEqual(vars[k], someVars[i]) {
|
if !reflect.DeepEqual(vars[i], someVars[i]) {
|
||||||
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[k], someVars[i])
|
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortedKeys(m map[string]types.Var) (result []string) {
|
|
||||||
for k := range m {
|
|
||||||
result = append(result, k)
|
|
||||||
}
|
|
||||||
sort.Strings(result)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAllVarsNested(t *testing.T) {
|
func TestGetAllVarsNested(t *testing.T) {
|
||||||
th := NewKustTestHarness(t, "/app/overlays/o2")
|
th := NewKustTestHarness(t, "/app/overlays/o2")
|
||||||
th.writeK("/app/base", `
|
th.writeK("/app/base", `
|
||||||
@@ -403,16 +396,20 @@ vars:
|
|||||||
bases:
|
bases:
|
||||||
- ../o1
|
- ../o1
|
||||||
`)
|
`)
|
||||||
vars, err := th.makeKustTarget().getAllVars()
|
ra, err := th.makeKustTarget().accumulateTarget()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
|
vars := ra.varSet.Set()
|
||||||
if len(vars) != 4 {
|
if len(vars) != 4 {
|
||||||
t.Fatalf("unexpected size %d", len(vars))
|
for i, v := range vars {
|
||||||
|
fmt.Printf("%v: %v\n", i, v)
|
||||||
|
}
|
||||||
|
t.Fatalf("expected 4 vars, got %d", len(vars))
|
||||||
}
|
}
|
||||||
for i, k := range sortedKeys(vars) {
|
for i := range vars {
|
||||||
if !reflect.DeepEqual(vars[k], someVars[i]) {
|
if !reflect.DeepEqual(vars[i], someVars[i]) {
|
||||||
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[k], someVars[i])
|
t.Fatalf("unexpected var[%d]:\n %v\n %v", i, vars[i], someVars[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,11 +449,12 @@ vars:
|
|||||||
bases:
|
bases:
|
||||||
- ../o1
|
- ../o1
|
||||||
`)
|
`)
|
||||||
_, err := th.makeKustTarget().getAllVars()
|
_, err := th.makeKustTarget().accumulateTarget()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected var collision")
|
t.Fatalf("expected var collision")
|
||||||
}
|
}
|
||||||
if _, ok := err.(ErrVarCollision); !ok {
|
if !strings.Contains(err.Error(),
|
||||||
|
"var AWARD already encountered") {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
134
pkg/target/resaccumulator.go
Normal file
134
pkg/target/resaccumulator.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package target
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResAccumulator accumulates resources and the rules
|
||||||
|
// used to customize those resources.
|
||||||
|
// TODO(monopole): Move to "accumulator" package and make members private.
|
||||||
|
// This will make a better separation between KustTarget, which should
|
||||||
|
// be mainly concerned with data loading, and this class, which could
|
||||||
|
// become the home of all transformation data and logic.
|
||||||
|
type ResAccumulator struct {
|
||||||
|
resMap resmap.ResMap
|
||||||
|
tConfig *config.TransformerConfig
|
||||||
|
varSet types.VarSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeEmptyAccumulator() *ResAccumulator {
|
||||||
|
ra := &ResAccumulator{}
|
||||||
|
ra.resMap = make(resmap.ResMap)
|
||||||
|
ra.tConfig = &config.TransformerConfig{}
|
||||||
|
ra.varSet = types.VarSet{}
|
||||||
|
return ra
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResMap returns a copy of the internal resMap.
|
||||||
|
func (ra *ResAccumulator) ResMap() resmap.ResMap {
|
||||||
|
result := make(resmap.ResMap)
|
||||||
|
for k, v := range ra.resMap {
|
||||||
|
result[k] = v
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) MergeResourcesWithErrorOnIdCollision(
|
||||||
|
resources resmap.ResMap) (err error) {
|
||||||
|
ra.resMap, err = resmap.MergeWithErrorOnIdCollision(
|
||||||
|
resources, ra.resMap)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) MergeResourcesWithOverride(
|
||||||
|
resources resmap.ResMap) (err error) {
|
||||||
|
ra.resMap, err = resmap.MergeWithOverride(
|
||||||
|
ra.resMap, resources)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) MergeConfig(
|
||||||
|
tConfig *config.TransformerConfig) (err error) {
|
||||||
|
ra.tConfig, err = ra.tConfig.Merge(tConfig)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
||||||
|
return ra.varSet.MergeSlice(incoming)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) MergeAccumulator(other *ResAccumulator) (err error) {
|
||||||
|
err = ra.MergeResourcesWithErrorOnIdCollision(other.resMap)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ra.MergeConfig(other.tConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ra.varSet.MergeSet(&other.varSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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]string, error) {
|
||||||
|
result := map[string]string{}
|
||||||
|
for _, v := range ra.varSet.Set() {
|
||||||
|
id := resid.NewResId(v.ObjRef.GVK(), v.ObjRef.Name)
|
||||||
|
if r, found := ra.resMap.DemandOneMatchForId(id); found {
|
||||||
|
s, err := r.GetFieldValue(v.FieldRef.FieldPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("field path err for var: %+v", v)
|
||||||
|
}
|
||||||
|
result[v.Name] = s
|
||||||
|
} else {
|
||||||
|
// Should this be an error?
|
||||||
|
log.Printf("var %v defined but not used", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) Transform(t transformers.Transformer) error {
|
||||||
|
return t.Transform(ra.resMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) ResolveVars() error {
|
||||||
|
replacementMap, err := ra.makeVarReplacementMap()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ra.Transform(transformers.NewRefVarTransformer(
|
||||||
|
replacementMap, ra.tConfig.VarReference))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *ResAccumulator) FixBackReferences() (err error) {
|
||||||
|
if ra.tConfig.NameReference == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ra.Transform(transformers.NewNameReferenceTransformer(
|
||||||
|
ra.tConfig.NameReference))
|
||||||
|
}
|
||||||
132
pkg/target/resaccumulator_test.go
Normal file
132
pkg/target/resaccumulator_test.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package target
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolveVars(t *testing.T) {
|
||||||
|
ra := MakeEmptyAccumulator()
|
||||||
|
err := ra.MergeConfig(config.NewFactory(nil).DefaultConfig())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
rf := resource.NewFactory(
|
||||||
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
|
ra.MergeResourcesWithErrorOnIdCollision(resmap.ResMap{
|
||||||
|
resid.NewResId(
|
||||||
|
gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
"deploy1"): rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"template": map[string]interface{}{
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"command": []interface{}{
|
||||||
|
"myserver",
|
||||||
|
"--somebackendService $(FOO)",
|
||||||
|
"--yetAnother $(BAR)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
resid.NewResId(
|
||||||
|
gvk.Gvk{Version: "v1", Kind: "Service"},
|
||||||
|
"backendOne"): rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "backendOne",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
resid.NewResId(
|
||||||
|
gvk.Gvk{Version: "v1", Kind: "Service"},
|
||||||
|
"backendTwo"): rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "backendTwo",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
err = ra.MergeVars([]types.Var{
|
||||||
|
{
|
||||||
|
Name: "FOO",
|
||||||
|
ObjRef: types.Target{
|
||||||
|
Gvk: gvk.Gvk{Version: "v1", Kind: "Service"},
|
||||||
|
Name: "backendOne"},
|
||||||
|
}, {
|
||||||
|
Name: "BAR",
|
||||||
|
ObjRef: types.Target{
|
||||||
|
Gvk: gvk.Gvk{Version: "v1", Kind: "Service"},
|
||||||
|
Name: "backendTwo"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
err = ra.ResolveVars()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
c := getCommand(find("deploy1", ra.ResMap()))
|
||||||
|
if c != "myserver --somebackendService backendOne --yetAnother backendTwo" {
|
||||||
|
t.Fatalf("unexpected command: %s", c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func find(name string, resMap resmap.ResMap) *resource.Resource {
|
||||||
|
for k, v := range resMap {
|
||||||
|
if k.Name() == name {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assumes arg is a deployment, returns the command of first container.
|
||||||
|
func getCommand(r *resource.Resource) string {
|
||||||
|
var m map[string]interface{}
|
||||||
|
var c []interface{}
|
||||||
|
m, _ = r.Map()["spec"].(map[string]interface{})
|
||||||
|
m, _ = m["template"].(map[string]interface{})
|
||||||
|
m, _ = m["spec"].(map[string]interface{})
|
||||||
|
c, _ = m["containers"].([]interface{})
|
||||||
|
m, _ = c[0].(map[string]interface{})
|
||||||
|
return strings.Join(m["command"].([]string), " ")
|
||||||
|
}
|
||||||
@@ -17,11 +17,15 @@ limitations under the License.
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const defaultFieldPath = "metadata.name"
|
||||||
|
|
||||||
// Var represents a variable whose value will be sourced
|
// Var represents a variable whose value will be sourced
|
||||||
// from a field in a Kubernetes object.
|
// from a field in a Kubernetes object.
|
||||||
type Var struct {
|
type Var struct {
|
||||||
@@ -38,7 +42,7 @@ type Var struct {
|
|||||||
// FieldRef refers to the field of the object referred to by
|
// FieldRef refers to the field of the object referred to by
|
||||||
// ObjRef whose value will be extracted for use in
|
// ObjRef whose value will be extracted for use in
|
||||||
// replacing $(FOO).
|
// replacing $(FOO).
|
||||||
// If unspecified, this defaults to fieldPath: metadata.name
|
// If unspecified, this defaults to fieldPath: $defaultFieldPath
|
||||||
FieldRef FieldSelector `json:"fieldref,omitempty" yaml:"fieldref,omitempty"`
|
FieldRef FieldSelector `json:"fieldref,omitempty" yaml:"fieldref,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,20 +56,76 @@ type Target struct {
|
|||||||
Name string `json:"name" yaml:"name"`
|
Name string `json:"name" yaml:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldSelector contains the fieldPath to an object field, such as metadata.name
|
// FieldSelector contains the fieldPath to an object field.
|
||||||
// This struct is added to keep the backward compatibility of using ObjectFieldSelector
|
// This struct is added to keep the backward compatibility of using ObjectFieldSelector
|
||||||
// for Var.FieldRef
|
// for Var.FieldRef
|
||||||
type FieldSelector struct {
|
type FieldSelector struct {
|
||||||
FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
|
FieldPath string `json:"fieldPath,omitempty" yaml:"fieldPath,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defaulting sets reference to field used by default.
|
// defaulting sets reference to field used by default.
|
||||||
func (v *Var) Defaulting() {
|
func (v *Var) defaulting() {
|
||||||
if v.FieldRef.FieldPath == "" {
|
if v.FieldRef.FieldPath == "" {
|
||||||
v.FieldRef.FieldPath = "metadata.name"
|
v.FieldRef.FieldPath = defaultFieldPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VarSet is a slice of Vars where no var.Name is repeated.
|
||||||
|
type VarSet struct {
|
||||||
|
set []Var
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set returns the var set.
|
||||||
|
func (vs *VarSet) Set() []Var {
|
||||||
|
return vs.set
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeSet absorbs other vars with error on name collision.
|
||||||
|
func (vs *VarSet) MergeSet(incoming *VarSet) error {
|
||||||
|
return vs.MergeSlice(incoming.set)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MergeSlice absorbs other vars with error on name collision.
|
||||||
|
// Empty fields in incoming vars are defaulted.
|
||||||
|
func (vs *VarSet) MergeSlice(incoming []Var) error {
|
||||||
|
for _, v := range incoming {
|
||||||
|
if vs.Contains(v) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"var %s already encountered", v.Name)
|
||||||
|
}
|
||||||
|
v.defaulting()
|
||||||
|
vs.insert(v)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vs *VarSet) insert(v Var) {
|
||||||
|
index := sort.Search(
|
||||||
|
len(vs.set),
|
||||||
|
func(i int) bool { return vs.set[i].Name > v.Name })
|
||||||
|
// make room
|
||||||
|
vs.set = append(vs.set, Var{})
|
||||||
|
// shift right at index.
|
||||||
|
// copy will not increase size of destination.
|
||||||
|
copy(vs.set[index+1:], vs.set[index:])
|
||||||
|
vs.set[index] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains is true if the set has the other var.
|
||||||
|
func (vs *VarSet) Contains(other Var) bool {
|
||||||
|
return vs.Get(other.Name) != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the var with the given name, else nil.
|
||||||
|
func (vs *VarSet) Get(name string) *Var {
|
||||||
|
for _, v := range vs.set {
|
||||||
|
if v.Name == name {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GVK returns the Gvk object in Target
|
// GVK returns the Gvk object in Target
|
||||||
func (t *Target) GVK() gvk.Gvk {
|
func (t *Target) GVK() gvk.Gvk {
|
||||||
if t.APIVersion == "" {
|
if t.APIVersion == "" {
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ limitations under the License.
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGVK(t *testing.T) {
|
func TestGVK(t *testing.T) {
|
||||||
@@ -79,8 +81,73 @@ func TestDefaulting(t *testing.T) {
|
|||||||
Name: "my-secret",
|
Name: "my-secret",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
v.Defaulting()
|
v.defaulting()
|
||||||
if v.FieldRef.FieldPath != "metadata.name" {
|
if v.FieldRef.FieldPath != defaultFieldPath {
|
||||||
t.Fatalf("var defaulting doesn't behave correctly.\n expected metadata.name, but got %v", v.FieldRef.FieldPath)
|
t.Fatalf("expected %s, got %v",
|
||||||
|
defaultFieldPath, v.FieldRef.FieldPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVarSet(t *testing.T) {
|
||||||
|
set := &VarSet{}
|
||||||
|
vars := []Var{
|
||||||
|
{
|
||||||
|
Name: "SHELLVARS",
|
||||||
|
ObjRef: Target{
|
||||||
|
APIVersion: "v7",
|
||||||
|
Gvk: gvk.Gvk{Kind: "ConfigMap"},
|
||||||
|
Name: "bash"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "BACKEND",
|
||||||
|
ObjRef: Target{
|
||||||
|
APIVersion: "v7",
|
||||||
|
Gvk: gvk.Gvk{Kind: "Deployment"},
|
||||||
|
Name: "myTiredBackend"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "AWARD",
|
||||||
|
ObjRef: Target{
|
||||||
|
APIVersion: "v7",
|
||||||
|
Gvk: gvk.Gvk{Kind: "Service"},
|
||||||
|
Name: "nobelPrize"},
|
||||||
|
FieldRef: FieldSelector{FieldPath: "some.arbitrary.path"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := set.MergeSlice(vars)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
for _, v := range vars {
|
||||||
|
if !set.Contains(v) {
|
||||||
|
t.Fatalf("set %v should contain var %v", set.Set(), v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set2 := &VarSet{}
|
||||||
|
err = set2.MergeSet(set)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
err = set2.MergeSlice(vars)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected err")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "var SHELLVARS already encountered") {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
v := set2.Get("BACKEND")
|
||||||
|
if v == nil {
|
||||||
|
t.Fatalf("expected var")
|
||||||
|
}
|
||||||
|
// Confirm defaulting.
|
||||||
|
if v.FieldRef.FieldPath != defaultFieldPath {
|
||||||
|
t.Fatalf("unexpected field path: %v", v.FieldRef.FieldPath)
|
||||||
|
}
|
||||||
|
// Confirm sorting.
|
||||||
|
names := set2.Set()
|
||||||
|
if names[0].Name != "AWARD" ||
|
||||||
|
names[1].Name != "BACKEND" ||
|
||||||
|
names[2].Name != "SHELLVARS" {
|
||||||
|
t.Fatalf("unexpected order in : %v", names)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user