Merge pull request #4373 from natasha41575/TransformerAnnotationsFull

set transformer annotations when the option is specified
This commit is contained in:
Kubernetes Prow Robot
2022-01-19 21:47:51 -08:00
committed by GitHub
12 changed files with 771 additions and 66 deletions

View File

@@ -83,20 +83,24 @@ func (l *Loader) LoadGenerator(
}
func (l *Loader) LoadTransformers(
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) ([]resmap.Transformer, error) {
var result []resmap.Transformer
ldr ifc.Loader, v ifc.Validator, rm resmap.ResMap) ([]*resmap.TransformerWithProperties, error) {
var result []*resmap.TransformerWithProperties
for _, res := range rm.Resources() {
t, err := l.LoadTransformer(ldr, v, res)
if err != nil {
return nil, err
}
result = append(result, t)
transformerOrigin, err := resource.OriginFromCustomPlugin(res)
if err != nil {
return nil, err
}
result = append(result, &resmap.TransformerWithProperties{Transformer: t, Origin: transformerOrigin})
}
return result, nil
}
func (l *Loader) LoadTransformer(
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (resmap.Transformer, error) {
ldr ifc.Loader, v ifc.Validator, res *resource.Resource) (*resmap.TransformerWithProperties, error) {
c, err := l.loadAndConfigurePlugin(ldr, v, res)
if err != nil {
return nil, err
@@ -105,7 +109,7 @@ func (l *Loader) LoadTransformer(
if !ok {
return nil, fmt.Errorf("plugin %s not a transformer", res.OrgId())
}
return t, nil
return &resmap.TransformerWithProperties{Transformer: t}, nil
}
func relativePluginPath(id resid.ResId) string {

View File

@@ -35,6 +35,7 @@ type KustTarget struct {
validator ifc.Validator
rFactory *resmap.Factory
pLdr *loader.Loader
origin *resource.Origin
}
// NewKustTarget returns a new instance of KustTarget.
@@ -119,10 +120,11 @@ func (kt *KustTarget) MakeCustomizedResMap() (resmap.ResMap, error) {
func (kt *KustTarget) makeCustomizedResMap() (resmap.ResMap, error) {
var origin *resource.Origin
if utils.StringSliceContains(kt.kustomization.BuildMetadata, types.OriginAnnotations) {
if len(kt.kustomization.BuildMetadata) != 0 {
origin = &resource.Origin{}
}
ra, err := kt.AccumulateTarget(origin)
kt.origin = origin
ra, err := kt.AccumulateTarget()
if err != nil {
return nil, err
}
@@ -174,20 +176,20 @@ func (kt *KustTarget) addHashesToNames(
// 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(origin *resource.Origin) (
func (kt *KustTarget) AccumulateTarget() (
ra *accumulator.ResAccumulator, err error) {
return kt.accumulateTarget(accumulator.MakeEmptyAccumulator(), origin)
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, origin *resource.Origin) (
func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator) (
resRa *accumulator.ResAccumulator, err error) {
ra, err = kt.accumulateResources(ra, kt.kustomization.Resources, origin)
ra, err = kt.accumulateResources(ra, kt.kustomization.Resources)
if err != nil {
return nil, errors.Wrap(err, "accumulating resources")
}
ra, err = kt.accumulateComponents(ra, kt.kustomization.Components, origin)
ra, err = kt.accumulateComponents(ra, kt.kustomization.Components)
if err != nil {
return nil, errors.Wrap(err, "accumulating components")
}
@@ -211,7 +213,7 @@ func (kt *KustTarget) accumulateTarget(ra *accumulator.ResAccumulator, origin *r
return nil, errors.Wrapf(
err, "merging CRDs %v", crdTc)
}
err = kt.runGenerators(ra, origin)
err = kt.runGenerators(ra)
if err != nil {
return nil, err
}
@@ -249,20 +251,19 @@ func (kt *KustTarget) IgnoreLocal(ra *accumulator.ResAccumulator) error {
}
func (kt *KustTarget) runGenerators(
ra *accumulator.ResAccumulator, origin *resource.Origin) error {
ra *accumulator.ResAccumulator) error {
var generators []*resmap.GeneratorWithProperties
gs, err := kt.configureBuiltinGenerators(origin)
gs, err := kt.configureBuiltinGenerators()
if err != nil {
return err
}
generators = append(generators, gs...)
gs, err = kt.configureExternalGenerators(origin)
gs, err = kt.configureExternalGenerators()
if err != nil {
return errors.Wrap(err, "loading generator plugins")
}
generators = append(generators, gs...)
for i, g := range generators {
resMap, err := g.Generate()
if err != nil {
@@ -282,7 +283,7 @@ func (kt *KustTarget) runGenerators(
return nil
}
func (kt *KustTarget) configureExternalGenerators(origin *resource.Origin) (
func (kt *KustTarget) configureExternalGenerators() (
[]*resmap.GeneratorWithProperties, error) {
ra := accumulator.MakeEmptyAccumulator()
var generatorPaths []string
@@ -293,19 +294,18 @@ func (kt *KustTarget) configureExternalGenerators(origin *resource.Origin) (
// not an inline config
generatorPaths = append(generatorPaths, p)
continue
} else {
// inline config, track the origin
if origin != nil {
resources := rm.Resources()
for _, r := range resources {
r.SetOrigin(origin.Append(kt.kustFileName))
rm.Replace(r)
}
}
// 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)
}
}
ra.AppendAll(rm)
}
ra, err := kt.accumulateResources(ra, generatorPaths, origin)
ra, err := kt.accumulateResources(ra, generatorPaths)
if err != nil {
return nil, err
}
@@ -313,7 +313,7 @@ func (kt *KustTarget) configureExternalGenerators(origin *resource.Origin) (
}
func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
var r []resmap.Transformer
var r []*resmap.TransformerWithProperties
tConfig := ra.GetTransformerConfig()
lts, err := kt.configureBuiltinTransformers(tConfig)
if err != nil {
@@ -325,10 +325,14 @@ func (kt *KustTarget) runTransformers(ra *accumulator.ResAccumulator) error {
return err
}
r = append(r, lts...)
return ra.Transform(newMultiTransformer(r))
err = ra.Transform(newMultiTransformer(r))
if err != nil {
return err
}
return nil
}
func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]resmap.Transformer, error) {
func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]*resmap.TransformerWithProperties, error) {
ra := accumulator.MakeEmptyAccumulator()
var transformerPaths []string
for _, p := range transformers {
@@ -339,9 +343,17 @@ func (kt *KustTarget) configureExternalTransformers(transformers []string) ([]re
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)
}
}
ra.AppendAll(rm)
}
ra, err := kt.accumulateResources(ra, transformerPaths, &resource.Origin{})
ra, err := kt.accumulateResources(ra, transformerPaths)
if err != nil {
return nil, err
}
@@ -389,10 +401,10 @@ func (kt *KustTarget) removeValidatedByLabel(rm resmap.ResMap) error {
// accumulateResources fills the given resourceAccumulator
// with resources read from the given list of paths.
func (kt *KustTarget) accumulateResources(
ra *accumulator.ResAccumulator, paths []string, origin *resource.Origin) (*accumulator.ResAccumulator, error) {
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, origin); errF != nil {
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.ErrorHTTP) {
return nil, errF
@@ -402,10 +414,15 @@ func (kt *KustTarget) accumulateResources(
return nil, errors.Wrapf(
err, "accumulation err='%s'", errF.Error())
}
if origin != nil {
ra, err = kt.accumulateDirectory(ra, ldr, origin.Append(path), false)
// 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, nil, false)
ra, err = kt.accumulateDirectory(ra, ldr, false)
}
if err != nil {
return nil, errors.Wrapf(
@@ -419,7 +436,7 @@ func (kt *KustTarget) accumulateResources(
// accumulateResources fills the given resourceAccumulator
// with resources read from the given list of paths.
func (kt *KustTarget) accumulateComponents(
ra *accumulator.ResAccumulator, paths []string, origin *resource.Origin) (*accumulator.ResAccumulator, error) {
ra *accumulator.ResAccumulator, paths []string) (*accumulator.ResAccumulator, error) {
for _, path := range paths {
// Components always refer to directories
ldr, errL := kt.ldr.New(path)
@@ -427,10 +444,15 @@ func (kt *KustTarget) accumulateComponents(
return nil, fmt.Errorf("loader.New %q", errL)
}
var errD error
if origin != nil {
ra, errD = kt.accumulateDirectory(ra, ldr, origin.Append(path), true)
// 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, nil, true)
ra, errD = kt.accumulateDirectory(ra, ldr, true)
}
if errD != nil {
return nil, fmt.Errorf("accumulateDirectory: %q", errD)
@@ -440,7 +462,7 @@ func (kt *KustTarget) accumulateComponents(
}
func (kt *KustTarget) accumulateDirectory(
ra *accumulator.ResAccumulator, ldr ifc.Loader, origin *resource.Origin, isComponent bool) (*accumulator.ResAccumulator, error) {
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()
@@ -449,6 +471,7 @@ func (kt *KustTarget) accumulateDirectory(
err, "couldn't make target for path '%s'", ldr.Root())
}
subKt.kustomization.BuildMetadata = kt.kustomization.BuildMetadata
subKt.origin = kt.origin
var bytes []byte
path := ldr.Root()
if openApiPath, exists := subKt.Kustomization().OpenAPI["path"]; exists {
@@ -472,12 +495,12 @@ func (kt *KustTarget) accumulateDirectory(
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, origin)
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(origin)
subRa, err = subKt.AccumulateTarget()
}
if err != nil {
return nil, errors.Wrapf(
@@ -492,13 +515,13 @@ func (kt *KustTarget) accumulateDirectory(
}
func (kt *KustTarget) accumulateFile(
ra *accumulator.ResAccumulator, path string, origin *resource.Origin) error {
ra *accumulator.ResAccumulator, path string) error {
resources, err := kt.rFactory.FromFile(kt.ldr, path)
if err != nil {
return errors.Wrapf(err, "accumulating resources from '%s'", path)
}
if origin != nil {
originAnno, err := origin.Append(path).String()
if kt.origin != nil {
originAnno, err := kt.origin.Append(path).String()
if err != nil {
return errors.Wrapf(err, "cannot add path annotation for '%s'", path)
}

View File

@@ -30,7 +30,7 @@ import (
// image tag transforms. In these cases, we'll need
// N plugin instances with differing configurations.
func (kt *KustTarget) configureBuiltinGenerators(origin *resource.Origin) (
func (kt *KustTarget) configureBuiltinGenerators() (
result []*resmap.GeneratorWithProperties, err error) {
for _, bpt := range []builtinhelpers.BuiltinPluginType{
builtinhelpers.ConfigMapGenerator,
@@ -44,11 +44,11 @@ func (kt *KustTarget) configureBuiltinGenerators(origin *resource.Origin) (
}
var generatorOrigin *resource.Origin
if origin != nil {
if kt.origin != nil {
generatorOrigin = &resource.Origin{
Repo: origin.Repo,
Ref: origin.Ref,
ConfiguredIn: filepath.Join(origin.Path, kt.kustFileName),
Repo: kt.origin.Repo,
Ref: kt.origin.Ref,
ConfiguredIn: filepath.Join(kt.origin.Path, kt.kustFileName),
ConfiguredBy: yaml.ResourceIdentifier{
TypeMeta: yaml.TypeMeta{
APIVersion: "builtin",
@@ -67,7 +67,7 @@ func (kt *KustTarget) configureBuiltinGenerators(origin *resource.Origin) (
func (kt *KustTarget) configureBuiltinTransformers(
tc *builtinconfig.TransformerConfig) (
result []resmap.Transformer, err error) {
result []*resmap.TransformerWithProperties, err error) {
for _, bpt := range []builtinhelpers.BuiltinPluginType{
builtinhelpers.PatchStrategicMergeTransformer,
builtinhelpers.PatchTransformer,
@@ -86,7 +86,23 @@ func (kt *KustTarget) configureBuiltinTransformers(
if err != nil {
return nil, err
}
result = append(result, r...)
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
}
@@ -169,6 +185,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
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
@@ -252,6 +271,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
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
}
for _, label := range kt.kustomization.Labels {
var c struct {
Labels map[string]string
@@ -294,6 +316,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
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
@@ -311,6 +336,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
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"`
@@ -328,6 +356,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
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"`
@@ -364,6 +395,9 @@ var transformerConfigurators = map[builtinhelpers.BuiltinPluginType]func(
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
}

View File

@@ -9,15 +9,15 @@ import (
// multiTransformer contains a list of transformers.
type multiTransformer struct {
transformers []resmap.Transformer
transformers []*resmap.TransformerWithProperties
}
var _ resmap.Transformer = &multiTransformer{}
// newMultiTransformer constructs a multiTransformer.
func newMultiTransformer(t []resmap.Transformer) resmap.Transformer {
func newMultiTransformer(t []*resmap.TransformerWithProperties) resmap.Transformer {
r := &multiTransformer{
transformers: make([]resmap.Transformer, len(t)),
transformers: make([]*resmap.TransformerWithProperties, len(t)),
}
copy(r.transformers, t)
return r
@@ -30,6 +30,11 @@ func (o *multiTransformer) Transform(m resmap.ResMap) error {
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

View File

@@ -8,7 +8,6 @@ import (
"strings"
"testing"
"sigs.k8s.io/kustomize/api/resource"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/resid"
@@ -66,7 +65,7 @@ vars:
apiVersion: v300
`)
ra, err := makeAndLoadKustTarget(
t, th.GetFSys(), "/app").AccumulateTarget(&resource.Origin{})
t, th.GetFSys(), "/app").AccumulateTarget()
if err != nil {
t.Fatalf("Err: %v", err)
}
@@ -121,7 +120,7 @@ resources:
`)
ra, err := makeAndLoadKustTarget(
t, th.GetFSys(), "/app/overlays/o2").AccumulateTarget(&resource.Origin{})
t, th.GetFSys(), "/app/overlays/o2").AccumulateTarget()
if err != nil {
t.Fatalf("Err: %v", err)
}
@@ -178,7 +177,7 @@ resources:
- ../o1
`)
_, err := makeAndLoadKustTarget(
t, th.GetFSys(), "/app/overlays/o2").AccumulateTarget(&resource.Origin{})
t, th.GetFSys(), "/app/overlays/o2").AccumulateTarget()
if err == nil {
t.Fatalf("expected var collision")
}

View File

@@ -20,7 +20,7 @@ const (
// for keeping track of origin and transformer data
OriginAnnotationKey = "config.kubernetes.io/origin"
TransformerAnnotationKey = "config.kubernetes.io/transformations"
TransformerAnnotationKey = "alpha.config.kubernetes.io/transformations"
Enabled = "enabled"
)

View File

@@ -26,7 +26,6 @@ type: Opaque
apiVersion: v1
kind: Service
metadata:
annotations: {}
labels:
app: test-minecraft
chart: minecraft-3.1.3

View File

@@ -112,5 +112,11 @@ func (b *Kustomizer) Run(
}
}
m.RemoveBuildAnnotations()
if !utils.StringSliceContains(kt.Kustomization().BuildMetadata, types.OriginAnnotations) {
m.RemoveOriginAnnotations()
}
if !utils.StringSliceContains(kt.Kustomization().BuildMetadata, types.TransformerAnnotations) {
m.RemoveTransformerAnnotations()
}
return m, nil
}

View File

@@ -1004,3 +1004,142 @@ metadata:
name: bob-79t79mt227
`)
}
func TestAnnoOriginGeneratorInTransformersField(t *testing.T) {
fSys := filesys.MakeFsOnDisk()
th := kusttest_test.MakeHarnessWithFs(t, fSys)
o := th.MakeOptionsPluginsEnabled()
o.PluginConfig.FnpLoadingOptions.EnableExec = true
tmpDir, err := filesys.NewTmpConfirmedDir()
assert.NoError(t, err)
th.WriteK(tmpDir.String(), `
transformers:
- gener.yaml
buildMetadata: [originAnnotations]
`)
th.WriteF(filepath.Join(tmpDir.String(), "generateDeployment.sh"), generateDeploymentDotSh)
assert.NoError(t, os.Chmod(filepath.Join(tmpDir.String(), "generateDeployment.sh"), 0777))
th.WriteF(filepath.Join(tmpDir.String(), "gener.yaml"), `
kind: executable
metadata:
name: demo
annotations:
config.kubernetes.io/function: |
exec:
path: ./generateDeployment.sh
spec:
`)
m := th.Run(tmpDir.String(), o)
assert.NoError(t, err)
yml, err := m.AsYaml()
assert.NoError(t, err)
assert.Equal(t, `apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
config.kubernetes.io/origin: |
configuredIn: gener.yaml
configuredBy:
kind: executable
name: demo
tshirt-size: small
labels:
app: nginx
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
`, string(yml))
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
}
func TestAnnoOriginGeneratorInTransformersFieldWithOverlay(t *testing.T) {
fSys := filesys.MakeFsOnDisk()
th := kusttest_test.MakeHarnessWithFs(t, fSys)
o := th.MakeOptionsPluginsEnabled()
o.PluginConfig.FnpLoadingOptions.EnableExec = true
tmpDir, err := filesys.NewTmpConfirmedDir()
assert.NoError(t, err)
base := filepath.Join(tmpDir.String(), "base")
prod := filepath.Join(tmpDir.String(), "prod")
assert.NoError(t, fSys.Mkdir(base))
assert.NoError(t, fSys.Mkdir(prod))
th.WriteK(base, `
transformers:
- gener.yaml
`)
th.WriteF(filepath.Join(base, "generateDeployment.sh"), generateDeploymentDotSh)
assert.NoError(t, os.Chmod(filepath.Join(base, "generateDeployment.sh"), 0777))
th.WriteF(filepath.Join(base, "gener.yaml"), `
kind: executable
metadata:
name: demo
annotations:
config.kubernetes.io/function: |
exec:
path: ./generateDeployment.sh
spec:
`)
th.WriteK(prod, `
resources:
- ../base
nameSuffix: -foo
buildMetadata: [originAnnotations, transformerAnnotations]
`)
m := th.Run(prod, o)
assert.NoError(t, err)
yml, err := m.AsYaml()
assert.NoError(t, err)
assert.Equal(t, `apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: SuffixTransformer
config.kubernetes.io/origin: |
configuredIn: ../base/gener.yaml
configuredBy:
kind: executable
name: demo
tshirt-size: small
labels:
app: nginx
name: nginx-foo
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
`, string(yml))
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
}

View File

@@ -0,0 +1,495 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"sigs.k8s.io/kustomize/api/internal/utils"
"sigs.k8s.io/kustomize/api/krusty"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
const generateDeploymentWithOriginDotSh = `#!/bin/sh
cat <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
annotations:
tshirt-size: small # this injects the resource reservations
config.kubernetes.io/origin: |
path: somefile.yaml
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
EOF
`
func TestAnnoTransformerBuiltinLocal(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
ports:
- port: 7002
`)
th.WriteK(".", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service.yaml
buildMetadata: [transformerAnnotations]
namePrefix: foo-
`)
options := th.MakeDefaultOptions()
m := th.Run(".", options)
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Service
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
name: foo-myService
spec:
ports:
- port: 7002
`)
}
func TestAnnoOriginAndTransformerBuiltinLocal(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteF("service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
spec:
ports:
- port: 7002
`)
th.WriteK(".", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service.yaml
buildMetadata: [originAnnotations, transformerAnnotations]
namePrefix: foo-
`)
options := th.MakeDefaultOptions()
m := th.Run(".", options)
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Service
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
config.kubernetes.io/origin: |
path: service.yaml
name: foo-myService
spec:
ports:
- port: 7002
`)
}
func TestAnnoTransformerLocalFilesWithOverlay(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("base", `
namePrefix: b-
resources:
- namespace.yaml
- role.yaml
- service.yaml
- deployment.yaml
`)
th.WriteF("base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService
`)
th.WriteF("base/namespace.yaml", `
apiVersion: v1
kind: Namespace
metadata:
name: myNs
`)
th.WriteF("base/role.yaml", `
apiVersion: v1
kind: Role
metadata:
name: myRole
`)
th.WriteF("base/deployment.yaml", `
apiVersion: v1
kind: Deployment
metadata:
name: myDep
`)
th.WriteK("prod", `
namePrefix: p-
resources:
- ../base
- service.yaml
- namespace.yaml
buildMetadata: [transformerAnnotations]
`)
th.WriteF("prod/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: myService2
`)
th.WriteF("prod/namespace.yaml", `
apiVersion: v1
kind: Namespace
metadata:
name: myNs2
`)
m := th.Run("prod", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: v1
kind: Namespace
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: ../base/kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
name: myNs
---
apiVersion: v1
kind: Role
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: ../base/kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
name: p-b-myRole
---
apiVersion: v1
kind: Service
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: ../base/kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
name: p-b-myService
---
apiVersion: v1
kind: Deployment
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: ../base/kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
name: p-b-myDep
---
apiVersion: v1
kind: Service
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
name: p-myService2
---
apiVersion: v1
kind: Namespace
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
name: myNs2
`)
}
func TestAnnoOriginRemoteBuiltinTransformer(t *testing.T) {
fSys := filesys.MakeFsOnDisk()
b := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
tmpDir, err := filesys.NewTmpConfirmedDir()
assert.NoError(t, err)
assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
resources:
- github.com/kubernetes-sigs/kustomize/examples/multibases/production/?ref=v1.0.6
buildMetadata: [transformerAnnotations]
`)))
m, err := b.Run(
fSys,
tmpDir.String())
if utils.IsErrTimeout(err) {
// Don't fail on timeouts.
t.SkipNow()
}
if !assert.NoError(t, err) {
t.FailNow()
}
yml, err := m.AsYaml()
assert.NoError(t, err)
assert.Equal(t, `apiVersion: v1
kind: Pod
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- repo: https://github.com/kubernetes-sigs/kustomize
ref: v1.0.6
configuredIn: examples/multibases/production/kustomization.yaml
configuredBy:
apiVersion: builtin
kind: PrefixTransformer
labels:
app: myapp
name: prod-myapp-pod
spec:
containers:
- image: nginx:1.7.9
name: nginx
`, string(yml))
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
}
func TestAnnoTransformerBuiltinInline(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t)
defer th.Reset()
th.WriteF("resource.yaml", `
apiVersion: apps/v1
kind: ConfigMap
metadata:
name: whatever
data: {}
`)
th.WriteK(".", `
resources:
- resource.yaml
transformers:
- |-
apiVersion: builtin
kind: NamespaceTransformer
metadata:
name: not-important-to-example
namespace: test
fieldSpecs:
- path: metadata/namespace
create: true
buildMetadata: [transformerAnnotations]
`)
expected := `
apiVersion: apps/v1
data: {}
kind: ConfigMap
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: kustomization.yaml
configuredBy:
apiVersion: builtin
kind: NamespaceTransformer
name: not-important-to-example
namespace: test
name: whatever
namespace: test
`
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, expected)
}
func TestAnnoOriginCustomInlineTransformer(t *testing.T) {
fSys := filesys.MakeFsOnDisk()
th := kusttest_test.MakeHarnessWithFs(t, fSys)
o := th.MakeOptionsPluginsEnabled()
o.PluginConfig.FnpLoadingOptions.EnableExec = true
tmpDir, err := filesys.NewTmpConfirmedDir()
assert.NoError(t, err)
th.WriteK(tmpDir.String(), `
transformers:
- |-
kind: executable
metadata:
name: demo
annotations:
config.kubernetes.io/function: |
exec:
path: ./generateDeployment.sh
spec:
buildMetadata: [transformerAnnotations]
`)
// generateDeploymentWithOriginDotSh creates a resource that already has an origin annotation,
// which will cause kustomize to record the plugin origin data as a transformation
th.WriteF(filepath.Join(tmpDir.String(), "generateDeployment.sh"), generateDeploymentWithOriginDotSh)
assert.NoError(t, os.Chmod(filepath.Join(tmpDir.String(), "generateDeployment.sh"), 0777))
th.WriteF(filepath.Join(tmpDir.String(), "gener.yaml"), `
kind: executable
metadata:
name: demo
annotations:
config.kubernetes.io/function: |
exec:
path: ./generateDeployment.sh
spec:
`)
m := th.Run(tmpDir.String(), o)
assert.NoError(t, err)
yml, err := m.AsYaml()
assert.NoError(t, err)
assert.Equal(t, `apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: kustomization.yaml
configuredBy:
kind: executable
name: demo
tshirt-size: small
labels:
app: nginx
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
`, string(yml))
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
}
func TestAnnoOriginCustomExecTransformerWithOverlay(t *testing.T) {
fSys := filesys.MakeFsOnDisk()
th := kusttest_test.MakeHarnessWithFs(t, fSys)
o := th.MakeOptionsPluginsEnabled()
o.PluginConfig.FnpLoadingOptions.EnableExec = true
tmpDir, err := filesys.NewTmpConfirmedDir()
assert.NoError(t, err)
base := filepath.Join(tmpDir.String(), "base")
prod := filepath.Join(tmpDir.String(), "prod")
assert.NoError(t, fSys.Mkdir(base))
assert.NoError(t, fSys.Mkdir(prod))
th.WriteK(base, `
transformers:
- gener.yaml
`)
th.WriteK(prod, `
resources:
- ../base
buildMetadata: [transformerAnnotations]
`)
th.WriteF(filepath.Join(base, "gener.yaml"), `
kind: executable
metadata:
name: demo
annotations:
config.kubernetes.io/function: |
exec:
path: ./generateDeployment.sh
spec:
`)
// generateDeploymentWithOriginDotSh creates a resource that already has an origin annotation,
// which will cause kustomize to record the plugin origin data as a transformation
th.WriteF(filepath.Join(base, "generateDeployment.sh"), generateDeploymentWithOriginDotSh)
assert.NoError(t, os.Chmod(filepath.Join(base, "generateDeployment.sh"), 0777))
m := th.Run(prod, o)
assert.NoError(t, err)
yml, err := m.AsYaml()
assert.NoError(t, err)
assert.Equal(t, `apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
alpha.config.kubernetes.io/transformations: |
- configuredIn: ../base/gener.yaml
configuredBy:
kind: executable
name: demo
tshirt-size: small
labels:
app: nginx
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
`, string(yml))
assert.NoError(t, fSys.RemoveAll(tmpDir.String()))
}

View File

@@ -1506,7 +1506,7 @@ kind: Deployment
metadata:
name: clown
annotations:
config.kubernetes.io/transformations: |
alpha.config.kubernetes.io/transformations: |
- repo: github.com/myrepo
ref: master
configuredIn: config.yaml
@@ -1524,7 +1524,7 @@ kind: Deployment
metadata:
name: clown
annotations:
config.kubernetes.io/transformations: |
alpha.config.kubernetes.io/transformations: |
- repo: github.com/myrepo
ref: master
configuredIn: config.yaml

View File

@@ -18,8 +18,9 @@ const (
ComponentKind = "Component"
MetadataNamespacePath = "metadata/namespace"
OriginAnnotations = "originAnnotations"
ManagedByLabelOption = "managedByLabel"
OriginAnnotations = "originAnnotations"
TransformerAnnotations = "transformerAnnotations"
ManagedByLabelOption = "managedByLabel"
)
// Kustomization holds the information needed to generate customized k8s api resources.