mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 17:34:21 +00:00
Simplify code base.
- In ResMap, drop concept of internal Id to Resource map. The ResMap is now (just) a list, allowing only very particular edits. - Resources should now be maintained in the order loaded. A later PR can adjust tests to remove the internal legacy sorting, and confirm order-out is predictable from order-in. The PR would suppress the sort in tests, and reorder the output to make all tests pass again, and confirm that the new order matched depth-first input traversal. The FromMap fixture function was removed from all test inputs to establish a predictable input order. - Resources now have two 'Ids', OriginalId and CurrentId. The former is fixed as GVK-name-namespace at load time, the latter changes during transformations. The latter can be used to narrow name references when the former maps to multiple resources. We allow bases to be loaded more than once in a build (a diamond pattern), so the OriginalId is not unique across the resources set. The CurrentId is (and must be) unique, but is constantly mutating. Failing to make this distinction clear, and attempting to maintain a mapping from a single mutating Id to a resource was making the code too complex. - Drop prefix/suffix from ResId - the ResId is now immutable. A later PR can remove the distinction with ItemId. - This PR increases coverage of ResMap is since this is a large refactor. Higher level tests didn't need much change outside reordering of results at the resource level.
This commit is contained in:
@@ -9,11 +9,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var secret = gvk.Gvk{Version: "v1", Kind: "Secret"}
|
|
||||||
|
|
||||||
func TestConfigMapHash(t *testing.T) {
|
func TestConfigMapHash(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
desc string
|
desc string
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func (jmp *jsonMergePatch) findConflict(
|
|||||||
if i == conflictingPatchIdx {
|
if i == conflictingPatchIdx {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !patches[conflictingPatchIdx].Id().GvknEquals(patch.Id()) {
|
if !patches[conflictingPatchIdx].OrgId().GvknEquals(patch.OrgId()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
conflict, err := mergepatch.HasConflicts(
|
conflict, err := mergepatch.HasConflicts(
|
||||||
@@ -100,7 +100,7 @@ func (smp *strategicMergePatch) findConflict(
|
|||||||
if i == conflictingPatchIdx {
|
if i == conflictingPatchIdx {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !patches[conflictingPatchIdx].Id().GvknEquals(patch.Id()) {
|
if !patches[conflictingPatchIdx].OrgId().GvknEquals(patch.OrgId()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
conflict, err := strategicpatch.MergingMapsHaveConflicts(
|
conflict, err := strategicpatch.MergingMapsHaveConflicts(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
|
"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"
|
||||||
@@ -36,33 +37,22 @@ func NewTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Transform apply the patches on top of the base resources.
|
// Transform apply the patches on top of the base resources.
|
||||||
func (tf *transformer) Transform(baseResourceMap resmap.ResMap) error {
|
// nolint:ineffassign
|
||||||
// Merge and then index the patches by Id.
|
func (tf *transformer) Transform(m resmap.ResMap) error {
|
||||||
patches, err := tf.mergePatches()
|
patches, err := tf.mergePatches()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strategic merge the resources exist in both base and patches.
|
|
||||||
for _, patch := range patches.Resources() {
|
for _, patch := range patches.Resources() {
|
||||||
// Merge patches with base resource.
|
target, err := tf.findPatchTarget(m, patch.OrgId())
|
||||||
id := patch.Id()
|
|
||||||
matchedIds := baseResourceMap.GetMatchingIds(id.GvknEquals)
|
|
||||||
if len(matchedIds) == 0 {
|
|
||||||
return fmt.Errorf("failed to find an object with %s to apply the patch", id.GvknString())
|
|
||||||
}
|
|
||||||
if len(matchedIds) > 1 {
|
|
||||||
return fmt.Errorf("found multiple objects %#v targeted by patch %#v (ambiguous)", matchedIds, id)
|
|
||||||
}
|
|
||||||
id = matchedIds[0]
|
|
||||||
base := baseResourceMap.GetById(id)
|
|
||||||
merged := map[string]interface{}{}
|
merged := map[string]interface{}{}
|
||||||
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk()))
|
versionedObj, err := scheme.Scheme.New(
|
||||||
baseName := base.GetName()
|
toSchemaGvk(patch.OrgId().Gvk))
|
||||||
|
saveName := target.GetName()
|
||||||
switch {
|
switch {
|
||||||
case runtime.IsNotRegisteredError(err):
|
case runtime.IsNotRegisteredError(err):
|
||||||
// Use JSON merge patch to handle types w/o schema
|
// Use JSON merge patch to handle types w/o schema
|
||||||
baseBytes, err := json.Marshal(base.Map())
|
baseBytes, err := json.Marshal(target.Map())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -83,39 +73,56 @@ func (tf *transformer) Transform(baseResourceMap resmap.ResMap) error {
|
|||||||
default:
|
default:
|
||||||
// Use Strategic-Merge-Patch to handle types w/ schema
|
// Use Strategic-Merge-Patch to handle types w/ schema
|
||||||
// TODO: Change this to use the new Merge package.
|
// TODO: Change this to use the new Merge package.
|
||||||
// Store the name of the base object, because this name may have been munged.
|
// Store the name of the target object, because this name may have been munged.
|
||||||
// Apply this name to the patched object.
|
// Apply this name to the patched object.
|
||||||
lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObj)
|
lookupPatchMeta, err := strategicpatch.NewPatchMetaFromStruct(versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
merged, err = strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta(
|
merged, err = strategicpatch.StrategicMergeMapPatchUsingLookupPatchMeta(
|
||||||
base.Map(),
|
target.Map(),
|
||||||
patch.Map(),
|
patch.Map(),
|
||||||
lookupPatchMeta)
|
lookupPatchMeta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
baseResourceMap.GetById(id).SetMap(merged)
|
target.SetMap(merged)
|
||||||
base.SetName(baseName)
|
target.SetName(saveName)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergePatches merge and index patches by Id.
|
func (tf *transformer) findPatchTarget(
|
||||||
|
m resmap.ResMap, id resid.ResId) (*resource.Resource, error) {
|
||||||
|
match, err := m.GetByOriginalId(id)
|
||||||
|
if err == nil {
|
||||||
|
return match, nil
|
||||||
|
}
|
||||||
|
match, err = m.GetByCurrentId(id)
|
||||||
|
if err == nil {
|
||||||
|
return match, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"failed to find target for patch %s", id.GvknString())
|
||||||
|
}
|
||||||
|
|
||||||
|
// mergePatches merge and index patches by OrgId.
|
||||||
// It errors out if there is conflict between patches.
|
// It errors out if there is conflict between patches.
|
||||||
func (tf *transformer) mergePatches() (resmap.ResMap, error) {
|
func (tf *transformer) mergePatches() (resmap.ResMap, error) {
|
||||||
rc := resmap.New()
|
rc := resmap.New()
|
||||||
for ix, patch := range tf.patches {
|
for ix, patch := range tf.patches {
|
||||||
id := patch.Id()
|
id := patch.OrgId()
|
||||||
existing := rc.GetById(id)
|
existing := rc.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
||||||
if existing == nil {
|
if len(existing) == 0 {
|
||||||
rc.AppendWithId(id, patch)
|
rc.Append(patch)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if len(existing) > 1 {
|
||||||
|
return nil, fmt.Errorf("self conflict in patches")
|
||||||
|
}
|
||||||
|
|
||||||
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk()))
|
versionedObj, err := scheme.Scheme.New(toSchemaGvk(id.Gvk))
|
||||||
if err != nil && !runtime.IsNotRegisteredError(err) {
|
if err != nil && !runtime.IsNotRegisteredError(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -129,7 +136,7 @@ func (tf *transformer) mergePatches() (resmap.ResMap, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conflict, err := cd.hasConflict(existing, patch)
|
conflict, err := cd.hasConflict(existing[0], patch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -142,11 +149,11 @@ func (tf *transformer) mergePatches() (resmap.ResMap, error) {
|
|||||||
"conflict between %#v and %#v",
|
"conflict between %#v and %#v",
|
||||||
conflictingPatch.Map(), patch.Map())
|
conflictingPatch.Map(), patch.Map())
|
||||||
}
|
}
|
||||||
merged, err := cd.mergePatches(existing, patch)
|
merged, err := cd.mergePatches(existing[0], patch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rc.ReplaceResource(id, merged)
|
rc.Replace(merged)
|
||||||
}
|
}
|
||||||
return rc, nil
|
return rc, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,45 +9,39 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
var rf = resource.NewFactory(
|
var rf = resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
var deploy = gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"}
|
|
||||||
var foo = gvk.Gvk{Group: "example.com", Version: "v1", Kind: "Foo"}
|
|
||||||
|
|
||||||
func TestOverlayRun(t *testing.T) {
|
func TestOverlayRun(t *testing.T) {
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "deploy1",
|
||||||
"name": "deploy1",
|
},
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"template": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
"labels": map[string]interface{}{
|
"old-label": "old-value",
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"containers": []interface{}{
|
"spec": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"name": "nginx",
|
map[string]interface{}{
|
||||||
"image": "nginx",
|
"name": "nginx",
|
||||||
},
|
"image": "nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
patch := []*resource.Resource{
|
patch := []*resource.Resource{
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
@@ -78,43 +72,40 @@ func TestOverlayRun(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
expected := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "deploy1",
|
||||||
"name": "deploy1",
|
},
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"template": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
"labels": map[string]interface{}{
|
"old-label": "old-value",
|
||||||
"old-label": "old-value",
|
"another-label": "foo",
|
||||||
"another-label": "foo",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"containers": []interface{}{
|
"spec": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"name": "nginx",
|
map[string]interface{}{
|
||||||
"image": "nginx:latest",
|
"name": "nginx",
|
||||||
"env": []interface{}{
|
"image": "nginx:latest",
|
||||||
map[string]interface{}{
|
"env": []interface{}{
|
||||||
"name": "SOMEENV",
|
map[string]interface{}{
|
||||||
"value": "BAR",
|
"name": "SOMEENV",
|
||||||
},
|
"value": "BAR",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
lt, err := NewTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
@@ -124,34 +115,32 @@ func TestOverlayRun(t *testing.T) {
|
|||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(base, expected) {
|
if !reflect.DeepEqual(base, expected) {
|
||||||
err = expected.ErrorIfNotEqualSets(base)
|
err = expected.ErrorIfNotEqualLists(base)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiplePatches(t *testing.T) {
|
func TestMultiplePatches(t *testing.T) {
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "deploy1",
|
||||||
"name": "deploy1",
|
},
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"template": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"containers": []interface{}{
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "nginx",
|
||||||
"name": "nginx",
|
"image": "nginx",
|
||||||
"image": "nginx",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
patch := []*resource.Resource{
|
patch := []*resource.Resource{
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
@@ -177,8 +166,7 @@ func TestMultiplePatches(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
@@ -206,45 +194,42 @@ func TestMultiplePatches(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
expected := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "deploy1",
|
||||||
"name": "deploy1",
|
},
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"template": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"containers": []interface{}{
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "nginx",
|
||||||
"name": "nginx",
|
"image": "nginx:latest",
|
||||||
"image": "nginx:latest",
|
"env": []interface{}{
|
||||||
"env": []interface{}{
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "ANOTHERENV",
|
||||||
"name": "ANOTHERENV",
|
"value": "HELLO",
|
||||||
"value": "HELLO",
|
},
|
||||||
},
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "SOMEENV",
|
||||||
"name": "SOMEENV",
|
"value": "BAR",
|
||||||
"value": "BAR",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
},
|
||||||
"name": "busybox",
|
map[string]interface{}{
|
||||||
"image": "busybox",
|
"name": "busybox",
|
||||||
},
|
"image": "busybox",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
lt, err := NewTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
@@ -254,34 +239,33 @@ func TestMultiplePatches(t *testing.T) {
|
|||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(base, expected) {
|
if !reflect.DeepEqual(base, expected) {
|
||||||
err = expected.ErrorIfNotEqualSets(base)
|
err = expected.ErrorIfNotEqualLists(base)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultiplePatchesWithConflict(t *testing.T) {
|
func TestMultiplePatchesWithConflict(t *testing.T) {
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "deploy1",
|
||||||
"name": "deploy1",
|
},
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"template": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"containers": []interface{}{
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "nginx",
|
||||||
"name": "nginx",
|
"image": "nginx",
|
||||||
"image": "nginx",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
|
|
||||||
patch := []*resource.Resource{
|
patch := []*resource.Resource{
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
@@ -307,8 +291,7 @@ func TestMultiplePatchesWithConflict(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
@@ -327,8 +310,7 @@ func TestMultiplePatchesWithConflict(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
@@ -345,22 +327,20 @@ func TestMultiplePatchesWithConflict(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNoSchemaOverlayRun(t *testing.T) {
|
func TestNoSchemaOverlayRun(t *testing.T) {
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(foo, "my-foo"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "example.com/v1",
|
||||||
"apiVersion": "example.com/v1",
|
"kind": "Foo",
|
||||||
"kind": "Foo",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "my-foo",
|
||||||
"name": "my-foo",
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"bar": map[string]interface{}{
|
||||||
|
"A": "X",
|
||||||
|
"B": "Y",
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"bar": map[string]interface{}{
|
}).ResMap()
|
||||||
"A": "X",
|
|
||||||
"B": "Y",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
patch := []*resource.Resource{
|
patch := []*resource.Resource{
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
@@ -374,11 +354,10 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
|||||||
"C": "Z",
|
"C": "Z",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
expected := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(foo, "my-foo"): rf.FromMap(
|
Add(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
"kind": "Foo",
|
"kind": "Foo",
|
||||||
@@ -391,8 +370,7 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
|||||||
"C": "Z",
|
"C": "Z",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}).ResMap()
|
||||||
})
|
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -402,28 +380,26 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err = expected.ErrorIfNotEqualSets(base); err != nil {
|
if err = expected.ErrorIfNotEqualLists(base); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNoSchemaMultiplePatches(t *testing.T) {
|
func TestNoSchemaMultiplePatches(t *testing.T) {
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(foo, "my-foo"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "example.com/v1",
|
||||||
"apiVersion": "example.com/v1",
|
"kind": "Foo",
|
||||||
"kind": "Foo",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "my-foo",
|
||||||
"name": "my-foo",
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"bar": map[string]interface{}{
|
||||||
|
"A": "X",
|
||||||
|
"B": "Y",
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"bar": map[string]interface{}{
|
}).ResMap()
|
||||||
"A": "X",
|
|
||||||
"B": "Y",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
patch := []*resource.Resource{
|
patch := []*resource.Resource{
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
@@ -437,8 +413,7 @@ func TestNoSchemaMultiplePatches(t *testing.T) {
|
|||||||
"C": "Z",
|
"C": "Z",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
"kind": "Foo",
|
"kind": "Foo",
|
||||||
@@ -454,29 +429,26 @@ func TestNoSchemaMultiplePatches(t *testing.T) {
|
|||||||
"hello": "world",
|
"hello": "world",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
}
|
}
|
||||||
expected := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(foo, "my-foo"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "example.com/v1",
|
||||||
"apiVersion": "example.com/v1",
|
"kind": "Foo",
|
||||||
"kind": "Foo",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "my-foo",
|
||||||
"name": "my-foo",
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"bar": map[string]interface{}{
|
||||||
|
"A": "X",
|
||||||
|
"C": "Z",
|
||||||
|
"D": "W",
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
"baz": map[string]interface{}{
|
||||||
"bar": map[string]interface{}{
|
"hello": "world",
|
||||||
"A": "X",
|
|
||||||
"C": "Z",
|
|
||||||
"D": "W",
|
|
||||||
},
|
|
||||||
"baz": map[string]interface{}{
|
|
||||||
"hello": "world",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
|
|
||||||
lt, err := NewTransformer(patch, rf)
|
lt, err := NewTransformer(patch, rf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -486,28 +458,26 @@ func TestNoSchemaMultiplePatches(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err = expected.ErrorIfNotEqualSets(base); err != nil {
|
if err = expected.ErrorIfNotEqualLists(base); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) {
|
func TestNoSchemaMultiplePatchesWithConflict(t *testing.T) {
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(foo, "my-foo"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "example.com/v1",
|
||||||
"apiVersion": "example.com/v1",
|
"kind": "Foo",
|
||||||
"kind": "Foo",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "my-foo",
|
||||||
"name": "my-foo",
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"bar": map[string]interface{}{
|
||||||
|
"A": "X",
|
||||||
|
"B": "Y",
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"bar": map[string]interface{}{
|
}).ResMap()
|
||||||
"A": "X",
|
|
||||||
"B": "Y",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
patch := []*resource.Resource{
|
patch := []*resource.Resource{
|
||||||
rf.FromMap(map[string]interface{}{
|
rf.FromMap(map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ func (ra *ResAccumulator) GetTransformerConfig() *config.TransformerConfig {
|
|||||||
|
|
||||||
func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
||||||
for _, v := range incoming {
|
for _, v := range incoming {
|
||||||
matched := ra.resMap.GetMatchingIds(
|
matched := ra.resMap.GetMatchingResourcesByOriginalId(
|
||||||
resid.NewResId(v.ObjRef.GVK(), v.ObjRef.Name).GvknEquals)
|
resid.NewResId(v.ObjRef.GVK(), v.ObjRef.Name).GvknEquals)
|
||||||
if len(matched) > 1 {
|
if len(matched) > 1 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
@@ -73,7 +73,7 @@ func (ra *ResAccumulator) MergeVars(incoming []types.Var) error {
|
|||||||
len(matched), v)
|
len(matched), v)
|
||||||
}
|
}
|
||||||
if len(matched) == 1 {
|
if len(matched) == 1 {
|
||||||
ra.resMap.GetById(matched[0]).AppendRefVarName(v)
|
matched[0].AppendRefVarName(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ra.varSet.MergeSlice(incoming)
|
return ra.varSet.MergeSlice(incoming)
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 accumulator_test
|
package accumulator_test
|
||||||
|
|
||||||
@@ -26,78 +13,65 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
. "sigs.k8s.io/kustomize/pkg/accumulator"
|
. "sigs.k8s.io/kustomize/pkg/accumulator"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
"sigs.k8s.io/kustomize/pkg/types"
|
"sigs.k8s.io/kustomize/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeResAccumulator() (*ResAccumulator, *resource.Factory, error) {
|
func makeResAccumulator(t *testing.T) (*ResAccumulator, *resource.Factory) {
|
||||||
ra := MakeEmptyAccumulator()
|
ra := MakeEmptyAccumulator()
|
||||||
err := ra.MergeConfig(config.MakeDefaultConfig())
|
err := ra.MergeConfig(config.MakeDefaultConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
rf := resource.NewFactory(
|
rf := resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
err = ra.AppendAll(
|
err = ra.AppendAll(
|
||||||
resmap.FromMap(map[resid.ResId]*resource.Resource{
|
resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(
|
Add(map[string]interface{}{
|
||||||
gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
"apiVersion": "apps/v1",
|
||||||
"deploy1"): rf.FromMap(
|
"kind": "Deployment",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"name": "deploy1",
|
||||||
"kind": "Deployment",
|
},
|
||||||
"metadata": map[string]interface{}{
|
"spec": map[string]interface{}{
|
||||||
"name": "deploy1",
|
"template": map[string]interface{}{
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"template": map[string]interface{}{
|
map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"command": []interface{}{
|
||||||
"containers": []interface{}{
|
"myserver",
|
||||||
map[string]interface{}{
|
"--somebackendService $(SERVICE_ONE)",
|
||||||
"command": []interface{}{
|
"--yetAnother $(SERVICE_TWO)",
|
||||||
"myserver",
|
|
||||||
"--somebackendService $(SERVICE_ONE)",
|
|
||||||
"--yetAnother $(SERVICE_TWO)",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}}).
|
||||||
resid.NewResId(
|
Add(map[string]interface{}{
|
||||||
gvk.Gvk{Version: "v1", Kind: "Service"},
|
"apiVersion": "v1",
|
||||||
"backendOne"): rf.FromMap(
|
"kind": "Service",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"name": "backendOne",
|
||||||
"kind": "Service",
|
}}).
|
||||||
"metadata": map[string]interface{}{
|
Add(map[string]interface{}{
|
||||||
"name": "backendOne",
|
"apiVersion": "v1",
|
||||||
},
|
"kind": "Service",
|
||||||
}),
|
"metadata": map[string]interface{}{
|
||||||
resid.NewResId(
|
"name": "backendTwo",
|
||||||
gvk.Gvk{Version: "v1", Kind: "Service"},
|
}}).ResMap())
|
||||||
"backendTwo"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "Service",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "backendTwo",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}))
|
|
||||||
return ra, rf, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestResolveVarsHappy(t *testing.T) {
|
|
||||||
ra, _, err := makeResAccumulator()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
err = ra.MergeVars([]types.Var{
|
return ra, rf
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveVarsHappy(t *testing.T) {
|
||||||
|
ra, _ := makeResAccumulator(t)
|
||||||
|
err := ra.MergeVars([]types.Var{
|
||||||
{
|
{
|
||||||
Name: "SERVICE_ONE",
|
Name: "SERVICE_ONE",
|
||||||
ObjRef: types.Target{
|
ObjRef: types.Target{
|
||||||
@@ -125,11 +99,8 @@ func TestResolveVarsHappy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveVarsOneUnused(t *testing.T) {
|
func TestResolveVarsOneUnused(t *testing.T) {
|
||||||
ra, _, err := makeResAccumulator()
|
ra, _ := makeResAccumulator(t)
|
||||||
if err != nil {
|
err := ra.MergeVars([]types.Var{
|
||||||
t.Fatalf("unexpected err: %v", err)
|
|
||||||
}
|
|
||||||
err = ra.MergeVars([]types.Var{
|
|
||||||
{
|
{
|
||||||
Name: "SERVICE_ONE",
|
Name: "SERVICE_ONE",
|
||||||
ObjRef: types.Target{
|
ObjRef: types.Target{
|
||||||
@@ -169,13 +140,10 @@ func expectLog(t *testing.T, log bytes.Buffer, expect string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveVarsVarNeedsDisambiguation(t *testing.T) {
|
func TestResolveVarsVarNeedsDisambiguation(t *testing.T) {
|
||||||
ra, rf, err := makeResAccumulator()
|
ra, rf := makeResAccumulator(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rm0 := resmap.New()
|
rm0 := resmap.New()
|
||||||
rm0.Append(
|
err := rm0.Append(
|
||||||
rf.FromMap(
|
rf.FromMap(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
@@ -185,6 +153,9 @@ func TestResolveVarsVarNeedsDisambiguation(t *testing.T) {
|
|||||||
"namespace": "fooNamespace",
|
"namespace": "fooNamespace",
|
||||||
},
|
},
|
||||||
}))
|
}))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
err = ra.AppendAll(rm0)
|
err = ra.AppendAll(rm0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
@@ -209,11 +180,8 @@ func TestResolveVarsVarNeedsDisambiguation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveVarsGoodResIdBadField(t *testing.T) {
|
func TestResolveVarsGoodResIdBadField(t *testing.T) {
|
||||||
ra, _, err := makeResAccumulator()
|
ra, _ := makeResAccumulator(t)
|
||||||
if err != nil {
|
err := ra.MergeVars([]types.Var{
|
||||||
t.Fatalf("unexpected err: %v", err)
|
|
||||||
}
|
|
||||||
err = ra.MergeVars([]types.Var{
|
|
||||||
{
|
{
|
||||||
Name: "SERVICE_ONE",
|
Name: "SERVICE_ONE",
|
||||||
ObjRef: types.Target{
|
ObjRef: types.Target{
|
||||||
@@ -237,11 +205,8 @@ func TestResolveVarsGoodResIdBadField(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveVarsUnmappableVar(t *testing.T) {
|
func TestResolveVarsUnmappableVar(t *testing.T) {
|
||||||
ra, _, err := makeResAccumulator()
|
ra, _ := makeResAccumulator(t)
|
||||||
if err != nil {
|
err := ra.MergeVars([]types.Var{
|
||||||
t.Fatalf("unexpected err: %v", err)
|
|
||||||
}
|
|
||||||
err = ra.MergeVars([]types.Var{
|
|
||||||
{
|
{
|
||||||
Name: "SERVICE_THREE",
|
Name: "SERVICE_THREE",
|
||||||
ObjRef: types.Target{
|
ObjRef: types.Target{
|
||||||
@@ -263,13 +228,9 @@ func TestResolveVarsUnmappableVar(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveVarsWithNoambiguiation(t *testing.T) {
|
func TestResolveVarsWithNoambiguation(t *testing.T) {
|
||||||
ra, rf, err := makeResAccumulator()
|
ra1, rf := makeResAccumulator(t)
|
||||||
if err != nil {
|
err := ra1.MergeVars([]types.Var{
|
||||||
t.Fatalf("unexpected err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ra.MergeVars([]types.Var{
|
|
||||||
{
|
{
|
||||||
Name: "SERVICE_ONE",
|
Name: "SERVICE_ONE",
|
||||||
ObjRef: types.Target{
|
ObjRef: types.Target{
|
||||||
@@ -283,45 +244,48 @@ func TestResolveVarsWithNoambiguiation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create another accumulator having a resource with different prefix
|
// Create another accumulator having a resource with different prefix
|
||||||
ra1 := MakeEmptyAccumulator()
|
ra2 := MakeEmptyAccumulator()
|
||||||
rm1 := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResId(gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
"deploy2"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "deploy2",
|
||||||
"name": "deploy2",
|
},
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"template": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"containers": []interface{}{
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"command": []interface{}{
|
||||||
"command": []interface{}{
|
"myserver",
|
||||||
"myserver",
|
"--somebackendService $(SUB_SERVICE_ONE)",
|
||||||
"--somebackendService $(SUB_SERVICE_ONE)",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}}).
|
||||||
resid.NewResIdWithPrefixNamespace(
|
Add(map[string]interface{}{
|
||||||
gvk.Gvk{Version: "v1", Kind: "Service"},
|
"apiVersion": "v1",
|
||||||
"backendOne", "sub-", ""): rf.FromMap(
|
"kind": "Service",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"name": "backendOne",
|
||||||
"kind": "Service",
|
}}).ResMap()
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "backendOne",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
ra1.AppendAll(rm1)
|
|
||||||
|
|
||||||
err = ra1.MergeVars([]types.Var{
|
// Make it seem like this resource
|
||||||
|
// went through a prefix transformer.
|
||||||
|
r := m.GetByIndex(1)
|
||||||
|
r.AddNamePrefix("sub-")
|
||||||
|
r.SetName("sub-backendOne") // original name remains "backendOne"
|
||||||
|
|
||||||
|
err = ra2.AppendAll(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ra2.MergeVars([]types.Var{
|
||||||
{
|
{
|
||||||
Name: "SUB_SERVICE_ONE",
|
Name: "SUB_SERVICE_ONE",
|
||||||
ObjRef: types.Target{
|
ObjRef: types.Target{
|
||||||
@@ -333,12 +297,12 @@ func TestResolveVarsWithNoambiguiation(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
err = ra.MergeAccumulator(ra1)
|
err = ra1.MergeAccumulator(ra2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ra.ResolveVars()
|
err = ra1.ResolveVars()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 gvk
|
package gvk
|
||||||
|
|
||||||
@@ -193,12 +180,3 @@ func (x Gvk) IsClusterKind() bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterLevelGvks returns a slice of cluster-level Gvks
|
|
||||||
func ClusterLevelGvks() []Gvk {
|
|
||||||
var result []Gvk
|
|
||||||
for _, k := range clusterLevelKinds {
|
|
||||||
result = append(result, Gvk{Kind: k})
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import (
|
|||||||
//References are important in inventory management
|
//References are important in inventory management
|
||||||
//because one may not delete an object before all
|
//because one may not delete an object before all
|
||||||
//objects referencing it have been removed.
|
//objects referencing it have been removed.
|
||||||
type Refs map[resid.ItemId][]resid.ItemId
|
type Refs map[resid.ResId][]resid.ResId
|
||||||
|
|
||||||
func NewRefs() Refs {
|
func NewRefs() Refs {
|
||||||
return Refs{}
|
return Refs{}
|
||||||
@@ -44,7 +44,7 @@ func (rf Refs) Merge(b Refs) Refs {
|
|||||||
// removeIfContains removes the reference relationship
|
// removeIfContains removes the reference relationship
|
||||||
// a --> b
|
// a --> b
|
||||||
// from the Refs if it exists
|
// from the Refs if it exists
|
||||||
func (rf Refs) RemoveIfContains(a, b resid.ItemId) {
|
func (rf Refs) RemoveIfContains(a, b resid.ResId) {
|
||||||
refs, ok := rf[a]
|
refs, ok := rf[a]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
@@ -98,15 +98,15 @@ func (a *Inventory) UpdateCurrent(curref Refs) *Inventory {
|
|||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Inventory) removeNewlyOrphanedItemsFromPrevious() []resid.ItemId {
|
func (a *Inventory) removeNewlyOrphanedItemsFromPrevious() []resid.ResId {
|
||||||
var results []resid.ItemId
|
var results []resid.ResId
|
||||||
for item, refs := range a.Previous {
|
for item, refs := range a.Previous {
|
||||||
if _, ok := a.Current[item]; ok {
|
if _, ok := a.Current[item]; ok {
|
||||||
delete(a.Previous, item)
|
delete(a.Previous, item)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var newRefs []resid.ItemId
|
var newRefs []resid.ResId
|
||||||
toDelete := true
|
toDelete := true
|
||||||
for _, ref := range refs {
|
for _, ref := range refs {
|
||||||
if _, ok := a.Current[ref]; ok {
|
if _, ok := a.Current[ref]; ok {
|
||||||
@@ -124,8 +124,8 @@ func (a *Inventory) removeNewlyOrphanedItemsFromPrevious() []resid.ItemId {
|
|||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Inventory) removeOrphanedItemsFromPreviousThatAreNotInCurrent() []resid.ItemId {
|
func (a *Inventory) removeOrphanedItemsFromPreviousThatAreNotInCurrent() []resid.ResId {
|
||||||
var results []resid.ItemId
|
var results []resid.ResId
|
||||||
for item, refs := range a.Previous {
|
for item, refs := range a.Previous {
|
||||||
if _, ok := a.Current[item]; ok {
|
if _, ok := a.Current[item]; ok {
|
||||||
continue
|
continue
|
||||||
@@ -159,7 +159,7 @@ func (a *Inventory) removeOrphanedItemsFromPreviousThatAreInCurrent() {
|
|||||||
// and returns a list of Items that can be pruned.
|
// and returns a list of Items that can be pruned.
|
||||||
// An item that can be pruned shows up only in Previous refs.
|
// An item that can be pruned shows up only in Previous refs.
|
||||||
// Prune also updates the Previous refs with those items removed
|
// Prune also updates the Previous refs with those items removed
|
||||||
func (a *Inventory) Prune() []resid.ItemId {
|
func (a *Inventory) Prune() []resid.ResId {
|
||||||
a.removeOrphanedItemsFromPreviousThatAreInCurrent()
|
a.removeOrphanedItemsFromPreviousThatAreInCurrent()
|
||||||
|
|
||||||
// These are candidates for deletion from the cluster.
|
// These are candidates for deletion from the cluster.
|
||||||
@@ -170,13 +170,13 @@ func (a *Inventory) Prune() []resid.ItemId {
|
|||||||
|
|
||||||
// inventory is the internal type used for serialization
|
// inventory is the internal type used for serialization
|
||||||
type inventory struct {
|
type inventory struct {
|
||||||
Current map[string][]resid.ItemId `json:"current,omitempty"`
|
Current map[string][]resid.ResId `json:"current,omitempty"`
|
||||||
Previous map[string][]resid.ItemId `json:"previous,omitempty"`
|
Previous map[string][]resid.ResId `json:"previous,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Inventory) toInternalType() inventory {
|
func (a *Inventory) toInternalType() inventory {
|
||||||
prev := map[string][]resid.ItemId{}
|
prev := map[string][]resid.ResId{}
|
||||||
curr := map[string][]resid.ItemId{}
|
curr := map[string][]resid.ResId{}
|
||||||
for id, refs := range a.Current {
|
for id, refs := range a.Current {
|
||||||
curr[id.String()] = refs
|
curr[id.String()] = refs
|
||||||
}
|
}
|
||||||
@@ -204,8 +204,8 @@ func (a *Inventory) marshal() ([]byte, error) {
|
|||||||
|
|
||||||
func (a *Inventory) unMarshal(data []byte) error {
|
func (a *Inventory) unMarshal(data []byte) error {
|
||||||
inv := &inventory{
|
inv := &inventory{
|
||||||
Current: map[string][]resid.ItemId{},
|
Current: map[string][]resid.ResId{},
|
||||||
Previous: map[string][]resid.ItemId{},
|
Previous: map[string][]resid.ResId{},
|
||||||
}
|
}
|
||||||
err := json.Unmarshal(data, inv)
|
err := json.Unmarshal(data, inv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ func makeRefs() (Refs, Refs) {
|
|||||||
b := resid.FromString("G2_V2_K2|ns2|nm2")
|
b := resid.FromString("G2_V2_K2|ns2|nm2")
|
||||||
c := resid.FromString("G3_V3_K3|ns3|nm3")
|
c := resid.FromString("G3_V3_K3|ns3|nm3")
|
||||||
current := NewRefs()
|
current := NewRefs()
|
||||||
current[a] = []resid.ItemId{b, c}
|
current[a] = []resid.ResId{b, c}
|
||||||
current[b] = []resid.ItemId{}
|
current[b] = []resid.ResId{}
|
||||||
current[c] = []resid.ItemId{}
|
current[c] = []resid.ResId{}
|
||||||
newRefs := NewRefs()
|
newRefs := NewRefs()
|
||||||
newRefs[a] = []resid.ItemId{b}
|
newRefs[a] = []resid.ResId{b}
|
||||||
newRefs[b] = []resid.ItemId{}
|
newRefs[b] = []resid.ResId{}
|
||||||
return current, newRefs
|
return current, newRefs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ kind: Kustomization
|
|||||||
`+content)
|
`+content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (th *KustTestHarness) RF() *resource.Factory {
|
||||||
|
return th.rf.RF()
|
||||||
|
}
|
||||||
|
|
||||||
func (th *KustTestHarness) FromMap(m map[string]interface{}) *resource.Resource {
|
func (th *KustTestHarness) FromMap(m map[string]interface{}) *resource.Resource {
|
||||||
return th.rf.RF().FromMap(m)
|
return th.rf.RF().FromMap(m)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ import (
|
|||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
"sigs.k8s.io/kustomize/internal/loadertest"
|
"sigs.k8s.io/kustomize/internal/loadertest"
|
||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
"sigs.k8s.io/kustomize/pkg/types"
|
"sigs.k8s.io/kustomize/pkg/types"
|
||||||
)
|
)
|
||||||
@@ -184,65 +182,60 @@ func TestNewPatchJson6902FactoryMulti(t *testing.T) {
|
|||||||
t.Fatal("the returned transformer should not be nil")
|
t.Fatal("the returned transformer should not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
id := resid.NewResId(gvk.FromKind("foo"), "some-name")
|
base := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
Add(map[string]interface{}{
|
||||||
id: rf.FromMap(
|
"kind": "foo",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"kind": "foo",
|
"name": "some-name",
|
||||||
"metadata": map[string]interface{}{
|
},
|
||||||
"name": "some-name",
|
"spec": map[string]interface{}{
|
||||||
},
|
"template": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"old-label": "old-value",
|
||||||
"labels": map[string]interface{}{
|
},
|
||||||
"old-label": "old-value",
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"image": "nginx",
|
||||||
|
"name": "nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"containers": []interface{}{
|
},
|
||||||
map[string]interface{}{
|
},
|
||||||
"image": "nginx",
|
}).ResMap()
|
||||||
"name": "nginx",
|
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
|
Add(map[string]interface{}{
|
||||||
|
"kind": "foo",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "some-name",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"replica": "3",
|
||||||
|
"template": map[string]interface{}{
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"old-label": "old-value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"image": "nginx",
|
||||||
|
"name": "my-nginx",
|
||||||
|
"command": []interface{}{
|
||||||
|
"arg1",
|
||||||
|
"arg2",
|
||||||
|
"arg3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
expected := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
id: rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"kind": "foo",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "some-name",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"replica": "3",
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"containers": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"image": "nginx",
|
|
||||||
"name": "my-nginx",
|
|
||||||
"command": []interface{}{
|
|
||||||
"arg1",
|
|
||||||
"arg2",
|
|
||||||
"arg3",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
err = tr.Transform(base)
|
err = tr.Transform(base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error : %v", err)
|
t.Fatalf("unexpected error : %v", err)
|
||||||
@@ -275,12 +268,12 @@ func TestNewPatchJson6902FactoryMultiConflict(t *testing.T) {
|
|||||||
jsonPatches := []byte(`
|
jsonPatches := []byte(`
|
||||||
- target:
|
- target:
|
||||||
kind: foo
|
kind: foo
|
||||||
name: some-name
|
name: somename
|
||||||
path: patch.json
|
path: patch.json
|
||||||
|
|
||||||
- target:
|
- target:
|
||||||
kind: foo
|
kind: foo
|
||||||
name: some-name
|
name: somename
|
||||||
path: patch.yaml
|
path: patch.yaml
|
||||||
`)
|
`)
|
||||||
var p []types.PatchJson6902
|
var p []types.PatchJson6902
|
||||||
@@ -298,35 +291,32 @@ func TestNewPatchJson6902FactoryMultiConflict(t *testing.T) {
|
|||||||
t.Fatal("the returned transformer should not be nil")
|
t.Fatal("the returned transformer should not be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
id := resid.NewResId(gvk.FromKind("foo"), "some-name")
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
Add(map[string]interface{}{
|
||||||
id: rf.FromMap(
|
"kind": "foo",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"kind": "foo",
|
"name": "somename",
|
||||||
"metadata": map[string]interface{}{
|
},
|
||||||
"name": "somename",
|
"spec": map[string]interface{}{
|
||||||
},
|
"template": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"old-label": "old-value",
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"containers": []interface{}{
|
"spec": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"image": "nginx",
|
map[string]interface{}{
|
||||||
"name": "nginx",
|
"image": "nginx",
|
||||||
},
|
"name": "nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
|
|
||||||
err = tr.Transform(base)
|
err = tr.Transform(m)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("expected conflict")
|
t.Fatal("expected conflict")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func (t *patchJson6902JSONTransformer) Transform(m resmap.ResMap) error {
|
|||||||
|
|
||||||
func (t *patchJson6902JSONTransformer) findTargetObj(
|
func (t *patchJson6902JSONTransformer) findTargetObj(
|
||||||
m resmap.ResMap) (*resource.Resource, error) {
|
m resmap.ResMap) (*resource.Resource, error) {
|
||||||
var matched []resid.ResId
|
var matched []*resource.Resource
|
||||||
// TODO(monopole): namespace bug in json patch?
|
// TODO(monopole): namespace bug in json patch?
|
||||||
// Since introduction in PR #300
|
// Since introduction in PR #300
|
||||||
// (see pkg/patch/transformer/util.go),
|
// (see pkg/patch/transformer/util.go),
|
||||||
@@ -95,10 +95,10 @@ func (t *patchJson6902JSONTransformer) findTargetObj(
|
|||||||
// rather than like an additional restriction to match
|
// rather than like an additional restriction to match
|
||||||
// only the empty namespace. No test coverage to confirm.
|
// only the empty namespace. No test coverage to confirm.
|
||||||
// Not sure if desired, keeping it for now.
|
// Not sure if desired, keeping it for now.
|
||||||
if t.target.Namespace() != "" {
|
if t.target.Namespace != "" {
|
||||||
matched = m.GetMatchingIds(t.target.NsGvknEquals)
|
matched = m.GetMatchingResourcesByOriginalId(t.target.Equals)
|
||||||
} else {
|
} else {
|
||||||
matched = m.GetMatchingIds(t.target.GvknEquals)
|
matched = m.GetMatchingResourcesByOriginalId(t.target.GvknEquals)
|
||||||
}
|
}
|
||||||
if len(matched) == 0 {
|
if len(matched) == 0 {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
@@ -109,5 +109,5 @@ func (t *patchJson6902JSONTransformer) findTargetObj(
|
|||||||
"found multiple targets %v matching %v for json patch",
|
"found multiple targets %v matching %v for json patch",
|
||||||
matched, t.target)
|
matched, t.target)
|
||||||
}
|
}
|
||||||
return m.GetById(matched[0]), nil
|
return matched[0], nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,34 +33,31 @@ var deploy = gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"}
|
|||||||
func TestJsonPatchJSONTransformer_Transform(t *testing.T) {
|
func TestJsonPatchJSONTransformer_Transform(t *testing.T) {
|
||||||
rf := resource.NewFactory(
|
rf := resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
id := resid.NewResId(deploy, "deploy1")
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
Add(map[string]interface{}{
|
||||||
id: rf.FromMap(
|
"apiVersion": "apps/v1",
|
||||||
map[string]interface{}{
|
"kind": "Deployment",
|
||||||
"apiVersion": "apps/v1",
|
"metadata": map[string]interface{}{
|
||||||
"kind": "Deployment",
|
"name": "deploy1",
|
||||||
"metadata": map[string]interface{}{
|
},
|
||||||
"name": "deploy1",
|
"spec": map[string]interface{}{
|
||||||
},
|
"template": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"old-label": "old-value",
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"containers": []interface{}{
|
"spec": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"name": "nginx",
|
map[string]interface{}{
|
||||||
"image": "nginx",
|
"name": "nginx",
|
||||||
},
|
"image": "nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
|
|
||||||
operations := []byte(`[
|
operations := []byte(`[
|
||||||
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
{"op": "replace", "path": "/spec/template/spec/containers/0/name", "value": "my-nginx"},
|
||||||
@@ -68,49 +65,50 @@ func TestJsonPatchJSONTransformer_Transform(t *testing.T) {
|
|||||||
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
{"op": "add", "path": "/spec/template/spec/containers/0/command", "value": ["arg1", "arg2", "arg3"]}
|
||||||
]`)
|
]`)
|
||||||
|
|
||||||
expected := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
id: rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "apps/v1",
|
||||||
"apiVersion": "apps/v1",
|
"kind": "Deployment",
|
||||||
"kind": "Deployment",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "deploy1",
|
||||||
"name": "deploy1",
|
},
|
||||||
},
|
"spec": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"replica": "3",
|
||||||
"replica": "3",
|
"template": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
"labels": map[string]interface{}{
|
"old-label": "old-value",
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"containers": []interface{}{
|
"spec": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"image": "nginx",
|
map[string]interface{}{
|
||||||
"name": "my-nginx",
|
"image": "nginx",
|
||||||
"command": []interface{}{
|
"name": "my-nginx",
|
||||||
"arg1",
|
"command": []interface{}{
|
||||||
"arg2",
|
"arg1",
|
||||||
"arg3",
|
"arg2",
|
||||||
},
|
"arg3",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
jpt, err := newPatchJson6902JSONTransformer(id, operations)
|
|
||||||
|
patchId := m.GetByIndex(0).OrgId()
|
||||||
|
|
||||||
|
jpt, err := newPatchJson6902JSONTransformer(patchId, operations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error : %v", err)
|
t.Fatalf("unexpected error : %v", err)
|
||||||
}
|
}
|
||||||
err = jpt.Transform(base)
|
err = jpt.Transform(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(base, expected) {
|
if !reflect.DeepEqual(m, expected) {
|
||||||
err = expected.ErrorIfNotEqualSets(base)
|
err = expected.ErrorIfNotEqualSets(m)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,48 +116,48 @@ func TestJsonPatchJSONTransformer_Transform(t *testing.T) {
|
|||||||
func TestJsonPatchJSONTransformer_UnHappyTransform(t *testing.T) {
|
func TestJsonPatchJSONTransformer_UnHappyTransform(t *testing.T) {
|
||||||
rf := resource.NewFactory(
|
rf := resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
id := resid.NewResId(deploy, "deploy1")
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
base := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
Add(map[string]interface{}{
|
||||||
id: rf.FromMap(
|
"apiVersion": "apps/v1",
|
||||||
map[string]interface{}{
|
"kind": "Deployment",
|
||||||
"apiVersion": "apps/v1",
|
"metadata": map[string]interface{}{
|
||||||
"kind": "Deployment",
|
"name": "deploy1",
|
||||||
"metadata": map[string]interface{}{
|
},
|
||||||
"name": "deploy1",
|
"spec": map[string]interface{}{
|
||||||
},
|
"template": map[string]interface{}{
|
||||||
"spec": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"template": map[string]interface{}{
|
"labels": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"old-label": "old-value",
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"old-label": "old-value",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
},
|
||||||
"containers": []interface{}{
|
"spec": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"containers": []interface{}{
|
||||||
"name": "nginx",
|
map[string]interface{}{
|
||||||
"image": "nginx",
|
"name": "nginx",
|
||||||
},
|
"image": "nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
},
|
||||||
})
|
}).ResMap()
|
||||||
|
|
||||||
operations := []byte(`[
|
operations := []byte(`[
|
||||||
{"op": "add", "path": "/spec/template/spec/containers/0/command/", "value": ["arg1", "arg2", "arg3"]}
|
{"op": "add", "path": "/spec/template/spec/containers/0/command/", "value": ["arg1", "arg2", "arg3"]}
|
||||||
]`)
|
]`)
|
||||||
|
|
||||||
jpt, err := newPatchJson6902JSONTransformer(id, operations)
|
jpt, err := newPatchJson6902JSONTransformer(
|
||||||
|
m.GetByIndex(0).OrgId(), operations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error : %v", err)
|
t.Fatalf("unexpected error : %v", err)
|
||||||
}
|
}
|
||||||
err = jpt.Transform(base)
|
err = jpt.Transform(m)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error didn't happen")
|
t.Fatalf("expected error didn't happen")
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(err.Error(), "failed to apply json patch") || !strings.Contains(err.Error(), string(operations)) {
|
if !strings.HasPrefix(
|
||||||
|
err.Error(), "failed to apply json patch") ||
|
||||||
|
!strings.Contains(err.Error(), string(operations)) {
|
||||||
t.Fatalf("expected error didn't happen, but got %v", err)
|
t.Fatalf("expected error didn't happen, but got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,8 +192,8 @@ func (p *ExecPlugin) getEnv() []string {
|
|||||||
// Returns a new copy of the given ResMap with the ResIds annotated in each Resource
|
// Returns a new copy of the given ResMap with the ResIds annotated in each Resource
|
||||||
func (p *ExecPlugin) getResMapWithIdAnnotation(rm resmap.ResMap) (resmap.ResMap, error) {
|
func (p *ExecPlugin) getResMapWithIdAnnotation(rm resmap.ResMap) (resmap.ResMap, error) {
|
||||||
inputRM := rm.DeepCopy()
|
inputRM := rm.DeepCopy()
|
||||||
for id, r := range inputRM.AsMap() {
|
for _, r := range inputRM.Resources() {
|
||||||
idString, err := yaml.Marshal(id)
|
idString, err := yaml.Marshal(r.CurId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -230,9 +230,9 @@ func (p *ExecPlugin) updateResMapValues(output []byte, rm resmap.ResMap) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
res := rm.GetById(id)
|
res, err := rm.GetByCurrentId(id)
|
||||||
if res == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to find id %s in resource map", id.String())
|
return fmt.Errorf("unable to find unique match to %s", id.String())
|
||||||
}
|
}
|
||||||
// remove the annotation set by Kustomize to track the resource
|
// remove the annotation set by Kustomize to track the resource
|
||||||
delete(annotations, idAnnotation)
|
delete(annotations, idAnnotation)
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ s/$BAR/bar/g
|
|||||||
p := NewExecPlugin(
|
p := NewExecPlugin(
|
||||||
AbsolutePluginPath(
|
AbsolutePluginPath(
|
||||||
DefaultPluginConfig(),
|
DefaultPluginConfig(),
|
||||||
pluginConfig.Id()))
|
pluginConfig.OrgId()))
|
||||||
|
|
||||||
yaml, err := pluginConfig.AsYAML()
|
yaml, err := pluginConfig.AsYAML()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (l *Loader) LoadGenerator(
|
|||||||
}
|
}
|
||||||
g, ok := c.(transformers.Generator)
|
g, ok := c.(transformers.Generator)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("plugin %s not a generator", res.Id())
|
return nil, fmt.Errorf("plugin %s not a generator", res.OrgId())
|
||||||
}
|
}
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
@@ -79,21 +79,21 @@ func (l *Loader) LoadTransformer(
|
|||||||
}
|
}
|
||||||
t, ok := c.(transformers.Transformer)
|
t, ok := c.(transformers.Transformer)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("plugin %s not a transformer", res.Id())
|
return nil, fmt.Errorf("plugin %s not a transformer", res.OrgId())
|
||||||
}
|
}
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func relativePluginPath(id resid.ResId) string {
|
func relativePluginPath(id resid.ResId) string {
|
||||||
return filepath.Join(
|
return filepath.Join(
|
||||||
id.Gvk().Group,
|
id.Group,
|
||||||
id.Gvk().Version,
|
id.Version,
|
||||||
strings.ToLower(id.Gvk().Kind))
|
strings.ToLower(id.Kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
func AbsolutePluginPath(pc *types.PluginConfig, id resid.ResId) string {
|
func AbsolutePluginPath(pc *types.PluginConfig, id resid.ResId) string {
|
||||||
return filepath.Join(
|
return filepath.Join(
|
||||||
pc.DirectoryPath, relativePluginPath(id), id.Gvk().Kind)
|
pc.DirectoryPath, relativePluginPath(id), id.Kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Loader) absolutePluginPath(id resid.ResId) string {
|
func (l *Loader) absolutePluginPath(id resid.ResId) string {
|
||||||
@@ -104,25 +104,25 @@ func (l *Loader) absolutePluginPath(id resid.ResId) string {
|
|||||||
func (l *Loader) loadAndConfigurePlugin(
|
func (l *Loader) loadAndConfigurePlugin(
|
||||||
ldr ifc.Loader, res *resource.Resource) (c Configurable, err error) {
|
ldr ifc.Loader, res *resource.Resource) (c Configurable, err error) {
|
||||||
if !l.pc.Enabled {
|
if !l.pc.Enabled {
|
||||||
return nil, NotEnabledErr(res.Id().Gvk().Kind)
|
return nil, NotEnabledErr(res.OrgId().Kind)
|
||||||
}
|
}
|
||||||
if p := NewExecPlugin(
|
if p := NewExecPlugin(
|
||||||
l.absolutePluginPath(res.Id())); p.isAvailable() {
|
l.absolutePluginPath(res.OrgId())); p.isAvailable() {
|
||||||
c = p
|
c = p
|
||||||
} else {
|
} else {
|
||||||
c, err = l.loadGoPlugin(res.Id())
|
c, err = l.loadGoPlugin(res.OrgId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yaml, err := res.AsYAML()
|
yaml, err := res.AsYAML()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "marshalling yaml from res %s", res.Id())
|
return nil, errors.Wrapf(err, "marshalling yaml from res %s", res.OrgId())
|
||||||
}
|
}
|
||||||
err = c.Config(ldr, l.rf, yaml)
|
err = c.Config(ldr, l.rf, yaml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(
|
return nil, errors.Wrapf(
|
||||||
err, "plugin %s fails configuration", res.Id())
|
err, "plugin %s fails configuration", res.OrgId())
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 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 resid
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ItemId contains the group, version, kind, namespace
|
|
||||||
// and name of a resource
|
|
||||||
type ItemId struct {
|
|
||||||
// Gvk of the resource.
|
|
||||||
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
|
||||||
|
|
||||||
// Name of the resource before transformation.
|
|
||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
|
||||||
|
|
||||||
// Namespace the resource belongs to.
|
|
||||||
// An untransformed resource has no namespace.
|
|
||||||
// A fully transformed resource has the namespace
|
|
||||||
// from the top most overlay.
|
|
||||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// String of ItemId based on GVK, name and namespace
|
|
||||||
func (i ItemId) String() string {
|
|
||||||
ns := i.Namespace
|
|
||||||
if ns == "" {
|
|
||||||
ns = noNamespace
|
|
||||||
}
|
|
||||||
nm := i.Name
|
|
||||||
if nm == "" {
|
|
||||||
nm = noName
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(
|
|
||||||
[]string{i.Gvk.String(), ns, nm}, separator)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i ItemId) Equals(o ItemId) bool {
|
|
||||||
return i.Name == o.Name &&
|
|
||||||
i.Namespace == o.Namespace &&
|
|
||||||
i.Gvk.Equals(o.Gvk)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewItemId(g gvk.Gvk, ns, nm string) ItemId {
|
|
||||||
return ItemId{
|
|
||||||
Gvk: g,
|
|
||||||
Namespace: ns,
|
|
||||||
Name: nm,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FromString(s string) ItemId {
|
|
||||||
values := strings.Split(s, separator)
|
|
||||||
g := gvk.FromString(values[0])
|
|
||||||
|
|
||||||
ns := values[1]
|
|
||||||
if ns == noNamespace {
|
|
||||||
ns = ""
|
|
||||||
}
|
|
||||||
nm := values[2]
|
|
||||||
if nm == noName {
|
|
||||||
nm = ""
|
|
||||||
}
|
|
||||||
return ItemId{
|
|
||||||
Gvk: g,
|
|
||||||
Namespace: ns,
|
|
||||||
Name: nm,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2019 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 resid
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
|
||||||
)
|
|
||||||
|
|
||||||
var itemIds = []ItemId{
|
|
||||||
{
|
|
||||||
Namespace: "ns",
|
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Namespace: "ns",
|
|
||||||
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Namespace: "ns",
|
|
||||||
Gvk: gvk.Gvk{Kind: "k"},
|
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Namespace: "ns",
|
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestItemIds(t *testing.T) {
|
|
||||||
for _, item := range itemIds {
|
|
||||||
newItem := FromString(item.String())
|
|
||||||
if newItem != item {
|
|
||||||
t.Fatalf("Actual: %v, Expected: '%s'", newItem, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 resid
|
package resid
|
||||||
|
|
||||||
@@ -22,177 +9,89 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResId is an immutable identifier of a k8s resource object.
|
// ResId is an identifier of a k8s resource object.
|
||||||
type ResId struct {
|
type ResId struct {
|
||||||
ItemId
|
// Gvk of the resource.
|
||||||
// namePrefix of the resource.
|
gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"`
|
||||||
// An untransformed resource has no prefix.
|
|
||||||
// A fully transformed resource has an arbitrary
|
|
||||||
// number of prefixes concatenated together.
|
|
||||||
Prefix string `json:"prefix,omitempty"`
|
|
||||||
|
|
||||||
// nameSuffix of the resource.
|
// Name of the resource before transformation.
|
||||||
// An untransformed resource has no suffix.
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
// A fully transformed resource has an arbitrary
|
|
||||||
// number of suffixes concatenated together.
|
// Namespace the resource belongs to.
|
||||||
Suffix string `json:"suffix,omitempty"`
|
// An untransformed resource has no namespace.
|
||||||
|
// A fully transformed resource has the namespace
|
||||||
|
// from the top most overlay.
|
||||||
|
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResIdWithNamespace creates new resource identifier
|
// NewResIdWithNamespace creates new ResId
|
||||||
// in a given namespace.
|
// in a given namespace.
|
||||||
func NewResIdWithNamespace(k gvk.Gvk, n, ns string) ResId {
|
func NewResIdWithNamespace(k gvk.Gvk, n, ns string) ResId {
|
||||||
return ResId{ItemId: ItemId{Gvk: k, Name: n, Namespace: ns}}
|
return ResId{Gvk: k, Name: n, Namespace: ns}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResIdWithPrefixSuffixNamespace creates new resource identifier with a prefix, suffix and a namespace
|
// NewResId creates new ResId.
|
||||||
func NewResIdWithPrefixSuffixNamespace(k gvk.Gvk, n, p, s, ns string) ResId {
|
|
||||||
return ResId{ItemId: ItemId{Gvk: k, Name: n, Namespace: ns}, Prefix: p, Suffix: s}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResIdWithPrefixNamespace creates new resource identifier with a prefix and a namespace
|
|
||||||
func NewResIdWithPrefixNamespace(k gvk.Gvk, n, p, ns string) ResId {
|
|
||||||
return ResId{ItemId: ItemId{Gvk: k, Name: n, Namespace: ns}, Prefix: p}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResIdWithSuffixNamespace creates new resource identifier with a suffix and a namespace
|
|
||||||
func NewResIdWithSuffixNamespace(k gvk.Gvk, n, s, ns string) ResId {
|
|
||||||
return ResId{ItemId: ItemId{Gvk: k, Name: n, Namespace: ns}, Suffix: s}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResId creates new resource identifier
|
|
||||||
func NewResId(k gvk.Gvk, n string) ResId {
|
func NewResId(k gvk.Gvk, n string) ResId {
|
||||||
return ResId{ItemId: ItemId{Gvk: k, Name: n}}
|
return ResId{Gvk: k, Name: n}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResIdKindOnly creates new resource identifier
|
// NewResIdKindOnly creates a new ResId.
|
||||||
func NewResIdKindOnly(k string, n string) ResId {
|
func NewResIdKindOnly(k string, n string) ResId {
|
||||||
return ResId{ItemId: ItemId{Gvk: gvk.FromKind(k), Name: n}}
|
return ResId{Gvk: gvk.FromKind(k), Name: n}
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
noNamespace = "~X"
|
noNamespace = "~X"
|
||||||
noPrefix = "~P"
|
|
||||||
noName = "~N"
|
noName = "~N"
|
||||||
noSuffix = "~S"
|
|
||||||
separator = "|"
|
separator = "|"
|
||||||
)
|
)
|
||||||
|
|
||||||
// String of ResId based on GVK, name and prefix
|
// String of ResId based on GVK, name and prefix
|
||||||
func (n ResId) String() string {
|
func (id ResId) String() string {
|
||||||
ns := n.ItemId.Namespace
|
ns := id.Namespace
|
||||||
if ns == "" {
|
if ns == "" {
|
||||||
ns = noNamespace
|
ns = noNamespace
|
||||||
}
|
}
|
||||||
p := n.Prefix
|
nm := id.Name
|
||||||
if p == "" {
|
|
||||||
p = noPrefix
|
|
||||||
}
|
|
||||||
nm := n.ItemId.Name
|
|
||||||
if nm == "" {
|
if nm == "" {
|
||||||
nm = noName
|
nm = noName
|
||||||
}
|
}
|
||||||
s := n.Suffix
|
|
||||||
if s == "" {
|
|
||||||
s = noSuffix
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(
|
return strings.Join(
|
||||||
[]string{n.ItemId.Gvk.String(), ns, p, nm, s}, separator)
|
[]string{id.Gvk.String(), ns, nm}, separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromString(s string) ResId {
|
||||||
|
values := strings.Split(s, separator)
|
||||||
|
g := gvk.FromString(values[0])
|
||||||
|
|
||||||
|
ns := values[1]
|
||||||
|
if ns == noNamespace {
|
||||||
|
ns = ""
|
||||||
|
}
|
||||||
|
nm := values[2]
|
||||||
|
if nm == noName {
|
||||||
|
nm = ""
|
||||||
|
}
|
||||||
|
return ResId{
|
||||||
|
Gvk: g,
|
||||||
|
Namespace: ns,
|
||||||
|
Name: nm,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GvknString of ResId based on GVK and name
|
// GvknString of ResId based on GVK and name
|
||||||
func (n ResId) GvknString() string {
|
func (id ResId) GvknString() string {
|
||||||
return n.ItemId.Gvk.String() + separator + n.ItemId.Name
|
return id.Gvk.String() + separator + id.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// GvknEquals returns true if the other id matches
|
// GvknEquals returns true if the other id matches
|
||||||
// Group/Version/Kind/name.
|
// Group/Version/Kind/name.
|
||||||
func (n ResId) GvknEquals(id ResId) bool {
|
func (id ResId) GvknEquals(o ResId) bool {
|
||||||
return n.ItemId.Name == id.ItemId.Name && n.ItemId.Gvk.Equals(id.ItemId.Gvk)
|
return id.Name == o.Name && id.Gvk.Equals(o.Gvk)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NsGvknEquals returns true if the other id matches
|
// Equals returns true if the other id matches
|
||||||
// namespace/Group/Version/Kind/name.
|
// namespace/Group/Version/Kind/name.
|
||||||
func (n ResId) NsGvknEquals(id ResId) bool {
|
func (id ResId) Equals(o ResId) bool {
|
||||||
// TODO: same a n.ItemId.Equals(id.ItemId)
|
return id.Namespace == o.Namespace && id.GvknEquals(o)
|
||||||
return n.ItemId.Namespace == id.ItemId.Namespace && n.GvknEquals(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gvk returns Group/Version/Kind of the resource.
|
|
||||||
func (n ResId) Gvk() gvk.Gvk {
|
|
||||||
return n.ItemId.Gvk
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name returns resource name.
|
|
||||||
func (n ResId) Name() string {
|
|
||||||
return n.ItemId.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Namespace returns resource namespace.
|
|
||||||
func (n ResId) Namespace() string {
|
|
||||||
return n.ItemId.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyWithNewPrefixSuffix make a new copy from current ResId
|
|
||||||
// and append a new prefix and suffix
|
|
||||||
func (n ResId) CopyWithNewPrefixSuffix(p, s string) ResId {
|
|
||||||
result := n
|
|
||||||
if p != "" {
|
|
||||||
result.Prefix = n.concatPrefix(p)
|
|
||||||
}
|
|
||||||
if s != "" {
|
|
||||||
result.Suffix = n.concatSuffix(s)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyWithNewNamespace make a new copy from current ResId and set a new namespace
|
|
||||||
func (n ResId) CopyWithNewNamespace(ns string) ResId {
|
|
||||||
result := n
|
|
||||||
result.ItemId.Namespace = ns
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasSameLeftmostPrefix check if two ResIds have the same
|
|
||||||
// left most prefix.
|
|
||||||
func (n ResId) HasSameLeftmostPrefix(id ResId) bool {
|
|
||||||
prefixes1 := n.prefixList()
|
|
||||||
prefixes2 := id.prefixList()
|
|
||||||
return prefixes1[0] == prefixes2[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasSameRightmostSuffix check if two ResIds have the same
|
|
||||||
// right most suffix.
|
|
||||||
func (n ResId) HasSameRightmostSuffix(id ResId) bool {
|
|
||||||
suffixes1 := n.suffixList()
|
|
||||||
suffixes2 := id.suffixList()
|
|
||||||
return suffixes1[len(suffixes1)-1] == suffixes2[len(suffixes2)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n ResId) concatPrefix(p string) string {
|
|
||||||
if p == "" {
|
|
||||||
return n.Prefix
|
|
||||||
}
|
|
||||||
if n.Prefix == "" {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
return p + ":" + n.Prefix
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n ResId) concatSuffix(s string) string {
|
|
||||||
if s == "" {
|
|
||||||
return n.Suffix
|
|
||||||
}
|
|
||||||
if n.Suffix == "" {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return n.Suffix + ":" + s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n ResId) prefixList() []string {
|
|
||||||
return strings.Split(n.Prefix, ":")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n ResId) suffixList() []string {
|
|
||||||
return strings.Split(n.Suffix, ":")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 resid
|
package resid
|
||||||
|
|
||||||
@@ -28,93 +15,65 @@ var stringTests = []struct {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"g_v_k|ns|p|nm|s",
|
"g_v_k|ns|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_v_k|ns|p|nm|s",
|
"~G_v_k|ns|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_k|ns|p|nm|s",
|
"~G_~V_k|ns|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|ns|p|nm|s",
|
"~G_~V_~K|ns|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|~X|p|nm|s",
|
"~G_~V_~K|~X|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|~X|~P|nm|s",
|
"~G_~V_~K|~X|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
},
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|~X|~P|~N|s",
|
"~G_~V_~K|~X|~N",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|~X|~P|~N|~S",
|
"~G_~V_~K|~X|~N",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{},
|
ResId{},
|
||||||
"~G_~V_~K|~X|~P|~N|~S",
|
"~G_~V_~K|~X|~N",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,87 +91,59 @@ var gvknStringTests = []struct {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"g_v_k|nm",
|
"g_v_k|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_v_k|nm",
|
"~G_v_k|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_k|nm",
|
"~G_~V_k|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "ns",
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|nm",
|
"~G_~V_~K|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "p",
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|nm",
|
"~G_~V_~K|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|nm",
|
"~G_~V_~K|nm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
},
|
|
||||||
Suffix: "s",
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|",
|
"~G_~V_~K|",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ResId{
|
ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{},
|
||||||
Gvk: gvk.Gvk{},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"~G_~V_~K|",
|
"~G_~V_~K|",
|
||||||
},
|
},
|
||||||
@@ -238,129 +169,81 @@ var GvknEqualsTest = []struct {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
id1: ResId{
|
id1: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "X",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "AA",
|
|
||||||
Suffix: "aa",
|
|
||||||
},
|
},
|
||||||
id2: ResId{
|
id2: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "X",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "BB",
|
|
||||||
Suffix: "bb",
|
|
||||||
},
|
},
|
||||||
gVknResult: true,
|
gVknResult: true,
|
||||||
nSgVknResult: true,
|
nSgVknResult: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id1: ResId{
|
id1: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "X",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "AA",
|
|
||||||
Suffix: "aa",
|
|
||||||
},
|
},
|
||||||
id2: ResId{
|
id2: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "Z",
|
||||||
Namespace: "Z",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "BB",
|
|
||||||
Suffix: "bb",
|
|
||||||
},
|
},
|
||||||
gVknResult: true,
|
gVknResult: true,
|
||||||
nSgVknResult: false,
|
nSgVknResult: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id1: ResId{
|
id1: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "X",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "AA",
|
|
||||||
Suffix: "aa",
|
|
||||||
},
|
},
|
||||||
id2: ResId{
|
id2: ResId{
|
||||||
ItemId: ItemId{
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "BB",
|
|
||||||
Suffix: "bb",
|
|
||||||
},
|
},
|
||||||
gVknResult: true,
|
gVknResult: true,
|
||||||
nSgVknResult: false,
|
nSgVknResult: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id1: ResId{
|
id1: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "X",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "AA",
|
|
||||||
Suffix: "aa",
|
|
||||||
},
|
},
|
||||||
id2: ResId{
|
id2: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "Z",
|
||||||
Namespace: "Z",
|
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "BB",
|
|
||||||
Suffix: "bb",
|
|
||||||
},
|
},
|
||||||
gVknResult: true,
|
gVknResult: true,
|
||||||
nSgVknResult: false,
|
nSgVknResult: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id1: ResId{
|
id1: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "X",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "AA",
|
|
||||||
Suffix: "aa",
|
|
||||||
},
|
},
|
||||||
id2: ResId{
|
id2: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "Z",
|
||||||
Namespace: "Z",
|
Gvk: gvk.Gvk{Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "BB",
|
|
||||||
Suffix: "bb",
|
|
||||||
},
|
},
|
||||||
gVknResult: true,
|
gVknResult: true,
|
||||||
nSgVknResult: false,
|
nSgVknResult: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id1: ResId{
|
id1: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "X",
|
||||||
Namespace: "X",
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "AA",
|
|
||||||
Suffix: "aa",
|
|
||||||
},
|
},
|
||||||
id2: ResId{
|
id2: ResId{
|
||||||
ItemId: ItemId{
|
Namespace: "Z",
|
||||||
Namespace: "Z",
|
Name: "nm",
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "BB",
|
|
||||||
Suffix: "bb",
|
|
||||||
},
|
},
|
||||||
gVknResult: true,
|
gVknResult: true,
|
||||||
nSgVknResult: false,
|
nSgVknResult: false,
|
||||||
@@ -373,59 +256,52 @@ func TestEquals(t *testing.T) {
|
|||||||
t.Fatalf("GvknEquals(\n%v,\n%v\n) should be %v",
|
t.Fatalf("GvknEquals(\n%v,\n%v\n) should be %v",
|
||||||
tst.id1, tst.id2, tst.gVknResult)
|
tst.id1, tst.id2, tst.gVknResult)
|
||||||
}
|
}
|
||||||
if tst.id1.NsGvknEquals(tst.id2) != tst.nSgVknResult {
|
if tst.id1.Equals(tst.id2) != tst.nSgVknResult {
|
||||||
t.Fatalf("NsGvknEquals(\n%v,\n%v\n) should be %v",
|
t.Fatalf("NsGvknEquals(\n%v,\n%v\n) should be %v",
|
||||||
tst.id1, tst.id2, tst.nSgVknResult)
|
tst.id1, tst.id2, tst.nSgVknResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCopyWithNewPrefixSuffix(t *testing.T) {
|
var ids = []ResId{
|
||||||
r1 := ResId{
|
{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
},
|
||||||
},
|
{
|
||||||
Prefix: "a",
|
Namespace: "ns",
|
||||||
Suffix: "b",
|
Gvk: gvk.Gvk{Version: "v", Kind: "k"},
|
||||||
}
|
Name: "nm",
|
||||||
r2 := r1.CopyWithNewPrefixSuffix("p-", "-s")
|
},
|
||||||
expected := ResId{
|
{
|
||||||
ItemId: ItemId{
|
Namespace: "ns",
|
||||||
Namespace: "X",
|
Gvk: gvk.Gvk{Kind: "k"},
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
Name: "nm",
|
||||||
Name: "nm",
|
},
|
||||||
},
|
{
|
||||||
Prefix: "p-a",
|
Namespace: "ns",
|
||||||
Suffix: "b-s",
|
Gvk: gvk.Gvk{},
|
||||||
}
|
Name: "nm",
|
||||||
if !r2.GvknEquals(expected) {
|
},
|
||||||
t.Fatalf("%v should equal %v", r2, expected)
|
{
|
||||||
}
|
Gvk: gvk.Gvk{},
|
||||||
|
Name: "nm",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Gvk: gvk.Gvk{},
|
||||||
|
Name: "nm",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Gvk: gvk.Gvk{},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCopyWithNewNamespace(t *testing.T) {
|
func TestFromString(t *testing.T) {
|
||||||
r1 := ResId{
|
for _, id := range ids {
|
||||||
ItemId: ItemId{
|
newId := FromString(id.String())
|
||||||
Namespace: "X",
|
if newId != id {
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
t.Fatalf("Actual: %v, Expected: '%s'", newId, id)
|
||||||
Name: "nm",
|
}
|
||||||
},
|
|
||||||
Prefix: "a",
|
|
||||||
Suffix: "b",
|
|
||||||
}
|
|
||||||
r2 := r1.CopyWithNewNamespace("zzz")
|
|
||||||
expected := ResId{
|
|
||||||
ItemId: ItemId{
|
|
||||||
Namespace: "zzz",
|
|
||||||
Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
|
|
||||||
Name: "nm",
|
|
||||||
},
|
|
||||||
Prefix: "a",
|
|
||||||
Suffix: "b",
|
|
||||||
}
|
|
||||||
if !r2.GvknEquals(expected) {
|
|
||||||
t.Fatalf("%v should equal %v", r2, expected)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"sigs.k8s.io/kustomize/internal/kusterr"
|
"sigs.k8s.io/kustomize/internal/kusterr"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
"sigs.k8s.io/kustomize/pkg/types"
|
"sigs.k8s.io/kustomize/pkg/types"
|
||||||
)
|
)
|
||||||
@@ -63,29 +62,6 @@ func (rmF *Factory) NewResMapFromBytes(b []byte) (ResMap, error) {
|
|||||||
return newResMapFromResourceSlice(resources)
|
return newResMapFromResourceSlice(resources)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated.
|
|
||||||
// FromMap returns a ResMap with arbitrary internal ordering,
|
|
||||||
// panicing on error. For tests only.
|
|
||||||
// See also ErrorIfNotEqualSets.
|
|
||||||
func FromMap(arg map[resid.ResId]*resource.Resource) ResMap {
|
|
||||||
result, err := fromMap(arg)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func fromMap(arg map[resid.ResId]*resource.Resource) (ResMap, error) {
|
|
||||||
result := New()
|
|
||||||
for id, r := range arg {
|
|
||||||
err := result.AppendWithId(id, r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewResMapFromConfigMapArgs returns a Resource slice given
|
// NewResMapFromConfigMapArgs returns a Resource slice given
|
||||||
// a configmap metadata slice from kustomization file.
|
// a configmap metadata slice from kustomization file.
|
||||||
func (rmF *Factory) NewResMapFromConfigMapArgs(
|
func (rmF *Factory) NewResMapFromConfigMapArgs(
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ metadata:
|
|||||||
if m.Size() != 3 {
|
if m.Size() != 3 {
|
||||||
t.Fatalf("result should contain 3, but got %d", m.Size())
|
t.Fatalf("result should contain 3, but got %d", m.Size())
|
||||||
}
|
}
|
||||||
if err := expected.ErrorIfNotEqualSets(m); err != nil {
|
if err := expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ var _ sort.Interface = IdSlice{}
|
|||||||
func (a IdSlice) Len() int { return len(a) }
|
func (a IdSlice) Len() int { return len(a) }
|
||||||
func (a IdSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
func (a IdSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
func (a IdSlice) Less(i, j int) bool {
|
func (a IdSlice) Less(i, j int) bool {
|
||||||
if !a[i].Gvk().Equals(a[j].Gvk()) {
|
if !a[i].Gvk.Equals(a[j].Gvk) {
|
||||||
return a[i].Gvk().IsLessThan(a[j].Gvk())
|
return a[i].Gvk.IsLessThan(a[j].Gvk)
|
||||||
}
|
}
|
||||||
return a[i].String() < a[j].String()
|
return a[i].String() < a[j].String()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ package resmap
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
"sigs.k8s.io/kustomize/pkg/types"
|
"sigs.k8s.io/kustomize/pkg/types"
|
||||||
@@ -17,53 +17,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// ResMap is an interface describing operations on the
|
// ResMap is an interface describing operations on the
|
||||||
// core kustomize data structure.
|
// core kustomize data structure, a list of Resources.
|
||||||
//
|
//
|
||||||
// TODO: delete the commentary below when/if the issues
|
// Every Resource has two ResIds: OriginalId and CurId.
|
||||||
// discussed are addressed.
|
|
||||||
//
|
//
|
||||||
// It's a temporary(?) interface used during a refactoring
|
// A ResId is a tuple of {Namespace, Group, Version, Kind, Name}.
|
||||||
// from a bare map (map[resid.ResId]*resource.Resource) to a
|
|
||||||
// pointer to struct (currently named *resWrangler).
|
|
||||||
// Replacing it with a ptr to struct will ease click-thrus
|
|
||||||
// to implementation during development.
|
|
||||||
// OTOH, hackery in a PR might be easier to see if the
|
|
||||||
// interface is left in place.
|
|
||||||
//
|
//
|
||||||
// The old (bare map) ResMap had pervasive problems:
|
// In a ResMap, no two resources may have the same CurId,
|
||||||
|
// but they may have the same OriginalId. The latter can happen
|
||||||
|
// when mixing two or more different overlays apply different
|
||||||
|
// transformations to a common base.
|
||||||
//
|
//
|
||||||
// * It was mutated inside loops over itself.
|
|
||||||
//
|
|
||||||
// Bugs introduced this way were hard to find since the
|
|
||||||
// bare map was recursively passed everywhere, sometimes
|
|
||||||
// mid loop.
|
|
||||||
//
|
|
||||||
// * Its keys (ResId) aren't opaque, and are effectively
|
|
||||||
// mutated (via copy and replace) for data storage reasons
|
|
||||||
// as a hack.
|
|
||||||
//
|
|
||||||
// ResId was modified a long time ago as a hack to
|
|
||||||
// store name transformation data (prefix and suffix),
|
|
||||||
// destabilizing the basic map concept and resulting
|
|
||||||
// in the need for silly ResId functions like
|
|
||||||
// NewResIdWithPrefixSuffixNamespace, NsGvknEquals,
|
|
||||||
// HasSameLeftmostPrefix, CopyWithNewPrefixSuffix, etc.
|
|
||||||
// plus logic to use them, and overly complex tests.
|
|
||||||
//
|
|
||||||
// If this data were stored in the Resource object
|
|
||||||
// (not in Kunstructured, but as a sibling to it next to
|
|
||||||
// GenArgs, references, etc.) then much code could be
|
|
||||||
// deleted and the remainder simplified.
|
|
||||||
//
|
|
||||||
// * It doesn't preserve (by definition) value order.
|
|
||||||
//
|
|
||||||
// Preserving order is now needed to support
|
|
||||||
// transformer plugins (they aren't commutative).
|
|
||||||
//
|
|
||||||
// One way to fix this is deprecate use of ResId as the
|
|
||||||
// key in favor of ItemId. See use of the resmap.Remove
|
|
||||||
// function to spot the places that need fixing to allow
|
|
||||||
// this.
|
|
||||||
type ResMap interface {
|
type ResMap interface {
|
||||||
// Size reports the number of resources.
|
// Size reports the number of resources.
|
||||||
Size() int
|
Size() int
|
||||||
@@ -73,17 +37,12 @@ type ResMap interface {
|
|||||||
// as appended.
|
// as appended.
|
||||||
Resources() []*resource.Resource
|
Resources() []*resource.Resource
|
||||||
|
|
||||||
// Append adds a Resource, automatically computing its
|
// Append adds a Resource.
|
||||||
// associated Id.
|
// Error on OrgId collision.
|
||||||
// Error on Id collision.
|
|
||||||
Append(*resource.Resource) error
|
Append(*resource.Resource) error
|
||||||
|
|
||||||
// AppendWithId adds a Resource with the given Id.
|
|
||||||
// Error on Id collision.
|
|
||||||
AppendWithId(resid.ResId, *resource.Resource) error
|
|
||||||
|
|
||||||
// AppendAll appends another ResMap to self,
|
// AppendAll appends another ResMap to self,
|
||||||
// failing on any Id collision.
|
// failing on any OrgId collision.
|
||||||
AppendAll(ResMap) error
|
AppendAll(ResMap) error
|
||||||
|
|
||||||
// AbsorbAll appends, replaces or merges the contents
|
// AbsorbAll appends, replaces or merges the contents
|
||||||
@@ -99,49 +58,56 @@ type ResMap interface {
|
|||||||
// self, then its behavior _cannot_ be merge or replace.
|
// self, then its behavior _cannot_ be merge or replace.
|
||||||
AbsorbAll(ResMap) error
|
AbsorbAll(ResMap) error
|
||||||
|
|
||||||
// AsMap returns (ResId, *Resource) pairs in
|
|
||||||
// arbitrary order via a generated map.
|
|
||||||
// The map is discardable, and edits to map structure
|
|
||||||
// have no impact on the ResMap.
|
|
||||||
// The Ids are copies, but the resources are pointers,
|
|
||||||
// so the resources themselves can be modified.
|
|
||||||
AsMap() map[resid.ResId]*resource.Resource
|
|
||||||
|
|
||||||
// AsYaml returns the yaml form of resources.
|
// AsYaml returns the yaml form of resources.
|
||||||
AsYaml() ([]byte, error)
|
AsYaml() ([]byte, error)
|
||||||
|
|
||||||
// Gets the resource with the given Id, else nil.
|
// GetByIndex returns a resource at the given index,
|
||||||
GetById(resid.ResId) *resource.Resource
|
// nil if out of range.
|
||||||
|
GetByIndex(int) *resource.Resource
|
||||||
|
|
||||||
// ReplaceResource associates a new resource with
|
// GetIndexOfCurrentId returns the index of the resource
|
||||||
// an _existing_ Id.
|
// with the given CurId.
|
||||||
// Error if Id unknown, or if some other Id points
|
// Returns error if there is more than one match.
|
||||||
// to the same resource object.
|
// Returns (-1, nil) if there is no match.
|
||||||
ReplaceResource(resid.ResId, *resource.Resource) error
|
GetIndexOfCurrentId(id resid.ResId) (int, error)
|
||||||
|
|
||||||
// AllIds returns all known Ids.
|
// GetMatchingResourcesByCurrentId returns the resources
|
||||||
// Result order is arbitrary.
|
// who's CurId is matched by the argument.
|
||||||
|
GetMatchingResourcesByCurrentId(matches IdMatcher) []*resource.Resource
|
||||||
|
|
||||||
|
// GetMatchingResourcesByOriginalId returns the resources
|
||||||
|
// who's OriginalId is matched by the argument.
|
||||||
|
GetMatchingResourcesByOriginalId(matches IdMatcher) []*resource.Resource
|
||||||
|
|
||||||
|
// GetByCurrentId is shorthand for calling
|
||||||
|
// GetMatchingResourcesByCurrentId with a matcher requiring
|
||||||
|
// an exact match, returning an error on multiple or no matches.
|
||||||
|
GetByCurrentId(resid.ResId) (*resource.Resource, error)
|
||||||
|
|
||||||
|
// GetByOriginalId is shorthand for calling
|
||||||
|
// GetMatchingResourcesByOriginalId with a matcher requiring
|
||||||
|
// an exact match, returning an error on multiple or no matches.
|
||||||
|
GetByOriginalId(resid.ResId) (*resource.Resource, error)
|
||||||
|
|
||||||
|
// Deprecated.
|
||||||
|
// Same as GetByOriginalId.
|
||||||
|
GetById(resid.ResId) (*resource.Resource, error)
|
||||||
|
|
||||||
|
// AllIds returns all CurrentIds.
|
||||||
AllIds() []resid.ResId
|
AllIds() []resid.ResId
|
||||||
|
|
||||||
// GetMatchingIds returns a slice of Ids that
|
// Replace replaces the resource with the matching CurId.
|
||||||
// satisfy the given matcher function.
|
// Error if there's no match or more than one match.
|
||||||
// Result order is arbitrary.
|
// Returns the index where the replacement happened.
|
||||||
GetMatchingIds(IdMatcher) []resid.ResId
|
Replace(*resource.Resource) (int, error)
|
||||||
|
|
||||||
// Remove removes the Id and the resource it points to.
|
// Remove removes the resource whose CurId matches the argument.
|
||||||
|
// Error if not found.
|
||||||
Remove(resid.ResId) error
|
Remove(resid.ResId) error
|
||||||
|
|
||||||
// Clear removes all resources and Ids.
|
// Clear removes all resources and Ids.
|
||||||
Clear()
|
Clear()
|
||||||
|
|
||||||
// SubsetThatCouldBeReferencedById returns a ResMap subset
|
|
||||||
// of self with resources that could be referenced by the
|
|
||||||
// resource represented by the argument Id.
|
|
||||||
// This is a filter; it excludes things that cannot be
|
|
||||||
// referenced by the Id's resource, e.g. objects in other
|
|
||||||
// namespaces. Cluster wide objects are never excluded.
|
|
||||||
SubsetThatCouldBeReferencedById(resid.ResId) ResMap
|
|
||||||
|
|
||||||
// SubsetThatCouldBeReferencedByResource returns a ResMap subset
|
// SubsetThatCouldBeReferencedByResource returns a ResMap subset
|
||||||
// of self with resources that could be referenced by the
|
// of self with resources that could be referenced by the
|
||||||
// resource argument.
|
// resource argument.
|
||||||
@@ -158,8 +124,8 @@ type ResMap interface {
|
|||||||
ShallowCopy() ResMap
|
ShallowCopy() ResMap
|
||||||
|
|
||||||
// ErrorIfNotEqualSets returns an error if the
|
// ErrorIfNotEqualSets returns an error if the
|
||||||
// argument doesn't have the same Ids and resource
|
// argument doesn't have the same resources as self.
|
||||||
// data as self. Ordering is _not_ taken into account,
|
// Ordering is _not_ taken into account,
|
||||||
// as this function was solely used in tests written
|
// as this function was solely used in tests written
|
||||||
// before internal resource order was maintained,
|
// before internal resource order was maintained,
|
||||||
// and those tests are initialized with maps which
|
// and those tests are initialized with maps which
|
||||||
@@ -174,7 +140,7 @@ type ResMap interface {
|
|||||||
// data as self, in the same order.
|
// data as self, in the same order.
|
||||||
// Meta information is ignored; this is similar
|
// Meta information is ignored; this is similar
|
||||||
// to comparing the AsYaml() strings, but allows
|
// to comparing the AsYaml() strings, but allows
|
||||||
// for printing pointers, etc.
|
// for more informed errors on not equals.
|
||||||
ErrorIfNotEqualLists(ResMap) error
|
ErrorIfNotEqualLists(ResMap) error
|
||||||
|
|
||||||
// Debug prints the ResMap.
|
// Debug prints the ResMap.
|
||||||
@@ -190,14 +156,6 @@ type resWrangler struct {
|
|||||||
// specify in kustomizations to be maintained and
|
// specify in kustomizations to be maintained and
|
||||||
// available as an option for final YAML rendering.
|
// available as an option for final YAML rendering.
|
||||||
rList []*resource.Resource
|
rList []*resource.Resource
|
||||||
|
|
||||||
// A map from id to an index into rList.
|
|
||||||
// At the time of writing, the ids used as keys in
|
|
||||||
// this map cannot be assumed to match the id
|
|
||||||
// generated from the resource.Id() method pointed
|
|
||||||
// to by the map's value (via rList). These keys
|
|
||||||
// have been hacked to store prefix/suffix data.
|
|
||||||
rIndex map[resid.ResId]int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOne() *resWrangler {
|
func newOne() *resWrangler {
|
||||||
@@ -209,14 +167,10 @@ func newOne() *resWrangler {
|
|||||||
// Clear implements ResMap.
|
// Clear implements ResMap.
|
||||||
func (m *resWrangler) Clear() {
|
func (m *resWrangler) Clear() {
|
||||||
m.rList = nil
|
m.rList = nil
|
||||||
m.rIndex = make(map[resid.ResId]int)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size implements ResMap.
|
// Size implements ResMap.
|
||||||
func (m *resWrangler) Size() int {
|
func (m *resWrangler) Size() int {
|
||||||
if len(m.rList) != len(m.rIndex) {
|
|
||||||
panic("class size invariant violation")
|
|
||||||
}
|
|
||||||
return len(m.rList)
|
return len(m.rList)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,94 +190,51 @@ func (m *resWrangler) Resources() []*resource.Resource {
|
|||||||
return tmp
|
return tmp
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetById implements ResMap.
|
|
||||||
func (m *resWrangler) GetById(id resid.ResId) *resource.Resource {
|
|
||||||
if i, ok := m.rIndex[id]; ok {
|
|
||||||
return m.rList[i]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append implements ResMap.
|
// Append implements ResMap.
|
||||||
func (m *resWrangler) Append(res *resource.Resource) error {
|
func (m *resWrangler) Append(res *resource.Resource) error {
|
||||||
return m.AppendWithId(res.Id(), res)
|
id := res.CurId()
|
||||||
|
if r := m.GetMatchingResourcesByCurrentId(id.Equals); len(r) > 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"may not add resource with an already registered id: %s", id)
|
||||||
|
}
|
||||||
|
m.rList = append(m.rList, res)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove implements ResMap.
|
// Remove implements ResMap.
|
||||||
func (m *resWrangler) Remove(adios resid.ResId) error {
|
func (m *resWrangler) Remove(adios resid.ResId) error {
|
||||||
tmp := newOne()
|
tmp := newOne()
|
||||||
for i, r := range m.rList {
|
for _, r := range m.rList {
|
||||||
id, err := m.idMappingToIndex(i)
|
if r.CurId() != adios {
|
||||||
if err != nil {
|
tmp.Append(r)
|
||||||
return errors.Wrap(err, "assumption failure in remove")
|
|
||||||
}
|
|
||||||
if id != adios {
|
|
||||||
tmp.AppendWithId(id, r)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tmp.Size() != m.Size()-1 {
|
if tmp.Size() != m.Size()-1 {
|
||||||
return fmt.Errorf("id %s not found in removal", adios)
|
return fmt.Errorf("id %s not found in removal", adios)
|
||||||
}
|
}
|
||||||
m.rIndex = tmp.rIndex
|
|
||||||
m.rList = tmp.rList
|
m.rList = tmp.rList
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendWithId implements ResMap.
|
// Replace implements ResMap.
|
||||||
func (m *resWrangler) AppendWithId(id resid.ResId, res *resource.Resource) error {
|
func (m *resWrangler) Replace(res *resource.Resource) (int, error) {
|
||||||
if already, ok := m.rIndex[id]; ok {
|
id := res.CurId()
|
||||||
return fmt.Errorf(
|
i, err := m.GetIndexOfCurrentId(id)
|
||||||
"attempt to add res %s at id %s; that id already maps to %d",
|
if err != nil {
|
||||||
res, id, already)
|
return -1, errors.Wrap(err, "in Replace")
|
||||||
}
|
}
|
||||||
i := m.indexOfResource(res)
|
if i < 0 {
|
||||||
if i >= 0 {
|
return -1, fmt.Errorf("cannot find resource with id %s to replace", id)
|
||||||
return fmt.Errorf(
|
|
||||||
"attempt to add res %s that is already held",
|
|
||||||
res)
|
|
||||||
}
|
}
|
||||||
m.rList = append(m.rList, res)
|
m.rList[i] = res
|
||||||
m.rIndex[id] = len(m.rList) - 1
|
return i, nil
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplaceResource implements ResMap.
|
|
||||||
func (m *resWrangler) ReplaceResource(
|
|
||||||
id resid.ResId, newGuy *resource.Resource) error {
|
|
||||||
insertAt, ok := m.rIndex[id]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"attempt to reset resource at id %s; that id not used", id)
|
|
||||||
}
|
|
||||||
existingSpot := m.indexOfResource(newGuy)
|
|
||||||
if insertAt == existingSpot {
|
|
||||||
// Be idempotent.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if existingSpot >= 0 {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"the new resource %s is already present", newGuy.Id())
|
|
||||||
}
|
|
||||||
m.rList[insertAt] = newGuy
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AsMap implements ResMap.
|
|
||||||
func (m *resWrangler) AsMap() map[resid.ResId]*resource.Resource {
|
|
||||||
result := make(map[resid.ResId]*resource.Resource, m.Size())
|
|
||||||
for id, i := range m.rIndex {
|
|
||||||
result[id] = m.rList[i]
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllIds implements ResMap.
|
// AllIds implements ResMap.
|
||||||
func (m *resWrangler) AllIds() (ids []resid.ResId) {
|
func (m *resWrangler) AllIds() (ids []resid.ResId) {
|
||||||
ids = make([]resid.ResId, m.Size())
|
ids = make([]resid.ResId, m.Size())
|
||||||
i := 0
|
for i, r := range m.rList {
|
||||||
for id := range m.rIndex {
|
ids[i] = r.CurId()
|
||||||
ids[i] = id
|
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -338,7 +249,7 @@ func (m *resWrangler) Debug(title string) {
|
|||||||
} else {
|
} else {
|
||||||
fmt.Println("---")
|
fmt.Println("---")
|
||||||
}
|
}
|
||||||
fmt.Printf("# %d %s\n", i, m.debugIdMappingToIndex(i))
|
fmt.Printf("# %d %s\n", i, r.OrgId())
|
||||||
blob, err := yaml.Marshal(r.Map())
|
blob, err := yaml.Marshal(r.Map())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -347,45 +258,91 @@ func (m *resWrangler) Debug(title string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *resWrangler) debugIdMappingToIndex(i int) string {
|
|
||||||
id, err := m.idMappingToIndex(i)
|
|
||||||
if err != nil {
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
return id.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *resWrangler) idMappingToIndex(i int) (resid.ResId, error) {
|
|
||||||
var foundId resid.ResId
|
|
||||||
found := false
|
|
||||||
for id, index := range m.rIndex {
|
|
||||||
if index == i {
|
|
||||||
if found {
|
|
||||||
return foundId, fmt.Errorf("found multiple")
|
|
||||||
}
|
|
||||||
found = true
|
|
||||||
foundId = id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return foundId, fmt.Errorf("cannot find index %d", i)
|
|
||||||
}
|
|
||||||
return foundId, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type IdMatcher func(resid.ResId) bool
|
type IdMatcher func(resid.ResId) bool
|
||||||
|
|
||||||
// GetMatchingIds implements ResMap.
|
// GetByIndex implements ResMap.
|
||||||
func (m *resWrangler) GetMatchingIds(matches IdMatcher) []resid.ResId {
|
func (m *resWrangler) GetByIndex(i int) *resource.Resource {
|
||||||
var result []resid.ResId
|
if i < 0 || i >= m.Size() {
|
||||||
for id := range m.rIndex {
|
return nil
|
||||||
if matches(id) {
|
}
|
||||||
result = append(result, id)
|
return m.rList[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIndexOfCurrentId implements ResMap.
|
||||||
|
func (m *resWrangler) GetIndexOfCurrentId(id resid.ResId) (int, error) {
|
||||||
|
count := 0
|
||||||
|
result := -1
|
||||||
|
for i, r := range m.rList {
|
||||||
|
if id.Equals(r.CurId()) {
|
||||||
|
count++
|
||||||
|
result = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count > 1 {
|
||||||
|
return -1, fmt.Errorf("id matched %d resources", count)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type IdFromResource func(r *resource.Resource) resid.ResId
|
||||||
|
|
||||||
|
func GetOriginalId(r *resource.Resource) resid.ResId { return r.OrgId() }
|
||||||
|
func GetCurrentId(r *resource.Resource) resid.ResId { return r.CurId() }
|
||||||
|
|
||||||
|
// GetMatchingResourcesByCurrentId implements ResMap.
|
||||||
|
func (m *resWrangler) GetMatchingResourcesByCurrentId(
|
||||||
|
matches IdMatcher) []*resource.Resource {
|
||||||
|
return m.filteredById(matches, GetCurrentId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMatchingResourcesByOriginalId implements ResMap.
|
||||||
|
func (m *resWrangler) GetMatchingResourcesByOriginalId(
|
||||||
|
matches IdMatcher) []*resource.Resource {
|
||||||
|
return m.filteredById(matches, GetOriginalId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *resWrangler) filteredById(
|
||||||
|
matches IdMatcher, idGetter IdFromResource) []*resource.Resource {
|
||||||
|
var result []*resource.Resource
|
||||||
|
for _, r := range m.rList {
|
||||||
|
if matches(idGetter(r)) {
|
||||||
|
result = append(result, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByCurrentId implements ResMap.
|
||||||
|
func (m *resWrangler) GetByCurrentId(
|
||||||
|
id resid.ResId) (*resource.Resource, error) {
|
||||||
|
return demandOneMatch(m.GetMatchingResourcesByCurrentId, id, "Current")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetByOriginalId implements ResMap.
|
||||||
|
func (m *resWrangler) GetByOriginalId(
|
||||||
|
id resid.ResId) (*resource.Resource, error) {
|
||||||
|
return demandOneMatch(m.GetMatchingResourcesByOriginalId, id, "Original")
|
||||||
|
}
|
||||||
|
|
||||||
|
type resFinder func(IdMatcher) []*resource.Resource
|
||||||
|
|
||||||
|
func demandOneMatch(
|
||||||
|
f resFinder, id resid.ResId, s string) (*resource.Resource, error) {
|
||||||
|
r := f(id.Equals)
|
||||||
|
if len(r) == 1 {
|
||||||
|
return r[0], nil
|
||||||
|
}
|
||||||
|
if len(r) > 1 {
|
||||||
|
return nil, fmt.Errorf("multiple matches for %sId %s", s, id)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no matches for %sId %s", s, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetById implements ResMap.
|
||||||
|
func (m *resWrangler) GetById(id resid.ResId) (*resource.Resource, error) {
|
||||||
|
return m.GetByCurrentId(id)
|
||||||
|
}
|
||||||
|
|
||||||
// AsYaml implements ResMap.
|
// AsYaml implements ResMap.
|
||||||
func (m *resWrangler) AsYaml() ([]byte, error) {
|
func (m *resWrangler) AsYaml() ([]byte, error) {
|
||||||
firstObj := true
|
firstObj := true
|
||||||
@@ -421,17 +378,28 @@ func (m *resWrangler) ErrorIfNotEqualSets(other ResMap) error {
|
|||||||
"lists have different number of entries: %#v doesn't equal %#v",
|
"lists have different number of entries: %#v doesn't equal %#v",
|
||||||
m.rList, m2.rList)
|
m.rList, m2.rList)
|
||||||
}
|
}
|
||||||
for id, i := range m.rIndex {
|
seen := make(map[int]bool)
|
||||||
r1 := m.rList[i]
|
for _, r1 := range m.rList {
|
||||||
r2 := m2.GetById(id)
|
id := r1.CurId()
|
||||||
if r2 == nil {
|
others := m2.GetMatchingResourcesByCurrentId(id.Equals)
|
||||||
return fmt.Errorf("id in self missing from other; id: %s", id)
|
if len(others) < 0 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"id in self missing from other; id: %s", id)
|
||||||
}
|
}
|
||||||
|
if len(others) > 1 {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"id in self matches %d in other; id: %s", len(others), id)
|
||||||
|
}
|
||||||
|
r2 := others[0]
|
||||||
if !r1.KunstructEqual(r2) {
|
if !r1.KunstructEqual(r2) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"kuns equal mismatch: \n -- %s,\n -- %s\n\n--\n%#v\n------\n%#v\n",
|
"kunstruct not equal: \n -- %s,\n -- %s\n\n--\n%#v\n------\n%#v\n",
|
||||||
r1, r2, r1, r2)
|
r1, r2, r1, r2)
|
||||||
}
|
}
|
||||||
|
seen[m2.indexOfResource(r2)] = true
|
||||||
|
}
|
||||||
|
if len(seen) != m.Size() {
|
||||||
|
return fmt.Errorf("counting problem %d != %d", len(seen), m.Size())
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -449,10 +417,10 @@ func (m *resWrangler) ErrorIfNotEqualLists(other ResMap) error {
|
|||||||
}
|
}
|
||||||
for i, r1 := range m.rList {
|
for i, r1 := range m.rList {
|
||||||
r2 := m2.rList[i]
|
r2 := m2.rList[i]
|
||||||
if !r1.KunstructEqual(r2) {
|
if !r1.Equals(r2) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"Item i=%d differs:\n n1 = %s\n n2 = %s\n",
|
"Item i=%d differs:\n n1 = %s\n n2 = %s\n o1 = %s\n o2 = %s\n",
|
||||||
i, r1.Id(), r2.Id())
|
i, r1.OrgId(), r2.OrgId(), r1, r2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -479,34 +447,9 @@ func (m *resWrangler) DeepCopy() ResMap {
|
|||||||
// makeCopy copies the ResMap.
|
// makeCopy copies the ResMap.
|
||||||
func (m *resWrangler) makeCopy(copier resCopier) ResMap {
|
func (m *resWrangler) makeCopy(copier resCopier) ResMap {
|
||||||
result := &resWrangler{}
|
result := &resWrangler{}
|
||||||
result.rIndex = make(map[resid.ResId]int, m.Size())
|
|
||||||
result.rList = make([]*resource.Resource, m.Size())
|
result.rList = make([]*resource.Resource, m.Size())
|
||||||
for i, r := range m.rList {
|
for i, r := range m.rList {
|
||||||
result.rList[i] = copier(r)
|
result.rList[i] = copier(r)
|
||||||
id, err := m.idMappingToIndex(i)
|
|
||||||
if err != nil {
|
|
||||||
panic("corrupt index map")
|
|
||||||
}
|
|
||||||
result.rIndex[id] = i
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubsetThatCouldBeReferencedById implements ResMap.
|
|
||||||
func (m *resWrangler) SubsetThatCouldBeReferencedById(inputId resid.ResId) ResMap {
|
|
||||||
if inputId.Gvk().IsClusterKind() {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
result := New()
|
|
||||||
for id, i := range m.rIndex {
|
|
||||||
if id.Gvk().IsClusterKind() || id.Namespace() == inputId.Namespace() &&
|
|
||||||
id.HasSameLeftmostPrefix(inputId) &&
|
|
||||||
id.HasSameRightmostSuffix(inputId) {
|
|
||||||
err := result.AppendWithId(id, m.rList[i])
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -514,13 +457,13 @@ func (m *resWrangler) SubsetThatCouldBeReferencedById(inputId resid.ResId) ResMa
|
|||||||
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
// SubsetThatCouldBeReferencedByResource implements ResMap.
|
||||||
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
func (m *resWrangler) SubsetThatCouldBeReferencedByResource(
|
||||||
inputRes *resource.Resource) ResMap {
|
inputRes *resource.Resource) ResMap {
|
||||||
inputId := inputRes.Id()
|
inputId := inputRes.OrgId()
|
||||||
if inputId.Gvk().IsClusterKind() {
|
if inputId.IsClusterKind() {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
result := New()
|
result := New()
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
if r.Id().Gvk().IsClusterKind() || inputRes.InSameFuzzyNamespace(r) {
|
if r.OrgId().IsClusterKind() || inputRes.InSameFuzzyNamespace(r) {
|
||||||
err := result.Append(r)
|
err := result.Append(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -535,17 +478,8 @@ func (m *resWrangler) AppendAll(other ResMap) error {
|
|||||||
if other == nil {
|
if other == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
w2, ok := other.(*resWrangler)
|
for _, res := range other.Resources() {
|
||||||
if !ok {
|
if err := m.Append(res); err != nil {
|
||||||
panic("bad cast")
|
|
||||||
}
|
|
||||||
for i, res := range w2.Resources() {
|
|
||||||
id, err := w2.idMappingToIndex(i)
|
|
||||||
if err != nil {
|
|
||||||
panic("map is irrecoverably corrupted; " + err.Error())
|
|
||||||
}
|
|
||||||
err = m.AppendWithId(id, res)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -557,16 +491,8 @@ func (m *resWrangler) AbsorbAll(other ResMap) error {
|
|||||||
if other == nil {
|
if other == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
w2, ok := other.(*resWrangler)
|
for _, r := range other.Resources() {
|
||||||
if !ok {
|
err := m.appendReplaceOrMerge(r)
|
||||||
panic("bad cast")
|
|
||||||
}
|
|
||||||
for i, r := range w2.Resources() {
|
|
||||||
id, err := w2.idMappingToIndex(i)
|
|
||||||
if err != nil {
|
|
||||||
panic("map is irrecoverably corrupted; " + err.Error())
|
|
||||||
}
|
|
||||||
err = m.appendReplaceOrMerge(id, r)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -575,48 +501,52 @@ func (m *resWrangler) AbsorbAll(other ResMap) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *resWrangler) appendReplaceOrMerge(
|
func (m *resWrangler) appendReplaceOrMerge(
|
||||||
idForRes resid.ResId, res *resource.Resource) error {
|
res *resource.Resource) error {
|
||||||
matchedId := m.GetMatchingIds(idForRes.GvknEquals)
|
id := res.CurId()
|
||||||
switch len(matchedId) {
|
// Maybe also try by current id if nothing matches?
|
||||||
|
matches := m.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
||||||
|
switch len(matches) {
|
||||||
case 0:
|
case 0:
|
||||||
switch res.Behavior() {
|
switch res.Behavior() {
|
||||||
case types.BehaviorMerge, types.BehaviorReplace:
|
case types.BehaviorMerge, types.BehaviorReplace:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"id %#v does not exist; cannot merge or replace", idForRes)
|
"id %#v does not exist; cannot merge or replace", id)
|
||||||
default:
|
default:
|
||||||
// presumably types.BehaviorCreate
|
// presumably types.BehaviorCreate
|
||||||
err := m.AppendWithId(idForRes, res)
|
err := m.Append(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
mId := matchedId[0]
|
old := matches[0]
|
||||||
old := m.GetById(mId)
|
|
||||||
if old == nil {
|
if old == nil {
|
||||||
return fmt.Errorf("id lookup failure")
|
return fmt.Errorf("id lookup failure")
|
||||||
}
|
}
|
||||||
|
index := m.indexOfResource(old)
|
||||||
|
if index < 0 {
|
||||||
|
return fmt.Errorf("indexing problem")
|
||||||
|
}
|
||||||
switch res.Behavior() {
|
switch res.Behavior() {
|
||||||
case types.BehaviorReplace:
|
case types.BehaviorReplace:
|
||||||
res.Replace(old)
|
res.Replace(old)
|
||||||
err := m.ReplaceResource(mId, res)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case types.BehaviorMerge:
|
case types.BehaviorMerge:
|
||||||
res.Merge(old)
|
res.Merge(old)
|
||||||
err := m.ReplaceResource(mId, res)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"id %#v exists; must merge or replace", idForRes)
|
"id %#v exists; must merge or replace", id)
|
||||||
|
}
|
||||||
|
i, err := m.Replace(res)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if i != index {
|
||||||
|
return fmt.Errorf("unexpected index in replacement")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"found multiple objects %v that could accept merge of %v",
|
"found multiple objects %v that could accept merge of %v",
|
||||||
matchedId, idForRes)
|
matches, id)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
. "sigs.k8s.io/kustomize/pkg/resmap"
|
. "sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
@@ -55,10 +54,10 @@ func TestAppendRemove(t *testing.T) {
|
|||||||
doAppend(t, w1, makeCm(5))
|
doAppend(t, w1, makeCm(5))
|
||||||
doAppend(t, w1, makeCm(6))
|
doAppend(t, w1, makeCm(6))
|
||||||
doAppend(t, w1, makeCm(7))
|
doAppend(t, w1, makeCm(7))
|
||||||
doRemove(t, w1, makeCm(1).Id())
|
doRemove(t, w1, makeCm(1).OrgId())
|
||||||
doRemove(t, w1, makeCm(3).Id())
|
doRemove(t, w1, makeCm(3).OrgId())
|
||||||
doRemove(t, w1, makeCm(5).Id())
|
doRemove(t, w1, makeCm(5).OrgId())
|
||||||
doRemove(t, w1, makeCm(7).Id())
|
doRemove(t, w1, makeCm(7).OrgId())
|
||||||
|
|
||||||
w2 := New()
|
w2 := New()
|
||||||
doAppend(t, w2, makeCm(2))
|
doAppend(t, w2, makeCm(2))
|
||||||
@@ -79,7 +78,7 @@ func TestAppendRemove(t *testing.T) {
|
|||||||
func TestRemove(t *testing.T) {
|
func TestRemove(t *testing.T) {
|
||||||
w := New()
|
w := New()
|
||||||
r := makeCm(1)
|
r := makeCm(1)
|
||||||
err := w.Remove(r.Id())
|
err := w.Remove(r.OrgId())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error")
|
t.Fatalf("expected error")
|
||||||
}
|
}
|
||||||
@@ -87,20 +86,20 @@ func TestRemove(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = w.Remove(r.Id())
|
err = w.Remove(r.OrgId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
err = w.Remove(r.Id())
|
err = w.Remove(r.OrgId())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error")
|
t.Fatalf("expected error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReplaceResource(t *testing.T) {
|
func TestReplace(t *testing.T) {
|
||||||
cm5 := makeCm(5)
|
cm5 := makeCm(5)
|
||||||
cm700 := makeCm(700)
|
cm700 := makeCm(700)
|
||||||
cm888 := makeCm(888)
|
otherCm5 := makeCm(5)
|
||||||
|
|
||||||
w := New()
|
w := New()
|
||||||
doAppend(t, w, makeCm(1))
|
doAppend(t, w, makeCm(1))
|
||||||
@@ -112,40 +111,27 @@ func TestReplaceResource(t *testing.T) {
|
|||||||
doAppend(t, w, makeCm(7))
|
doAppend(t, w, makeCm(7))
|
||||||
|
|
||||||
oldSize := w.Size()
|
oldSize := w.Size()
|
||||||
err := w.ReplaceResource(cm5.Id(), cm700)
|
_, err := w.Replace(otherCm5)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if w.Size() != oldSize {
|
if w.Size() != oldSize {
|
||||||
t.Fatalf("unexpected size %d", w.Size())
|
t.Fatalf("unexpected size %d", w.Size())
|
||||||
}
|
}
|
||||||
if w.GetById(cm5.Id()) != cm700 {
|
if r, err := w.GetByCurrentId(cm5.OrgId()); err != nil || r != otherCm5 {
|
||||||
t.Fatalf("unexpected result")
|
t.Fatalf("unexpected result r=%s, err=%v", r.CurId(), err)
|
||||||
}
|
}
|
||||||
if err := w.Append(cm5); err == nil {
|
if err := w.Append(cm5); err == nil {
|
||||||
t.Fatalf("expected id already there error")
|
t.Fatalf("expected id already there error")
|
||||||
}
|
}
|
||||||
if err := w.AppendWithId(cm888.Id(), cm5); err != nil {
|
if err := w.Remove(cm5.OrgId()); err != nil {
|
||||||
// Okay to add with some unused Id.
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if err := w.Append(cm700); err == nil {
|
|
||||||
t.Fatalf("expected resource already there error")
|
|
||||||
}
|
|
||||||
if err := w.Remove(cm5.Id()); err != nil {
|
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
if err := w.Append(cm700); err != nil {
|
if err := w.Append(cm700); err != nil {
|
||||||
t.Fatalf("unexpected err: %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
if err := w.Append(cm5); err == nil {
|
|
||||||
t.Fatalf("expected err; object is still there under id 888")
|
|
||||||
}
|
|
||||||
if err := w.Remove(cm888.Id()); err != nil {
|
|
||||||
t.Fatalf("unexpected err: %v", err)
|
|
||||||
}
|
|
||||||
if err := w.Append(cm5); err != nil {
|
if err := w.Append(cm5); err != nil {
|
||||||
t.Fatalf("unexpected err; %v", err)
|
t.Fatalf("unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,205 +170,249 @@ metadata:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDemandOneGvknMatchForId(t *testing.T) {
|
func TestGetMatchingResourcesByCurrentId(t *testing.T) {
|
||||||
rm1 := FromMap(map[resid.ResId]*resource.Resource{
|
r1 := rf.FromMap(
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "cm1", "prefix1", "ns1"): rf.FromMap(
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"apiVersion": "v1",
|
"kind": "ConfigMap",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "alice",
|
||||||
"name": "cm1",
|
},
|
||||||
},
|
})
|
||||||
}),
|
r2 := rf.FromMap(
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "cm2", "prefix1", "ns1"): rf.FromMap(
|
map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"apiVersion": "v1",
|
"kind": "ConfigMap",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "bob",
|
||||||
"name": "cm2",
|
},
|
||||||
},
|
})
|
||||||
}),
|
r3 := rf.FromMap(
|
||||||
})
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "bob",
|
||||||
|
"namespace": "happy",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r4 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "charlie",
|
||||||
|
"namespace": "happy",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r5 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "charlie",
|
||||||
|
"namespace": "happy",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
result := rm1.GetMatchingIds(
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "cm2", "prefix1", "ns1").GvknEquals)
|
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).ResMap()
|
||||||
|
|
||||||
|
result := m.GetMatchingResourcesByCurrentId(
|
||||||
|
resid.NewResId(cmap, "alice").GvknEquals)
|
||||||
|
if len(result) != 1 {
|
||||||
|
t.Fatalf("Expected single map entry but got %v", result)
|
||||||
|
}
|
||||||
|
result = m.GetMatchingResourcesByCurrentId(
|
||||||
|
resid.NewResId(cmap, "bob").GvknEquals)
|
||||||
|
if len(result) != 2 {
|
||||||
|
t.Fatalf("Expected two, got %v", result)
|
||||||
|
}
|
||||||
|
result = m.GetMatchingResourcesByCurrentId(
|
||||||
|
resid.NewResIdWithNamespace(cmap, "bob", "system").GvknEquals)
|
||||||
|
if len(result) != 2 {
|
||||||
|
t.Fatalf("Expected two but got %v", result)
|
||||||
|
}
|
||||||
|
result = m.GetMatchingResourcesByCurrentId(
|
||||||
|
resid.NewResIdWithNamespace(cmap, "bob", "happy").Equals)
|
||||||
|
if len(result) != 1 {
|
||||||
|
t.Fatalf("Expected single map entry but got %v", result)
|
||||||
|
}
|
||||||
|
result = m.GetMatchingResourcesByCurrentId(
|
||||||
|
resid.NewResId(cmap, "charlie").GvknEquals)
|
||||||
if len(result) != 1 {
|
if len(result) != 1 {
|
||||||
t.Fatalf("Expected single map entry but got %v", result)
|
t.Fatalf("Expected single map entry but got %v", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// confirm that ns and prefix are not included in match
|
// nolint:goconst
|
||||||
result = rm1.GetMatchingIds(
|
tests := []struct {
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "cm2", "prefix", "ns").GvknEquals)
|
name string
|
||||||
if len(result) != 1 {
|
matcher IdMatcher
|
||||||
t.Fatalf("Expected single map entry but got %v", result)
|
count int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"match everything",
|
||||||
|
func(resid.ResId) bool { return true },
|
||||||
|
5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match nothing",
|
||||||
|
func(resid.ResId) bool { return false },
|
||||||
|
0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name is alice",
|
||||||
|
func(x resid.ResId) bool { return x.Name == "alice" },
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name is charlie",
|
||||||
|
func(x resid.ResId) bool { return x.Name == "charlie" },
|
||||||
|
2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name is bob",
|
||||||
|
func(x resid.ResId) bool { return x.Name == "bob" },
|
||||||
|
2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"happy namespace",
|
||||||
|
func(x resid.ResId) bool {
|
||||||
|
return x.Namespace == "happy"
|
||||||
|
},
|
||||||
|
3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"happy deployment",
|
||||||
|
func(x resid.ResId) bool {
|
||||||
|
return x.Namespace == "happy" &&
|
||||||
|
x.Gvk.Kind == "Deployment"
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"happy ConfigMap",
|
||||||
|
func(x resid.ResId) bool {
|
||||||
|
return x.Namespace == "happy" &&
|
||||||
|
x.Gvk.Kind == "ConfigMap"
|
||||||
|
},
|
||||||
|
2,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
for _, tst := range tests {
|
||||||
// confirm that name is matched correctly
|
result := m.GetMatchingResourcesByCurrentId(tst.matcher)
|
||||||
result = rm1.GetMatchingIds(
|
if len(result) != tst.count {
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "cm3", "prefix1", "ns1").GvknEquals)
|
t.Fatalf("test '%s'; actual: %d, expected: %d",
|
||||||
if len(result) > 0 {
|
tst.name, len(result), tst.count)
|
||||||
t.Fatalf("Expected no map entries but got %v", result)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cmap2 := gvk.Gvk{Version: "v2", Kind: "ConfigMap"}
|
|
||||||
|
|
||||||
// confirm that gvk is matched correctly
|
|
||||||
result = rm1.GetMatchingIds(
|
|
||||||
resid.NewResIdWithPrefixNamespace(cmap2, "cm2", "prefix1", "ns1").GvknEquals)
|
|
||||||
if len(result) > 0 {
|
|
||||||
t.Fatalf("Expected no map entries but got %v", result)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFilterBy(t *testing.T) {
|
func TestSubsetThatCouldBeReferencedByResource(t *testing.T) {
|
||||||
|
r1 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "alice",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r2 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "bob",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r3 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "bob",
|
||||||
|
"namespace": "happy",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r4 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "charlie",
|
||||||
|
"namespace": "happy",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r5 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "charlie",
|
||||||
|
"namespace": "happy",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r5.AddNamePrefix("little-")
|
||||||
|
r6 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "domino",
|
||||||
|
"namespace": "happy",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r6.AddNamePrefix("little-")
|
||||||
|
r7 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ClusterRoleBinding",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "meh",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
resMap ResMap
|
filter *resource.Resource
|
||||||
filter resid.ResId
|
|
||||||
expected ResMap
|
expected ResMap
|
||||||
}{
|
}{
|
||||||
"different namespace": {
|
"default namespace 1": {
|
||||||
resMap: FromMap(map[resid.ResId]*resource.Resource{
|
filter: r2,
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map", "prefix", "suffix", "namespace1"): rf.FromMap(
|
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
map[string]interface{}{
|
AddR(r1).AddR(r2).AddR(r7).ResMap(),
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
filter: resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map", "prefix", "suffix", "namespace2"),
|
|
||||||
expected: New(),
|
|
||||||
},
|
},
|
||||||
"different prefix": {
|
"default namespace 2": {
|
||||||
resMap: FromMap(map[resid.ResId]*resource.Resource{
|
filter: r1,
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map", "prefix1", "suffix", "namespace"): rf.FromMap(
|
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
map[string]interface{}{
|
AddR(r1).AddR(r2).AddR(r7).ResMap(),
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
filter: resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map", "prefix2", "suffix", "namespace"),
|
|
||||||
expected: New(),
|
|
||||||
},
|
},
|
||||||
"different suffix": {
|
"happy namespace no prefix": {
|
||||||
resMap: FromMap(map[resid.ResId]*resource.Resource{
|
filter: r3,
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map", "prefix", "suffix1", "namespace"): rf.FromMap(
|
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
map[string]interface{}{
|
AddR(r3).AddR(r4).AddR(r7).ResMap(),
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
filter: resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map", "prefix", "suffix2", "namespace"),
|
|
||||||
expected: New(),
|
|
||||||
},
|
},
|
||||||
"same namespace, same prefix": {
|
"happy namespace with prefix": {
|
||||||
resMap: FromMap(map[resid.ResId]*resource.Resource{
|
filter: r5,
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "config-map1", "prefix", "namespace"): rf.FromMap(
|
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
map[string]interface{}{
|
AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
filter: resid.NewResIdWithPrefixNamespace(cmap, "config-map2", "prefix", "namespace"),
|
|
||||||
expected: FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "config-map1", "prefix", "namespace"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
"same namespace, same suffix": {
|
"cluster level": {
|
||||||
resMap: FromMap(map[resid.ResId]*resource.Resource{
|
filter: r7,
|
||||||
resid.NewResIdWithSuffixNamespace(cmap, "config-map1", "suffix", "namespace"): rf.FromMap(
|
expected: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
map[string]interface{}{
|
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap(),
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
filter: resid.NewResIdWithSuffixNamespace(cmap, "config-map2", "suffix", "namespace"),
|
|
||||||
expected: FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResIdWithSuffixNamespace(cmap, "config-map1", "suffix", "namespace"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
"same namespace, same prefix, same suffix": {
|
|
||||||
resMap: FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map1", "prefix", "suffix", "namespace"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
filter: resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map2", "prefix", "suffix", "namespace"),
|
|
||||||
expected: FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(cmap, "config-map1", "prefix", "suffix", "namespace"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
"filter by cluster-level Gvk": {
|
|
||||||
resMap: FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "config-map", "prefix", "namespace"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
filter: resid.NewResId(gvk.Gvk{Kind: "ClusterRoleBinding"}, "cluster-role-binding"),
|
|
||||||
expected: FromMap(map[resid.ResId]*resource.Resource{
|
|
||||||
resid.NewResIdWithPrefixNamespace(cmap, "config-map", "prefix", "namespace"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "config-map",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
|
AddR(r1).AddR(r2).AddR(r3).AddR(r4).AddR(r5).AddR(r6).AddR(r7).ResMap()
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
test := test
|
test := test
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
got := test.resMap.SubsetThatCouldBeReferencedById(test.filter)
|
got := m.SubsetThatCouldBeReferencedByResource(test.filter)
|
||||||
err := test.expected.ErrorIfNotEqualSets(got)
|
err := test.expected.ErrorIfNotEqualLists(got)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Expected %v but got back %v", test.expected, got)
|
test.expected.Debug("expected")
|
||||||
|
got.Debug("actual")
|
||||||
|
t.Fatalf("Expected match")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -410,163 +440,145 @@ func TestDeepCopy(t *testing.T) {
|
|||||||
if &rm1 == &rm2 {
|
if &rm1 == &rm2 {
|
||||||
t.Fatal("DeepCopy returned a reference to itself instead of a copy")
|
t.Fatal("DeepCopy returned a reference to itself instead of a copy")
|
||||||
}
|
}
|
||||||
err := rm1.ErrorIfNotEqualSets(rm1)
|
err := rm1.ErrorIfNotEqualLists(rm1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetMatchingIds(t *testing.T) {
|
func TestErrorIfNotEqualSets(t *testing.T) {
|
||||||
|
r1 := rf.FromMap(
|
||||||
m := FromMap(map[resid.ResId]*resource.Resource{
|
map[string]interface{}{
|
||||||
resid.NewResId(
|
"apiVersion": "v1",
|
||||||
gvk.Gvk{Kind: "vegetable"},
|
"kind": "ConfigMap",
|
||||||
"bedlam"): rf.FromMap(
|
"metadata": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "cm1",
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "whatever1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResId(
|
|
||||||
gvk.Gvk{Group: "g1", Version: "v1", Kind: "vegetable"},
|
|
||||||
"domino"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "whatever2",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResIdWithPrefixNamespace(
|
|
||||||
gvk.Gvk{Kind: "vegetable"},
|
|
||||||
"peter", "p", "happy"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "whatever3",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResIdWithPrefixNamespace(
|
|
||||||
gvk.Gvk{Version: "v1", Kind: "fruit"},
|
|
||||||
"shatterstar", "p", "happy"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "whatever4",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
matcher IdMatcher
|
|
||||||
count int
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"match everything",
|
|
||||||
func(resid.ResId) bool { return true },
|
|
||||||
4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"match nothing",
|
|
||||||
func(resid.ResId) bool { return false },
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name is peter",
|
|
||||||
func(x resid.ResId) bool { return x.Name() == "peter" },
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"happy vegetable",
|
|
||||||
func(x resid.ResId) bool {
|
|
||||||
return x.Namespace() == "happy" &&
|
|
||||||
x.Gvk().Kind == "vegetable"
|
|
||||||
},
|
},
|
||||||
1,
|
})
|
||||||
},
|
r2 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r3 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm2",
|
||||||
|
"namespace": "system",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
m1 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||||
|
if err := m1.ErrorIfNotEqualSets(m1); err != nil {
|
||||||
|
t.Fatalf("object should equal itself %v", err)
|
||||||
}
|
}
|
||||||
for _, tst := range tests {
|
|
||||||
result := m.GetMatchingIds(tst.matcher)
|
m2 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).ResMap()
|
||||||
if len(result) != tst.count {
|
if err := m1.ErrorIfNotEqualSets(m2); err == nil {
|
||||||
t.Fatalf("test '%s'; actual: %d, expected: %d",
|
t.Fatalf("%v should not equal %v %v", m1, m2, err)
|
||||||
tst.name, len(result), tst.count)
|
}
|
||||||
}
|
|
||||||
|
m3 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
}}).ResMap()
|
||||||
|
if err := m2.ErrorIfNotEqualSets(m3); err != nil {
|
||||||
|
t.Fatalf("%v should equal %v %v", m2, m3, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m4 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||||
|
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||||
|
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m4 = resmaptest_test.NewRmBuilder(t, rf).AddR(r3).AddR(r1).AddR(r2).ResMap()
|
||||||
|
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||||
|
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m4 = m1.ShallowCopy()
|
||||||
|
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||||
|
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||||
|
}
|
||||||
|
m4 = m1.DeepCopy()
|
||||||
|
if err := m1.ErrorIfNotEqualSets(m4); err != nil {
|
||||||
|
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorIfNotEqual(t *testing.T) {
|
func TestErrorIfNotEqualLists(t *testing.T) {
|
||||||
rm1 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
r1 := rf.FromMap(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "cm1",
|
"name": "cm1",
|
||||||
},
|
},
|
||||||
}).Add(map[string]interface{}{
|
})
|
||||||
"apiVersion": "v1",
|
r2 := rf.FromMap(
|
||||||
"kind": "ConfigMap",
|
map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"name": "cm2",
|
"kind": "ConfigMap",
|
||||||
},
|
"metadata": map[string]interface{}{
|
||||||
}).ResMap()
|
"name": "cm2",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
r3 := rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm2",
|
||||||
|
"namespace": "system",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
err := rm1.ErrorIfNotEqualSets(rm1)
|
m1 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||||
if err != nil {
|
if err := m1.ErrorIfNotEqualLists(m1); err != nil {
|
||||||
t.Fatalf("%v should equal itself %v", rm1, err)
|
t.Fatalf("object should equal itself %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rm2 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
m2 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).ResMap()
|
||||||
|
if err := m1.ErrorIfNotEqualLists(m2); err == nil {
|
||||||
|
t.Fatalf("%v should not equal %v %v", m1, m2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m3 := resmaptest_test.NewRmBuilder(t, rf).Add(
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "cm1",
|
"name": "cm1",
|
||||||
},
|
}}).ResMap()
|
||||||
}).ResMap()
|
if err := m2.ErrorIfNotEqualLists(m3); err != nil {
|
||||||
|
t.Fatalf("%v should equal %v %v", m2, m3, err)
|
||||||
// test the different number of keys path
|
|
||||||
err = rm1.ErrorIfNotEqualSets(rm2)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("%v should not equal %v %v", rm1, rm2, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rm3 := FromMap(map[resid.ResId]*resource.Resource{
|
m4 := resmaptest_test.NewRmBuilder(t, rf).AddR(r1).AddR(r2).AddR(r3).ResMap()
|
||||||
resid.NewResId(cmap, "cm2"): rf.FromMap(
|
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||||
map[string]interface{}{
|
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "cm1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
// test the different key values path
|
|
||||||
err = rm2.ErrorIfNotEqualSets(rm3)
|
|
||||||
if err == nil {
|
|
||||||
t.Fatalf("%v should not equal %v %v", rm1, rm2, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rm4 := FromMap(map[resid.ResId]*resource.Resource{
|
m4 = resmaptest_test.NewRmBuilder(t, rf).AddR(r3).AddR(r1).AddR(r2).ResMap()
|
||||||
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
if err := m1.ErrorIfNotEqualLists(m4); err == nil {
|
||||||
map[string]interface{}{
|
t.Fatalf("expected inequality between %v and %v, %v", m1, m4, err)
|
||||||
"apiVersion": "v1",
|
}
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "cm3",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
// test the deepcopy path
|
m4 = m1.ShallowCopy()
|
||||||
err = rm2.ErrorIfNotEqualSets(rm4)
|
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||||
if err == nil {
|
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||||
t.Fatalf("%v should not equal %v %v", rm1, rm2, err)
|
}
|
||||||
|
m4 = m1.DeepCopy()
|
||||||
|
if err := m1.ErrorIfNotEqualLists(m4); err != nil {
|
||||||
|
t.Fatalf("expected equality between %v and %v, %v", m1, m4, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,7 +613,7 @@ func TestAppendAll(t *testing.T) {
|
|||||||
if err := input1.AppendAll(input2); err != nil {
|
if err := input1.AppendAll(input2); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := expected.ErrorIfNotEqualSets(input1); err != nil {
|
if err := expected.ErrorIfNotEqualLists(input1); err != nil {
|
||||||
input1.Debug("1")
|
input1.Debug("1")
|
||||||
expected.Debug("ex")
|
expected.Debug("ex")
|
||||||
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||||
@@ -609,7 +621,7 @@ func TestAppendAll(t *testing.T) {
|
|||||||
if err := input1.AppendAll(nil); err != nil {
|
if err := input1.AppendAll(nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := expected.ErrorIfNotEqualSets(input1); err != nil {
|
if err := expected.ErrorIfNotEqualLists(input1); err != nil {
|
||||||
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
t.Fatalf("%#v doesn't equal expected %#v", input1, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -671,14 +683,14 @@ func TestAbsorbAll(t *testing.T) {
|
|||||||
if err := w.AbsorbAll(makeMap2(types.BehaviorMerge)); err != nil {
|
if err := w.AbsorbAll(makeMap2(types.BehaviorMerge)); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := expected.ErrorIfNotEqualSets(w); err != nil {
|
if err := expected.ErrorIfNotEqualLists(w); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
w = makeMap1()
|
w = makeMap1()
|
||||||
if err := w.AbsorbAll(nil); err != nil {
|
if err := w.AbsorbAll(nil); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := w.ErrorIfNotEqualSets(makeMap1()); err != nil {
|
if err := w.ErrorIfNotEqualLists(makeMap1()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
w = makeMap1()
|
w = makeMap1()
|
||||||
@@ -686,7 +698,7 @@ func TestAbsorbAll(t *testing.T) {
|
|||||||
if err := w.AbsorbAll(w2); err != nil {
|
if err := w.AbsorbAll(w2); err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err := w2.ErrorIfNotEqualSets(w); err != nil {
|
if err := w2.ErrorIfNotEqualLists(w); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
w = makeMap1()
|
w = makeMap1()
|
||||||
|
|||||||
@@ -27,7 +27,11 @@ func NewRmBuilder(t *testing.T, rf *resource.Factory) *rmBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rm *rmBuilder) Add(m map[string]interface{}) *rmBuilder {
|
func (rm *rmBuilder) Add(m map[string]interface{}) *rmBuilder {
|
||||||
err := rm.m.Append(rm.rf.FromMap(m))
|
return rm.AddR(rm.rf.FromMap(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rm *rmBuilder) AddR(r *resource.Resource) *rmBuilder {
|
||||||
|
err := rm.m.Append(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rm.t.Fatalf("test setup failure: %v", err)
|
rm.t.Fatalf("test setup failure: %v", err)
|
||||||
}
|
}
|
||||||
@@ -35,7 +39,7 @@ func (rm *rmBuilder) Add(m map[string]interface{}) *rmBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rm *rmBuilder) AddWithId(id resid.ResId, m map[string]interface{}) *rmBuilder {
|
func (rm *rmBuilder) AddWithId(id resid.ResId, m map[string]interface{}) *rmBuilder {
|
||||||
err := rm.m.AppendWithId(id, rm.rf.FromMap(m))
|
err := rm.m.Append(rm.rf.FromMap(m))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rm.t.Fatalf("test setup failure: %v", err)
|
rm.t.Fatalf("test setup failure: %v", err)
|
||||||
}
|
}
|
||||||
@@ -60,7 +64,7 @@ func (rm *rmBuilder) AddWithNs(ns string, m map[string]interface{}) *rmBuilder {
|
|||||||
|
|
||||||
func (rm *rmBuilder) ReplaceResource(m map[string]interface{}) *rmBuilder {
|
func (rm *rmBuilder) ReplaceResource(m map[string]interface{}) *rmBuilder {
|
||||||
r := rm.rf.FromMap(m)
|
r := rm.rf.FromMap(m)
|
||||||
err := rm.m.ReplaceResource(r.Id(), r)
|
_, err := rm.m.Replace(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rm.t.Fatalf("test setup failure: %v", err)
|
rm.t.Fatalf("test setup failure: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 resource implements representations of k8s API resources as "unstructured" objects.
|
// Package resource implements representations of k8s API resources as "unstructured" objects.
|
||||||
package resource
|
package resource
|
||||||
@@ -36,6 +23,8 @@ type Resource struct {
|
|||||||
options *types.GenArgs
|
options *types.GenArgs
|
||||||
refBy []resid.ResId
|
refBy []resid.ResId
|
||||||
refVarNames []string
|
refVarNames []string
|
||||||
|
namePrefixes []string
|
||||||
|
nameSuffixes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopy returns a new copy of resource
|
// DeepCopy returns a new copy of resource
|
||||||
@@ -61,7 +50,33 @@ func (r *Resource) copyOtherFields(other *Resource) {
|
|||||||
r.originalNs = other.originalNs
|
r.originalNs = other.originalNs
|
||||||
r.options = other.options
|
r.options = other.options
|
||||||
r.refBy = other.copyRefBy()
|
r.refBy = other.copyRefBy()
|
||||||
r.refVarNames = other.copyRefVarNames()
|
r.refVarNames = copyStringSlice(other.refVarNames)
|
||||||
|
r.namePrefixes = copyStringSlice(other.namePrefixes)
|
||||||
|
r.nameSuffixes = copyStringSlice(other.nameSuffixes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resource) Equals(o *Resource) bool {
|
||||||
|
return r.ReferencesEqual(o) &&
|
||||||
|
reflect.DeepEqual(r.Kunstructured, o.Kunstructured)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resource) ReferencesEqual(o *Resource) bool {
|
||||||
|
setSelf := make(map[resid.ResId]bool)
|
||||||
|
setOther := make(map[resid.ResId]bool)
|
||||||
|
for _, ref := range o.refBy {
|
||||||
|
setOther[ref] = true
|
||||||
|
}
|
||||||
|
for _, ref := range r.refBy {
|
||||||
|
if _, ok := setOther[ref]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
setSelf[ref] = true
|
||||||
|
}
|
||||||
|
return len(setSelf) == len(setOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resource) KunstructEqual(o *Resource) bool {
|
||||||
|
return reflect.DeepEqual(r.Kunstructured, o.Kunstructured)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge performs merge with other resource.
|
// Merge performs merge with other resource.
|
||||||
@@ -71,23 +86,49 @@ func (r *Resource) Merge(other *Resource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) copyRefBy() []resid.ResId {
|
func (r *Resource) copyRefBy() []resid.ResId {
|
||||||
|
if r.refBy == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
s := make([]resid.ResId, len(r.refBy))
|
s := make([]resid.ResId, len(r.refBy))
|
||||||
copy(s, r.refBy)
|
copy(s, r.refBy)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) copyRefVarNames() []string {
|
func copyStringSlice(s []string) []string {
|
||||||
s := make([]string, len(r.refVarNames))
|
if s == nil {
|
||||||
copy(s, r.refVarNames)
|
return nil
|
||||||
return s
|
}
|
||||||
|
c := make([]string, len(s))
|
||||||
|
copy(c, s)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resource) AddNamePrefix(p string) {
|
||||||
|
r.namePrefixes = append(r.namePrefixes, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resource) AddNameSuffix(s string) {
|
||||||
|
r.nameSuffixes = append(r.nameSuffixes, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resource) GetOutermostNamePrefix() string {
|
||||||
|
if len(r.namePrefixes) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return r.namePrefixes[len(r.namePrefixes)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Resource) GetOutermostNameSuffix() string {
|
||||||
|
if len(r.nameSuffixes) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return r.nameSuffixes[len(r.nameSuffixes)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) InSameFuzzyNamespace(o *Resource) bool {
|
func (r *Resource) InSameFuzzyNamespace(o *Resource) bool {
|
||||||
return r.GetNamespace() == o.GetNamespace()
|
return r.GetNamespace() == o.GetNamespace() &&
|
||||||
}
|
r.GetOutermostNamePrefix() == o.GetOutermostNamePrefix() &&
|
||||||
|
r.GetOutermostNameSuffix() == o.GetOutermostNameSuffix()
|
||||||
func (r *Resource) KunstructEqual(o *Resource) bool {
|
|
||||||
return reflect.DeepEqual(r.Kunstructured, o.Kunstructured)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resource) GetOriginalName() string {
|
func (r *Resource) GetOriginalName() string {
|
||||||
@@ -146,14 +187,18 @@ func (r *Resource) GetNamespace() string {
|
|||||||
return namespace
|
return namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id returns the immutable ResId for the resource.
|
// OrgId returns the original, immutable ResId for the resource.
|
||||||
func (r *Resource) Id() resid.ResId {
|
// This doesn't have to be unique in a ResMap.
|
||||||
|
// TODO: compute this once and save it in the resource.
|
||||||
|
func (r *Resource) OrgId() resid.ResId {
|
||||||
return resid.NewResIdWithNamespace(
|
return resid.NewResIdWithNamespace(
|
||||||
r.GetGvk(), r.GetOriginalName(), r.GetOriginalNs())
|
r.GetGvk(), r.GetOriginalName(), r.GetOriginalNs())
|
||||||
}
|
}
|
||||||
|
|
||||||
// FinalId returns a ResId for the resource using the mutable bits.
|
// CurId returns a ResId for the resource using the
|
||||||
func (r *Resource) FinalId() resid.ResId {
|
// mutable parts of the resource.
|
||||||
|
// This should be unique in any ResMap.
|
||||||
|
func (r *Resource) CurId() resid.ResId {
|
||||||
return resid.NewResIdWithNamespace(
|
return resid.NewResIdWithNamespace(
|
||||||
r.GetGvk(), r.GetName(), r.GetNamespace())
|
r.GetGvk(), r.GetName(), r.GetNamespace())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ func TestResourceId(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
if test.in.Id() != test.id {
|
if test.in.OrgId() != test.id {
|
||||||
t.Fatalf("Expected %v, but got %v\n", test.id, test.in.Id())
|
t.Fatalf("Expected %v, but got %v\n", test.id, test.in.OrgId())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/plugins"
|
"sigs.k8s.io/kustomize/pkg/plugins"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(monopole): Make prefixsuffixtransformer changes
|
func TestOrderPreserved(t *testing.T) {
|
||||||
// needed to enable this test.
|
|
||||||
func disabledTestOrderPreserved(t *testing.T) {
|
|
||||||
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
|
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
|
||||||
th.WriteK("/app/base", `
|
th.WriteK("/app/base", `
|
||||||
namePrefix: b-
|
namePrefix: b-
|
||||||
@@ -86,8 +84,36 @@ metadata:
|
|||||||
t.Fatalf("Err: %v", err)
|
t.Fatalf("Err: %v", err)
|
||||||
}
|
}
|
||||||
th.AssertActualEqualsExpectedNoSort(m, `
|
th.AssertActualEqualsExpectedNoSort(m, `
|
||||||
TBD
|
apiVersion: v1
|
||||||
./tr `)
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: p-b-myNs
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: p-b-myRole
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: p-b-myService
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: p-b-myDep
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: p-myService2
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: p-myNs2
|
||||||
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBaseInResourceList(t *testing.T) {
|
func TestBaseInResourceList(t *testing.T) {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ kind: Secret
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.1
|
chart: minecraft-1.0.3
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: LOOOOOOOONG-release-name-minecraft
|
name: LOOOOOOOONG-release-name-minecraft
|
||||||
@@ -72,7 +72,7 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.1
|
chart: minecraft-1.0.3
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: LOOOOOOOONG-release-name-minecraft
|
name: LOOOOOOOONG-release-name-minecraft
|
||||||
@@ -93,7 +93,7 @@ metadata:
|
|||||||
volume.alpha.kubernetes.io/storage-class: default
|
volume.alpha.kubernetes.io/storage-class: default
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.1
|
chart: minecraft-1.0.3
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: LOOOOOOOONG-release-name-minecraft-datadir
|
name: LOOOOOOOONG-release-name-minecraft-datadir
|
||||||
|
|||||||
@@ -312,6 +312,15 @@ spec:
|
|||||||
location: SE
|
location: SE
|
||||||
---
|
---
|
||||||
kind: Gorilla
|
kind: Gorilla
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
movie: planetOfTheApes
|
||||||
|
name: o-ursus
|
||||||
|
spec:
|
||||||
|
diet: heston
|
||||||
|
location: Arizona
|
||||||
|
---
|
||||||
|
kind: Gorilla
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: myApp
|
app: myApp
|
||||||
@@ -320,14 +329,5 @@ metadata:
|
|||||||
spec:
|
spec:
|
||||||
diet: bambooshoots
|
diet: bambooshoots
|
||||||
location: SW
|
location: SW
|
||||||
---
|
|
||||||
kind: Gorilla
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
movie: planetOfTheApes
|
|
||||||
name: o-ursus
|
|
||||||
spec:
|
|
||||||
diet: heston
|
|
||||||
location: Arizona
|
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -374,6 +374,16 @@ secretGenerator:
|
|||||||
}
|
}
|
||||||
th.AssertActualEqualsExpected(m, `
|
th.AssertActualEqualsExpected(m, `
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
hello: world
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
env: staging
|
||||||
|
team: override-foo
|
||||||
|
name: staging-configmap-in-overlay-k7cbc75tg8
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
foo: override-bar
|
foo: override-bar
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
@@ -388,16 +398,6 @@ metadata:
|
|||||||
name: staging-team-foo-configmap-in-base-gh9d7t85gb
|
name: staging-team-foo-configmap-in-base-gh9d7t85gb
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
|
||||||
hello: world
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
env: staging
|
|
||||||
team: override-foo
|
|
||||||
name: staging-configmap-in-overlay-k7cbc75tg8
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
data:
|
data:
|
||||||
password: c29tZXB3
|
password: c29tZXB3
|
||||||
proxy: aGFwcm94eQ==
|
proxy: aGFwcm94eQ==
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/pkg/kusttest"
|
"sigs.k8s.io/kustomize/pkg/kusttest"
|
||||||
"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/target"
|
. "sigs.k8s.io/kustomize/pkg/target"
|
||||||
@@ -80,64 +79,53 @@ func TestResources(t *testing.T) {
|
|||||||
th.WriteF("/whatever/namespace.yaml", namespaceContent)
|
th.WriteF("/whatever/namespace.yaml", namespaceContent)
|
||||||
th.WriteF("/whatever/jsonpatch.json", jsonpatchContent)
|
th.WriteF("/whatever/jsonpatch.json", jsonpatchContent)
|
||||||
|
|
||||||
expected := resmap.New()
|
resources := []*resource.Resource{
|
||||||
expected.AppendWithId(
|
th.RF().FromMapWithName("dply1", map[string]interface{}{
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(
|
"apiVersion": "apps/v1",
|
||||||
gvk.Gvk{Group: "apps", Version: "v1", Kind: "Deployment"},
|
"kind": "Deployment",
|
||||||
"dply1", "foo-", "-bar", "ns1"), th.FromMap(
|
"metadata": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "foo-dply1-bar",
|
||||||
"apiVersion": "apps/v1",
|
"namespace": "ns1",
|
||||||
"kind": "Deployment",
|
"labels": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"app": "nginx",
|
||||||
"name": "foo-dply1-bar",
|
},
|
||||||
"namespace": "ns1",
|
"annotations": map[string]interface{}{
|
||||||
"labels": map[string]interface{}{
|
"note": "This is a test annotation",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"replica": "3",
|
||||||
|
"selector": map[string]interface{}{
|
||||||
|
"matchLabels": map[string]interface{}{
|
||||||
"app": "nginx",
|
"app": "nginx",
|
||||||
},
|
},
|
||||||
"annotations": map[string]interface{}{
|
|
||||||
"note": "This is a test annotation",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"spec": map[string]interface{}{
|
"template": map[string]interface{}{
|
||||||
"replica": "3",
|
"metadata": map[string]interface{}{
|
||||||
"selector": map[string]interface{}{
|
"annotations": map[string]interface{}{
|
||||||
"matchLabels": map[string]interface{}{
|
"note": "This is a test annotation",
|
||||||
|
},
|
||||||
|
"labels": map[string]interface{}{
|
||||||
"app": "nginx",
|
"app": "nginx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"annotations": map[string]interface{}{
|
|
||||||
"note": "This is a test annotation",
|
|
||||||
},
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"app": "nginx",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}))
|
},
|
||||||
expected.AppendWithId(
|
}),
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(
|
th.RF().FromMapWithName("ns1", map[string]interface{}{
|
||||||
gvk.Gvk{Version: "v1", Kind: "Namespace"},
|
"apiVersion": "v1",
|
||||||
"ns1", "foo-", "-bar", ""), th.FromMap(
|
"kind": "Namespace",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"name": "foo-ns1-bar",
|
||||||
"kind": "Namespace",
|
"labels": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"app": "nginx",
|
||||||
"name": "foo-ns1-bar",
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"app": "nginx",
|
|
||||||
},
|
|
||||||
"annotations": map[string]interface{}{
|
|
||||||
"note": "This is a test annotation",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}))
|
"annotations": map[string]interface{}{
|
||||||
expected.AppendWithId(
|
"note": "This is a test annotation",
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(
|
},
|
||||||
gvk.Gvk{Version: "v1", Kind: "ConfigMap"},
|
},
|
||||||
"literalConfigMap", "foo-", "-bar", "ns1"), th.FromMap(
|
}),
|
||||||
|
th.RF().FromMapWithName("literalConfigMap",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
@@ -155,11 +143,8 @@ func TestResources(t *testing.T) {
|
|||||||
"DB_USERNAME": "admin",
|
"DB_USERNAME": "admin",
|
||||||
"DB_PASSWORD": "somepw",
|
"DB_PASSWORD": "somepw",
|
||||||
},
|
},
|
||||||
}))
|
}),
|
||||||
expected.AppendWithId(
|
th.RF().FromMapWithName("secret",
|
||||||
resid.NewResIdWithPrefixSuffixNamespace(
|
|
||||||
gvk.Gvk{Version: "v1", Kind: "Secret"},
|
|
||||||
"secret", "foo-", "-bar", "ns1"), th.FromMap(
|
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Secret",
|
"kind": "Secret",
|
||||||
@@ -178,13 +163,22 @@ func TestResources(t *testing.T) {
|
|||||||
"DB_USERNAME": base64.StdEncoding.EncodeToString([]byte("admin")),
|
"DB_USERNAME": base64.StdEncoding.EncodeToString([]byte("admin")),
|
||||||
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
|
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
|
||||||
},
|
},
|
||||||
}))
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := resmap.New()
|
||||||
|
for _, r := range resources {
|
||||||
|
if err := expected.Append(r); err != nil {
|
||||||
|
t.Fatalf("unexpected error %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
actual, err := th.MakeKustTarget().MakeCustomizedResMap()
|
actual, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected Resources error %v", err)
|
t.Fatalf("unexpected Resources error %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = expected.ErrorIfNotEqualSets(actual); err != nil {
|
if err = expected.ErrorIfNotEqualLists(actual); err != nil {
|
||||||
t.Fatalf("unexpected inequality: %v", err)
|
t.Fatalf("unexpected inequality: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -215,7 +209,7 @@ func TestResourceNotFound(t *testing.T) {
|
|||||||
|
|
||||||
func findSecret(m resmap.ResMap) *resource.Resource {
|
func findSecret(m resmap.ResMap) *resource.Resource {
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
if r.Id().Gvk().Kind == "Secret" {
|
if r.OrgId().Kind == "Secret" {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,6 +149,15 @@ spec:
|
|||||||
}
|
}
|
||||||
th.AssertActualEqualsExpected(m, `
|
th.AssertActualEqualsExpected(m, `
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
hello: world
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
env: staging
|
||||||
|
name: staging-configmap-in-overlay-k7cbc75tg8
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
data:
|
data:
|
||||||
foo: bar
|
foo: bar
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
@@ -163,15 +172,6 @@ metadata:
|
|||||||
name: staging-team-foo-configmap-in-base-g7k6gt2889
|
name: staging-team-foo-configmap-in-base-g7k6gt2889
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
data:
|
|
||||||
hello: world
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
env: staging
|
|
||||||
name: staging-configmap-in-overlay-k7cbc75tg8
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
annotations:
|
||||||
|
|||||||
@@ -10,14 +10,19 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/kusttest"
|
"sigs.k8s.io/kustomize/pkg/kusttest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeCombinedOverlays(th *kusttest_test.KustTestHarness) {
|
func writeBase(th *kusttest_test.KustTestHarness) {
|
||||||
// Base
|
|
||||||
th.WriteK("/app/base", `
|
th.WriteK("/app/base", `
|
||||||
resources:
|
resources:
|
||||||
- serviceaccount.yaml
|
- serviceaccount.yaml
|
||||||
- rolebinding.yaml
|
- rolebinding.yaml
|
||||||
namePrefix: base-
|
namePrefix: pfx-
|
||||||
nameSuffix: -suffix
|
nameSuffix: -sfx
|
||||||
|
`)
|
||||||
|
th.WriteF("/app/base/serviceaccount.yaml", `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: serviceaccount
|
||||||
`)
|
`)
|
||||||
th.WriteF("/app/base/rolebinding.yaml", `
|
th.WriteF("/app/base/rolebinding.yaml", `
|
||||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
@@ -32,13 +37,9 @@ subjects:
|
|||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: serviceaccount
|
name: serviceaccount
|
||||||
`)
|
`)
|
||||||
th.WriteF("/app/base/serviceaccount.yaml", `
|
}
|
||||||
apiVersion: v1
|
|
||||||
kind: ServiceAccount
|
|
||||||
metadata:
|
|
||||||
name: serviceaccount
|
|
||||||
`)
|
|
||||||
|
|
||||||
|
func writeMidOverlays(th *kusttest_test.KustTestHarness) {
|
||||||
// Mid-level overlays
|
// Mid-level overlays
|
||||||
th.WriteK("/app/overlays/a", `
|
th.WriteK("/app/overlays/a", `
|
||||||
bases:
|
bases:
|
||||||
@@ -52,7 +53,9 @@ bases:
|
|||||||
namePrefix: b-
|
namePrefix: b-
|
||||||
nameSuffix: -suffixB
|
nameSuffix: -suffixB
|
||||||
`)
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeTopOverlay(th *kusttest_test.KustTestHarness) {
|
||||||
// Top overlay, combining the mid-level overlays
|
// Top overlay, combining the mid-level overlays
|
||||||
th.WriteK("/app/combined", `
|
th.WriteK("/app/combined", `
|
||||||
bases:
|
bases:
|
||||||
@@ -61,9 +64,9 @@ bases:
|
|||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultibasesNoConflict(t *testing.T) {
|
func TestBase(t *testing.T) {
|
||||||
th := kusttest_test.NewKustTestHarness(t, "/app/combined")
|
th := kusttest_test.NewKustTestHarness(t, "/app/base")
|
||||||
writeCombinedOverlays(th)
|
writeBase(th)
|
||||||
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected err: %v", err)
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
@@ -72,42 +75,129 @@ func TestMultibasesNoConflict(t *testing.T) {
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: a-base-serviceaccount-suffix-suffixA
|
name: pfx-serviceaccount-sfx
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: pfx-rolebinding-sfx
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: pfx-serviceaccount-sfx
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMidLevelA(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/app/overlays/a")
|
||||||
|
writeBase(th)
|
||||||
|
writeMidOverlays(th)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMidLevelB(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/app/overlays/b")
|
||||||
|
writeBase(th)
|
||||||
|
writeMidOverlays(th)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: role
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMultibasesNoConflict(t *testing.T) {
|
||||||
|
th := kusttest_test.NewKustTestHarness(t, "/app/combined")
|
||||||
|
writeBase(th)
|
||||||
|
writeMidOverlays(th)
|
||||||
|
writeTopOverlay(th)
|
||||||
|
m, err := th.MakeKustTarget().MakeCustomizedResMap()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
|
}
|
||||||
|
th.AssertActualEqualsExpected(m, `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ServiceAccount
|
kind: ServiceAccount
|
||||||
metadata:
|
metadata:
|
||||||
name: b-base-serviceaccount-suffix-suffixB
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
metadata:
|
metadata:
|
||||||
name: a-base-rolebinding-suffix-suffixA
|
name: a-pfx-rolebinding-sfx-suffixA
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: Role
|
||||||
name: role
|
name: role
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: a-base-serviceaccount-suffix-suffixA
|
name: a-pfx-serviceaccount-sfx-suffixA
|
||||||
---
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1beta1
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
kind: RoleBinding
|
kind: RoleBinding
|
||||||
metadata:
|
metadata:
|
||||||
name: b-base-rolebinding-suffix-suffixB
|
name: b-pfx-rolebinding-sfx-suffixB
|
||||||
roleRef:
|
roleRef:
|
||||||
apiGroup: rbac.authorization.k8s.io
|
apiGroup: rbac.authorization.k8s.io
|
||||||
kind: Role
|
kind: Role
|
||||||
name: role
|
name: role
|
||||||
subjects:
|
subjects:
|
||||||
- kind: ServiceAccount
|
- kind: ServiceAccount
|
||||||
name: b-base-serviceaccount-suffix-suffixB
|
name: b-pfx-serviceaccount-sfx-suffixB
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMultibasesWithConflict(t *testing.T) {
|
func TestMultibasesWithConflict(t *testing.T) {
|
||||||
th := kusttest_test.NewKustTestHarness(t, "/app/combined")
|
th := kusttest_test.NewKustTestHarness(t, "/app/combined")
|
||||||
writeCombinedOverlays(th)
|
writeBase(th)
|
||||||
|
writeMidOverlays(th)
|
||||||
|
writeTopOverlay(th)
|
||||||
|
|
||||||
th.WriteK("/app/overlays/a", `
|
th.WriteK("/app/overlays/a", `
|
||||||
bases:
|
bases:
|
||||||
@@ -131,7 +221,7 @@ metadata:
|
|||||||
t.Fatalf("Expected resource conflict.")
|
t.Fatalf("Expected resource conflict.")
|
||||||
}
|
}
|
||||||
if !strings.Contains(
|
if !strings.Contains(
|
||||||
err.Error(), "Multiple matches for name ~G_v1_ServiceAccount") {
|
err.Error(), "multiple matches for ~G_v1_ServiceAccount") {
|
||||||
t.Fatalf("Unexpected err: %v", err)
|
t.Fatalf("Unexpected err: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -411,10 +411,16 @@ metadata:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
|
annotations:
|
||||||
|
prometheus.io/path: _status/vars
|
||||||
|
prometheus.io/port: "8080"
|
||||||
|
prometheus.io/scrape: "true"
|
||||||
|
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
||||||
labels:
|
labels:
|
||||||
app: cockroachdb
|
app: cockroachdb
|
||||||
name: dev-base-cockroachdb-public
|
name: dev-base-cockroachdb
|
||||||
spec:
|
spec:
|
||||||
|
clusterIP: None
|
||||||
ports:
|
ports:
|
||||||
- name: grpc
|
- name: grpc
|
||||||
port: 26257
|
port: 26257
|
||||||
@@ -428,16 +434,10 @@ spec:
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
annotations:
|
|
||||||
prometheus.io/path: _status/vars
|
|
||||||
prometheus.io/port: "8080"
|
|
||||||
prometheus.io/scrape: "true"
|
|
||||||
service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
|
|
||||||
labels:
|
labels:
|
||||||
app: cockroachdb
|
app: cockroachdb
|
||||||
name: dev-base-cockroachdb
|
name: dev-base-cockroachdb-public
|
||||||
spec:
|
spec:
|
||||||
clusterIP: None
|
|
||||||
ports:
|
ports:
|
||||||
- name: grpc
|
- name: grpc
|
||||||
port: 26257
|
port: 26257
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func (pt *imageTransformer) Transform(m resmap.ResMap) error {
|
|||||||
}
|
}
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
for _, path := range pt.fieldSpecs {
|
for _, path := range pt.fieldSpecs {
|
||||||
if !r.Id().Gvk().IsSelected(&path.Gvk) {
|
if !r.OrgId().IsSelected(&path.Gvk) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := MutateField(r.Map(), path.PathSlice(), false, pt.mutateImage)
|
err := MutateField(r.Map(), path.PathSlice(), false, pt.mutateImage)
|
||||||
@@ -55,7 +55,7 @@ func (pt *imageTransformer) Transform(m resmap.ResMap) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Kept for backward compatibility
|
// Kept for backward compatibility
|
||||||
if err := pt.findAndReplaceImage(r.Map()); err != nil && r.Id().Kind != `CustomResourceDefinition` {
|
if err := pt.findAndReplaceImage(r.Map()); err != nil && r.OrgId().Kind != `CustomResourceDefinition` {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func NewMapTransformer(
|
|||||||
func (o *mapTransformer) Transform(m resmap.ResMap) error {
|
func (o *mapTransformer) Transform(m resmap.ResMap) error {
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
for _, path := range o.fieldSpecs {
|
for _, path := range o.fieldSpecs {
|
||||||
if !r.Id().Gvk().IsSelected(&path.Gvk) {
|
if !r.OrgId().IsSelected(&path.Gvk) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err := MutateField(
|
err := MutateField(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ package transformers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
)
|
)
|
||||||
@@ -44,14 +45,15 @@ func NewNameReferenceTransformer(br []config.NameBackReferences) Transformer {
|
|||||||
//
|
//
|
||||||
// - kind: Deployment
|
// - kind: Deployment
|
||||||
// fieldSpecs:
|
// fieldSpecs:
|
||||||
// - path: spec/scaleTargetRef/name
|
// - kind: HorizontalPodAutoscaler
|
||||||
// kind: HorizontalPodAutoscaler
|
// path: spec/scaleTargetRef/name
|
||||||
//
|
//
|
||||||
// saying that an HPA, via its 'spec/scaleTargetRef/name'
|
// This entry says that an HPA, via its
|
||||||
// field, may refer to a Deployment. This match to HPA
|
// 'spec/scaleTargetRef/name' field, may refer to a
|
||||||
// means we may need to modify the value in its
|
// Deployment. This match to HPA means we may need to
|
||||||
// 'spec/scaleTargetRef/name' field, by searching for
|
// modify the value in its 'spec/scaleTargetRef/name'
|
||||||
// the thing it refers to, and getting its new name.
|
// field, by searching for the thing it refers to,
|
||||||
|
// and getting its new name.
|
||||||
//
|
//
|
||||||
// As a filter, and search optimization, we compute a
|
// As a filter, and search optimization, we compute a
|
||||||
// subset of all resources that the HPA could refer to,
|
// subset of all resources that the HPA could refer to,
|
||||||
@@ -76,19 +78,23 @@ func NewNameReferenceTransformer(br []config.NameBackReferences) Transformer {
|
|||||||
//
|
//
|
||||||
func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
|
func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
|
||||||
// TODO: Too much looping, here and in transitive calls.
|
// TODO: Too much looping, here and in transitive calls.
|
||||||
for referrer, res := range m.AsMap() {
|
for _, referrer := range m.Resources() {
|
||||||
var candidates resmap.ResMap
|
var candidates resmap.ResMap
|
||||||
for _, target := range o.backRefs {
|
for _, target := range o.backRefs {
|
||||||
for _, fSpec := range target.FieldSpecs {
|
for _, fSpec := range target.FieldSpecs {
|
||||||
if referrer.Gvk().IsSelected(&fSpec.Gvk) {
|
if referrer.OrgId().IsSelected(&fSpec.Gvk) {
|
||||||
if candidates == nil {
|
if candidates == nil {
|
||||||
candidates = m.SubsetThatCouldBeReferencedById(referrer)
|
candidates = m.SubsetThatCouldBeReferencedByResource(referrer)
|
||||||
}
|
}
|
||||||
err := MutateField(
|
err := MutateField(
|
||||||
res.Map(),
|
referrer.Map(),
|
||||||
fSpec.PathSlice(),
|
fSpec.PathSlice(),
|
||||||
fSpec.CreateIfNotPresent,
|
fSpec.CreateIfNotPresent,
|
||||||
o.getNewName(
|
o.getNewNameFunc(
|
||||||
|
// referrer could be an HPA instance,
|
||||||
|
// target could be Gvk for Deployment,
|
||||||
|
// candidate a list of resources "reachable"
|
||||||
|
// from the HPA.
|
||||||
referrer, target.Gvk, candidates))
|
referrer, target.Gvk, candidates))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -100,26 +106,28 @@ func (o *nameReferenceTransformer) Transform(m resmap.ResMap) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *nameReferenceTransformer) getNewName(
|
func (o *nameReferenceTransformer) getNewNameFunc(
|
||||||
referrer resid.ResId,
|
referrer *resource.Resource,
|
||||||
target gvk.Gvk,
|
target gvk.Gvk,
|
||||||
referralCandidates resmap.ResMap) func(in interface{}) (interface{}, error) {
|
referralCandidates resmap.ResMap) func(in interface{}) (interface{}, error) {
|
||||||
return func(in interface{}) (interface{}, error) {
|
return func(in interface{}) (interface{}, error) {
|
||||||
switch in.(type) {
|
switch in.(type) {
|
||||||
case string:
|
case string:
|
||||||
oldName, _ := in.(string)
|
oldName, _ := in.(string)
|
||||||
for id, res := range referralCandidates.AsMap() {
|
for _, res := range referralCandidates.Resources() {
|
||||||
if id.Gvk().IsSelected(&target) && id.Name() == oldName {
|
id := res.OrgId()
|
||||||
matchedIds := referralCandidates.GetMatchingIds(id.GvknEquals)
|
if id.IsSelected(&target) && res.GetOriginalName() == oldName {
|
||||||
|
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
||||||
// If there's more than one match, there's no way
|
// If there's more than one match, there's no way
|
||||||
// to know which one to pick, so emit error.
|
// to know which one to pick, so emit error.
|
||||||
if len(matchedIds) > 1 {
|
if len(matches) > 1 {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"Multiple matches for name %s:\n %v", id, matchedIds)
|
"string case - multiple matches for %s:\n %v",
|
||||||
|
id, getIds(matches))
|
||||||
}
|
}
|
||||||
// In the resource, note that it is referenced
|
// In the resource, note that it is referenced
|
||||||
// by the referrer.
|
// by the referrer.
|
||||||
res.AppendRefBy(referrer)
|
res.AppendRefBy(referrer.CurId())
|
||||||
// Return transformed name of the object,
|
// Return transformed name of the object,
|
||||||
// complete with prefixes, hashes, etc.
|
// complete with prefixes, hashes, etc.
|
||||||
return res.GetName(), nil
|
return res.GetName(), nil
|
||||||
@@ -137,18 +145,20 @@ func (o *nameReferenceTransformer) getNewName(
|
|||||||
}
|
}
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
for id, res := range referralCandidates.AsMap() {
|
for _, res := range referralCandidates.Resources() {
|
||||||
indexes := indexOf(id.Name(), names)
|
indexes := indexOf(res.GetOriginalName(), names)
|
||||||
if id.Gvk().IsSelected(&target) && len(indexes) > 0 {
|
id := res.OrgId()
|
||||||
matchedIds := referralCandidates.GetMatchingIds(id.GvknEquals)
|
if id.IsSelected(&target) && len(indexes) > 0 {
|
||||||
if len(matchedIds) > 1 {
|
matches := referralCandidates.GetMatchingResourcesByOriginalId(id.GvknEquals)
|
||||||
|
if len(matches) > 1 {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"Multiple matches for name %s:\n %v", id, matchedIds)
|
"slice case - multiple matches for %s:\n %v",
|
||||||
|
id, getIds(matches))
|
||||||
}
|
}
|
||||||
for _, index := range indexes {
|
for _, index := range indexes {
|
||||||
l[index] = res.GetName()
|
l[index] = res.GetName()
|
||||||
}
|
}
|
||||||
res.AppendRefBy(referrer)
|
res.AppendRefBy(referrer.CurId())
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,3 +179,11 @@ func indexOf(s string, slice []string) []int {
|
|||||||
}
|
}
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getIds(rs []*resource.Resource) []string {
|
||||||
|
var result []string
|
||||||
|
for _, r := range rs {
|
||||||
|
result = append(result, r.CurId().String()+"\n")
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,14 +4,12 @@
|
|||||||
package transformers
|
package transformers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -466,7 +464,7 @@ func TestNameReferenceHappyRun(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err = expected.ErrorIfNotEqualSets(m); err != nil {
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -537,7 +535,8 @@ func TestNameReferenceUnhappyRun(t *testing.T) {
|
|||||||
func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
|
func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
|
||||||
rf := resource.NewFactory(
|
rf := resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
m := resmaptest_test.NewRmBuilder(t, rf).AddWithName(
|
|
||||||
|
v1 := rf.FromMapWithName(
|
||||||
"volume1",
|
"volume1",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
@@ -545,7 +544,8 @@ func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
|
|||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "someprefix-volume1",
|
"name": "someprefix-volume1",
|
||||||
},
|
},
|
||||||
}).AddWithName(
|
})
|
||||||
|
c1 := rf.FromMapWithName(
|
||||||
"claim1",
|
"claim1",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
@@ -557,17 +557,10 @@ func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
|
|||||||
"spec": map[string]interface{}{
|
"spec": map[string]interface{}{
|
||||||
"volumeName": "volume1",
|
"volumeName": "volume1",
|
||||||
},
|
},
|
||||||
}).ResMap()
|
})
|
||||||
|
|
||||||
expected := resmaptest_test.NewRmBuilder(t, rf).AddWithName(
|
v2 := v1.DeepCopy()
|
||||||
"volume1",
|
c2 := rf.FromMapWithName(
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "PersistentVolume",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "someprefix-volume1",
|
|
||||||
},
|
|
||||||
}).AddWithName(
|
|
||||||
"claim1",
|
"claim1",
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
@@ -579,16 +572,19 @@ func TestNameReferencePersistentVolumeHappyRun(t *testing.T) {
|
|||||||
"spec": map[string]interface{}{
|
"spec": map[string]interface{}{
|
||||||
"volumeName": "someprefix-volume1",
|
"volumeName": "someprefix-volume1",
|
||||||
},
|
},
|
||||||
}).ResMap()
|
})
|
||||||
expected.GetById(
|
|
||||||
resid.NewResId(gvk.Gvk{Version: "v1", Kind: "PersistentVolume"}, "volume1")).AppendRefBy(
|
m1 := resmaptest_test.NewRmBuilder(t, rf).AddR(v1).AddR(c1).ResMap()
|
||||||
resid.NewResId(gvk.Gvk{Version: "v1", Kind: "PersistentVolumeClaim"}, "claim1"))
|
|
||||||
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
nrt := NewNameReferenceTransformer(defaultTransformerConfig.NameReference)
|
||||||
err := nrt.Transform(m)
|
if err := nrt.Transform(m1); err != nil {
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err = expected.ErrorIfNotEqualSets(m); err != nil {
|
|
||||||
|
m2 := resmaptest_test.NewRmBuilder(t, rf).AddR(v2).AddR(c2).ResMap()
|
||||||
|
v2.AppendRefBy(c2.CurId())
|
||||||
|
|
||||||
|
if err := m1.ErrorIfNotEqualLists(m2); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +1,52 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 transformers
|
package transformers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
|
"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/transformers/config"
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type namespaceTransformer struct {
|
type namespaceTransformer struct {
|
||||||
namespace string
|
namespace string
|
||||||
fieldSpecsToUse []config.FieldSpec
|
fieldSpecsToUse []config.FieldSpec
|
||||||
fieldSpecsToSkip []config.FieldSpec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Transformer = &namespaceTransformer{}
|
var _ Transformer = &namespaceTransformer{}
|
||||||
|
|
||||||
// NewNamespaceTransformer construct a namespaceTransformer.
|
// NewNamespaceTransformer construct a namespaceTransformer.
|
||||||
func NewNamespaceTransformer(ns string, cf []config.FieldSpec) Transformer {
|
func NewNamespaceTransformer(ns string, cf []config.FieldSpec) Transformer {
|
||||||
if len(ns) == 0 {
|
|
||||||
return NewNoOpTransformer()
|
|
||||||
}
|
|
||||||
var skip []config.FieldSpec
|
|
||||||
for _, g := range gvk.ClusterLevelGvks() {
|
|
||||||
skip = append(skip, config.FieldSpec{Gvk: g})
|
|
||||||
}
|
|
||||||
return &namespaceTransformer{
|
return &namespaceTransformer{
|
||||||
namespace: ns,
|
namespace: ns,
|
||||||
fieldSpecsToUse: cf,
|
fieldSpecsToUse: cf,
|
||||||
fieldSpecsToSkip: skip,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const metaNamespace = "metadata/namespace"
|
||||||
|
|
||||||
// Transform adds the namespace.
|
// Transform adds the namespace.
|
||||||
func (o *namespaceTransformer) Transform(m resmap.ResMap) error {
|
func (o *namespaceTransformer) Transform(m resmap.ResMap) (err error) {
|
||||||
mf := o.filterResmap(m)
|
if len(o.namespace) == 0 {
|
||||||
|
return nil
|
||||||
for id, res := range mf.AsMap() {
|
}
|
||||||
objMap := res.Map()
|
for _, r := range m.Resources() {
|
||||||
for _, path := range o.fieldSpecsToUse {
|
id := r.OrgId()
|
||||||
switch path.Path {
|
fs, ok := o.isSelected(id)
|
||||||
// Special casing .metadata.namespace since it is a common metadata field across all runtime.Object
|
if !ok {
|
||||||
// We should add namespace if it's namespaced resource; otherwise, we should not.
|
continue
|
||||||
case "metadata/namespace":
|
}
|
||||||
if id.Gvk().IsSelected(&path.Gvk) && !id.Gvk().IsClusterKind() {
|
if len(r.Map()) == 0 {
|
||||||
if len(objMap) > 0 {
|
// Don't mutate empty objects?
|
||||||
err := MutateField(
|
continue
|
||||||
objMap, path.PathSlice(), path.CreateIfNotPresent,
|
}
|
||||||
func(_ interface{}) (interface{}, error) {
|
if doIt(id, fs) {
|
||||||
return o.namespace, nil
|
err = o.changeNamespace(r, fs)
|
||||||
})
|
if err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if !id.Gvk().IsSelected(&path.Gvk) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// make sure the object is non empty
|
|
||||||
if len(objMap) > 0 {
|
|
||||||
err := MutateField(
|
|
||||||
objMap, path.PathSlice(), path.CreateIfNotPresent,
|
|
||||||
func(_ interface{}) (interface{}, error) {
|
|
||||||
return o.namespace, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !id.Gvk().IsClusterKind() {
|
|
||||||
newid := id.CopyWithNewNamespace(o.namespace)
|
|
||||||
m.AppendWithId(newid, res)
|
|
||||||
} else {
|
|
||||||
m.AppendWithId(id, res)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,35 +54,46 @@ func (o *namespaceTransformer) Transform(m resmap.ResMap) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *namespaceTransformer) filterResmap(m resmap.ResMap) resmap.ResMap {
|
// Special casing metadata.namespace since
|
||||||
mf := resmap.New()
|
// all objects have it, even "ClusterKind" objects
|
||||||
for id, res := range m.AsMap() {
|
// that don't exist in a namespace (the Namespace
|
||||||
found := false
|
// object itself doesn't live in a namespace).
|
||||||
for _, path := range o.fieldSpecsToSkip {
|
func doIt(id resid.ResId, fs *config.FieldSpec) bool {
|
||||||
if id.Gvk().IsSelected(&path.Gvk) {
|
return fs.Path != metaNamespace ||
|
||||||
found = true
|
(fs.Path == metaNamespace && !id.IsClusterKind())
|
||||||
mf.AppendWithId(id, res)
|
}
|
||||||
m.Remove(id)
|
|
||||||
}
|
func (o *namespaceTransformer) changeNamespace(
|
||||||
}
|
r *resource.Resource, fs *config.FieldSpec) error {
|
||||||
if !found {
|
return MutateField(
|
||||||
mf.AppendWithId(id, res)
|
r.Map(), fs.PathSlice(), fs.CreateIfNotPresent,
|
||||||
m.Remove(id)
|
func(_ interface{}) (interface{}, error) {
|
||||||
|
return o.namespace, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *namespaceTransformer) isSelected(
|
||||||
|
id resid.ResId) (*config.FieldSpec, bool) {
|
||||||
|
for _, fs := range o.fieldSpecsToUse {
|
||||||
|
if id.IsSelected(&fs.Gvk) {
|
||||||
|
return &fs, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return mf
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *namespaceTransformer) updateClusterRoleBinding(m resmap.ResMap) {
|
func (o *namespaceTransformer) updateClusterRoleBinding(m resmap.ResMap) {
|
||||||
|
srvAccount := gvk.Gvk{Version: "v1", Kind: "ServiceAccount"}
|
||||||
saMap := map[string]bool{}
|
saMap := map[string]bool{}
|
||||||
for id := range m.AsMap() {
|
for _, id := range m.AllIds() {
|
||||||
if id.Gvk().Equals(gvk.Gvk{Version: "v1", Kind: "ServiceAccount"}) {
|
if id.Gvk.Equals(srvAccount) {
|
||||||
saMap[id.Name()] = true
|
saMap[id.Name] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for id, res := range m.AsMap() {
|
for _, res := range m.Resources() {
|
||||||
if id.Gvk().Kind != "ClusterRoleBinding" && id.Gvk().Kind != "RoleBinding" {
|
if res.OrgId().Kind != "ClusterRoleBinding" &&
|
||||||
|
res.OrgId().Kind != "RoleBinding" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
objMap := res.Map()
|
objMap := res.Map()
|
||||||
@@ -138,15 +105,17 @@ func (o *namespaceTransformer) updateClusterRoleBinding(m resmap.ResMap) {
|
|||||||
subject := subjects[i].(map[string]interface{})
|
subject := subjects[i].(map[string]interface{})
|
||||||
kind, foundk := subject["kind"]
|
kind, foundk := subject["kind"]
|
||||||
name, foundn := subject["name"]
|
name, foundn := subject["name"]
|
||||||
if !foundk || !foundn || kind.(string) != "ServiceAccount" {
|
if !foundk || !foundn || kind.(string) != srvAccount.Kind {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// a ServiceAccount named “default” exists in every active namespace
|
// a ServiceAccount named “default” exists in every active namespace
|
||||||
if name.(string) == "default" || saMap[name.(string)] {
|
if name.(string) == "default" || saMap[name.(string)] {
|
||||||
subject := subjects[i].(map[string]interface{})
|
subject := subjects[i].(map[string]interface{})
|
||||||
MutateField(subject, []string{"namespace"}, true, func(_ interface{}) (interface{}, error) {
|
MutateField(
|
||||||
return o.namespace, nil
|
subject, []string{"namespace"},
|
||||||
})
|
true, func(_ interface{}) (interface{}, error) {
|
||||||
|
return o.namespace, nil
|
||||||
|
})
|
||||||
subjects[i] = subject
|
subjects[i] = subject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 transformers
|
package transformers
|
||||||
|
|
||||||
@@ -20,184 +7,148 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
"sigs.k8s.io/kustomize/k8sdeps/kunstruct"
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNamespaceRun(t *testing.T) {
|
func TestNamespaceRun(t *testing.T) {
|
||||||
rf := resource.NewFactory(
|
rf := resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
m := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"apiVersion": "v1",
|
"kind": "ConfigMap",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "cm1",
|
||||||
"name": "cm1",
|
}}).
|
||||||
},
|
Add(map[string]interface{}{
|
||||||
}),
|
"apiVersion": "v1",
|
||||||
resid.NewResId(cmap, "cm2"): rf.FromMap(
|
"kind": "ConfigMap",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"name": "cm2",
|
||||||
"kind": "ConfigMap",
|
"namespace": "foo",
|
||||||
"metadata": map[string]interface{}{
|
}}).
|
||||||
"name": "cm2",
|
Add(map[string]interface{}{
|
||||||
"namespace": "foo",
|
"apiVersion": "v1",
|
||||||
},
|
"kind": "Namespace",
|
||||||
}),
|
"metadata": map[string]interface{}{
|
||||||
resid.NewResId(cmap, "cm3"): rf.FromMap(
|
"name": "ns1",
|
||||||
map[string]interface{}{},
|
}}).
|
||||||
),
|
Add(map[string]interface{}{
|
||||||
resid.NewResId(ns, "ns1"): rf.FromMap(
|
"apiVersion": "v1",
|
||||||
map[string]interface{}{
|
"kind": "ServiceAccount",
|
||||||
"apiVersion": "v1",
|
"metadata": map[string]interface{}{
|
||||||
"kind": "Namespace",
|
"name": "default",
|
||||||
"metadata": map[string]interface{}{
|
"namespace": "system",
|
||||||
"name": "ns1",
|
}}).
|
||||||
},
|
Add(map[string]interface{}{
|
||||||
}),
|
"apiVersion": "v1",
|
||||||
resid.NewResId(sa, "default"): rf.FromMap(
|
"kind": "ServiceAccount",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"name": "service-account",
|
||||||
"kind": "ServiceAccount",
|
"namespace": "system",
|
||||||
"metadata": map[string]interface{}{
|
}}).
|
||||||
|
Add(map[string]interface{}{
|
||||||
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
|
"kind": "ClusterRoleBinding",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "manager-rolebinding",
|
||||||
|
},
|
||||||
|
"subjects": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"kind": "ServiceAccount",
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"namespace": "system",
|
"namespace": "system",
|
||||||
},
|
},
|
||||||
}),
|
map[string]interface{}{
|
||||||
resid.NewResId(sa, "service-account"): rf.FromMap(
|
"kind": "ServiceAccount",
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ServiceAccount",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "service-account",
|
"name": "service-account",
|
||||||
"namespace": "system",
|
"namespace": "system",
|
||||||
},
|
},
|
||||||
}),
|
map[string]interface{}{
|
||||||
resid.NewResId(crb, "crb"): rf.FromMap(
|
"kind": "ServiceAccount",
|
||||||
map[string]interface{}{
|
"name": "another",
|
||||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
"namespace": "random",
|
||||||
"kind": "ClusterRoleBinding",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "manager-rolebinding",
|
|
||||||
},
|
},
|
||||||
"subjects": []interface{}{
|
}}).
|
||||||
map[string]interface{}{
|
Add(map[string]interface{}{
|
||||||
"kind": "ServiceAccount",
|
"apiVersion": "apiextensions.k8s.io/v1beta1",
|
||||||
"name": "default",
|
"kind": "CustomResourceDefinition",
|
||||||
"namespace": "system",
|
"metadata": map[string]interface{}{
|
||||||
},
|
"name": "crd",
|
||||||
map[string]interface{}{
|
}}).ResMap()
|
||||||
"kind": "ServiceAccount",
|
|
||||||
"name": "service-account",
|
expected := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
"namespace": "system",
|
Add(map[string]interface{}{
|
||||||
},
|
"apiVersion": "v1",
|
||||||
map[string]interface{}{
|
"kind": "ConfigMap",
|
||||||
"kind": "ServiceAccount",
|
"metadata": map[string]interface{}{
|
||||||
"name": "another",
|
"name": "cm1",
|
||||||
"namespace": "random",
|
"namespace": "test",
|
||||||
},
|
}}).
|
||||||
},
|
Add(map[string]interface{}{
|
||||||
}),
|
"apiVersion": "v1",
|
||||||
resid.NewResId(crd, "crd"): rf.FromMap(
|
"kind": "ConfigMap",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "apiextensions.k8s.io/v1beta1",
|
"name": "cm2",
|
||||||
"kind": "CustomResourceDefinition",
|
"namespace": "test",
|
||||||
"metadata": map[string]interface{}{
|
}}).
|
||||||
"name": "crd",
|
Add(map[string]interface{}{
|
||||||
},
|
"apiVersion": "v1",
|
||||||
}),
|
"kind": "Namespace",
|
||||||
})
|
"metadata": map[string]interface{}{
|
||||||
expected := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
"name": "ns1",
|
||||||
resid.NewResIdWithNamespace(ns, "ns1", ""): rf.FromMap(
|
}}).
|
||||||
map[string]interface{}{
|
Add(map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Namespace",
|
"kind": "ServiceAccount",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "ns1",
|
"name": "default",
|
||||||
},
|
"namespace": "test",
|
||||||
}),
|
}}).
|
||||||
resid.NewResIdWithNamespace(cmap, "cm1", "test"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"apiVersion": "v1",
|
"kind": "ServiceAccount",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "service-account",
|
||||||
"name": "cm1",
|
"namespace": "test",
|
||||||
"namespace": "test",
|
}}).
|
||||||
},
|
Add(map[string]interface{}{
|
||||||
}),
|
"apiVersion": "rbac.authorization.k8s.io/v1",
|
||||||
resid.NewResIdWithNamespace(cmap, "cm2", "test"): rf.FromMap(
|
"kind": "ClusterRoleBinding",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"name": "manager-rolebinding",
|
||||||
"kind": "ConfigMap",
|
},
|
||||||
"metadata": map[string]interface{}{
|
"subjects": []interface{}{
|
||||||
"name": "cm2",
|
map[string]interface{}{
|
||||||
"namespace": "test",
|
"kind": "ServiceAccount",
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResIdWithNamespace(cmap, "cm3", "test"): rf.FromMap(
|
|
||||||
map[string]interface{}{},
|
|
||||||
),
|
|
||||||
resid.NewResIdWithNamespace(sa, "default", "test"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ServiceAccount",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "default",
|
"name": "default",
|
||||||
"namespace": "test",
|
"namespace": "test",
|
||||||
},
|
},
|
||||||
}),
|
map[string]interface{}{
|
||||||
resid.NewResIdWithNamespace(sa, "service-account", "test"): rf.FromMap(
|
"kind": "ServiceAccount",
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ServiceAccount",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "service-account",
|
"name": "service-account",
|
||||||
"namespace": "test",
|
"namespace": "test",
|
||||||
},
|
},
|
||||||
}),
|
map[string]interface{}{
|
||||||
resid.NewResId(crb, "crb"): rf.FromMap(
|
"kind": "ServiceAccount",
|
||||||
map[string]interface{}{
|
"name": "another",
|
||||||
"apiVersion": "rbac.authorization.k8s.io/v1",
|
"namespace": "random",
|
||||||
"kind": "ClusterRoleBinding",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "manager-rolebinding",
|
|
||||||
},
|
},
|
||||||
"subjects": []interface{}{
|
}}).
|
||||||
map[string]interface{}{
|
Add(map[string]interface{}{
|
||||||
"kind": "ServiceAccount",
|
"apiVersion": "apiextensions.k8s.io/v1beta1",
|
||||||
"name": "default",
|
"kind": "CustomResourceDefinition",
|
||||||
"namespace": "test",
|
"metadata": map[string]interface{}{
|
||||||
},
|
"name": "crd",
|
||||||
map[string]interface{}{
|
}}).ResMap()
|
||||||
"kind": "ServiceAccount",
|
|
||||||
"name": "service-account",
|
|
||||||
"namespace": "test",
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"kind": "ServiceAccount",
|
|
||||||
"name": "another",
|
|
||||||
"namespace": "random",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResId(crd, "crd"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "apiextensions.k8s.io/v1beta1",
|
|
||||||
"kind": "CustomResourceDefinition",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "crd",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
nst := NewNamespaceTransformer("test", defaultTransformerConfig.NameSpace)
|
nst := NewNamespaceTransformer("test", defaultTransformerConfig.NameSpace)
|
||||||
err := nst.Transform(m)
|
err := nst.Transform(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err = expected.ErrorIfNotEqualSets(m); err != nil {
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,45 +156,34 @@ func TestNamespaceRun(t *testing.T) {
|
|||||||
func TestNamespaceRunForClusterLevelKind(t *testing.T) {
|
func TestNamespaceRunForClusterLevelKind(t *testing.T) {
|
||||||
rf := resource.NewFactory(
|
rf := resource.NewFactory(
|
||||||
kunstruct.NewKunstructuredFactoryImpl())
|
kunstruct.NewKunstructuredFactoryImpl())
|
||||||
m := resmap.FromMap(map[resid.ResId]*resource.Resource{
|
m := resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(ns, "ns1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"apiVersion": "v1",
|
"kind": "Namespace",
|
||||||
"kind": "Namespace",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "ns1",
|
||||||
"name": "ns1",
|
}}).
|
||||||
},
|
Add(map[string]interface{}{
|
||||||
}),
|
"kind": "CustomResourceDefinition",
|
||||||
resid.NewResId(crd, "crd1"): rf.FromMap(
|
"metadata": map[string]interface{}{
|
||||||
map[string]interface{}{
|
"name": "crd1",
|
||||||
"kind": "CustomResourceDefinition",
|
}}).
|
||||||
"metadata": map[string]interface{}{
|
Add(map[string]interface{}{
|
||||||
"name": "crd1",
|
"kind": "PersistentVolume",
|
||||||
},
|
"metadata": map[string]interface{}{
|
||||||
}),
|
"name": "pv1",
|
||||||
resid.NewResId(pv, "pv1"): rf.FromMap(
|
}}).
|
||||||
map[string]interface{}{
|
Add(map[string]interface{}{
|
||||||
"kind": "PersistentVolume",
|
"kind": "ClusterRole",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": "pv1",
|
"name": "cr1",
|
||||||
},
|
}}).
|
||||||
}),
|
Add(map[string]interface{}{
|
||||||
resid.NewResId(cr, "cr1"): rf.FromMap(
|
"kind": "ClusterRoleBinding",
|
||||||
map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"kind": "ClusterRole",
|
"name": "crb1",
|
||||||
"metadata": map[string]interface{}{
|
},
|
||||||
"name": "cr1",
|
"subjects": []interface{}{}}).ResMap()
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResId(crb, "crb1"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"kind": "ClusterRoleBinding",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "crb1",
|
|
||||||
},
|
|
||||||
"subjects": []interface{}{},
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
|
|
||||||
expected := m.DeepCopy()
|
expected := m.DeepCopy()
|
||||||
|
|
||||||
@@ -253,7 +193,7 @@ func TestNamespaceRunForClusterLevelKind(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if err = expected.ErrorIfNotEqualSets(m); err != nil {
|
if err = expected.ErrorIfNotEqualLists(m); err != nil {
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ func (rv *RefVarTransformer) Transform(m resmap.ResMap) error {
|
|||||||
rv.replacementCounts, rv.varMap)
|
rv.replacementCounts, rv.varMap)
|
||||||
for _, res := range m.Resources() {
|
for _, res := range m.Resources() {
|
||||||
for _, fieldSpec := range rv.fieldSpecs {
|
for _, fieldSpec := range rv.fieldSpecs {
|
||||||
if res.Id().Gvk().IsSelected(&fieldSpec.Gvk) {
|
if res.OrgId().IsSelected(&fieldSpec.Gvk) {
|
||||||
if err := MutateField(
|
if err := MutateField(
|
||||||
res.Map(), fieldSpec.PathSlice(),
|
res.Map(), fieldSpec.PathSlice(),
|
||||||
false, rv.replaceVars); err != nil {
|
false, rv.replaceVars); err != nil {
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
/*
|
// Copyright 2019 The Kubernetes Authors.
|
||||||
Copyright 2018 The Kubernetes Authors.
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
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 transformers
|
package transformers
|
||||||
|
|
||||||
@@ -20,9 +7,9 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resmaptest"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,38 +36,33 @@ func TestVarRef(t *testing.T) {
|
|||||||
"BAR": "replacementForBar",
|
"BAR": "replacementForBar",
|
||||||
},
|
},
|
||||||
fs: []config.FieldSpec{
|
fs: []config.FieldSpec{
|
||||||
{Gvk: cmap, Path: "data"},
|
{Gvk: gvk.Gvk{Version: "v1", Kind: "ConfigMap"}, Path: "data"},
|
||||||
},
|
},
|
||||||
res: resmap.FromMap(map[resid.ResId]*resource.Resource{
|
res: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"apiVersion": "v1",
|
"kind": "ConfigMap",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "cm1",
|
||||||
"name": "cm1",
|
},
|
||||||
},
|
"data": map[string]interface{}{
|
||||||
"data": map[string]interface{}{
|
"item1": "$(FOO)",
|
||||||
"item1": "$(FOO)",
|
"item2": "bla",
|
||||||
"item2": "bla",
|
},
|
||||||
},
|
}).ResMap(),
|
||||||
}),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
expected: expected{
|
expected: expected{
|
||||||
res: resmap.FromMap(map[resid.ResId]*resource.Resource{
|
res: resmaptest_test.NewRmBuilder(t, rf).
|
||||||
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
Add(map[string]interface{}{
|
||||||
map[string]interface{}{
|
"apiVersion": "v1",
|
||||||
"apiVersion": "v1",
|
"kind": "ConfigMap",
|
||||||
"kind": "ConfigMap",
|
"metadata": map[string]interface{}{
|
||||||
"metadata": map[string]interface{}{
|
"name": "cm1",
|
||||||
"name": "cm1",
|
},
|
||||||
},
|
"data": map[string]interface{}{
|
||||||
"data": map[string]interface{}{
|
"item1": "replacementForFoo",
|
||||||
"item1": "replacementForFoo",
|
"item2": "bla",
|
||||||
"item2": "bla",
|
}}).ResMap(),
|
||||||
},
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
unused: []string{"BAR"},
|
unused: []string{"BAR"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -101,7 +83,7 @@ func TestVarRef(t *testing.T) {
|
|||||||
|
|
||||||
a, e := tc.given.res, tc.expected.res
|
a, e := tc.given.res, tc.expected.res
|
||||||
if !reflect.DeepEqual(a, e) {
|
if !reflect.DeepEqual(a, e) {
|
||||||
err = e.ErrorIfNotEqualSets(a)
|
err = e.ErrorIfNotEqualLists(a)
|
||||||
t.Fatalf("actual doesn't match expected: \nACTUAL:\n%v\nEXPECTED:\n%v\nERR: %v", a, e, err)
|
t.Fatalf("actual doesn't match expected: \nACTUAL:\n%v\nEXPECTED:\n%v\nERR: %v", a, e, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type AnnotationsTransformerPlugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewAnnotationsTransformerPlugin() *AnnotationsTransformerPlugin {
|
func NewAnnotationsTransformerPlugin() *AnnotationsTransformerPlugin {
|
||||||
return &AnnotationsTransformerPlugin{}
|
return &AnnotationsTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type ConfigMapGeneratorPlugin struct {
|
|||||||
types.ConfigMapArgs
|
types.ConfigMapArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewConfigMapGeneratorPlugin() *ConfigMapGeneratorPlugin {
|
func NewConfigMapGeneratorPlugin() *ConfigMapGeneratorPlugin {
|
||||||
return &ConfigMapGeneratorPlugin{}
|
return &ConfigMapGeneratorPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ type HashTransformerPlugin struct {
|
|||||||
hasher ifc.KunstructuredHasher
|
hasher ifc.KunstructuredHasher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewHashTransformerPlugin() *HashTransformerPlugin {
|
func NewHashTransformerPlugin() *HashTransformerPlugin {
|
||||||
return &HashTransformerPlugin{}
|
return &HashTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type ImageTagTransformerPlugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewImageTagTransformerPlugin() *ImageTagTransformerPlugin {
|
func NewImageTagTransformerPlugin() *ImageTagTransformerPlugin {
|
||||||
return &ImageTagTransformerPlugin{}
|
return &ImageTagTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package builtin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
|
|
||||||
@@ -24,6 +23,7 @@ type InventoryTransformerPlugin struct {
|
|||||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewInventoryTransformerPlugin() *InventoryTransformerPlugin {
|
func NewInventoryTransformerPlugin() *InventoryTransformerPlugin {
|
||||||
return &InventoryTransformerPlugin{}
|
return &InventoryTransformerPlugin{}
|
||||||
}
|
}
|
||||||
@@ -98,32 +98,33 @@ func makeInventory(m resmap.ResMap) (
|
|||||||
inv = inventory.NewInventory()
|
inv = inventory.NewInventory()
|
||||||
var keys []string
|
var keys []string
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
ns := getNamespace(r)
|
ns := r.GetNamespace()
|
||||||
item := resid.NewItemId(r.GetGvk(), ns, r.GetName())
|
item := resid.NewResIdWithNamespace(r.GetGvk(), r.GetName(), ns)
|
||||||
if _, ok := inv.Current[item]; ok {
|
if _, ok := inv.Current[item]; ok {
|
||||||
return nil, "", fmt.Errorf(
|
return nil, "", fmt.Errorf(
|
||||||
"item '%v' already in inventory", item)
|
"item '%v' already in inventory", item)
|
||||||
}
|
}
|
||||||
inv.Current[item] = computeRefs(r, m)
|
inv.Current[item], err = computeRefs(r, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
keys = append(keys, item.String())
|
keys = append(keys, item.String())
|
||||||
}
|
}
|
||||||
h, err := hasher.SortArrayAndComputeHash(keys)
|
h, err := hasher.SortArrayAndComputeHash(keys)
|
||||||
return inv, h, err
|
return inv, h, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNamespace(r *resource.Resource) string {
|
func computeRefs(
|
||||||
ns, err := r.GetFieldValue("metadata.namespace")
|
r *resource.Resource, m resmap.ResMap) (refs []resid.ResId, err error) {
|
||||||
if err != nil && !strings.Contains(err.Error(), "no field named") {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return ns
|
|
||||||
}
|
|
||||||
|
|
||||||
func computeRefs(r *resource.Resource, m resmap.ResMap) (refs []resid.ItemId) {
|
|
||||||
for _, refid := range r.GetRefBy() {
|
for _, refid := range r.GetRefBy() {
|
||||||
ref := m.GetById(refid)
|
ref, err := m.GetByCurrentId(refid)
|
||||||
ns := getNamespace(ref)
|
if err != nil {
|
||||||
refs = append(refs, resid.NewItemId(ref.GetGvk(), ns, ref.GetName()))
|
return nil, err
|
||||||
|
}
|
||||||
|
refs = append(
|
||||||
|
refs,
|
||||||
|
resid.NewResIdWithNamespace(
|
||||||
|
ref.GetGvk(), ref.GetName(), ref.GetNamespace()))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type LabelTransformerPlugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewLabelTransformerPlugin() *LabelTransformerPlugin {
|
func NewLabelTransformerPlugin() *LabelTransformerPlugin {
|
||||||
return &LabelTransformerPlugin{}
|
return &LabelTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
package builtin
|
package builtin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
@@ -15,6 +16,7 @@ import (
|
|||||||
// (like ValidatingWebhookConfiguration) last.
|
// (like ValidatingWebhookConfiguration) last.
|
||||||
type LegacyOrderTransformerPlugin struct{}
|
type LegacyOrderTransformerPlugin struct{}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewLegacyOrderTransformerPlugin() *LegacyOrderTransformerPlugin {
|
func NewLegacyOrderTransformerPlugin() *LegacyOrderTransformerPlugin {
|
||||||
return &LegacyOrderTransformerPlugin{}
|
return &LegacyOrderTransformerPlugin{}
|
||||||
}
|
}
|
||||||
@@ -25,16 +27,19 @@ func (p *LegacyOrderTransformerPlugin) Config(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *LegacyOrderTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *LegacyOrderTransformerPlugin) Transform(m resmap.ResMap) (err error) {
|
||||||
resources := make([]*resource.Resource, m.Size())
|
resources := make([]*resource.Resource, m.Size())
|
||||||
ids := m.AllIds()
|
ids := m.AllIds()
|
||||||
sort.Sort(resmap.IdSlice(ids))
|
sort.Sort(resmap.IdSlice(ids))
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
resources[i] = m.GetById(id)
|
resources[i], err = m.GetByCurrentId(id)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "expected match for sorting")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m.Clear()
|
m.Clear()
|
||||||
for i, id := range ids {
|
for _, r := range resources {
|
||||||
m.AppendWithId(id, resources[i])
|
m.Append(r)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type NamespaceTransformerPlugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewNamespaceTransformerPlugin() *NamespaceTransformerPlugin {
|
func NewNamespaceTransformerPlugin() *NamespaceTransformerPlugin {
|
||||||
return &NamespaceTransformerPlugin{}
|
return &NamespaceTransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type PatchJson6902TransformerPlugin struct {
|
|||||||
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
|
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewPatchJson6902TransformerPlugin() *PatchJson6902TransformerPlugin {
|
func NewPatchJson6902TransformerPlugin() *PatchJson6902TransformerPlugin {
|
||||||
return &PatchJson6902TransformerPlugin{}
|
return &PatchJson6902TransformerPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
@@ -20,6 +21,7 @@ type PrefixSuffixTransformerPlugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewPrefixSuffixTransformerPlugin() *PrefixSuffixTransformerPlugin {
|
func NewPrefixSuffixTransformerPlugin() *PrefixSuffixTransformerPlugin {
|
||||||
return &PrefixSuffixTransformerPlugin{}
|
return &PrefixSuffixTransformerPlugin{}
|
||||||
}
|
}
|
||||||
@@ -50,46 +52,54 @@ func (p *PrefixSuffixTransformerPlugin) Transform(m resmap.ResMap) error {
|
|||||||
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
|
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
for _, r := range m.Resources() {
|
||||||
// Fill map "mf" with entries subject to name modification, and
|
if p.shouldSkip(r.OrgId()) {
|
||||||
// delete these entries from "m", so that for now m retains only
|
continue
|
||||||
// the entries whose names will not be modified.
|
|
||||||
mf := resmap.New()
|
|
||||||
for id, r := range m.AsMap() {
|
|
||||||
found := false
|
|
||||||
for _, path := range prefixSuffixFieldSpecsToSkip {
|
|
||||||
if id.Gvk().IsSelected(&path.Gvk) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !found {
|
fs, ok := p.shouldInclude(r.OrgId())
|
||||||
mf.AppendWithId(id, r)
|
if !ok {
|
||||||
m.Remove(id)
|
continue
|
||||||
}
|
}
|
||||||
}
|
if smellsLikeANameChange(fs) {
|
||||||
|
r.AddNamePrefix(p.Prefix)
|
||||||
for id, r := range mf.AsMap() {
|
r.AddNameSuffix(p.Suffix)
|
||||||
objMap := r.Map()
|
}
|
||||||
for _, path := range p.FieldSpecs {
|
err := transformers.MutateField(
|
||||||
if !id.Gvk().IsSelected(&path.Gvk) {
|
r.Map(),
|
||||||
continue
|
fs.PathSlice(),
|
||||||
}
|
fs.CreateIfNotPresent,
|
||||||
err := transformers.MutateField(
|
p.addPrefixSuffix)
|
||||||
objMap,
|
if err != nil {
|
||||||
path.PathSlice(),
|
return err
|
||||||
path.CreateIfNotPresent,
|
|
||||||
p.addPrefixSuffix)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newId := id.CopyWithNewPrefixSuffix(p.Prefix, p.Suffix)
|
|
||||||
m.AppendWithId(newId, r)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func smellsLikeANameChange(fs *config.FieldSpec) bool {
|
||||||
|
return fs.Path == "metadata/name"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrefixSuffixTransformerPlugin) shouldInclude(
|
||||||
|
id resid.ResId) (*config.FieldSpec, bool) {
|
||||||
|
for _, path := range p.FieldSpecs {
|
||||||
|
if id.IsSelected(&path.Gvk) {
|
||||||
|
return &path, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrefixSuffixTransformerPlugin) shouldSkip(
|
||||||
|
id resid.ResId) bool {
|
||||||
|
for _, path := range prefixSuffixFieldSpecsToSkip {
|
||||||
|
if id.IsSelected(&path.Gvk) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
|
func (p *PrefixSuffixTransformerPlugin) addPrefixSuffix(
|
||||||
in interface{}) (interface{}, error) {
|
in interface{}) (interface{}, error) {
|
||||||
s, ok := in.(string)
|
s, ok := in.(string)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type ReplicaCountTransformerPlugin struct {
|
|||||||
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewReplicaCountTransformerPlugin() *ReplicaCountTransformerPlugin {
|
func NewReplicaCountTransformerPlugin() *ReplicaCountTransformerPlugin {
|
||||||
return &ReplicaCountTransformerPlugin{}
|
return &ReplicaCountTransformerPlugin{}
|
||||||
}
|
}
|
||||||
@@ -35,11 +36,11 @@ func (p *ReplicaCountTransformerPlugin) Config(
|
|||||||
|
|
||||||
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *ReplicaCountTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
matcher := func(r resid.ResId) bool {
|
matcher := func(r resid.ResId) bool {
|
||||||
return r.ItemId.Name == p.Replica.Name
|
return r.Name == p.Replica.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, id := range m.GetMatchingIds(matcher) {
|
for _, r := range m.GetMatchingResourcesByOriginalId(matcher) {
|
||||||
kMap := m.GetById(id).Map()
|
kMap := r.Map()
|
||||||
|
|
||||||
specInterface, ok := kMap[fldSpec]
|
specInterface, ok := kMap[fldSpec]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type SecretGeneratorPlugin struct {
|
|||||||
types.SecretArgs
|
types.SecretArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
func NewSecretGeneratorPlugin() *SecretGeneratorPlugin {
|
func NewSecretGeneratorPlugin() *SecretGeneratorPlugin {
|
||||||
return &SecretGeneratorPlugin{}
|
return &SecretGeneratorPlugin{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type plugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type plugin struct {
|
|||||||
types.ConfigMapArgs
|
types.ConfigMapArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type plugin struct {
|
|||||||
hasher ifc.KunstructuredHasher
|
hasher ifc.KunstructuredHasher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ type plugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
|
|
||||||
@@ -27,6 +26,7 @@ type plugin struct {
|
|||||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
@@ -99,32 +99,33 @@ func makeInventory(m resmap.ResMap) (
|
|||||||
inv = inventory.NewInventory()
|
inv = inventory.NewInventory()
|
||||||
var keys []string
|
var keys []string
|
||||||
for _, r := range m.Resources() {
|
for _, r := range m.Resources() {
|
||||||
ns := getNamespace(r)
|
ns := r.GetNamespace()
|
||||||
item := resid.NewItemId(r.GetGvk(), ns, r.GetName())
|
item := resid.NewResIdWithNamespace(r.GetGvk(), r.GetName(), ns)
|
||||||
if _, ok := inv.Current[item]; ok {
|
if _, ok := inv.Current[item]; ok {
|
||||||
return nil, "", fmt.Errorf(
|
return nil, "", fmt.Errorf(
|
||||||
"item '%v' already in inventory", item)
|
"item '%v' already in inventory", item)
|
||||||
}
|
}
|
||||||
inv.Current[item] = computeRefs(r, m)
|
inv.Current[item], err = computeRefs(r, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
keys = append(keys, item.String())
|
keys = append(keys, item.String())
|
||||||
}
|
}
|
||||||
h, err := hasher.SortArrayAndComputeHash(keys)
|
h, err := hasher.SortArrayAndComputeHash(keys)
|
||||||
return inv, h, err
|
return inv, h, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getNamespace(r *resource.Resource) string {
|
func computeRefs(
|
||||||
ns, err := r.GetFieldValue("metadata.namespace")
|
r *resource.Resource, m resmap.ResMap) (refs []resid.ResId, err error) {
|
||||||
if err != nil && !strings.Contains(err.Error(), "no field named") {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return ns
|
|
||||||
}
|
|
||||||
|
|
||||||
func computeRefs(r *resource.Resource, m resmap.ResMap) (refs []resid.ItemId) {
|
|
||||||
for _, refid := range r.GetRefBy() {
|
for _, refid := range r.GetRefBy() {
|
||||||
ref := m.GetById(refid)
|
ref, err := m.GetByCurrentId(refid)
|
||||||
ns := getNamespace(ref)
|
if err != nil {
|
||||||
refs = append(refs, resid.NewItemId(ref.GetGvk(), ns, ref.GetName()))
|
return nil, err
|
||||||
|
}
|
||||||
|
refs = append(
|
||||||
|
refs,
|
||||||
|
resid.NewResIdWithNamespace(
|
||||||
|
ref.GetGvk(), ref.GetName(), ref.GetNamespace()))
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type plugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
@@ -18,6 +19,7 @@ import (
|
|||||||
// (like ValidatingWebhookConfiguration) last.
|
// (like ValidatingWebhookConfiguration) last.
|
||||||
type plugin struct{}
|
type plugin struct{}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
// Nothing needed for configuration.
|
// Nothing needed for configuration.
|
||||||
@@ -26,16 +28,19 @@ func (p *plugin) Config(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
func (p *plugin) Transform(m resmap.ResMap) (err error) {
|
||||||
resources := make([]*resource.Resource, m.Size())
|
resources := make([]*resource.Resource, m.Size())
|
||||||
ids := m.AllIds()
|
ids := m.AllIds()
|
||||||
sort.Sort(resmap.IdSlice(ids))
|
sort.Sort(resmap.IdSlice(ids))
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
resources[i] = m.GetById(id)
|
resources[i], err = m.GetByCurrentId(id)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "expected match for sorting")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m.Clear()
|
m.Clear()
|
||||||
for i, id := range ids {
|
for _, r := range resources {
|
||||||
m.AppendWithId(id, resources[i])
|
m.Append(r)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type plugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type plugin struct {
|
|||||||
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
|
Patches []types.PatchJson6902 `json:"patches,omitempty" yaml:"patches,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/pkg/resmap"
|
"sigs.k8s.io/kustomize/pkg/resmap"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers"
|
"sigs.k8s.io/kustomize/pkg/transformers"
|
||||||
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
"sigs.k8s.io/kustomize/pkg/transformers/config"
|
||||||
@@ -23,6 +24,7 @@ type plugin struct {
|
|||||||
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
FieldSpecs []config.FieldSpec `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
// Not placed in a file yet due to lack of demand.
|
// Not placed in a file yet due to lack of demand.
|
||||||
@@ -51,46 +53,54 @@ func (p *plugin) Transform(m resmap.ResMap) error {
|
|||||||
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
|
if len(p.Prefix) == 0 && len(p.Suffix) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
for _, r := range m.Resources() {
|
||||||
// Fill map "mf" with entries subject to name modification, and
|
if p.shouldSkip(r.OrgId()) {
|
||||||
// delete these entries from "m", so that for now m retains only
|
continue
|
||||||
// the entries whose names will not be modified.
|
|
||||||
mf := resmap.New()
|
|
||||||
for id, r := range m.AsMap() {
|
|
||||||
found := false
|
|
||||||
for _, path := range prefixSuffixFieldSpecsToSkip {
|
|
||||||
if id.Gvk().IsSelected(&path.Gvk) {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if !found {
|
fs, ok := p.shouldInclude(r.OrgId())
|
||||||
mf.AppendWithId(id, r)
|
if !ok {
|
||||||
m.Remove(id)
|
continue
|
||||||
}
|
}
|
||||||
}
|
if smellsLikeANameChange(fs) {
|
||||||
|
r.AddNamePrefix(p.Prefix)
|
||||||
for id, r := range mf.AsMap() {
|
r.AddNameSuffix(p.Suffix)
|
||||||
objMap := r.Map()
|
}
|
||||||
for _, path := range p.FieldSpecs {
|
err := transformers.MutateField(
|
||||||
if !id.Gvk().IsSelected(&path.Gvk) {
|
r.Map(),
|
||||||
continue
|
fs.PathSlice(),
|
||||||
}
|
fs.CreateIfNotPresent,
|
||||||
err := transformers.MutateField(
|
p.addPrefixSuffix)
|
||||||
objMap,
|
if err != nil {
|
||||||
path.PathSlice(),
|
return err
|
||||||
path.CreateIfNotPresent,
|
|
||||||
p.addPrefixSuffix)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newId := id.CopyWithNewPrefixSuffix(p.Prefix, p.Suffix)
|
|
||||||
m.AppendWithId(newId, r)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func smellsLikeANameChange(fs *config.FieldSpec) bool {
|
||||||
|
return fs.Path == "metadata/name"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) shouldInclude(
|
||||||
|
id resid.ResId) (*config.FieldSpec, bool) {
|
||||||
|
for _, path := range p.FieldSpecs {
|
||||||
|
if id.IsSelected(&path.Gvk) {
|
||||||
|
return &path, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *plugin) shouldSkip(
|
||||||
|
id resid.ResId) bool {
|
||||||
|
for _, path := range prefixSuffixFieldSpecsToSkip {
|
||||||
|
if id.IsSelected(&path.Gvk) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *plugin) addPrefixSuffix(
|
func (p *plugin) addPrefixSuffix(
|
||||||
in interface{}) (interface{}, error) {
|
in interface{}) (interface{}, error) {
|
||||||
s, ok := in.(string)
|
s, ok := in.(string)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type plugin struct {
|
|||||||
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
Replica types.Replica `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
@@ -36,11 +37,11 @@ func (p *plugin) Config(
|
|||||||
|
|
||||||
func (p *plugin) Transform(m resmap.ResMap) error {
|
func (p *plugin) Transform(m resmap.ResMap) error {
|
||||||
matcher := func(r resid.ResId) bool {
|
matcher := func(r resid.ResId) bool {
|
||||||
return r.ItemId.Name == p.Replica.Name
|
return r.Name == p.Replica.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, id := range m.GetMatchingIds(matcher) {
|
for _, r := range m.GetMatchingResourcesByOriginalId(matcher) {
|
||||||
kMap := m.GetById(id).Map()
|
kMap := r.Map()
|
||||||
|
|
||||||
specInterface, ok := kMap[fldSpec]
|
specInterface, ok := kMap[fldSpec]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type plugin struct {
|
|||||||
types.SecretArgs
|
types.SecretArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) Config(
|
func (p *plugin) Config(
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ kind: Secret
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.1
|
chart: minecraft-1.0.3
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: release-name-minecraft
|
name: release-name-minecraft
|
||||||
@@ -53,7 +53,7 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.1
|
chart: minecraft-1.0.3
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: release-name-minecraft
|
name: release-name-minecraft
|
||||||
@@ -74,7 +74,7 @@ metadata:
|
|||||||
volume.alpha.kubernetes.io/storage-class: default
|
volume.alpha.kubernetes.io/storage-class: default
|
||||||
labels:
|
labels:
|
||||||
app: release-name-minecraft
|
app: release-name-minecraft
|
||||||
chart: minecraft-1.0.1
|
chart: minecraft-1.0.3
|
||||||
heritage: Tiller
|
heritage: Tiller
|
||||||
release: release-name
|
release: release-name
|
||||||
name: release-name-minecraft-datadir
|
name: release-name-minecraft-datadir
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ type plugin struct {
|
|||||||
t transformers.Transformer
|
t transformers.Transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
//nolint: golint
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) makePrefixSuffixPluginConfig() ([]byte, error) {
|
func (p *plugin) makePrefixSuffixPluginConfig() ([]byte, error) {
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ type plugin struct {
|
|||||||
Keys []string `json:"keys,omitempty" yaml:"keys,omitempty"`
|
Keys []string `json:"keys,omitempty" yaml:"keys,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
//nolint: golint
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
var database = map[string]string{
|
var database = map[string]string{
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ type plugin struct {
|
|||||||
Port string `json:"port,omitempty" yaml:"port,omitempty"`
|
Port string `json:"port,omitempty" yaml:"port,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
//nolint: golint
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
const tmpl = `
|
const tmpl = `
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ type metaData struct {
|
|||||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//noinspection GoUnusedGlobalVariable
|
||||||
|
//nolint: golint
|
||||||
var KustomizePlugin plugin
|
var KustomizePlugin plugin
|
||||||
|
|
||||||
func (p *plugin) makePrefixSuffixPluginConfig(n string) ([]byte, error) {
|
func (p *plugin) makePrefixSuffixPluginConfig(n string) ([]byte, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user