cleanup Resouce slice related code
This commit is contained in:
parent
94f9347974
commit
2e06ca8bc0
|
|
@ -17,8 +17,6 @@ limitations under the License.
|
|||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
|
|
@ -26,16 +24,15 @@ import (
|
|||
interror "k8s.io/kubectl/pkg/kinflate/internal/error"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/kinflate/transformers"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/loader"
|
||||
)
|
||||
|
||||
type Application interface {
|
||||
// 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.
|
||||
// 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{}
|
||||
|
|
@ -63,27 +60,22 @@ func New(loader loader.Loader) (Application, error) {
|
|||
}
|
||||
|
||||
// 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{}
|
||||
raw, err := a.RawResources()
|
||||
if err != nil {
|
||||
errs.Append(err)
|
||||
}
|
||||
|
||||
resources := []*resource.Resource{}
|
||||
cms, err := resource.NewFromConfigMaps(a.loader, a.manifest.Configmaps)
|
||||
if err != nil {
|
||||
errs.Append(err)
|
||||
} else {
|
||||
resources = append(resources, cms...)
|
||||
}
|
||||
secrets, err := resource.NewFromSecretGenerators(a.loader.Root(), a.manifest.SecretGenerators)
|
||||
if err != nil {
|
||||
errs.Append(err)
|
||||
} else {
|
||||
resources = append(resources, secrets...)
|
||||
}
|
||||
res, err := resourceCollectionFromResources(resources)
|
||||
res, err := resource.Merge(cms, secrets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -94,12 +86,7 @@ func (a *applicationImpl) Resources() (types.ResourceCollection, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ps, 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)
|
||||
patches, err := resource.NewFromPaths(a.loader, a.manifest.Patches)
|
||||
if err != nil {
|
||||
errs.Append(err)
|
||||
}
|
||||
|
|
@ -108,7 +95,7 @@ func (a *applicationImpl) Resources() (types.ResourceCollection, error) {
|
|||
return nil, errs
|
||||
}
|
||||
|
||||
err = types.Merge(res, raw)
|
||||
allRes, err := resource.Merge(res, raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -117,35 +104,30 @@ func (a *applicationImpl) Resources() (types.ResourceCollection, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = t.Transform(res)
|
||||
err = t.Transform(allRes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
return allRes, nil
|
||||
}
|
||||
|
||||
// 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()
|
||||
allRes, 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)
|
||||
resources, err := resource.NewFromPaths(a.loader, a.manifest.Resources)
|
||||
if err != nil {
|
||||
errs.Append(err)
|
||||
}
|
||||
|
||||
if len(errs.Get()) > 0 {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
err = types.Merge(allResources, subAppResources)
|
||||
return allResources, err
|
||||
return resource.Merge(resources, subAppResources)
|
||||
}
|
||||
|
||||
func (a *applicationImpl) subAppResources() (types.ResourceCollection, *interror.ManifestErrors) {
|
||||
allResources := types.ResourceCollection{}
|
||||
func (a *applicationImpl) subAppResources() (resource.ResourceCollection, *interror.ManifestErrors) {
|
||||
sliceOfSubAppResources := []resource.ResourceCollection{}
|
||||
errs := &interror.ManifestErrors{}
|
||||
for _, pkgPath := range a.manifest.Packages {
|
||||
subloader, err := a.loader.New(pkgPath)
|
||||
|
|
@ -164,7 +146,11 @@ func (a *applicationImpl) subAppResources() (types.ResourceCollection, *interror
|
|||
errs.Append(err)
|
||||
continue
|
||||
}
|
||||
types.Merge(allResources, subAppResources)
|
||||
sliceOfSubAppResources = append(sliceOfSubAppResources, subAppResources)
|
||||
}
|
||||
allResources, err := resource.Merge(sliceOfSubAppResources...)
|
||||
if err != nil {
|
||||
errs.Append(err)
|
||||
}
|
||||
return allResources, errs
|
||||
}
|
||||
|
|
@ -175,7 +161,7 @@ func (a *applicationImpl) subAppResources() (types.ResourceCollection, *interror
|
|||
// 3) apply labels
|
||||
// 4) apply annotations
|
||||
// 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{}
|
||||
|
||||
ot, err := transformers.NewOverlayTransformer(patches)
|
||||
|
|
@ -209,15 +195,3 @@ func (a *applicationImpl) getTransformer(patches types.ResourceCollection) (tran
|
|||
ts = append(ts, nrt)
|
||||
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"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/loader"
|
||||
"k8s.io/kubectl/pkg/loader/loadertest"
|
||||
|
|
@ -74,11 +75,12 @@ metadata:
|
|||
}
|
||||
|
||||
func TestResources(t *testing.T) {
|
||||
expected := types.ResourceCollection{
|
||||
expected := resource.ResourceCollection{
|
||||
types.GroupVersionKindName{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "dply1",
|
||||
}: &unstructured.Unstructured{
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
|
|
@ -110,10 +112,12 @@ func TestResources(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
types.GroupVersionKindName{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||
Name: "literalConfigMap",
|
||||
}: &unstructured.Unstructured{
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
|
|
@ -133,10 +137,12 @@ func TestResources(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
types.GroupVersionKindName{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||
Name: "secret",
|
||||
}: &unstructured.Unstructured{
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
|
|
@ -157,6 +163,7 @@ func TestResources(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
l := setupTest(t)
|
||||
app, err := New(l)
|
||||
|
|
@ -175,11 +182,12 @@ func TestResources(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRawResources(t *testing.T) {
|
||||
expected := types.ResourceCollection{
|
||||
expected := resource.ResourceCollection{
|
||||
types.GroupVersionKindName{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "dply1",
|
||||
}: &unstructured.Unstructured{
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
|
|
@ -188,6 +196,7 @@ func TestRawResources(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
l := setupTest(t)
|
||||
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) {
|
||||
keySet1 := []types.GroupVersionKindName{}
|
||||
keySet2 := []types.GroupVersionKindName{}
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ import (
|
|||
"time"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
cutil "k8s.io/kubectl/pkg/kinflate/configmapandsecret/util"
|
||||
"k8s.io/kubectl/pkg/kinflate/hash"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
)
|
||||
|
||||
|
|
@ -123,26 +123,22 @@ func makeSecret(secret manifest.SecretGenerator, path string) (*corev1.Secret, e
|
|||
return corev1secret, nil
|
||||
}
|
||||
|
||||
func populateMap(m types.ResourceCollection, obj *unstructured.Unstructured, newName string) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oldName := accessor.GetName()
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
func populateMap(m resource.ResourceCollection, obj *unstructured.Unstructured, newName string) error {
|
||||
oldName := obj.GetName()
|
||||
gvk := obj.GroupVersionKind()
|
||||
gvkn := types.GroupVersionKindName{GVK: gvk, Name: oldName}
|
||||
|
||||
if _, found := m[gvkn]; found {
|
||||
return fmt.Errorf("The <name: %q, GroupVersionKind: %v> already exists in the map", oldName, gvk)
|
||||
}
|
||||
accessor.SetName(newName)
|
||||
m[gvkn] = obj
|
||||
obj.SetName(newName)
|
||||
m[gvkn] = &resource.Resource{Data: obj}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeConfigMapsResourceCollection returns a map of <GVK, oldName> -> unstructured object.
|
||||
func MakeConfigMapsResourceCollection(maps []manifest.ConfigMap) (types.ResourceCollection, error) {
|
||||
m := types.ResourceCollection{}
|
||||
func MakeConfigMapsResourceCollection(maps []manifest.ConfigMap) (resource.ResourceCollection, error) {
|
||||
m := resource.ResourceCollection{}
|
||||
for _, cm := range maps {
|
||||
unstructuredConfigMap, nameWithHash, err := MakeConfigmapAndGenerateName(cm)
|
||||
if err != nil {
|
||||
|
|
@ -157,8 +153,8 @@ func MakeConfigMapsResourceCollection(maps []manifest.ConfigMap) (types.Resource
|
|||
}
|
||||
|
||||
// MakeSecretsResourceCollection returns a map of <GVK, oldName> -> unstructured object.
|
||||
func MakeSecretsResourceCollection(secrets []manifest.SecretGenerator, path string) (types.ResourceCollection, error) {
|
||||
m := types.ResourceCollection{}
|
||||
func MakeSecretsResourceCollection(secrets []manifest.SecretGenerator, path string) (resource.ResourceCollection, error) {
|
||||
m := resource.ResourceCollection{}
|
||||
for _, secret := range secrets {
|
||||
unstructuredSecret, nameWithHash, err := MakeSecretAndGenerateName(secret, path)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -17,37 +17,27 @@ limitations under the License.
|
|||
package resource
|
||||
|
||||
import (
|
||||
kutil "k8s.io/kubectl/pkg/kinflate/util"
|
||||
"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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
objs, err := kutil.Decode(content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var res []*Resource
|
||||
for _, obj := range objs {
|
||||
res = append(res, &Resource{Data: obj})
|
||||
}
|
||||
return res, nil
|
||||
return decodeToResourceCollection(content)
|
||||
}
|
||||
|
||||
// NewFromPaths returns a slice of Resources given a resource path slice from manifest file.
|
||||
func NewFromPaths(loader loader.Loader, paths []string) ([]*Resource, error) {
|
||||
allResources := []*Resource{}
|
||||
func NewFromPaths(loader loader.Loader, paths []string) (ResourceCollection, error) {
|
||||
allResources := []ResourceCollection{}
|
||||
for _, path := range paths {
|
||||
res, err := resourcesFromPath(loader, path)
|
||||
if err != nil {
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"reflect"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
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) {
|
||||
|
||||
resourceStr := `apiVersion: v1
|
||||
resourceStr := `apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dply1
|
||||
---
|
||||
apiVersion: v1
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dply2
|
||||
|
|
@ -38,9 +44,35 @@ metadata:
|
|||
if ferr := l.AddFile("/home/seans/project/deployment.yaml", []byte(resourceStr)); ferr != nil {
|
||||
t.Fatalf("Error adding fake file: %v\n", ferr)
|
||||
}
|
||||
expected := []*Resource{
|
||||
{Data: makeUnconstructed("dply1")},
|
||||
{Data: makeUnconstructed("dply2")},
|
||||
expected := ResourceCollection{
|
||||
{
|
||||
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"})
|
||||
|
|
@ -48,9 +80,31 @@ metadata:
|
|||
t.Fatalf("%#v should contain 2 appResource, but got %d", resources, len(resources))
|
||||
}
|
||||
|
||||
for i, r := range resources {
|
||||
if !reflect.DeepEqual(r.Data, expected[i].Data) {
|
||||
t.Fatalf("expected %v, but got %v", expected[i].Data, r.Data)
|
||||
if err := compareMap(resources, expected); err != nil {
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
func NewFromConfigMaps(loader loader.Loader, cmList []manifest.ConfigMap) ([]*Resource, error) {
|
||||
func NewFromConfigMaps(loader loader.Loader, cmList []manifest.ConfigMap) (ResourceCollection, error) {
|
||||
allResources := []*Resource{}
|
||||
for _, cm := range cmList {
|
||||
res, err := newFromConfigMap(loader, cm)
|
||||
|
|
@ -140,5 +140,5 @@ func NewFromConfigMaps(loader loader.Loader, cmList []manifest.ConfigMap) ([]*Re
|
|||
}
|
||||
allResources = append(allResources, res)
|
||||
}
|
||||
return allResources, nil
|
||||
return resourceCollectionFromResources(allResources)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/loader/loadertest"
|
||||
|
|
@ -32,7 +33,7 @@ func TestNewFromConfigMaps(t *testing.T) {
|
|||
input []manifest.ConfigMap
|
||||
filepath string
|
||||
content string
|
||||
expected []*resource.Resource
|
||||
expected resource.ResourceCollection
|
||||
}
|
||||
|
||||
l := loadertest.NewFakeLoader("/home/seans/project/")
|
||||
|
|
@ -49,8 +50,11 @@ func TestNewFromConfigMaps(t *testing.T) {
|
|||
},
|
||||
filepath: "/home/seans/project/app.env",
|
||||
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{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
|
|
@ -79,8 +83,11 @@ func TestNewFromConfigMaps(t *testing.T) {
|
|||
},
|
||||
filepath: "/home/seans/project/app-init.ini",
|
||||
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{
|
||||
Object: map[string]interface{}{
|
||||
"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{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package resource
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
|
|
@ -37,14 +36,13 @@ func (r *Resource) GVKN() types.GroupVersionKindName {
|
|||
if r.Data == nil {
|
||||
return emptyZVKN
|
||||
}
|
||||
accessor, err := meta.Accessor(r.Data)
|
||||
if err != nil {
|
||||
return emptyZVKN
|
||||
}
|
||||
gvk := r.Data.GetObjectKind().GroupVersionKind()
|
||||
return types.GroupVersionKindName{GVK: gvk, Name: accessor.GetName()}
|
||||
gvk := r.Data.GroupVersionKind()
|
||||
return types.GroupVersionKindName{GVK: gvk, Name: r.Data.GetName()}
|
||||
}
|
||||
|
||||
// ResourceCollection is a map from GroupVersionKindName to Resource
|
||||
type ResourceCollection map[types.GroupVersionKindName]*Resource
|
||||
|
||||
func objectToUnstructured(in runtime.Object) (*unstructured.Unstructured, error) {
|
||||
marshaled, err := json.Marshal(in)
|
||||
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
|
||||
// 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{}
|
||||
for _, secret := range secretList {
|
||||
res, err := newFromSecretGenerator(p, secret)
|
||||
|
|
@ -79,5 +79,5 @@ func NewFromSecretGenerators(p string, secretList []manifest.SecretGenerator) ([
|
|||
}
|
||||
allResources = append(allResources, res)
|
||||
}
|
||||
return allResources, nil
|
||||
return resourceCollectionFromResources(allResources)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
manifest "k8s.io/kubectl/pkg/apis/manifest/v1alpha1"
|
||||
)
|
||||
|
||||
|
|
@ -42,8 +43,12 @@ func TestNewFromSecretGenerators(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected := []*Resource{
|
||||
{Data: &unstructured.Unstructured{
|
||||
expected := ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||
Name: "secret",
|
||||
}: &Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
|
|
@ -57,7 +62,8 @@ func TestNewFromSecretGenerators(t *testing.T) {
|
|||
"DB_PASSWORD": base64.StdEncoding.EncodeToString([]byte("somepw")),
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
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"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"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
|
||||
// fields specified in mapTransformer.
|
||||
func (o *mapTransformer) Transform(m types.ResourceCollection) error {
|
||||
func (o *mapTransformer) Transform(m resource.ResourceCollection) error {
|
||||
for gvkn := range m {
|
||||
obj := m[gvkn]
|
||||
obj := m[gvkn].Data
|
||||
objMap := obj.UnstructuredContent()
|
||||
for _, path := range o.pathConfigs {
|
||||
if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) {
|
||||
|
|
|
|||
|
|
@ -22,23 +22,30 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
)
|
||||
|
||||
func makeConfigmap(name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
func TestLabelsRun(t *testing.T) {
|
||||
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": name,
|
||||
"name": "cm1",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeDeployment() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
},
|
||||
},
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "deploy1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"group": "apps",
|
||||
"apiVersion": "v1",
|
||||
|
|
@ -64,11 +71,13 @@ func makeDeployment() *unstructured.Unstructured {
|
|||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeService() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
},
|
||||
},
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||
Name: "svc1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Service",
|
||||
|
|
@ -84,28 +93,15 @@ func makeService() *unstructured.Unstructured {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeTestMap() types.ResourceCollection {
|
||||
return types.ResourceCollection{
|
||||
expected := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||
Name: "cm1",
|
||||
}: makeConfigmap("cm1"),
|
||||
{
|
||||
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{
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "ConfigMap",
|
||||
|
|
@ -117,11 +113,13 @@ func makeLabeledConfigMap() *unstructured.Unstructured {
|
|||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeLabeledDeployment() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
},
|
||||
},
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "deploy1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"group": "apps",
|
||||
"apiVersion": "v1",
|
||||
|
|
@ -159,11 +157,13 @@ func makeLabeledDeployment() *unstructured.Unstructured {
|
|||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeLabeledService() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
},
|
||||
},
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Service"},
|
||||
Name: "svc1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"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"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
|
|
@ -217,7 +199,6 @@ func TestLabelsRun(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected := makeLabeledMap()
|
||||
if !reflect.DeepEqual(m, expected) {
|
||||
err = compareMap(m, expected)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
|
|
@ -302,25 +283,163 @@ func makeAnnotatededService() *unstructured.Unstructured {
|
|||
}
|
||||
}
|
||||
|
||||
func makeAnnotatedMap() types.ResourceCollection {
|
||||
return types.ResourceCollection{
|
||||
func TestAnnotationsRun(t *testing.T) {
|
||||
m := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||
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"},
|
||||
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"},
|
||||
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"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
|
|
@ -329,7 +448,6 @@ func TestAnnotationsRun(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected := makeAnnotatedMap()
|
||||
if !reflect.DeepEqual(m, expected) {
|
||||
err = compareMap(m, expected)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
package transformers
|
||||
|
||||
import "k8s.io/kubectl/pkg/kinflate/types"
|
||||
import "k8s.io/kubectl/pkg/kinflate/resource"
|
||||
|
||||
// multiTransformer contains a list of transformers.
|
||||
type multiTransformer struct {
|
||||
|
|
@ -34,7 +34,7 @@ func NewMultiTransformer(t []Transformer) Transformer {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
err := t.Transform(m)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/hash"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
)
|
||||
|
||||
|
|
@ -39,14 +40,14 @@ func NewNameHashTransformer() Transformer {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
switch {
|
||||
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"}):
|
||||
appendHashForSecret(obj)
|
||||
appendHashForSecret(obj.Data)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -22,71 +22,183 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
)
|
||||
|
||||
func makeSecret(name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
func TestNameHashTransformer(t *testing.T) {
|
||||
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{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": name,
|
||||
"name": "secret1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeHashTestMap() types.ResourceCollection {
|
||||
return types.ResourceCollection{
|
||||
expected := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||
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"},
|
||||
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"},
|
||||
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"},
|
||||
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.Transform(objs)
|
||||
|
||||
expected := makeExpectedHashTestMap()
|
||||
|
||||
if !reflect.DeepEqual(objs, expected) {
|
||||
err := compareMap(objs, expected)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"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,
|
||||
// then the old name is k.Name and the new name is v.GetName()
|
||||
func (o *nameReferenceTransformer) Transform(
|
||||
m types.ResourceCollection) error {
|
||||
m resource.ResourceCollection) error {
|
||||
for GVKn := range m {
|
||||
obj := m[GVKn]
|
||||
obj := m[GVKn].Data
|
||||
objMap := obj.UnstructuredContent()
|
||||
for _, referencePathConfig := range o.pathConfigs {
|
||||
for _, path := range referencePathConfig.pathConfigs {
|
||||
|
|
@ -88,7 +89,7 @@ func (err noMatchingGVKNError) Error() string {
|
|||
|
||||
func (o *nameReferenceTransformer) updateNameReference(
|
||||
GVK schema.GroupVersionKind,
|
||||
m types.ResourceCollection,
|
||||
m resource.ResourceCollection,
|
||||
) func(in interface{}) (interface{}, error) {
|
||||
return func(in interface{}) (interface{}, error) {
|
||||
s, ok := in.(string)
|
||||
|
|
@ -101,7 +102,7 @@ func (o *nameReferenceTransformer) updateNameReference(
|
|||
continue
|
||||
}
|
||||
if GVKn.Name == s {
|
||||
return obj.GetName(), nil
|
||||
return obj.Data.GetName(), nil
|
||||
}
|
||||
}
|
||||
return in, nil
|
||||
|
|
|
|||
|
|
@ -22,11 +22,16 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
)
|
||||
|
||||
func makeReferencedConfigMap() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
func TestNameReferenceRun(t *testing.T) {
|
||||
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",
|
||||
|
|
@ -34,11 +39,13 @@ func makeReferencedConfigMap() *unstructured.Unstructured {
|
|||
"name": "someprefix-cm1-somehash",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeReferencedSecret() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
},
|
||||
},
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "Secret"},
|
||||
Name: "secret1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Secret",
|
||||
|
|
@ -46,11 +53,13 @@ func makeReferencedSecret() *unstructured.Unstructured {
|
|||
"name": "someprefix-secret1-somehash",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
},
|
||||
},
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "deploy1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"group": "apps",
|
||||
"apiVersion": "v1",
|
||||
|
|
@ -70,7 +79,7 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
|||
"name": "CM_FOO",
|
||||
"valueFrom": map[string]interface{}{
|
||||
"configMapKeyRef": map[string]interface{}{
|
||||
"name": cmName,
|
||||
"name": "cm1",
|
||||
"key": "somekey",
|
||||
},
|
||||
},
|
||||
|
|
@ -79,7 +88,7 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
|||
"name": "SECRET_FOO",
|
||||
"valueFrom": map[string]interface{}{
|
||||
"secretKeyRef": map[string]interface{}{
|
||||
"name": secretName,
|
||||
"name": "secret1",
|
||||
"key": "somekey",
|
||||
},
|
||||
},
|
||||
|
|
@ -88,13 +97,13 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
|||
"envFrom": []interface{}{
|
||||
map[string]interface{}{
|
||||
"configMapRef": map[string]interface{}{
|
||||
"name": cmName,
|
||||
"name": "cm1",
|
||||
"key": "somekey",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"secretRef": map[string]interface{}{
|
||||
"name": secretName,
|
||||
"name": "secret1",
|
||||
"key": "somekey",
|
||||
},
|
||||
},
|
||||
|
|
@ -103,61 +112,125 @@ func makeNameRefDeployment(cmName, secretName string) *unstructured.Unstructured
|
|||
},
|
||||
"volumes": map[string]interface{}{
|
||||
"configMap": map[string]interface{}{
|
||||
"name": cmName,
|
||||
"name": "cm1",
|
||||
},
|
||||
"secret": map[string]interface{}{
|
||||
"secretName": secretName,
|
||||
"secretName": "secret1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeNameReferenceTestMap() types.ResourceCollection {
|
||||
return types.ResourceCollection{
|
||||
expected := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"},
|
||||
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"},
|
||||
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"},
|
||||
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()
|
||||
err = nrt.Transform(m)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected := makeNameReferenceUpdatedTestMap()
|
||||
if !reflect.DeepEqual(m, expected) {
|
||||
err = compareMap(m, expected)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||
|
||||
package transformers
|
||||
|
||||
import "k8s.io/kubectl/pkg/kinflate/types"
|
||||
import "k8s.io/kubectl/pkg/kinflate/resource"
|
||||
|
||||
// noOpTransformer contains a no-op transformer.
|
||||
type noOpTransformer struct{}
|
||||
|
|
@ -29,6 +29,6 @@ func NewNoOpTransformer() Transformer {
|
|||
}
|
||||
|
||||
// Transform does nothing.
|
||||
func (o *noOpTransformer) Transform(_ types.ResourceCollection) error {
|
||||
func (o *noOpTransformer) Transform(_ resource.ResourceCollection) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,19 +24,19 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
)
|
||||
|
||||
// overlayTransformer contains a map of overlay objects
|
||||
type overlayTransformer struct {
|
||||
overlay types.ResourceCollection
|
||||
overlay resource.ResourceCollection
|
||||
}
|
||||
|
||||
var _ Transformer = &overlayTransformer{}
|
||||
|
||||
// NewOverlayTransformer constructs a overlayTransformer.
|
||||
func NewOverlayTransformer(overlay types.ResourceCollection) (Transformer, error) {
|
||||
func NewOverlayTransformer(overlay resource.ResourceCollection) (Transformer, error) {
|
||||
if len(overlay) == 0 {
|
||||
return NewNoOpTransformer(), nil
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ func NewOverlayTransformer(overlay types.ResourceCollection) (Transformer, error
|
|||
}
|
||||
|
||||
// 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.
|
||||
for gvkn, overlay := range o.overlay {
|
||||
// Merge overlay with base resource.
|
||||
|
|
@ -54,15 +54,15 @@ func (o *overlayTransformer) Transform(baseResourceMap types.ResourceCollection)
|
|||
}
|
||||
merged := map[string]interface{}{}
|
||||
versionedObj, err := scheme.Scheme.New(gvkn.GVK)
|
||||
baseName := base.GetName()
|
||||
baseName := base.Data.GetName()
|
||||
switch {
|
||||
case runtime.IsNotRegisteredError(err):
|
||||
// Use JSON merge patch to handle types w/o schema
|
||||
baseBytes, err := json.Marshal(base)
|
||||
baseBytes, err := json.Marshal(base.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
patchBytes, err := json.Marshal(overlay)
|
||||
patchBytes, err := json.Marshal(overlay.Data)
|
||||
if err != nil {
|
||||
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.
|
||||
// Apply this name to the StrategicMergePatched object.
|
||||
merged, err = strategicpatch.StrategicMergeMapPatch(
|
||||
base.UnstructuredContent(),
|
||||
overlay.UnstructuredContent(),
|
||||
base.Data.UnstructuredContent(),
|
||||
overlay.Data.UnstructuredContent(),
|
||||
versionedObj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
base.SetName(baseName)
|
||||
baseResourceMap[gvkn].Object = merged
|
||||
base.Data.SetName(baseName)
|
||||
baseResourceMap[gvkn].Data.Object = merged
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,11 +22,16 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
)
|
||||
|
||||
func makeBaseDeployment() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
func TestOverlayRun(t *testing.T) {
|
||||
base := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "deploy1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
|
|
@ -51,11 +56,15 @@ func makeBaseDeployment() *unstructured.Unstructured {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeOverlayDeployment() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
overlay := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "deploy1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
|
|
@ -86,11 +95,15 @@ func makeOverlayDeployment() *unstructured.Unstructured {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func makeMergedDeployment() *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
expected := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
|
||||
Name: "deploy1",
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
|
|
@ -122,21 +135,10 @@ func makeMergedDeployment() *unstructured.Unstructured {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
lt, err := NewOverlayTransformer(overlay)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
@ -144,7 +146,6 @@ func TestOverlayRun(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected := makeTestResourceCollection(makeMergedDeployment)
|
||||
if !reflect.DeepEqual(base, expected) {
|
||||
err = compareMap(base, expected)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
|
|
@ -152,11 +153,12 @@ func TestOverlayRun(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNoSchemaOverlayRun(t *testing.T) {
|
||||
base := types.ResourceCollection{
|
||||
base := resource.ResourceCollection{
|
||||
{
|
||||
GVK: schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Foo"},
|
||||
Name: "my-foo",
|
||||
}: {
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"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"},
|
||||
Name: "my-foo",
|
||||
}: {
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"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"},
|
||||
Name: "my-foo",
|
||||
}: {
|
||||
}: &resource.Resource{
|
||||
Data: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "example.com/v1",
|
||||
"kind": "Foo",
|
||||
|
|
@ -211,9 +217,10 @@ func TestNoSchemaOverlayRun(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
lt, err := NewOverlayTransformer(Overlay)
|
||||
lt, err := NewOverlayTransformer(overlay)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
)
|
||||
|
||||
|
|
@ -56,9 +57,9 @@ func NewNamePrefixTransformer(pc []PathConfig, np string) (Transformer, error) {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
obj := m[gvkn]
|
||||
obj := m[gvkn].Data
|
||||
objMap := obj.UnstructuredContent()
|
||||
for _, path := range o.pathConfigs {
|
||||
if !types.SelectByGVK(gvkn.GVK, path.GroupVersionKind) {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,74 @@ package transformers
|
|||
import (
|
||||
"reflect"
|
||||
"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) {
|
||||
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-")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
|
|
@ -31,7 +95,6 @@ func TestPrefixNameRun(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
expected := makeConfigMaps("cm1", "cm2", "someprefix-cm1", "someprefix-cm2")
|
||||
if !reflect.DeepEqual(m, expected) {
|
||||
err = compareMap(m, expected)
|
||||
t.Fatalf("actual doesn't match expected: %v", err)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ limitations under the License.
|
|||
|
||||
package transformers
|
||||
|
||||
import "k8s.io/kubectl/pkg/kinflate/types"
|
||||
import "k8s.io/kubectl/pkg/kinflate/resource"
|
||||
|
||||
// Transformer can transform objects.
|
||||
type Transformer interface {
|
||||
// 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"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
)
|
||||
|
||||
func makeConfigMap(name string) *unstructured.Unstructured {
|
||||
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 {
|
||||
func compareMap(m1, m2 resource.ResourceCollection) error {
|
||||
if len(m1) != len(m2) {
|
||||
keySet1 := []types.GroupVersionKindName{}
|
||||
keySet2 := []types.GroupVersionKindName{}
|
||||
|
|
@ -69,8 +41,8 @@ func compareMap(m1, m2 types.ResourceCollection) error {
|
|||
if !found {
|
||||
return fmt.Errorf("%#v doesn't exist in %#v", GVKn, m2)
|
||||
}
|
||||
if !reflect.DeepEqual(obj1, obj2) {
|
||||
return fmt.Errorf("%#v doesn't match %#v", obj1, obj2)
|
||||
if !reflect.DeepEqual(obj1.Data, obj2.Data) {
|
||||
return fmt.Errorf("%#v doesn't match %#v", obj1.Data, obj2.Data)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package types
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
|
|
@ -28,6 +27,3 @@ type GroupVersionKindName struct {
|
|||
// original name of the resource before transformation.
|
||||
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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
|
|
@ -59,15 +57,3 @@ func SelectByGVK(in schema.GroupVersionKind, selector *schema.GroupVersionKind)
|
|||
}
|
||||
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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"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/resource"
|
||||
"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 `---`.
|
||||
func Encode(in types.ResourceCollection) ([]byte, error) {
|
||||
func Encode(in resource.ResourceCollection) ([]byte, error) {
|
||||
gvknList := []types.GroupVersionKindName{}
|
||||
for gvkn := range in {
|
||||
gvknList = append(gvknList, gvkn)
|
||||
|
|
@ -104,7 +38,7 @@ func Encode(in types.ResourceCollection) ([]byte, error) {
|
|||
var b []byte
|
||||
buf := bytes.NewBuffer(b)
|
||||
for _, gvkn := range gvknList {
|
||||
obj := in[gvkn]
|
||||
obj := in[gvkn].Data
|
||||
out, err := yaml.Marshal(obj)
|
||||
if err != nil {
|
||||
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.
|
||||
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)
|
||||
if err != nil {
|
||||
return &Directory{}, err
|
||||
|
|
@ -137,7 +71,7 @@ func WriteToDir(in types.ResourceCollection, dirName string, printer Printer) (*
|
|||
return &Directory{}, err
|
||||
}
|
||||
defer f.Close()
|
||||
err = printer.Print(obj, f)
|
||||
err = printer.Print(obj.Data, f)
|
||||
if err != nil {
|
||||
return &Directory{}, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,10 +23,12 @@ import (
|
|||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/kubectl/pkg/kinflate/resource"
|
||||
"k8s.io/kubectl/pkg/kinflate/types"
|
||||
)
|
||||
|
||||
var encoded = []byte(`apiVersion: v1
|
||||
func TestEncode(t *testing.T) {
|
||||
encoded := []byte(`apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
|
|
@ -36,48 +38,37 @@ kind: ConfigMap
|
|||
metadata:
|
||||
name: cm2
|
||||
`)
|
||||
|
||||
func makeConfigMap(name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
input := 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": 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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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"))
|
||||
out, err := Encode(input)
|
||||
if err != nil {
|
||||
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) {
|
||||
keySet1 := []types.GroupVersionKindName{}
|
||||
keySet2 := []types.GroupVersionKindName{}
|
||||
|
|
|
|||
Loading…
Reference in New Issue