cleanup Resouce slice related code
This commit is contained in:
parent
94f9347974
commit
2e06ca8bc0
|
|
@ -17,8 +17,6 @@ limitations under the License.
|
||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
|
|
||||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||||
|
|
@ -26,16 +24,15 @@ import (
|
||||||
interror "k8s.io/kubectl/pkg/kinflate/internal/error"
|
interror "k8s.io/kubectl/pkg/kinflate/internal/error"
|
||||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/transformers"
|
"k8s.io/kubectl/pkg/kinflate/transformers"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
|
||||||
"k8s.io/kubectl/pkg/loader"
|
"k8s.io/kubectl/pkg/loader"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Application interface {
|
type Application interface {
|
||||||
// Resources computes and returns the resources for the app.
|
// Resources computes and returns the resources for the app.
|
||||||
Resources() (types.ResourceCollection, error)
|
Resources() (resource.ResourceCollection, error)
|
||||||
// RawResources computes and returns the raw resources from the manifest.
|
// RawResources computes and returns the raw resources from the manifest.
|
||||||
// It contains resources from 1) untransformed resources from current manifest 2) transformed resources from sub packages
|
// It contains resources from 1) untransformed resources from current manifest 2) transformed resources from sub packages
|
||||||
RawResources() (types.ResourceCollection, error)
|
RawResources() (resource.ResourceCollection, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Application = &applicationImpl{}
|
var _ Application = &applicationImpl{}
|
||||||
|
|
@ -63,27 +60,22 @@ func New(loader loader.Loader) (Application, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resources computes and returns the resources from the manifest.
|
// Resources computes and returns the resources from the manifest.
|
||||||
func (a *applicationImpl) Resources() (types.ResourceCollection, error) {
|
func (a *applicationImpl) Resources() (resource.ResourceCollection, error) {
|
||||||
errs := &interror.ManifestErrors{}
|
errs := &interror.ManifestErrors{}
|
||||||
raw, err := a.RawResources()
|
raw, err := a.RawResources()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(err)
|
errs.Append(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resources := []*resource.Resource{}
|
|
||||||
cms, err := resource.NewFromConfigMaps(a.loader, a.manifest.Configmaps)
|
cms, err := resource.NewFromConfigMaps(a.loader, a.manifest.Configmaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(err)
|
errs.Append(err)
|
||||||
} else {
|
|
||||||
resources = append(resources, cms...)
|
|
||||||
}
|
}
|
||||||
secrets, err := resource.NewFromSecretGenerators(a.loader.Root(), a.manifest.SecretGenerators)
|
secrets, err := resource.NewFromSecretGenerators(a.loader.Root(), a.manifest.SecretGenerators)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(err)
|
errs.Append(err)
|
||||||
} else {
|
|
||||||
resources = append(resources, secrets...)
|
|
||||||
}
|
}
|
||||||
res, err := resourceCollectionFromResources(resources)
|
res, err := resource.Merge(cms, secrets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -94,12 +86,7 @@ func (a *applicationImpl) Resources() (types.ResourceCollection, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ps, err := resource.NewFromPaths(a.loader, a.manifest.Patches)
|
patches, err := resource.NewFromPaths(a.loader, a.manifest.Patches)
|
||||||
if err != nil {
|
|
||||||
errs.Append(err)
|
|
||||||
}
|
|
||||||
// TODO: remove this func after migrating to ResourceCollection
|
|
||||||
patches, err := resourceCollectionFromResources(ps)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(err)
|
errs.Append(err)
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +95,7 @@ func (a *applicationImpl) Resources() (types.ResourceCollection, error) {
|
||||||
return nil, errs
|
return nil, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
err = types.Merge(res, raw)
|
allRes, err := resource.Merge(res, raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -117,35 +104,30 @@ func (a *applicationImpl) Resources() (types.ResourceCollection, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = t.Transform(res)
|
err = t.Transform(allRes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return res, nil
|
return allRes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RawResources computes and returns the raw resources from the manifest.
|
// RawResources computes and returns the raw resources from the manifest.
|
||||||
func (a *applicationImpl) RawResources() (types.ResourceCollection, error) {
|
func (a *applicationImpl) RawResources() (resource.ResourceCollection, error) {
|
||||||
subAppResources, errs := a.subAppResources()
|
subAppResources, errs := a.subAppResources()
|
||||||
allRes, err := resource.NewFromPaths(a.loader, a.manifest.Resources)
|
resources, err := resource.NewFromPaths(a.loader, a.manifest.Resources)
|
||||||
if err != nil {
|
|
||||||
errs.Append(err)
|
|
||||||
}
|
|
||||||
// TODO: remove this func after migrating to ResourceCollection
|
|
||||||
allResources, err := resourceCollectionFromResources(allRes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Append(err)
|
errs.Append(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs.Get()) > 0 {
|
if len(errs.Get()) > 0 {
|
||||||
return nil, errs
|
return nil, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
err = types.Merge(allResources, subAppResources)
|
return resource.Merge(resources, subAppResources)
|
||||||
return allResources, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *applicationImpl) subAppResources() (types.ResourceCollection, *interror.ManifestErrors) {
|
func (a *applicationImpl) subAppResources() (resource.ResourceCollection, *interror.ManifestErrors) {
|
||||||
allResources := types.ResourceCollection{}
|
sliceOfSubAppResources := []resource.ResourceCollection{}
|
||||||
errs := &interror.ManifestErrors{}
|
errs := &interror.ManifestErrors{}
|
||||||
for _, pkgPath := range a.manifest.Packages {
|
for _, pkgPath := range a.manifest.Packages {
|
||||||
subloader, err := a.loader.New(pkgPath)
|
subloader, err := a.loader.New(pkgPath)
|
||||||
|
|
@ -164,7 +146,11 @@ func (a *applicationImpl) subAppResources() (types.ResourceCollection, *interror
|
||||||
errs.Append(err)
|
errs.Append(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
types.Merge(allResources, subAppResources)
|
sliceOfSubAppResources = append(sliceOfSubAppResources, subAppResources)
|
||||||
|
}
|
||||||
|
allResources, err := resource.Merge(sliceOfSubAppResources...)
|
||||||
|
if err != nil {
|
||||||
|
errs.Append(err)
|
||||||
}
|
}
|
||||||
return allResources, errs
|
return allResources, errs
|
||||||
}
|
}
|
||||||
|
|
@ -175,7 +161,7 @@ func (a *applicationImpl) subAppResources() (types.ResourceCollection, *interror
|
||||||
// 3) apply labels
|
// 3) apply labels
|
||||||
// 4) apply annotations
|
// 4) apply annotations
|
||||||
// 5) update name reference
|
// 5) update name reference
|
||||||
func (a *applicationImpl) getTransformer(patches types.ResourceCollection) (transformers.Transformer, error) {
|
func (a *applicationImpl) getTransformer(patches resource.ResourceCollection) (transformers.Transformer, error) {
|
||||||
ts := []transformers.Transformer{}
|
ts := []transformers.Transformer{}
|
||||||
|
|
||||||
ot, err := transformers.NewOverlayTransformer(patches)
|
ot, err := transformers.NewOverlayTransformer(patches)
|
||||||
|
|
@ -209,15 +195,3 @@ func (a *applicationImpl) getTransformer(patches types.ResourceCollection) (tran
|
||||||
ts = append(ts, nrt)
|
ts = append(ts, nrt)
|
||||||
return transformers.NewMultiTransformer(ts), nil
|
return transformers.NewMultiTransformer(ts), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceCollectionFromResources(res []*resource.Resource) (types.ResourceCollection, error) {
|
|
||||||
out := types.ResourceCollection{}
|
|
||||||
for _, res := range res {
|
|
||||||
gvkn := res.GVKN()
|
|
||||||
if _, found := out[gvkn]; found {
|
|
||||||
return nil, fmt.Errorf("duplicated %#v is not allowed", gvkn)
|
|
||||||
}
|
|
||||||
out[gvkn] = res.Data
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
"k8s.io/kubectl/pkg/loader"
|
"k8s.io/kubectl/pkg/loader"
|
||||||
"k8s.io/kubectl/pkg/loader/loadertest"
|
"k8s.io/kubectl/pkg/loader/loadertest"
|
||||||
|
|
@ -74,11 +75,12 @@ metadata:
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResources(t *testing.T) {
|
func TestResources(t *testing.T) {
|
||||||
expected := types.ResourceCollection{
|
expected := resource.ResourceCollection{
|
||||||
types.GroupVersionKindName{
|
types.GroupVersionKindName{
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
Name: "dply1",
|
Name: "dply1",
|
||||||
}: &unstructured.Unstructured{
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
|
|
@ -110,10 +112,12 @@ func TestResources(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
types.GroupVersionKindName{
|
types.GroupVersionKindName{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
Name: "literalConfigMap",
|
Name: "literalConfigMap",
|
||||||
}: &unstructured.Unstructured{
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
|
|
@ -133,10 +137,12 @@ func TestResources(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
types.GroupVersionKindName{
|
types.GroupVersionKindName{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||||
Name: "secret",
|
Name: "secret",
|
||||||
}: &unstructured.Unstructured{
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Secret",
|
"kind": "Secret",
|
||||||
|
|
@ -157,6 +163,7 @@ func TestResources(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
l := setupTest(t)
|
l := setupTest(t)
|
||||||
app, err := New(l)
|
app, err := New(l)
|
||||||
|
|
@ -175,11 +182,12 @@ func TestResources(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRawResources(t *testing.T) {
|
func TestRawResources(t *testing.T) {
|
||||||
expected := types.ResourceCollection{
|
expected := resource.ResourceCollection{
|
||||||
types.GroupVersionKindName{
|
types.GroupVersionKindName{
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
Name: "dply1",
|
Name: "dply1",
|
||||||
}: &unstructured.Unstructured{
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
|
|
@ -188,6 +196,7 @@ func TestRawResources(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
l := setupTest(t)
|
l := setupTest(t)
|
||||||
app, err := New(l)
|
app, err := New(l)
|
||||||
|
|
@ -204,7 +213,7 @@ func TestRawResources(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareMap(m1, m2 types.ResourceCollection) error {
|
func compareMap(m1, m2 resource.ResourceCollection) error {
|
||||||
if len(m1) != len(m2) {
|
if len(m1) != len(m2) {
|
||||||
keySet1 := []types.GroupVersionKindName{}
|
keySet1 := []types.GroupVersionKindName{}
|
||||||
keySet2 := []types.GroupVersionKindName{}
|
keySet2 := []types.GroupVersionKindName{}
|
||||||
|
|
|
||||||
|
|
@ -26,12 +26,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||||
cutil "k8s.io/kubectl/pkg/kinflate/configmapandsecret/util"
|
cutil "k8s.io/kubectl/pkg/kinflate/configmapandsecret/util"
|
||||||
"k8s.io/kubectl/pkg/kinflate/hash"
|
"k8s.io/kubectl/pkg/kinflate/hash"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -123,26 +123,22 @@ func makeSecret(secret manifest.SecretGenerator, path string) (*corev1.Secret, e
|
||||||
return corev1secret, nil
|
return corev1secret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func populateMap(m types.ResourceCollection, obj *unstructured.Unstructured, newName string) error {
|
func populateMap(m resource.ResourceCollection, obj *unstructured.Unstructured, newName string) error {
|
||||||
accessor, err := meta.Accessor(obj)
|
oldName := obj.GetName()
|
||||||
if err != nil {
|
gvk := obj.GroupVersionKind()
|
||||||
return err
|
|
||||||
}
|
|
||||||
oldName := accessor.GetName()
|
|
||||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
|
||||||
gvkn := types.GroupVersionKindName{GVK: gvk, Name: oldName}
|
gvkn := types.GroupVersionKindName{GVK: gvk, Name: oldName}
|
||||||
|
|
||||||
if _, found := m[gvkn]; found {
|
if _, found := m[gvkn]; found {
|
||||||
return fmt.Errorf("The <name: %q, GroupVersionKind: %v> already exists in the map", oldName, gvk)
|
return fmt.Errorf("The <name: %q, GroupVersionKind: %v> already exists in the map", oldName, gvk)
|
||||||
}
|
}
|
||||||
accessor.SetName(newName)
|
obj.SetName(newName)
|
||||||
m[gvkn] = obj
|
m[gvkn] = &resource.Resource{Data: obj}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeConfigMapsResourceCollection returns a map of <GVK, oldName> -> unstructured object.
|
// MakeConfigMapsResourceCollection returns a map of <GVK, oldName> -> unstructured object.
|
||||||
func MakeConfigMapsResourceCollection(maps []manifest.ConfigMap) (types.ResourceCollection, error) {
|
func MakeConfigMapsResourceCollection(maps []manifest.ConfigMap) (resource.ResourceCollection, error) {
|
||||||
m := types.ResourceCollection{}
|
m := resource.ResourceCollection{}
|
||||||
for _, cm := range maps {
|
for _, cm := range maps {
|
||||||
unstructuredConfigMap, nameWithHash, err := MakeConfigmapAndGenerateName(cm)
|
unstructuredConfigMap, nameWithHash, err := MakeConfigmapAndGenerateName(cm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -157,8 +153,8 @@ func MakeConfigMapsResourceCollection(maps []manifest.ConfigMap) (types.Resource
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeSecretsResourceCollection returns a map of <GVK, oldName> -> unstructured object.
|
// MakeSecretsResourceCollection returns a map of <GVK, oldName> -> unstructured object.
|
||||||
func MakeSecretsResourceCollection(secrets []manifest.SecretGenerator, path string) (types.ResourceCollection, error) {
|
func MakeSecretsResourceCollection(secrets []manifest.SecretGenerator, path string) (resource.ResourceCollection, error) {
|
||||||
m := types.ResourceCollection{}
|
m := resource.ResourceCollection{}
|
||||||
for _, secret := range secrets {
|
for _, secret := range secrets {
|
||||||
unstructuredSecret, nameWithHash, err := MakeSecretAndGenerateName(secret, path)
|
unstructuredSecret, nameWithHash, err := MakeSecretAndGenerateName(secret, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,37 +17,27 @@ limitations under the License.
|
||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
kutil "k8s.io/kubectl/pkg/kinflate/util"
|
|
||||||
"k8s.io/kubectl/pkg/loader"
|
"k8s.io/kubectl/pkg/loader"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourcesFromPath(loader loader.Loader, path string) ([]*Resource, error) {
|
func resourcesFromPath(loader loader.Loader, path string) (ResourceCollection, error) {
|
||||||
content, err := loader.Load(path)
|
content, err := loader.Load(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
objs, err := kutil.Decode(content)
|
return decodeToResourceCollection(content)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var res []*Resource
|
|
||||||
for _, obj := range objs {
|
|
||||||
res = append(res, &Resource{Data: obj})
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFromPaths returns a slice of Resources given a resource path slice from manifest file.
|
// NewFromPaths returns a slice of Resources given a resource path slice from manifest file.
|
||||||
func NewFromPaths(loader loader.Loader, paths []string) ([]*Resource, error) {
|
func NewFromPaths(loader loader.Loader, paths []string) (ResourceCollection, error) {
|
||||||
allResources := []*Resource{}
|
allResources := []ResourceCollection{}
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
res, err := resourcesFromPath(loader, path)
|
res, err := resourcesFromPath(loader, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
allResources = append(allResources, res...)
|
allResources = append(allResources, res)
|
||||||
}
|
}
|
||||||
return allResources, nil
|
return Merge(allResources...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,40 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
"k8s.io/kubectl/pkg/loader/loadertest"
|
"k8s.io/kubectl/pkg/loader/loadertest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeUnconstructed(name string) *unstructured.Unstructured {
|
|
||||||
return &unstructured.Unstructured{
|
|
||||||
Object: map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewFromPaths(t *testing.T) {
|
func TestNewFromPaths(t *testing.T) {
|
||||||
|
|
||||||
resourceStr := `apiVersion: v1
|
resourceStr := `apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: dply1
|
name: dply1
|
||||||
---
|
---
|
||||||
apiVersion: v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: dply2
|
name: dply2
|
||||||
|
|
@ -38,9 +44,35 @@ metadata:
|
||||||
if ferr := l.AddFile("/home/seans/project/deployment.yaml", []byte(resourceStr)); ferr != nil {
|
if ferr := l.AddFile("/home/seans/project/deployment.yaml", []byte(resourceStr)); ferr != nil {
|
||||||
t.Fatalf("Error adding fake file: %v\n", ferr)
|
t.Fatalf("Error adding fake file: %v\n", ferr)
|
||||||
}
|
}
|
||||||
expected := []*Resource{
|
expected := ResourceCollection{
|
||||||
{Data: makeUnconstructed("dply1")},
|
{
|
||||||
{Data: makeUnconstructed("dply2")},
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
Name: "dply1",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "dply1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
Name: "dply2",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "dply2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
resources, _ := NewFromPaths(l, []string{"/home/seans/project/deployment.yaml"})
|
resources, _ := NewFromPaths(l, []string{"/home/seans/project/deployment.yaml"})
|
||||||
|
|
@ -48,9 +80,31 @@ metadata:
|
||||||
t.Fatalf("%#v should contain 2 appResource, but got %d", resources, len(resources))
|
t.Fatalf("%#v should contain 2 appResource, but got %d", resources, len(resources))
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, r := range resources {
|
if err := compareMap(resources, expected); err != nil {
|
||||||
if !reflect.DeepEqual(r.Data, expected[i].Data) {
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
t.Fatalf("expected %v, but got %v", expected[i].Data, r.Data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func compareMap(m1, m2 ResourceCollection) error {
|
||||||
|
if len(m1) != len(m2) {
|
||||||
|
keySet1 := []types.GroupVersionKindName{}
|
||||||
|
keySet2 := []types.GroupVersionKindName{}
|
||||||
|
for GVKn := range m1 {
|
||||||
|
keySet1 = append(keySet1, GVKn)
|
||||||
|
}
|
||||||
|
for GVKn := range m1 {
|
||||||
|
keySet2 = append(keySet2, GVKn)
|
||||||
|
}
|
||||||
|
return fmt.Errorf("maps has different number of entries: %#v doesn't equals %#v", keySet1, keySet2)
|
||||||
|
}
|
||||||
|
for GVKn, obj1 := range m1 {
|
||||||
|
obj2, found := m2[GVKn]
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("%#v doesn't exist in %#v", GVKn, m2)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(obj1.Data, obj2.Data) {
|
||||||
|
return fmt.Errorf("%#v doesn't match %#v", obj1.Data, obj2.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ func addKV(m map[string]string, kv kvPair) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFromConfigMaps returns a Resource slice given a configmap metadata slice from manifest file.
|
// NewFromConfigMaps returns a Resource slice given a configmap metadata slice from manifest file.
|
||||||
func NewFromConfigMaps(loader loader.Loader, cmList []manifest.ConfigMap) ([]*Resource, error) {
|
func NewFromConfigMaps(loader loader.Loader, cmList []manifest.ConfigMap) (ResourceCollection, error) {
|
||||||
allResources := []*Resource{}
|
allResources := []*Resource{}
|
||||||
for _, cm := range cmList {
|
for _, cm := range cmList {
|
||||||
res, err := newFromConfigMap(loader, cm)
|
res, err := newFromConfigMap(loader, cm)
|
||||||
|
|
@ -140,5 +140,5 @@ func NewFromConfigMaps(loader loader.Loader, cmList []manifest.ConfigMap) ([]*Re
|
||||||
}
|
}
|
||||||
allResources = append(allResources, res)
|
allResources = append(allResources, res)
|
||||||
}
|
}
|
||||||
return allResources, nil
|
return resourceCollectionFromResources(allResources)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/loader/loadertest"
|
"k8s.io/kubectl/pkg/loader/loadertest"
|
||||||
|
|
@ -32,7 +33,7 @@ func TestNewFromConfigMaps(t *testing.T) {
|
||||||
input []manifest.ConfigMap
|
input []manifest.ConfigMap
|
||||||
filepath string
|
filepath string
|
||||||
content string
|
content string
|
||||||
expected []*resource.Resource
|
expected resource.ResourceCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
l := loadertest.NewFakeLoader("/home/seans/project/")
|
l := loadertest.NewFakeLoader("/home/seans/project/")
|
||||||
|
|
@ -49,8 +50,11 @@ func TestNewFromConfigMaps(t *testing.T) {
|
||||||
},
|
},
|
||||||
filepath: "/home/seans/project/app.env",
|
filepath: "/home/seans/project/app.env",
|
||||||
content: "DB_USERNAME=admin\nDB_PASSWORD=somepw",
|
content: "DB_USERNAME=admin\nDB_PASSWORD=somepw",
|
||||||
expected: []*resource.Resource{
|
expected: resource.ResourceCollection{
|
||||||
{
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "envConfigMap",
|
||||||
|
}: &resource.Resource{
|
||||||
Data: &unstructured.Unstructured{
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
|
|
@ -79,8 +83,11 @@ func TestNewFromConfigMaps(t *testing.T) {
|
||||||
},
|
},
|
||||||
filepath: "/home/seans/project/app-init.ini",
|
filepath: "/home/seans/project/app-init.ini",
|
||||||
content: "FOO=bar\nBAR=baz\n",
|
content: "FOO=bar\nBAR=baz\n",
|
||||||
expected: []*resource.Resource{
|
expected: resource.ResourceCollection{
|
||||||
{
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "fileConfigMap",
|
||||||
|
}: &resource.Resource{
|
||||||
Data: &unstructured.Unstructured{
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
|
|
@ -109,8 +116,11 @@ BAR=baz
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: []*resource.Resource{
|
expected: resource.ResourceCollection{
|
||||||
{
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "literalConfigMap",
|
||||||
|
}: &resource.Resource{
|
||||||
Data: &unstructured.Unstructured{
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ package resource
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
|
|
@ -37,14 +36,13 @@ func (r *Resource) GVKN() types.GroupVersionKindName {
|
||||||
if r.Data == nil {
|
if r.Data == nil {
|
||||||
return emptyZVKN
|
return emptyZVKN
|
||||||
}
|
}
|
||||||
accessor, err := meta.Accessor(r.Data)
|
gvk := r.Data.GroupVersionKind()
|
||||||
if err != nil {
|
return types.GroupVersionKindName{GVK: gvk, Name: r.Data.GetName()}
|
||||||
return emptyZVKN
|
|
||||||
}
|
|
||||||
gvk := r.Data.GetObjectKind().GroupVersionKind()
|
|
||||||
return types.GroupVersionKindName{GVK: gvk, Name: accessor.GetName()}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceCollection is a map from GroupVersionKindName to Resource
|
||||||
|
type ResourceCollection map[types.GroupVersionKindName]*Resource
|
||||||
|
|
||||||
func objectToUnstructured(in runtime.Object) (*unstructured.Unstructured, error) {
|
func objectToUnstructured(in runtime.Object) (*unstructured.Unstructured, error) {
|
||||||
marshaled, err := json.Marshal(in)
|
marshaled, err := json.Marshal(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func createSecretKey(wd string, command string) ([]byte, error) {
|
||||||
|
|
||||||
// NewFromSecretGenerators takes a SecretGenerator slice and executes its command in directory p
|
// NewFromSecretGenerators takes a SecretGenerator slice and executes its command in directory p
|
||||||
// then writes the output to a Resource slice and return it.
|
// then writes the output to a Resource slice and return it.
|
||||||
func NewFromSecretGenerators(p string, secretList []manifest.SecretGenerator) ([]*Resource, error) {
|
func NewFromSecretGenerators(p string, secretList []manifest.SecretGenerator) (ResourceCollection, error) {
|
||||||
allResources := []*Resource{}
|
allResources := []*Resource{}
|
||||||
for _, secret := range secretList {
|
for _, secret := range secretList {
|
||||||
res, err := newFromSecretGenerator(p, secret)
|
res, err := newFromSecretGenerator(p, secret)
|
||||||
|
|
@ -79,5 +79,5 @@ func NewFromSecretGenerators(p string, secretList []manifest.SecretGenerator) ([
|
||||||
}
|
}
|
||||||
allResources = append(allResources, res)
|
allResources = append(allResources, res)
|
||||||
}
|
}
|
||||||
return allResources, nil
|
return resourceCollectionFromResources(allResources)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -42,8 +43,12 @@ func TestNewFromSecretGenerators(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
expected := []*Resource{
|
expected := ResourceCollection{
|
||||||
{Data: &unstructured.Unstructured{
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||||
|
Name: "secret",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Secret",
|
"kind": "Secret",
|
||||||
|
|
@ -57,7 +62,8 @@ func TestNewFromSecretGenerators(t *testing.T) {
|
||||||
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
|
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(re, expected) {
|
if !reflect.DeepEqual(re, expected) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package resource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// decode decodes a list of objects in byte array format
|
||||||
|
func decode(in []byte) ([]*unstructured.Unstructured, error) {
|
||||||
|
decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewReader(in), 1024)
|
||||||
|
objs := []*unstructured.Unstructured{}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for {
|
||||||
|
var out unstructured.Unstructured
|
||||||
|
err = decoder.Decode(&out)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
objs = append(objs, &out)
|
||||||
|
}
|
||||||
|
if err != io.EOF {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return objs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeToResourceCollection decodes a list of objects in byte array format.
|
||||||
|
// it will return a ResourceCollection.
|
||||||
|
func decodeToResourceCollection(in []byte) (ResourceCollection, error) {
|
||||||
|
objs, err := decode(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
into := ResourceCollection{}
|
||||||
|
for i, obj := range objs {
|
||||||
|
gvkn := types.GroupVersionKindName{
|
||||||
|
GVK: obj.GroupVersionKind(),
|
||||||
|
Name: obj.GetName(),
|
||||||
|
}
|
||||||
|
if _, found := into[gvkn]; found {
|
||||||
|
return into, fmt.Errorf("GroupVersionKindName: %#v already exists in the map", gvkn)
|
||||||
|
}
|
||||||
|
into[gvkn] = &Resource{Data: objs[i]}
|
||||||
|
}
|
||||||
|
return into, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceCollectionFromResources(resources []*Resource) (ResourceCollection, error) {
|
||||||
|
out := ResourceCollection{}
|
||||||
|
for _, res := range resources {
|
||||||
|
gvkn := res.GVKN()
|
||||||
|
if _, found := out[gvkn]; found {
|
||||||
|
return nil, fmt.Errorf("duplicated %#v is not allowed", gvkn)
|
||||||
|
}
|
||||||
|
out[gvkn] = res
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge will merge all of the entries in the slice of ResourceCollection.
|
||||||
|
func Merge(rcs ...ResourceCollection) (ResourceCollection, error) {
|
||||||
|
all := ResourceCollection{}
|
||||||
|
for _, rc := range rcs {
|
||||||
|
for gvkn, obj := range rc {
|
||||||
|
if _, found := all[gvkn]; found {
|
||||||
|
return nil, fmt.Errorf("there is already an entry: %q", gvkn)
|
||||||
|
}
|
||||||
|
all[gvkn] = obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return all, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package resource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDecodeToResourceCollection(t *testing.T) {
|
||||||
|
encoded := []byte(`apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm2
|
||||||
|
`)
|
||||||
|
expected := ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm2",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
m, err := decodeToResourceCollection(encoded)
|
||||||
|
fmt.Printf("%v\n", m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(m, expected) {
|
||||||
|
t.Fatalf("%#v doesn't match expected %#v", m, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMerge(t *testing.T) {
|
||||||
|
input1 := ResourceCollection{
|
||||||
|
types.GroupVersionKindName{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
Name: "deploy1",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "foo-deploy1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
input2 := ResourceCollection{
|
||||||
|
types.GroupVersionKindName{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"},
|
||||||
|
Name: "stateful1",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "StatefulSet",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "bar-stateful",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
input := []ResourceCollection{input1, input2}
|
||||||
|
expected := ResourceCollection{
|
||||||
|
types.GroupVersionKindName{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
Name: "deploy1",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "foo-deploy1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
types.GroupVersionKindName{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"},
|
||||||
|
Name: "stateful1",
|
||||||
|
}: &Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "StatefulSet",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "bar-stateful",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
merged, err := Merge(input...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(merged, expected) {
|
||||||
|
t.Fatalf("%#v doesn't equal expected %#v", merged, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -55,9 +56,9 @@ func NewMapTransformer(pc []PathConfig, m map[string]string) (Transformer, error
|
||||||
|
|
||||||
// Transform apply each <key, value> pair in the mapTransformer to the
|
// Transform apply each <key, value> pair in the mapTransformer to the
|
||||||
// fields specified in mapTransformer.
|
// fields specified in mapTransformer.
|
||||||
func (o *mapTransformer) Transform(m types.ResourceCollection) error {
|
func (o *mapTransformer) Transform(m resource.ResourceCollection) error {
|
||||||
for gvkn := range m {
|
for gvkn := range m {
|
||||||
obj := m[gvkn]
|
obj := m[gvkn].Data
|
||||||
objMap := obj.UnstructuredContent()
|
objMap := obj.UnstructuredContent()
|
||||||
for _, path := range o.pathConfigs {
|
for _, path := range o.pathConfigs {
|
||||||
if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) {
|
if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) {
|
||||||
|
|
|
||||||
|
|
@ -22,23 +22,30 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeConfigmap(name string) *unstructured.Unstructured {
|
func TestLabelsRun(t *testing.T) {
|
||||||
return &unstructured.Unstructured{
|
m := resource.ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": name,
|
"name": "cm1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func makeDeployment() *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
return &unstructured.Unstructured{
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"group": "apps",
|
"group": "apps",
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
|
|
@ -64,11 +71,13 @@ func makeDeployment() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func makeService() *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
return &unstructured.Unstructured{
|
Name: "svc1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Service",
|
"kind": "Service",
|
||||||
|
|
@ -84,28 +93,15 @@ func makeService() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
expected := resource.ResourceCollection{
|
||||||
|
|
||||||
func makeTestMap() types.ResourceCollection {
|
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
Name: "cm1",
|
Name: "cm1",
|
||||||
}: makeConfigmap("cm1"),
|
}: &resource.Resource{
|
||||||
{
|
Data: &unstructured.Unstructured{
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
|
||||||
Name: "deploy1",
|
|
||||||
}: makeDeployment(),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
|
||||||
Name: "svc1",
|
|
||||||
}: makeService(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeLabeledConfigMap() *unstructured.Unstructured {
|
|
||||||
return &unstructured.Unstructured{
|
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
|
|
@ -117,11 +113,13 @@ func makeLabeledConfigMap() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func makeLabeledDeployment() *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
return &unstructured.Unstructured{
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"group": "apps",
|
"group": "apps",
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
|
|
@ -159,11 +157,13 @@ func makeLabeledDeployment() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func makeLabeledService() *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
return &unstructured.Unstructured{
|
Name: "svc1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Service",
|
"kind": "Service",
|
||||||
|
|
@ -187,28 +187,10 @@ func makeLabeledService() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func makeLabeledMap() types.ResourceCollection {
|
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
|
||||||
Name: "cm1",
|
|
||||||
}: makeLabeledConfigMap(),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
|
||||||
Name: "deploy1",
|
|
||||||
}: makeLabeledDeployment(),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
|
||||||
Name: "svc1",
|
|
||||||
}: makeLabeledService(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLabelsRun(t *testing.T) {
|
|
||||||
m := makeTestMap()
|
|
||||||
lt, err := NewDefaultingLabelsMapTransformer(map[string]string{"label-key1": "label-value1", "label-key2": "label-value2"})
|
lt, err := NewDefaultingLabelsMapTransformer(map[string]string{"label-key1": "label-value1", "label-key2": "label-value2"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
|
@ -217,7 +199,6 @@ func TestLabelsRun(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
expected := makeLabeledMap()
|
|
||||||
if !reflect.DeepEqual(m, expected) {
|
if !reflect.DeepEqual(m, expected) {
|
||||||
err = compareMap(m, expected)
|
err = compareMap(m, expected)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
|
@ -302,25 +283,163 @@ func makeAnnotatededService() *unstructured.Unstructured {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeAnnotatedMap() types.ResourceCollection {
|
func TestAnnotationsRun(t *testing.T) {
|
||||||
return types.ResourceCollection{
|
m := resource.ResourceCollection{
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
Name: "cm1",
|
Name: "cm1",
|
||||||
}: makeAnnotatededConfigMap(),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
Name: "deploy1",
|
Name: "deploy1",
|
||||||
}: makeAnnotatededDeployment(),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"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{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
Name: "svc1",
|
Name: "svc1",
|
||||||
}: makeAnnotatededService(),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "svc1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"ports": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "port1",
|
||||||
|
"port": "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expected := resource.ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"template": map[string]interface{}{
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
"labels": map[string]interface{}{
|
||||||
|
"old-label": "old-value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
|
Name: "svc1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "svc1",
|
||||||
|
"annotations": map[string]interface{}{
|
||||||
|
"anno-key1": "anno-value1",
|
||||||
|
"anno-key2": "anno-value2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"ports": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "port1",
|
||||||
|
"port": "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestAnnotationsRun(t *testing.T) {
|
|
||||||
m := makeTestMap()
|
|
||||||
at, err := NewDefaultingAnnotationsMapTransformer(map[string]string{"anno-key1": "anno-value1", "anno-key2": "anno-value2"})
|
at, err := NewDefaultingAnnotationsMapTransformer(map[string]string{"anno-key1": "anno-value1", "anno-key2": "anno-value2"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
|
@ -329,7 +448,6 @@ func TestAnnotationsRun(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
expected := makeAnnotatedMap()
|
|
||||||
if !reflect.DeepEqual(m, expected) {
|
if !reflect.DeepEqual(m, expected) {
|
||||||
err = compareMap(m, expected)
|
err = compareMap(m, expected)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
package transformers
|
package transformers
|
||||||
|
|
||||||
import "k8s.io/kubectl/pkg/kinflate/types"
|
import "k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
|
|
||||||
// multiTransformer contains a list of transformers.
|
// multiTransformer contains a list of transformers.
|
||||||
type multiTransformer struct {
|
type multiTransformer struct {
|
||||||
|
|
@ -34,7 +34,7 @@ func NewMultiTransformer(t []Transformer) Transformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform prepends the name prefix.
|
// Transform prepends the name prefix.
|
||||||
func (o *multiTransformer) Transform(m types.ResourceCollection) error {
|
func (o *multiTransformer) Transform(m resource.ResourceCollection) error {
|
||||||
for _, t := range o.transformers {
|
for _, t := range o.transformers {
|
||||||
err := t.Transform(m)
|
err := t.Transform(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kubectl/pkg/kinflate/hash"
|
"k8s.io/kubectl/pkg/kinflate/hash"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -39,14 +40,14 @@ func NewNameHashTransformer() Transformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform appends hash to configmaps and secrets.
|
// Transform appends hash to configmaps and secrets.
|
||||||
func (o *nameHashTransformer) Transform(m types.ResourceCollection) error {
|
func (o *nameHashTransformer) Transform(m resource.ResourceCollection) error {
|
||||||
for gvkn, obj := range m {
|
for gvkn, obj := range m {
|
||||||
switch {
|
switch {
|
||||||
case types.SelectByGVK(gvkn.GVK, &schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}):
|
case types.SelectByGVK(gvkn.GVK, &schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}):
|
||||||
appendHashForConfigMap(obj)
|
appendHashForConfigMap(obj.Data)
|
||||||
|
|
||||||
case types.SelectByGVK(gvkn.GVK, &schema.GroupVersionKind{Version: "v1", Kind: "Secret"}):
|
case types.SelectByGVK(gvkn.GVK, &schema.GroupVersionKind{Version: "v1", Kind: "Secret"}):
|
||||||
appendHashForSecret(obj)
|
appendHashForSecret(obj.Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -22,71 +22,183 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeSecret(name string) *unstructured.Unstructured {
|
func TestNameHashTransformer(t *testing.T) {
|
||||||
return &unstructured.Unstructured{
|
objs := resource.ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"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{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
|
Name: "svc1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "svc1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"ports": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "port1",
|
||||||
|
"port": "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||||
|
Name: "secret1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Secret",
|
"kind": "Secret",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": name,
|
"name": "secret1",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func makeHashTestMap() types.ResourceCollection {
|
expected := resource.ResourceCollection{
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
Name: "cm1",
|
Name: "cm1",
|
||||||
}: makeConfigmap("cm1"),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1-m462kdfb68",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
Name: "deploy1",
|
Name: "deploy1",
|
||||||
}: makeDeployment(),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"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{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||||
Name: "svc1",
|
Name: "svc1",
|
||||||
}: makeService(),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Service",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "svc1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"ports": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "port1",
|
||||||
|
"port": "12345",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||||
Name: "secret1",
|
Name: "secret1",
|
||||||
}: makeSecret("secret1"),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Secret",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "secret1-7kc45hd5f7",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func makeExpectedHashTestMap() types.ResourceCollection {
|
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
|
||||||
Name: "cm1",
|
|
||||||
}: makeConfigmap("cm1-m462kdfb68"),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
|
||||||
Name: "deploy1",
|
|
||||||
}: makeDeployment(),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
|
||||||
Name: "svc1",
|
|
||||||
}: makeService(),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
|
||||||
Name: "secret1",
|
|
||||||
}: makeSecret("secret1-7kc45hd5f7"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNameHashTransformer(t *testing.T) {
|
|
||||||
objs := makeHashTestMap()
|
|
||||||
|
|
||||||
tran := NewNameHashTransformer()
|
tran := NewNameHashTransformer()
|
||||||
tran.Transform(objs)
|
tran.Transform(objs)
|
||||||
|
|
||||||
expected := makeExpectedHashTestMap()
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(objs, expected) {
|
if !reflect.DeepEqual(objs, expected) {
|
||||||
err := compareMap(objs, expected)
|
err := compareMap(objs, expected)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -50,9 +51,9 @@ func NewNameReferenceTransformer(pc []referencePathConfig) (Transformer, error)
|
||||||
// associated with the key. e.g. if <k, v> is one of the key-value pair in the map,
|
// associated with the key. e.g. if <k, v> is one of the key-value pair in the map,
|
||||||
// then the old name is k.Name and the new name is v.GetName()
|
// then the old name is k.Name and the new name is v.GetName()
|
||||||
func (o *nameReferenceTransformer) Transform(
|
func (o *nameReferenceTransformer) Transform(
|
||||||
m types.ResourceCollection) error {
|
m resource.ResourceCollection) error {
|
||||||
for GVKn := range m {
|
for GVKn := range m {
|
||||||
obj := m[GVKn]
|
obj := m[GVKn].Data
|
||||||
objMap := obj.UnstructuredContent()
|
objMap := obj.UnstructuredContent()
|
||||||
for _, referencePathConfig := range o.pathConfigs {
|
for _, referencePathConfig := range o.pathConfigs {
|
||||||
for _, path := range referencePathConfig.pathConfigs {
|
for _, path := range referencePathConfig.pathConfigs {
|
||||||
|
|
@ -88,7 +89,7 @@ func (err noMatchingGVKNError) Error() string {
|
||||||
|
|
||||||
func (o *nameReferenceTransformer) updateNameReference(
|
func (o *nameReferenceTransformer) updateNameReference(
|
||||||
GVK schema.GroupVersionKind,
|
GVK schema.GroupVersionKind,
|
||||||
m types.ResourceCollection,
|
m resource.ResourceCollection,
|
||||||
) func(in interface{}) (interface{}, error) {
|
) func(in interface{}) (interface{}, error) {
|
||||||
return func(in interface{}) (interface{}, error) {
|
return func(in interface{}) (interface{}, error) {
|
||||||
s, ok := in.(string)
|
s, ok := in.(string)
|
||||||
|
|
@ -101,7 +102,7 @@ func (o *nameReferenceTransformer) updateNameReference(
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if GVKn.Name == s {
|
if GVKn.Name == s {
|
||||||
return obj.GetName(), nil
|
return obj.Data.GetName(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return in, nil
|
return in, nil
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,16 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeReferencedConfigMap() *unstructured.Unstructured {
|
func TestNameReferenceRun(t *testing.T) {
|
||||||
return &unstructured.Unstructured{
|
m := resource.ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
|
|
@ -34,11 +39,13 @@ func makeReferencedConfigMap() *unstructured.Unstructured {
|
||||||
"name": "someprefix-cm1-somehash",
|
"name": "someprefix-cm1-somehash",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func makeReferencedSecret() *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||||
return &unstructured.Unstructured{
|
Name: "secret1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "Secret",
|
"kind": "Secret",
|
||||||
|
|
@ -46,11 +53,13 @@ func makeReferencedSecret() *unstructured.Unstructured {
|
||||||
"name": "someprefix-secret1-somehash",
|
"name": "someprefix-secret1-somehash",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
return &unstructured.Unstructured{
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"group": "apps",
|
"group": "apps",
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
|
|
@ -70,7 +79,7 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
||||||
"name": "CM_FOO",
|
"name": "CM_FOO",
|
||||||
"valueFrom": map[string]interface{}{
|
"valueFrom": map[string]interface{}{
|
||||||
"configMapKeyRef": map[string]interface{}{
|
"configMapKeyRef": map[string]interface{}{
|
||||||
"name": cmName,
|
"name": "cm1",
|
||||||
"key": "somekey",
|
"key": "somekey",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -79,7 +88,7 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
||||||
"name": "SECRET_FOO",
|
"name": "SECRET_FOO",
|
||||||
"valueFrom": map[string]interface{}{
|
"valueFrom": map[string]interface{}{
|
||||||
"secretKeyRef": map[string]interface{}{
|
"secretKeyRef": map[string]interface{}{
|
||||||
"name": secretName,
|
"name": "secret1",
|
||||||
"key": "somekey",
|
"key": "somekey",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -88,13 +97,13 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
||||||
"envFrom": []interface{}{
|
"envFrom": []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"configMapRef": map[string]interface{}{
|
"configMapRef": map[string]interface{}{
|
||||||
"name": cmName,
|
"name": "cm1",
|
||||||
"key": "somekey",
|
"key": "somekey",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"secretRef": map[string]interface{}{
|
"secretRef": map[string]interface{}{
|
||||||
"name": secretName,
|
"name": "secret1",
|
||||||
"key": "somekey",
|
"key": "somekey",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -103,10 +112,12 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
||||||
},
|
},
|
||||||
"volumes": map[string]interface{}{
|
"volumes": map[string]interface{}{
|
||||||
"configMap": map[string]interface{}{
|
"configMap": map[string]interface{}{
|
||||||
"name": cmName,
|
"name": "cm1",
|
||||||
},
|
},
|
||||||
"secret": map[string]interface{}{
|
"secret": map[string]interface{}{
|
||||||
"secretName": secretName,
|
"secretName": "secret1",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -114,50 +125,112 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func makeNameReferenceTestMap() types.ResourceCollection {
|
expected := resource.ResourceCollection{
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
Name: "cm1",
|
Name: "cm1",
|
||||||
}: makeReferencedConfigMap(),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "someprefix-cm1-somehash",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||||
Name: "secret1",
|
Name: "secret1",
|
||||||
}: makeReferencedSecret(),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Secret",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "someprefix-secret1-somehash",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
Name: "deploy1",
|
Name: "deploy1",
|
||||||
}: makeNameRefDeployment("cm1", "secret1"),
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"group": "apps",
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "deploy1",
|
||||||
|
},
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"template": map[string]interface{}{
|
||||||
|
"spec": map[string]interface{}{
|
||||||
|
"containers": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "nginx",
|
||||||
|
"image": "nginx:1.7.9",
|
||||||
|
"env": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "CM_FOO",
|
||||||
|
"valueFrom": map[string]interface{}{
|
||||||
|
"configMapKeyRef": map[string]interface{}{
|
||||||
|
"name": "someprefix-cm1-somehash",
|
||||||
|
"key": "somekey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"name": "SECRET_FOO",
|
||||||
|
"valueFrom": map[string]interface{}{
|
||||||
|
"secretKeyRef": map[string]interface{}{
|
||||||
|
"name": "someprefix-secret1-somehash",
|
||||||
|
"key": "somekey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"envFrom": []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"configMapRef": map[string]interface{}{
|
||||||
|
"name": "someprefix-cm1-somehash",
|
||||||
|
"key": "somekey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"secretRef": map[string]interface{}{
|
||||||
|
"name": "someprefix-secret1-somehash",
|
||||||
|
"key": "somekey",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"volumes": map[string]interface{}{
|
||||||
|
"configMap": map[string]interface{}{
|
||||||
|
"name": "someprefix-cm1-somehash",
|
||||||
|
},
|
||||||
|
"secret": map[string]interface{}{
|
||||||
|
"secretName": "someprefix-secret1-somehash",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func makeNameReferenceUpdatedTestMap() types.ResourceCollection {
|
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
|
||||||
Name: "cm1",
|
|
||||||
}: makeReferencedConfigMap(),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
|
||||||
Name: "secret1",
|
|
||||||
}: makeReferencedSecret(),
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
|
||||||
Name: "deploy1",
|
|
||||||
}: makeNameRefDeployment("someprefix-cm1-somehash", "someprefix-secret1-somehash"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNameReferenceRun(t *testing.T) {
|
|
||||||
m := makeNameReferenceTestMap()
|
|
||||||
nrt, err := NewDefaultingNameReferenceTransformer()
|
nrt, err := NewDefaultingNameReferenceTransformer()
|
||||||
err = nrt.Transform(m)
|
err = nrt.Transform(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
expected := makeNameReferenceUpdatedTestMap()
|
|
||||||
if !reflect.DeepEqual(m, expected) {
|
if !reflect.DeepEqual(m, expected) {
|
||||||
err = compareMap(m, expected)
|
err = compareMap(m, expected)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||||
|
|
||||||
package transformers
|
package transformers
|
||||||
|
|
||||||
import "k8s.io/kubectl/pkg/kinflate/types"
|
import "k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
|
|
||||||
// noOpTransformer contains a no-op transformer.
|
// noOpTransformer contains a no-op transformer.
|
||||||
type noOpTransformer struct{}
|
type noOpTransformer struct{}
|
||||||
|
|
@ -29,6 +29,6 @@ func NewNoOpTransformer() Transformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform does nothing.
|
// Transform does nothing.
|
||||||
func (o *noOpTransformer) Transform(_ types.ResourceCollection) error {
|
func (o *noOpTransformer) Transform(_ resource.ResourceCollection) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,19 +24,19 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/scheme"
|
"k8s.io/kubectl/pkg/scheme"
|
||||||
)
|
)
|
||||||
|
|
||||||
// overlayTransformer contains a map of overlay objects
|
// overlayTransformer contains a map of overlay objects
|
||||||
type overlayTransformer struct {
|
type overlayTransformer struct {
|
||||||
overlay types.ResourceCollection
|
overlay resource.ResourceCollection
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Transformer = &overlayTransformer{}
|
var _ Transformer = &overlayTransformer{}
|
||||||
|
|
||||||
// NewOverlayTransformer constructs a overlayTransformer.
|
// NewOverlayTransformer constructs a overlayTransformer.
|
||||||
func NewOverlayTransformer(overlay types.ResourceCollection) (Transformer, error) {
|
func NewOverlayTransformer(overlay resource.ResourceCollection) (Transformer, error) {
|
||||||
if len(overlay) == 0 {
|
if len(overlay) == 0 {
|
||||||
return NewNoOpTransformer(), nil
|
return NewNoOpTransformer(), nil
|
||||||
}
|
}
|
||||||
|
|
@ -44,7 +44,7 @@ func NewOverlayTransformer(overlay types.ResourceCollection) (Transformer, error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform apply the overlay on top of the base resources.
|
// Transform apply the overlay on top of the base resources.
|
||||||
func (o *overlayTransformer) Transform(baseResourceMap types.ResourceCollection) error {
|
func (o *overlayTransformer) Transform(baseResourceMap resource.ResourceCollection) error {
|
||||||
// Strategic merge the resources exist in both base and overlay.
|
// Strategic merge the resources exist in both base and overlay.
|
||||||
for gvkn, overlay := range o.overlay {
|
for gvkn, overlay := range o.overlay {
|
||||||
// Merge overlay with base resource.
|
// Merge overlay with base resource.
|
||||||
|
|
@ -54,15 +54,15 @@ func (o *overlayTransformer) Transform(baseResourceMap types.ResourceCollection)
|
||||||
}
|
}
|
||||||
merged := map[string]interface{}{}
|
merged := map[string]interface{}{}
|
||||||
versionedObj, err := scheme.Scheme.New(gvkn.GVK)
|
versionedObj, err := scheme.Scheme.New(gvkn.GVK)
|
||||||
baseName := base.GetName()
|
baseName := base.Data.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)
|
baseBytes, err := json.Marshal(base.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
patchBytes, err := json.Marshal(overlay)
|
patchBytes, err := json.Marshal(overlay.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -82,15 +82,15 @@ func (o *overlayTransformer) Transform(baseResourceMap types.ResourceCollection)
|
||||||
// Store the name of the base object, because this name may have been munged.
|
// Store the name of the base object, because this name may have been munged.
|
||||||
// Apply this name to the StrategicMergePatched object.
|
// Apply this name to the StrategicMergePatched object.
|
||||||
merged, err = strategicpatch.StrategicMergeMapPatch(
|
merged, err = strategicpatch.StrategicMergeMapPatch(
|
||||||
base.UnstructuredContent(),
|
base.Data.UnstructuredContent(),
|
||||||
overlay.UnstructuredContent(),
|
overlay.Data.UnstructuredContent(),
|
||||||
versionedObj)
|
versionedObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
base.SetName(baseName)
|
base.Data.SetName(baseName)
|
||||||
baseResourceMap[gvkn].Object = merged
|
baseResourceMap[gvkn].Data.Object = merged
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,16 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeBaseDeployment() *unstructured.Unstructured {
|
func TestOverlayRun(t *testing.T) {
|
||||||
return &unstructured.Unstructured{
|
base := resource.ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
|
|
@ -51,11 +56,15 @@ func makeBaseDeployment() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
overlay := resource.ResourceCollection{
|
||||||
|
{
|
||||||
func makeOverlayDeployment() *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
return &unstructured.Unstructured{
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
|
|
@ -86,11 +95,15 @@ func makeOverlayDeployment() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
expected := resource.ResourceCollection{
|
||||||
|
{
|
||||||
func makeMergedDeployment() *unstructured.Unstructured {
|
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||||
return &unstructured.Unstructured{
|
Name: "deploy1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "apps/v1",
|
"apiVersion": "apps/v1",
|
||||||
"kind": "Deployment",
|
"kind": "Deployment",
|
||||||
|
|
@ -122,21 +135,10 @@ func makeMergedDeployment() *unstructured.Unstructured {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
lt, err := NewOverlayTransformer(overlay)
|
||||||
|
|
||||||
func makeTestResourceCollection(genDeployment func() *unstructured.Unstructured) types.ResourceCollection {
|
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
|
||||||
Name: "deploy1",
|
|
||||||
}: genDeployment(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOverlayRun(t *testing.T) {
|
|
||||||
base := makeTestResourceCollection(makeBaseDeployment)
|
|
||||||
lt, err := NewOverlayTransformer(makeTestResourceCollection(makeOverlayDeployment))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +146,6 @@ func TestOverlayRun(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
expected := makeTestResourceCollection(makeMergedDeployment)
|
|
||||||
if !reflect.DeepEqual(base, expected) {
|
if !reflect.DeepEqual(base, expected) {
|
||||||
err = compareMap(base, expected)
|
err = compareMap(base, expected)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
|
@ -152,11 +153,12 @@ func TestOverlayRun(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNoSchemaOverlayRun(t *testing.T) {
|
func TestNoSchemaOverlayRun(t *testing.T) {
|
||||||
base := types.ResourceCollection{
|
base := resource.ResourceCollection{
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"},
|
GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"},
|
||||||
Name: "my-foo",
|
Name: "my-foo",
|
||||||
}: {
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
"kind": "Foo",
|
"kind": "Foo",
|
||||||
|
|
@ -171,12 +173,14 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Overlay := types.ResourceCollection{
|
overlay := resource.ResourceCollection{
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"},
|
GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"},
|
||||||
Name: "my-foo",
|
Name: "my-foo",
|
||||||
}: {
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
"kind": "Foo",
|
"kind": "Foo",
|
||||||
|
|
@ -191,12 +195,14 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
expected := types.ResourceCollection{
|
expected := resource.ResourceCollection{
|
||||||
{
|
{
|
||||||
GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"},
|
GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"},
|
||||||
Name: "my-foo",
|
Name: "my-foo",
|
||||||
}: {
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "example.com/v1",
|
"apiVersion": "example.com/v1",
|
||||||
"kind": "Foo",
|
"kind": "Foo",
|
||||||
|
|
@ -211,9 +217,10 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
lt, err := NewOverlayTransformer(Overlay)
|
lt, err := NewOverlayTransformer(overlay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -56,9 +57,9 @@ func NewNamePrefixTransformer(pc []PathConfig, np string) (Transformer, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Transform prepends the name prefix.
|
// Transform prepends the name prefix.
|
||||||
func (o *namePrefixTransformer) Transform(m types.ResourceCollection) error {
|
func (o *namePrefixTransformer) Transform(m resource.ResourceCollection) error {
|
||||||
for gvkn := range m {
|
for gvkn := range m {
|
||||||
obj := m[gvkn]
|
obj := m[gvkn].Data
|
||||||
objMap := obj.UnstructuredContent()
|
objMap := obj.UnstructuredContent()
|
||||||
for _, path := range o.pathConfigs {
|
for _, path := range o.pathConfigs {
|
||||||
if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) {
|
if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) {
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,74 @@ package transformers
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPrefixNameRun(t *testing.T) {
|
func TestPrefixNameRun(t *testing.T) {
|
||||||
m := makeConfigMaps("cm1", "cm2", "cm1", "cm2")
|
m := resource.ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm2",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
expected := resource.ResourceCollection{
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "someprefix-cm1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm2",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "someprefix-cm2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
npt, err := NewDefaultingNamePrefixTransformer("someprefix-")
|
npt, err := NewDefaultingNamePrefixTransformer("someprefix-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
|
@ -31,7 +95,6 @@ func TestPrefixNameRun(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
expected := makeConfigMaps("cm1", "cm2", "someprefix-cm1", "someprefix-cm2")
|
|
||||||
if !reflect.DeepEqual(m, expected) {
|
if !reflect.DeepEqual(m, expected) {
|
||||||
err = compareMap(m, expected)
|
err = compareMap(m, expected)
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ limitations under the License.
|
||||||
|
|
||||||
package transformers
|
package transformers
|
||||||
|
|
||||||
import "k8s.io/kubectl/pkg/kinflate/types"
|
import "k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
|
|
||||||
// Transformer can transform objects.
|
// Transformer can transform objects.
|
||||||
type Transformer interface {
|
type Transformer interface {
|
||||||
// Transform modifies objects in a map, e.g. add prefixes or additional labels.
|
// Transform modifies objects in a map, e.g. add prefixes or additional labels.
|
||||||
Transform(m types.ResourceCollection) error
|
Transform(m resource.ResourceCollection) error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,39 +20,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeConfigMap(name string) *unstructured.Unstructured {
|
func compareMap(m1, m2 resource.ResourceCollection) error {
|
||||||
return &unstructured.Unstructured{
|
|
||||||
Object: map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeConfigMaps(name1InGVKN, name2InGVKN, name1InObj, name2InObj string) types.ResourceCollection {
|
|
||||||
cm1 := makeConfigMap(name1InObj)
|
|
||||||
cm2 := makeConfigMap(name2InObj)
|
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
|
||||||
Name: name1InGVKN,
|
|
||||||
}: cm1,
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
|
||||||
Name: name2InGVKN,
|
|
||||||
}: cm2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareMap(m1, m2 types.ResourceCollection) error {
|
|
||||||
if len(m1) != len(m2) {
|
if len(m1) != len(m2) {
|
||||||
keySet1 := []types.GroupVersionKindName{}
|
keySet1 := []types.GroupVersionKindName{}
|
||||||
keySet2 := []types.GroupVersionKindName{}
|
keySet2 := []types.GroupVersionKindName{}
|
||||||
|
|
@ -69,8 +41,8 @@ func compareMap(m1, m2 types.ResourceCollection) error {
|
||||||
if !found {
|
if !found {
|
||||||
return fmt.Errorf("%#v doesn't exist in %#v", GVKn, m2)
|
return fmt.Errorf("%#v doesn't exist in %#v", GVKn, m2)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(obj1, obj2) {
|
if !reflect.DeepEqual(obj1.Data, obj2.Data) {
|
||||||
return fmt.Errorf("%#v doesn't match %#v", obj1, obj2)
|
return fmt.Errorf("%#v doesn't match %#v", obj1.Data, obj2.Data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -28,6 +27,3 @@ type GroupVersionKindName struct {
|
||||||
// original name of the resource before transformation.
|
// original name of the resource before transformation.
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResourceCollection is a map from GroupVersionKindName to unstructured objects
|
|
||||||
type ResourceCollection map[GroupVersionKindName]*unstructured.Unstructured
|
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,8 @@ limitations under the License.
|
||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -59,15 +57,3 @@ func SelectByGVK(in schema.GroupVersionKind, selector *schema.GroupVersionKind)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge will merge all the entries in m2 to m1.
|
|
||||||
func Merge(m1, m2 map[GroupVersionKindName]*unstructured.Unstructured,
|
|
||||||
) error {
|
|
||||||
for gvkn, obj := range m2 {
|
|
||||||
if _, found := m1[gvkn]; found {
|
|
||||||
return fmt.Errorf("there is already an entry: %q", gvkn)
|
|
||||||
}
|
|
||||||
m1[gvkn] = obj
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -18,82 +18,16 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decode decodes a list of objects in byte array format
|
|
||||||
func Decode(in []byte) ([]*unstructured.Unstructured, error) {
|
|
||||||
decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewReader(in), 1024)
|
|
||||||
objs := []*unstructured.Unstructured{}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
for {
|
|
||||||
var out unstructured.Unstructured
|
|
||||||
err = decoder.Decode(&out)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
objs = append(objs, &out)
|
|
||||||
}
|
|
||||||
if err != io.EOF {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return objs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeToResourceCollection decodes a list of objects in byte array format.
|
|
||||||
// Decoded object will be inserted in `into` if it's not nil. Otherwise, it will
|
|
||||||
// construct a new map and return it.
|
|
||||||
func DecodeToResourceCollection(in []byte, into types.ResourceCollection) (types.ResourceCollection, error) {
|
|
||||||
objs, err := Decode(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if into == nil {
|
|
||||||
into = types.ResourceCollection{}
|
|
||||||
}
|
|
||||||
for i := range objs {
|
|
||||||
metaAccessor, err := meta.Accessor(objs[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
name := metaAccessor.GetName()
|
|
||||||
typeAccessor, err := meta.TypeAccessor(objs[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
apiVersion := typeAccessor.GetAPIVersion()
|
|
||||||
kind := typeAccessor.GetKind()
|
|
||||||
gv, err := schema.ParseGroupVersion(apiVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
gvk := gv.WithKind(kind)
|
|
||||||
gvkn := types.GroupVersionKindName{
|
|
||||||
GVK: gvk,
|
|
||||||
Name: name,
|
|
||||||
}
|
|
||||||
if _, found := into[gvkn]; found {
|
|
||||||
return into, fmt.Errorf("GroupVersionKindName: %#v already exists in the map", gvkn)
|
|
||||||
}
|
|
||||||
into[gvkn] = objs[i]
|
|
||||||
}
|
|
||||||
return into, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode encodes the map `in` and output the encoded objects separated by `---`.
|
// Encode encodes the map `in` and output the encoded objects separated by `---`.
|
||||||
func Encode(in types.ResourceCollection) ([]byte, error) {
|
func Encode(in resource.ResourceCollection) ([]byte, error) {
|
||||||
gvknList := []types.GroupVersionKindName{}
|
gvknList := []types.GroupVersionKindName{}
|
||||||
for gvkn := range in {
|
for gvkn := range in {
|
||||||
gvknList = append(gvknList, gvkn)
|
gvknList = append(gvknList, gvkn)
|
||||||
|
|
@ -104,7 +38,7 @@ func Encode(in types.ResourceCollection) ([]byte, error) {
|
||||||
var b []byte
|
var b []byte
|
||||||
buf := bytes.NewBuffer(b)
|
buf := bytes.NewBuffer(b)
|
||||||
for _, gvkn := range gvknList {
|
for _, gvkn := range gvknList {
|
||||||
obj := in[gvkn]
|
obj := in[gvkn].Data
|
||||||
out, err := yaml.Marshal(obj)
|
out, err := yaml.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -125,7 +59,7 @@ func Encode(in types.ResourceCollection) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteToDir write each object in ResourceCollection to a file named with GroupVersionKindName.
|
// WriteToDir write each object in ResourceCollection to a file named with GroupVersionKindName.
|
||||||
func WriteToDir(in types.ResourceCollection, dirName string, printer Printer) (*Directory, error) {
|
func WriteToDir(in resource.ResourceCollection, dirName string, printer Printer) (*Directory, error) {
|
||||||
dir, err := CreateDirectory(dirName)
|
dir, err := CreateDirectory(dirName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Directory{}, err
|
return &Directory{}, err
|
||||||
|
|
@ -137,7 +71,7 @@ func WriteToDir(in types.ResourceCollection, dirName string, printer Printer) (*
|
||||||
return &Directory{}, err
|
return &Directory{}, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
err = printer.Print(obj, f)
|
err = printer.Print(obj.Data, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Directory{}, err
|
return &Directory{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,12 @@ import (
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||||
"k8s.io/kubectl/pkg/kinflate/types"
|
"k8s.io/kubectl/pkg/kinflate/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
var encoded = []byte(`apiVersion: v1
|
func TestEncode(t *testing.T) {
|
||||||
|
encoded := []byte(`apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: cm1
|
name: cm1
|
||||||
|
|
@ -36,48 +38,37 @@ kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: cm2
|
name: cm2
|
||||||
`)
|
`)
|
||||||
|
input := resource.ResourceCollection{
|
||||||
func makeConfigMap(name string) *unstructured.Unstructured {
|
{
|
||||||
return &unstructured.Unstructured{
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm1",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
"kind": "ConfigMap",
|
"kind": "ConfigMap",
|
||||||
"metadata": map[string]interface{}{
|
"metadata": map[string]interface{}{
|
||||||
"name": name,
|
"name": "cm1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||||
|
Name: "cm2",
|
||||||
|
}: &resource.Resource{
|
||||||
|
Data: &unstructured.Unstructured{
|
||||||
|
Object: map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm2",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
out, err := Encode(input)
|
||||||
|
|
||||||
func makeConfigMaps(name1InGVKN, name2InGVKN, name1InObj, name2InObj string) types.ResourceCollection {
|
|
||||||
cm1 := makeConfigMap(name1InObj)
|
|
||||||
cm2 := makeConfigMap(name2InObj)
|
|
||||||
return types.ResourceCollection{
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
|
||||||
Name: name1InGVKN,
|
|
||||||
}: cm1,
|
|
||||||
{
|
|
||||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
|
||||||
Name: name2InGVKN,
|
|
||||||
}: cm2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecodeToResourceCollection(t *testing.T) {
|
|
||||||
expected := makeConfigMaps("cm1", "cm2", "cm1", "cm2")
|
|
||||||
m, err := DecodeToResourceCollection(encoded, nil)
|
|
||||||
fmt.Printf("%v\n", m)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(m, expected) {
|
|
||||||
t.Fatalf("%#v doesn't match expected %#v", m, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncode(t *testing.T) {
|
|
||||||
out, err := Encode(makeConfigMaps("cm1", "cm2", "cm1", "cm2"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +77,7 @@ func TestEncode(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareMap(m1, m2 types.ResourceCollection) error {
|
func compareMap(m1, m2 resource.ResourceCollection) error {
|
||||||
if len(m1) != len(m2) {
|
if len(m1) != len(m2) {
|
||||||
keySet1 := []types.GroupVersionKindName{}
|
keySet1 := []types.GroupVersionKindName{}
|
||||||
keySet2 := []types.GroupVersionKindName{}
|
keySet2 := []types.GroupVersionKindName{}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue