mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Merge pull request #3956 from natasha41575/ReplacementPreviousIds
replacements should be able to use previous IDs
This commit is contained in:
@@ -44,11 +44,17 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targets []*types.T
|
||||
t.FieldPaths = []string{types.DefaultReplacementFieldPath}
|
||||
}
|
||||
for _, n := range nodes {
|
||||
id := makeResId(n)
|
||||
if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, id) {
|
||||
err := applyToNode(n, value, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
ids, err := utils.MakeResIds(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, id := range ids {
|
||||
if id.IsSelectedBy(t.Select.ResId) && !rejectId(t.Reject, &id) {
|
||||
err := applyToNode(n, value, t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -152,12 +158,19 @@ func getRefinedValue(options *types.FieldOptions, rn *yaml.RNode) (*yaml.RNode,
|
||||
func selectSourceNode(nodes []*yaml.RNode, selector *types.SourceSelector) (*yaml.RNode, error) {
|
||||
var matches []*yaml.RNode
|
||||
for _, n := range nodes {
|
||||
if makeResId(n).IsSelectedBy(selector.ResId) {
|
||||
if len(matches) > 0 {
|
||||
return nil, fmt.Errorf(
|
||||
"multiple matches for selector %s", selector)
|
||||
ids, err := utils.MakeResIds(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, id := range ids {
|
||||
if id.IsSelectedBy(selector.ResId) {
|
||||
if len(matches) > 0 {
|
||||
return nil, fmt.Errorf(
|
||||
"multiple matches for selector %s", selector)
|
||||
}
|
||||
matches = append(matches, n)
|
||||
break
|
||||
}
|
||||
matches = append(matches, n)
|
||||
}
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
@@ -165,17 +178,3 @@ func selectSourceNode(nodes []*yaml.RNode, selector *types.SourceSelector) (*yam
|
||||
}
|
||||
return matches[0], nil
|
||||
}
|
||||
|
||||
// makeResId makes a ResId from an RNode.
|
||||
func makeResId(n *yaml.RNode) *resid.ResId {
|
||||
apiVersion := n.Field(yaml.APIVersionField)
|
||||
var group, version string
|
||||
if apiVersion != nil {
|
||||
group, version = resid.ParseGroupVersion(yaml.GetValue(apiVersion.Value))
|
||||
}
|
||||
return &resid.ResId{
|
||||
Gvk: resid.Gvk{Group: group, Version: version, Kind: n.GetKind()},
|
||||
Name: n.GetName(),
|
||||
Namespace: n.GetNamespace(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1478,6 +1478,54 @@ spec:
|
||||
name: third
|
||||
version: latest
|
||||
property: third
|
||||
`,
|
||||
},
|
||||
"using a previous ID": {
|
||||
input: `apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: pre-deploy
|
||||
annotations:
|
||||
config.kubernetes.io/previousNames: deploy,deploy
|
||||
config.kubernetes.io/previousKinds: CronJob,Deployment
|
||||
config.kubernetes.io/previousNamespaces: default,default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.7.9
|
||||
name: nginx-tagged
|
||||
- image: postgres:1.8.0
|
||||
name: postgresdb
|
||||
`,
|
||||
replacements: `replacements:
|
||||
- source:
|
||||
kind: CronJob
|
||||
name: deploy
|
||||
fieldPath: spec.template.spec.containers.0.image
|
||||
targets:
|
||||
- select:
|
||||
kind: Deployment
|
||||
name: deploy
|
||||
fieldPaths:
|
||||
- spec.template.spec.containers.1.image
|
||||
`,
|
||||
expected: `apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: pre-deploy
|
||||
annotations:
|
||||
config.kubernetes.io/previousNames: deploy,deploy
|
||||
config.kubernetes.io/previousKinds: CronJob,Deployment
|
||||
config.kubernetes.io/previousNamespaces: default,default
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:1.7.9
|
||||
name: nginx-tagged
|
||||
- image: nginx:1.7.9
|
||||
name: postgresdb
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
79
api/internal/utils/makeResIds.go
Normal file
79
api/internal/utils/makeResIds.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
BuildAnnotationPreviousKinds = konfig.ConfigAnnoDomain + "/previousKinds"
|
||||
BuildAnnotationPreviousNames = konfig.ConfigAnnoDomain + "/previousNames"
|
||||
BuildAnnotationPrefixes = konfig.ConfigAnnoDomain + "/prefixes"
|
||||
BuildAnnotationSuffixes = konfig.ConfigAnnoDomain + "/suffixes"
|
||||
BuildAnnotationPreviousNamespaces = konfig.ConfigAnnoDomain + "/previousNamespaces"
|
||||
|
||||
// the following are only for patches, to specify whether they can change names
|
||||
// and kinds of their targets
|
||||
BuildAnnotationAllowNameChange = konfig.ConfigAnnoDomain + "/allowNameChange"
|
||||
BuildAnnotationAllowKindChange = konfig.ConfigAnnoDomain + "/allowKindChange"
|
||||
Allowed = "allowed"
|
||||
)
|
||||
|
||||
// MakeResIds returns all of an RNode's current and previous Ids
|
||||
func MakeResIds(n *yaml.RNode) ([]resid.ResId, error) {
|
||||
var result []resid.ResId
|
||||
apiVersion := n.Field(yaml.APIVersionField)
|
||||
var group, version string
|
||||
if apiVersion != nil {
|
||||
group, version = resid.ParseGroupVersion(yaml.GetValue(apiVersion.Value))
|
||||
}
|
||||
result = append(result, resid.NewResIdWithNamespace(
|
||||
resid.Gvk{Group: group, Version: version, Kind: n.GetKind()}, n.GetName(), n.GetNamespace()),
|
||||
)
|
||||
prevIds, err := PrevIds(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, prevIds...)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PrevIds returns all of an RNode's previous Ids
|
||||
func PrevIds(n *yaml.RNode) ([]resid.ResId, error) {
|
||||
var ids []resid.ResId
|
||||
// TODO: merge previous names and namespaces into one list of
|
||||
// pairs on one annotation so there is no chance of error
|
||||
annotations := n.GetAnnotations()
|
||||
if _, ok := annotations[BuildAnnotationPreviousNames]; !ok {
|
||||
return nil, nil
|
||||
}
|
||||
names := strings.Split(annotations[BuildAnnotationPreviousNames], ",")
|
||||
ns := strings.Split(annotations[BuildAnnotationPreviousNamespaces], ",")
|
||||
kinds := strings.Split(annotations[BuildAnnotationPreviousKinds], ",")
|
||||
// This should never happen
|
||||
if len(names) != len(ns) || len(names) != len(kinds) {
|
||||
return nil, fmt.Errorf(
|
||||
"number of previous names, " +
|
||||
"number of previous namespaces, " +
|
||||
"number of previous kinds not equal")
|
||||
}
|
||||
for i := range names {
|
||||
meta, err := n.GetMeta()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
group, version := resid.ParseGroupVersion(meta.APIVersion)
|
||||
gvk := resid.Gvk{
|
||||
Group: group,
|
||||
Version: version,
|
||||
Kind: kinds[i],
|
||||
}
|
||||
ids = append(ids, resid.NewResIdWithNamespace(
|
||||
gvk, names[i], ns[i]))
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
@@ -261,3 +261,84 @@ spec:
|
||||
name: nginx
|
||||
`)
|
||||
}
|
||||
|
||||
func TestReplacementTransformerWithOriginalName(t *testing.T) {
|
||||
th := kusttest_test.MakeEnhancedHarness(t)
|
||||
defer th.Reset()
|
||||
|
||||
th.WriteF("base/deployments.yaml", `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: target
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:oldtag
|
||||
name: nginx
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: source
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:newtag
|
||||
name: nginx
|
||||
`)
|
||||
th.WriteK("base", `
|
||||
resources:
|
||||
- deployments.yaml
|
||||
`)
|
||||
th.WriteK("overlay", `
|
||||
namePrefix: prefix1-
|
||||
resources:
|
||||
- ../base
|
||||
`)
|
||||
|
||||
th.WriteK(".", `
|
||||
namePrefix: prefix2-
|
||||
resources:
|
||||
- overlay
|
||||
replacements:
|
||||
- path: replacement.yaml
|
||||
`)
|
||||
th.WriteF("replacement.yaml", `
|
||||
source:
|
||||
name: source
|
||||
fieldPath: spec.template.spec.containers.0.image
|
||||
targets:
|
||||
- select:
|
||||
name: prefix1-target
|
||||
fieldPaths:
|
||||
- spec.template.spec.containers.[name=nginx].image
|
||||
`)
|
||||
|
||||
m := th.Run(".", th.MakeDefaultOptions())
|
||||
th.AssertActualEqualsExpected(m, `
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: prefix2-prefix1-target
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:newtag
|
||||
name: nginx
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: prefix2-prefix1-source
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- image: nginx:newtag
|
||||
name: nginx
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,13 @@
|
||||
package resource
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/kustomize/api/filters/patchstrategicmerge"
|
||||
"sigs.k8s.io/kustomize/api/ifc"
|
||||
"sigs.k8s.io/kustomize/api/konfig"
|
||||
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||
"sigs.k8s.io/kustomize/api/types"
|
||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||
@@ -28,28 +27,14 @@ type Resource struct {
|
||||
refVarNames []string
|
||||
}
|
||||
|
||||
const (
|
||||
buildAnnotationPreviousKinds = konfig.ConfigAnnoDomain + "/previousKinds"
|
||||
buildAnnotationPreviousNames = konfig.ConfigAnnoDomain + "/previousNames"
|
||||
buildAnnotationPrefixes = konfig.ConfigAnnoDomain + "/prefixes"
|
||||
buildAnnotationSuffixes = konfig.ConfigAnnoDomain + "/suffixes"
|
||||
buildAnnotationPreviousNamespaces = konfig.ConfigAnnoDomain + "/previousNamespaces"
|
||||
|
||||
// the following are only for patches, to specify whether they can change names
|
||||
// and kinds of their targets
|
||||
buildAnnotationAllowNameChange = konfig.ConfigAnnoDomain + "/allowNameChange"
|
||||
buildAnnotationAllowKindChange = konfig.ConfigAnnoDomain + "/allowKindChange"
|
||||
allowed = "allowed"
|
||||
)
|
||||
|
||||
var buildAnnotations = []string{
|
||||
buildAnnotationPreviousKinds,
|
||||
buildAnnotationPreviousNames,
|
||||
buildAnnotationPrefixes,
|
||||
buildAnnotationSuffixes,
|
||||
buildAnnotationPreviousNamespaces,
|
||||
buildAnnotationAllowNameChange,
|
||||
buildAnnotationAllowKindChange,
|
||||
var BuildAnnotations = []string{
|
||||
utils.BuildAnnotationPreviousKinds,
|
||||
utils.BuildAnnotationPreviousNames,
|
||||
utils.BuildAnnotationPrefixes,
|
||||
utils.BuildAnnotationSuffixes,
|
||||
utils.BuildAnnotationPreviousNamespaces,
|
||||
utils.BuildAnnotationAllowNameChange,
|
||||
utils.BuildAnnotationAllowKindChange,
|
||||
}
|
||||
|
||||
func (r *Resource) ResetRNode(incoming *Resource) {
|
||||
@@ -191,12 +176,12 @@ func copyStringSlice(s []string) []string {
|
||||
|
||||
// Implements ResCtx AddNamePrefix
|
||||
func (r *Resource) AddNamePrefix(p string) {
|
||||
r.appendCsvAnnotation(buildAnnotationPrefixes, p)
|
||||
r.appendCsvAnnotation(utils.BuildAnnotationPrefixes, p)
|
||||
}
|
||||
|
||||
// Implements ResCtx AddNameSuffix
|
||||
func (r *Resource) AddNameSuffix(s string) {
|
||||
r.appendCsvAnnotation(buildAnnotationSuffixes, s)
|
||||
r.appendCsvAnnotation(utils.BuildAnnotationSuffixes, s)
|
||||
}
|
||||
|
||||
func (r *Resource) appendCsvAnnotation(name, value string) {
|
||||
@@ -232,12 +217,12 @@ func SameEndingSubarray(shortest, longest []string) bool {
|
||||
|
||||
// Implements ResCtx GetNamePrefixes
|
||||
func (r *Resource) GetNamePrefixes() []string {
|
||||
return r.getCsvAnnotation(buildAnnotationPrefixes)
|
||||
return r.getCsvAnnotation(utils.BuildAnnotationPrefixes)
|
||||
}
|
||||
|
||||
// Implements ResCtx GetNameSuffixes
|
||||
func (r *Resource) GetNameSuffixes() []string {
|
||||
return r.getCsvAnnotation(buildAnnotationSuffixes)
|
||||
return r.getCsvAnnotation(utils.BuildAnnotationSuffixes)
|
||||
}
|
||||
|
||||
func (r *Resource) getCsvAnnotation(name string) []string {
|
||||
@@ -263,7 +248,7 @@ func (r *Resource) RemoveBuildAnnotations() {
|
||||
if len(annotations) == 0 {
|
||||
return
|
||||
}
|
||||
for _, a := range buildAnnotations {
|
||||
for _, a := range BuildAnnotations {
|
||||
delete(annotations, a)
|
||||
}
|
||||
if err := r.SetAnnotations(annotations); err != nil {
|
||||
@@ -272,16 +257,16 @@ func (r *Resource) RemoveBuildAnnotations() {
|
||||
}
|
||||
|
||||
func (r *Resource) setPreviousId(ns string, n string, k string) *Resource {
|
||||
r.appendCsvAnnotation(buildAnnotationPreviousNames, n)
|
||||
r.appendCsvAnnotation(buildAnnotationPreviousNamespaces, ns)
|
||||
r.appendCsvAnnotation(buildAnnotationPreviousKinds, k)
|
||||
r.appendCsvAnnotation(utils.BuildAnnotationPreviousNames, n)
|
||||
r.appendCsvAnnotation(utils.BuildAnnotationPreviousNamespaces, ns)
|
||||
r.appendCsvAnnotation(utils.BuildAnnotationPreviousKinds, k)
|
||||
return r
|
||||
}
|
||||
|
||||
// AllowNameChange allows name changes to the resource.
|
||||
func (r *Resource) AllowNameChange() {
|
||||
annotations := r.GetAnnotations()
|
||||
annotations[buildAnnotationAllowNameChange] = allowed
|
||||
annotations[utils.BuildAnnotationAllowNameChange] = utils.Allowed
|
||||
if err := r.SetAnnotations(annotations); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -289,14 +274,14 @@ func (r *Resource) AllowNameChange() {
|
||||
|
||||
func (r *Resource) NameChangeAllowed() bool {
|
||||
annotations := r.GetAnnotations()
|
||||
v, ok := annotations[buildAnnotationAllowNameChange]
|
||||
return ok && v == allowed
|
||||
v, ok := annotations[utils.BuildAnnotationAllowNameChange]
|
||||
return ok && v == utils.Allowed
|
||||
}
|
||||
|
||||
// AllowKindChange allows kind changes to the resource.
|
||||
func (r *Resource) AllowKindChange() {
|
||||
annotations := r.GetAnnotations()
|
||||
annotations[buildAnnotationAllowKindChange] = allowed
|
||||
annotations[utils.BuildAnnotationAllowKindChange] = utils.Allowed
|
||||
if err := r.SetAnnotations(annotations); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -304,8 +289,8 @@ func (r *Resource) AllowKindChange() {
|
||||
|
||||
func (r *Resource) KindChangeAllowed() bool {
|
||||
annotations := r.GetAnnotations()
|
||||
v, ok := annotations[buildAnnotationAllowKindChange]
|
||||
return ok && v == allowed
|
||||
v, ok := annotations[utils.BuildAnnotationAllowKindChange]
|
||||
return ok && v == utils.Allowed
|
||||
}
|
||||
|
||||
// String returns resource as JSON.
|
||||
@@ -369,26 +354,12 @@ func (r *Resource) OrgId() resid.ResId {
|
||||
// The returned array does not include the resource's current
|
||||
// ID. If there are no previous IDs, this will return nil.
|
||||
func (r *Resource) PrevIds() []resid.ResId {
|
||||
var ids []resid.ResId
|
||||
// TODO: merge previous names and namespaces into one list of
|
||||
// pairs on one annotation so there is no chance of error
|
||||
names := r.getCsvAnnotation(buildAnnotationPreviousNames)
|
||||
ns := r.getCsvAnnotation(buildAnnotationPreviousNamespaces)
|
||||
kinds := r.getCsvAnnotation(buildAnnotationPreviousKinds)
|
||||
if len(names) != len(ns) || len(names) != len(kinds) {
|
||||
panic(errors.New(
|
||||
"number of previous names, " +
|
||||
"number of previous namespaces, " +
|
||||
"number of previous kinds not equal"))
|
||||
prevIds, err := utils.PrevIds(&r.RNode)
|
||||
if err != nil {
|
||||
// this should never happen
|
||||
panic(err)
|
||||
}
|
||||
for i := range names {
|
||||
k := kinds[i]
|
||||
gvk := r.GetGvk()
|
||||
gvk.Kind = k
|
||||
ids = append(ids, resid.NewResIdWithNamespace(
|
||||
gvk, names[i], ns[i]))
|
||||
}
|
||||
return ids
|
||||
return prevIds
|
||||
}
|
||||
|
||||
// StorePreviousId stores the resource's current ID via build annotations.
|
||||
|
||||
Reference in New Issue
Block a user