mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
Further isolate unstructured with factories.
This commit is contained in:
@@ -22,20 +22,20 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KustKunstructuredFactory hides construction using apimachinery types.
|
// KunstructurerFactoryImpl hides construction using apimachinery types.
|
||||||
type KustKunstructuredFactory struct {
|
type KunstructurerFactoryImpl struct {
|
||||||
decoder ifc.Decoder
|
decoder ifc.Decoder
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ ifc.KunstructuredFactory = &KustKunstructuredFactory{}
|
var _ ifc.KunstructuredFactory = &KunstructurerFactoryImpl{}
|
||||||
|
|
||||||
// NewKustKunstructuredFactory returns a factory.
|
// NewKustKunstructuredFactory returns a factory.
|
||||||
func NewKustKunstructuredFactory(d ifc.Decoder) ifc.KunstructuredFactory {
|
func NewKustKunstructuredFactory(d ifc.Decoder) ifc.KunstructuredFactory {
|
||||||
return &KustKunstructuredFactory{decoder: d}
|
return &KunstructurerFactoryImpl{decoder: d}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SliceFromBytes returns a slice of Kunstructured.
|
// SliceFromBytes returns a slice of Kunstructured.
|
||||||
func (kf *KustKunstructuredFactory) SliceFromBytes(
|
func (kf *KunstructurerFactoryImpl) SliceFromBytes(
|
||||||
in []byte) ([]ifc.Kunstructured, error) {
|
in []byte) ([]ifc.Kunstructured, error) {
|
||||||
kf.decoder.SetInput(in)
|
kf.decoder.SetInput(in)
|
||||||
var result []ifc.Kunstructured
|
var result []ifc.Kunstructured
|
||||||
@@ -54,7 +54,7 @@ func (kf *KustKunstructuredFactory) SliceFromBytes(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FromMap returns an instance of Kunstructured.
|
// FromMap returns an instance of Kunstructured.
|
||||||
func (kf *KustKunstructuredFactory) FromMap(
|
func (kf *KunstructurerFactoryImpl) FromMap(
|
||||||
m map[string]interface{}) ifc.Kunstructured {
|
m map[string]interface{}) ifc.Kunstructured {
|
||||||
return &UnstructAdapter{Unstructured: unstructured.Unstructured{Object: m}}
|
return &UnstructAdapter{Unstructured: unstructured.Unstructured{Object: m}}
|
||||||
}
|
}
|
||||||
|
|||||||
89
pkg/resmap/factory.go
Normal file
89
pkg/resmap/factory.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
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 resmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
|
internal "sigs.k8s.io/kustomize/pkg/internal/error"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Factory makes instances of ResMap.
|
||||||
|
type Factory struct {
|
||||||
|
resF *resource.Factory
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFactory returns a new resmap.Factory.
|
||||||
|
func NewFactory(rf *resource.Factory) *Factory {
|
||||||
|
return &Factory{resF: rf}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RF returns a resource.Factory.
|
||||||
|
func (rmF *Factory) RF() *resource.Factory {
|
||||||
|
return rmF.resF
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromFiles returns a ResMap given a resource path slice.
|
||||||
|
func (rmF *Factory) FromFiles(
|
||||||
|
loader ifc.Loader, paths []string) (ResMap, error) {
|
||||||
|
var result []ResMap
|
||||||
|
for _, path := range paths {
|
||||||
|
content, err := loader.Load(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Load from path "+path+" failed")
|
||||||
|
}
|
||||||
|
res, err := rmF.newResMapFromBytes(content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, internal.Handler(err, path)
|
||||||
|
}
|
||||||
|
result = append(result, res)
|
||||||
|
}
|
||||||
|
return MergeWithoutOverride(result...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newResMapFromBytes decodes a list of objects in byte array format.
|
||||||
|
func (rmF *Factory) newResMapFromBytes(b []byte) (ResMap, error) {
|
||||||
|
resources, err := rmF.resF.SliceFromBytes(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := ResMap{}
|
||||||
|
for _, res := range resources {
|
||||||
|
id := res.Id()
|
||||||
|
if _, found := result[id]; found {
|
||||||
|
return result, fmt.Errorf("GroupVersionKindName: %#v already exists b the map", id)
|
||||||
|
}
|
||||||
|
result[id] = res
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newResMapFromResourceSlice(resources []*resource.Resource) (ResMap, error) {
|
||||||
|
result := ResMap{}
|
||||||
|
for _, res := range resources {
|
||||||
|
id := res.Id()
|
||||||
|
if _, found := result[id]; found {
|
||||||
|
return nil, fmt.Errorf("duplicated %#v is not allowed", id)
|
||||||
|
}
|
||||||
|
result[id] = res
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
115
pkg/resmap/factory_test.go
Normal file
115
pkg/resmap/factory_test.go
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
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 resmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFromFiles(t *testing.T) {
|
||||||
|
|
||||||
|
resourceStr := `apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dply1
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: dply2
|
||||||
|
---
|
||||||
|
# some comment
|
||||||
|
---
|
||||||
|
---
|
||||||
|
`
|
||||||
|
|
||||||
|
l := loadertest.NewFakeLoader("/home/seans/project")
|
||||||
|
if ferr := l.AddFile("/home/seans/project/deployment.yaml", []byte(resourceStr)); ferr != nil {
|
||||||
|
t.Fatalf("Error adding fake file: %v\n", ferr)
|
||||||
|
}
|
||||||
|
expected := ResMap{resid.NewResId(deploy, "dply1"): rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "dply1",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
resid.NewResId(deploy, "dply2"): rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "apps/v1",
|
||||||
|
"kind": "Deployment",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "dply2",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
m, _ := rmF.FromFiles(
|
||||||
|
l, []string{"/home/seans/project/deployment.yaml"})
|
||||||
|
if len(m) != 2 {
|
||||||
|
t.Fatalf("%#v should contain 2 appResource, but got %d", m, len(m))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := expected.ErrorIfNotEqual(m); err != nil {
|
||||||
|
t.Fatalf("actual doesn't match expected: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromBytes(t *testing.T) {
|
||||||
|
encoded := []byte(`apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: cm2
|
||||||
|
`)
|
||||||
|
expected := ResMap{
|
||||||
|
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm1",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
resid.NewResId(cmap, "cm2"): rf.FromMap(
|
||||||
|
map[string]interface{}{
|
||||||
|
"apiVersion": "v1",
|
||||||
|
"kind": "ConfigMap",
|
||||||
|
"metadata": map[string]interface{}{
|
||||||
|
"name": "cm2",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
m, err := rmF.newResMapFromBytes(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,9 +25,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
internal "sigs.k8s.io/kustomize/pkg/internal/error"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
)
|
)
|
||||||
@@ -135,69 +133,6 @@ func (m ResMap) FilterBy(inputId resid.ResId) ResMap {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Factory makes instances of ResMap.
|
|
||||||
type Factory struct {
|
|
||||||
resF *resource.Factory
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFactory returns a new resmap.Factory.
|
|
||||||
func NewFactory(rf *resource.Factory) *Factory {
|
|
||||||
return &Factory{resF: rf}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RF returns a resource.Factory.
|
|
||||||
func (rmF *Factory) RF() *resource.Factory {
|
|
||||||
return rmF.resF
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromFiles returns a ResMap given a resource path slice.
|
|
||||||
func (rmF *Factory) FromFiles(
|
|
||||||
loader ifc.Loader, paths []string) (ResMap, error) {
|
|
||||||
var result []ResMap
|
|
||||||
for _, path := range paths {
|
|
||||||
content, err := loader.Load(path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "Load from path "+path+" failed")
|
|
||||||
}
|
|
||||||
res, err := rmF.newResMapFromBytes(content)
|
|
||||||
if err != nil {
|
|
||||||
return nil, internal.Handler(err, path)
|
|
||||||
}
|
|
||||||
result = append(result, res)
|
|
||||||
}
|
|
||||||
return MergeWithoutOverride(result...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newResMapFromBytes decodes a list of objects in byte array format.
|
|
||||||
func (rmF *Factory) newResMapFromBytes(b []byte) (ResMap, error) {
|
|
||||||
resources, err := rmF.resF.SliceFromBytes(b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result := ResMap{}
|
|
||||||
for _, res := range resources {
|
|
||||||
id := res.Id()
|
|
||||||
if _, found := result[id]; found {
|
|
||||||
return result, fmt.Errorf("GroupVersionKindName: %#v already exists b the map", id)
|
|
||||||
}
|
|
||||||
result[id] = res
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newResMapFromResourceSlice(resources []*resource.Resource) (ResMap, error) {
|
|
||||||
result := ResMap{}
|
|
||||||
for _, res := range resources {
|
|
||||||
id := res.Id()
|
|
||||||
if _, found := result[id]; found {
|
|
||||||
return nil, fmt.Errorf("duplicated %#v is not allowed", id)
|
|
||||||
}
|
|
||||||
result[id] = res
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeWithoutOverride combines multiple ResMap instances, failing on key collision
|
// MergeWithoutOverride combines multiple ResMap instances, failing on key collision
|
||||||
// and skipping nil maps. In case if all of the maps are nil, an empty ResMap is returned.
|
// and skipping nil maps. In case if all of the maps are nil, an empty ResMap is returned.
|
||||||
func MergeWithoutOverride(maps ...ResMap) (ResMap, error) {
|
func MergeWithoutOverride(maps ...ResMap) (ResMap, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ limitations under the License.
|
|||||||
package resmap
|
package resmap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/internal/k8sdeps"
|
"sigs.k8s.io/kustomize/internal/k8sdeps"
|
||||||
"sigs.k8s.io/kustomize/pkg/gvk"
|
"sigs.k8s.io/kustomize/pkg/gvk"
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
"sigs.k8s.io/kustomize/pkg/resource"
|
"sigs.k8s.io/kustomize/pkg/resource"
|
||||||
)
|
)
|
||||||
@@ -273,95 +271,6 @@ func TestErrorIfNotEqual(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewMapFromFiles(t *testing.T) {
|
|
||||||
|
|
||||||
resourceStr := `apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: dply1
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: dply2
|
|
||||||
---
|
|
||||||
# some comment
|
|
||||||
---
|
|
||||||
---
|
|
||||||
`
|
|
||||||
|
|
||||||
l := loadertest.NewFakeLoader("/home/seans/project")
|
|
||||||
if ferr := l.AddFile("/home/seans/project/deployment.yaml", []byte(resourceStr)); ferr != nil {
|
|
||||||
t.Fatalf("Error adding fake file: %v\n", ferr)
|
|
||||||
}
|
|
||||||
expected := ResMap{resid.NewResId(deploy, "dply1"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "dply1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResId(deploy, "dply2"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "dply2",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
m, _ := rmF.FromFiles(
|
|
||||||
l, []string{"/home/seans/project/deployment.yaml"})
|
|
||||||
if len(m) != 2 {
|
|
||||||
t.Fatalf("%#v should contain 2 appResource, but got %d", m, len(m))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := expected.ErrorIfNotEqual(m); err != nil {
|
|
||||||
t.Fatalf("actual doesn't match expected: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewMapFromBytes(t *testing.T) {
|
|
||||||
encoded := []byte(`apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: cm1
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: cm2
|
|
||||||
`)
|
|
||||||
expected := ResMap{
|
|
||||||
resid.NewResId(cmap, "cm1"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "cm1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resid.NewResId(cmap, "cm2"): rf.FromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "ConfigMap",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "cm2",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
m, err := rmF.newResMapFromBytes(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 TestMergeWithoutOverride(t *testing.T) {
|
func TestMergeWithoutOverride(t *testing.T) {
|
||||||
input1 := ResMap{
|
input1 := ResMap{
|
||||||
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
resid.NewResId(deploy, "deploy1"): rf.FromMap(
|
||||||
|
|||||||
95
pkg/resource/factory.go
Normal file
95
pkg/resource/factory.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"sigs.k8s.io/kustomize/internal/k8sdeps"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
|
internal "sigs.k8s.io/kustomize/pkg/internal/error"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/patch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Factory makes instances of Resource.
|
||||||
|
type Factory struct {
|
||||||
|
kf ifc.KunstructuredFactory
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFactory makes an instance of Factory.
|
||||||
|
func NewFactory(kf ifc.KunstructuredFactory) *Factory {
|
||||||
|
return &Factory{kf: kf}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBehavior returns a new instance of Resource.
|
||||||
|
// TODO(monopole): This runtime dependence must be refactored away.
|
||||||
|
// The logic calling this has to move to k8sdeps.
|
||||||
|
func (rf *Factory) WithBehavior(
|
||||||
|
obj runtime.Object, b ifc.GenerationBehavior) (*Resource, error) {
|
||||||
|
// TODO(monopole): This k8sdeps dependence must be refactored away.
|
||||||
|
u, err := k8sdeps.NewKunstructuredFromObject(obj)
|
||||||
|
return &Resource{Kunstructured: u, b: b}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromMap returns a new instance of Resource.
|
||||||
|
func (rf *Factory) FromMap(m map[string]interface{}) *Resource {
|
||||||
|
return &Resource{
|
||||||
|
Kunstructured: rf.kf.FromMap(m),
|
||||||
|
b: ifc.BehaviorUnspecified}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromKunstructured returns a new instance of Resource.
|
||||||
|
func (rf *Factory) FromKunstructured(
|
||||||
|
u ifc.Kunstructured) *Resource {
|
||||||
|
if u == nil {
|
||||||
|
log.Fatal("unstruct ifc must not be null")
|
||||||
|
}
|
||||||
|
return &Resource{Kunstructured: u, b: ifc.BehaviorUnspecified}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SliceFromPatches returns a slice of resources given a patch path
|
||||||
|
// slice from a kustomization file.
|
||||||
|
func (rf *Factory) SliceFromPatches(
|
||||||
|
ldr ifc.Loader, paths []patch.StrategicMerge) ([]*Resource, error) {
|
||||||
|
var result []*Resource
|
||||||
|
for _, path := range paths {
|
||||||
|
content, err := ldr.Load(string(path))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res, err := rf.SliceFromBytes(content)
|
||||||
|
if err != nil {
|
||||||
|
return nil, internal.Handler(err, string(path))
|
||||||
|
}
|
||||||
|
result = append(result, res...)
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SliceFromBytes unmarshalls bytes into a Resource slice.
|
||||||
|
func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) {
|
||||||
|
kunStructs, err := rf.kf.SliceFromBytes(in)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var result []*Resource
|
||||||
|
for _, u := range kunStructs {
|
||||||
|
result = append(result, rf.FromKunstructured(u))
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
100
pkg/resource/factory_test.go
Normal file
100
pkg/resource/factory_test.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
||||||
|
"sigs.k8s.io/kustomize/pkg/patch"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSliceFromPatches(t *testing.T) {
|
||||||
|
|
||||||
|
patchGood1 := patch.StrategicMerge("/foo/patch1.yaml")
|
||||||
|
patch1 := `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: pooh
|
||||||
|
`
|
||||||
|
patchGood2 := patch.StrategicMerge("/foo/patch2.yaml")
|
||||||
|
patch2 := `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: winnie
|
||||||
|
---
|
||||||
|
# some comment
|
||||||
|
---
|
||||||
|
---
|
||||||
|
`
|
||||||
|
patchBad := patch.StrategicMerge("/foo/patch3.yaml")
|
||||||
|
patch3 := `
|
||||||
|
WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOT: woot
|
||||||
|
`
|
||||||
|
l := loadertest.NewFakeLoader("/foo")
|
||||||
|
l.AddFile(string(patchGood1), []byte(patch1))
|
||||||
|
l.AddFile(string(patchGood2), []byte(patch2))
|
||||||
|
l.AddFile(string(patchBad), []byte(patch3))
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []patch.StrategicMerge
|
||||||
|
expectedOut []*Resource
|
||||||
|
expectedErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "happy",
|
||||||
|
input: []patch.StrategicMerge{patchGood1, patchGood2},
|
||||||
|
expectedOut: []*Resource{testDeployment, testConfigMap},
|
||||||
|
expectedErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "badFileName",
|
||||||
|
input: []patch.StrategicMerge{patchGood1, "doesNotExist"},
|
||||||
|
expectedOut: []*Resource{},
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "badData",
|
||||||
|
input: []patch.StrategicMerge{patchGood1, patchBad},
|
||||||
|
expectedOut: []*Resource{},
|
||||||
|
expectedErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
rs, err := factory.SliceFromPatches(l, test.input)
|
||||||
|
if test.expectedErr && err == nil {
|
||||||
|
t.Fatalf("%v: should return error", test.name)
|
||||||
|
}
|
||||||
|
if !test.expectedErr && err != nil {
|
||||||
|
t.Fatalf("%v: unexpected error: %s", test.name, err)
|
||||||
|
}
|
||||||
|
if len(rs) != len(test.expectedOut) {
|
||||||
|
t.Fatalf("%s: length mismatch %d != %d",
|
||||||
|
test.name, len(rs), len(test.expectedOut))
|
||||||
|
}
|
||||||
|
for i := range rs {
|
||||||
|
if !reflect.DeepEqual(test.expectedOut[i], rs[i]) {
|
||||||
|
t.Fatalf("%s: Got: %v\nexpected:%v",
|
||||||
|
test.name, test.expectedOut[i], rs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,85 +18,12 @@ limitations under the License.
|
|||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"sigs.k8s.io/kustomize/internal/k8sdeps"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/ifc"
|
"sigs.k8s.io/kustomize/pkg/ifc"
|
||||||
internal "sigs.k8s.io/kustomize/pkg/internal/error"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/patch"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/resid"
|
"sigs.k8s.io/kustomize/pkg/resid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Factory makes instances of Resource.
|
|
||||||
type Factory struct {
|
|
||||||
kf ifc.KunstructuredFactory
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFactory makes an instance of Factory.
|
|
||||||
func NewFactory(kf ifc.KunstructuredFactory) *Factory {
|
|
||||||
return &Factory{kf: kf}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithBehavior returns a new instance of Resource.
|
|
||||||
// TODO(monopole): This runtime dependence must be refactored away.
|
|
||||||
// The logic calling this has to move to k8sdeps.
|
|
||||||
func (rf *Factory) WithBehavior(
|
|
||||||
obj runtime.Object, b ifc.GenerationBehavior) (*Resource, error) {
|
|
||||||
// TODO(monopole): This k8sdeps dependence must be refactored away.
|
|
||||||
u, err := k8sdeps.NewKunstructuredFromObject(obj)
|
|
||||||
return &Resource{Kunstructured: u, b: b}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromMap returns a new instance of Resource.
|
|
||||||
func (rf *Factory) FromMap(m map[string]interface{}) *Resource {
|
|
||||||
return &Resource{
|
|
||||||
Kunstructured: rf.kf.FromMap(m),
|
|
||||||
b: ifc.BehaviorUnspecified}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromKunstructured returns a new instance of Resource.
|
|
||||||
func (rf *Factory) FromKunstructured(
|
|
||||||
u ifc.Kunstructured) *Resource {
|
|
||||||
if u == nil {
|
|
||||||
log.Fatal("unstruct ifc must not be null")
|
|
||||||
}
|
|
||||||
return &Resource{Kunstructured: u, b: ifc.BehaviorUnspecified}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SliceFromPatches returns a slice of resources given a patch path
|
|
||||||
// slice from a kustomization file.
|
|
||||||
func (rf *Factory) SliceFromPatches(
|
|
||||||
ldr ifc.Loader, paths []patch.StrategicMerge) ([]*Resource, error) {
|
|
||||||
var result []*Resource
|
|
||||||
for _, path := range paths {
|
|
||||||
content, err := ldr.Load(string(path))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res, err := rf.SliceFromBytes(content)
|
|
||||||
if err != nil {
|
|
||||||
return nil, internal.Handler(err, string(path))
|
|
||||||
}
|
|
||||||
result = append(result, res...)
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SliceFromBytes unmarshalls bytes into a Resource slice.
|
|
||||||
func (rf *Factory) SliceFromBytes(in []byte) ([]*Resource, error) {
|
|
||||||
kunStructs, err := rf.kf.SliceFromBytes(in)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var result []*Resource
|
|
||||||
for _, u := range kunStructs {
|
|
||||||
result = append(result, rf.FromKunstructured(u))
|
|
||||||
}
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resource is map representation of a Kubernetes API resource object
|
// Resource is map representation of a Kubernetes API resource object
|
||||||
// paired with a GenerationBehavior.
|
// paired with a GenerationBehavior.
|
||||||
type Resource struct {
|
type Resource struct {
|
||||||
|
|||||||
@@ -17,12 +17,9 @@ limitations under the License.
|
|||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/internal/k8sdeps"
|
"sigs.k8s.io/kustomize/internal/k8sdeps"
|
||||||
"sigs.k8s.io/kustomize/pkg/internal/loadertest"
|
|
||||||
"sigs.k8s.io/kustomize/pkg/patch"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var factory = NewFactory(
|
var factory = NewFactory(
|
||||||
@@ -70,78 +67,3 @@ func TestResourceString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSliceFromPatches(t *testing.T) {
|
|
||||||
|
|
||||||
patchGood1 := patch.StrategicMerge("/foo/patch1.yaml")
|
|
||||||
patch1 := `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: pooh
|
|
||||||
`
|
|
||||||
patchGood2 := patch.StrategicMerge("/foo/patch2.yaml")
|
|
||||||
patch2 := `
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: winnie
|
|
||||||
---
|
|
||||||
# some comment
|
|
||||||
---
|
|
||||||
---
|
|
||||||
`
|
|
||||||
patchBad := patch.StrategicMerge("/foo/patch3.yaml")
|
|
||||||
patch3 := `
|
|
||||||
WOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOT: woot
|
|
||||||
`
|
|
||||||
l := loadertest.NewFakeLoader("/foo")
|
|
||||||
l.AddFile(string(patchGood1), []byte(patch1))
|
|
||||||
l.AddFile(string(patchGood2), []byte(patch2))
|
|
||||||
l.AddFile(string(patchBad), []byte(patch3))
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input []patch.StrategicMerge
|
|
||||||
expectedOut []*Resource
|
|
||||||
expectedErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "happy",
|
|
||||||
input: []patch.StrategicMerge{patchGood1, patchGood2},
|
|
||||||
expectedOut: []*Resource{testDeployment, testConfigMap},
|
|
||||||
expectedErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "badFileName",
|
|
||||||
input: []patch.StrategicMerge{patchGood1, "doesNotExist"},
|
|
||||||
expectedOut: []*Resource{},
|
|
||||||
expectedErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "badData",
|
|
||||||
input: []patch.StrategicMerge{patchGood1, patchBad},
|
|
||||||
expectedOut: []*Resource{},
|
|
||||||
expectedErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
rs, err := factory.SliceFromPatches(l, test.input)
|
|
||||||
if test.expectedErr && err == nil {
|
|
||||||
t.Fatalf("%v: should return error", test.name)
|
|
||||||
}
|
|
||||||
if !test.expectedErr && err != nil {
|
|
||||||
t.Fatalf("%v: unexpected error: %s", test.name, err)
|
|
||||||
}
|
|
||||||
if len(rs) != len(test.expectedOut) {
|
|
||||||
t.Fatalf("%s: length mismatch %d != %d",
|
|
||||||
test.name, len(rs), len(test.expectedOut))
|
|
||||||
}
|
|
||||||
for i := range rs {
|
|
||||||
if !reflect.DeepEqual(test.expectedOut[i], rs[i]) {
|
|
||||||
t.Fatalf("%s: Got: %v\nexpected:%v",
|
|
||||||
test.name, test.expectedOut[i], rs[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user