Checkpoint

This commit is contained in:
jregan
2020-07-16 17:14:24 -07:00
parent ef54f9be5a
commit e91cdb5eba
15 changed files with 851 additions and 12 deletions

View File

@@ -0,0 +1,25 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package merge
import (
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
)
// Merginator implements resmap.Merginator using kyaml libs.
type Merginator struct {
}
var _ resmap.Merginator = (*Merginator)(nil)
func NewMerginator(_ *resource.Factory) *Merginator {
return &Merginator{}
}
// Merge implements resmap.Merginator
func (m Merginator) Merge(
resources []*resource.Resource) (resmap.ResMap, error) {
panic("TODO(#Merginator): implement Merge")
}

View File

@@ -0,0 +1,4 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package merge_test

View File

@@ -0,0 +1,64 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package validate
import (
"sigs.k8s.io/kustomize/api/ifc"
)
// FieldValidator implements ifc.Validator to check
// the values of various KRM string fields,
// e.g. labels, annotations, names, namespaces.
type FieldValidator struct {
}
var _ ifc.Validator = (*FieldValidator)(nil)
func NewFieldValidator() *FieldValidator {
return &FieldValidator{}
}
// TODO(#FieldValidator): implement MakeAnnotationValidator
func (f FieldValidator) MakeAnnotationValidator() func(map[string]string) error {
return func(x map[string]string) error {
return nil
}
}
// TODO(#FieldValidator): implement MakeAnnotationNameValidator
func (f FieldValidator) MakeAnnotationNameValidator() func([]string) error {
return func(x []string) error {
return nil
}
}
// TODO(#FieldValidator): implement MakeLabelValidator
func (f FieldValidator) MakeLabelValidator() func(map[string]string) error {
return func(x map[string]string) error {
return nil
}
}
// TODO(#FieldValidator): implement MakeLabelNameValidator
func (f FieldValidator) MakeLabelNameValidator() func([]string) error {
return func(x []string) error {
return nil
}
}
// TODO(#FieldValidator): implement ValidateNamespace
func (f FieldValidator) ValidateNamespace(s string) []string {
var errs []string
return errs
}
// TODO(#FieldValidator): implement ErrIfInvalidKey
func (f FieldValidator) ErrIfInvalidKey(s string) error {
return nil
}
// TODO(#FieldValidator): implement IsEnvVarName
func (f FieldValidator) IsEnvVarName(k string) error {
return nil
}

View File

@@ -0,0 +1,4 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package validate_test

View File

@@ -0,0 +1,41 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy
import (
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/types"
)
// WNodeFactory makes instances of WNode.
// These instances in turn adapt
// sigs.k8s.io/kustomize/kyaml/yaml.RNode
// to implement ifc.Unstructured.
// This factory is meant to implement ifc.KunstructuredFactory.
type WNodeFactory struct {
}
var _ ifc.KunstructuredFactory = (*WNodeFactory)(nil)
func (k *WNodeFactory) SliceFromBytes(bs []byte) ([]ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement SliceFromBytes")
}
func (k *WNodeFactory) FromMap(m map[string]interface{}) ifc.Kunstructured {
panic("TODO(#WNodeFactory): implement FromMap")
}
func (k *WNodeFactory) Hasher() ifc.KunstructuredHasher {
panic("TODO(#WNodeFactory): implement Hasher")
}
func (k *WNodeFactory) MakeConfigMap(
kvLdr ifc.KvLoader, args *types.ConfigMapArgs) (ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement MakeConfigMap")
}
func (k *WNodeFactory) MakeSecret(
kvLdr ifc.KvLoader, args *types.SecretArgs) (ifc.Kunstructured, error) {
panic("TODO(#WNodeFactory): implement MakeSecret")
}

View File

@@ -0,0 +1,4 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy_test

View File

@@ -0,0 +1,143 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy
import (
"log"
"sigs.k8s.io/kustomize/api/ifc"
"sigs.k8s.io/kustomize/api/resid"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
// WNode implements ifc.Kunstructured using yaml.RNode.
//
// It exists only to help manage a switch from
// kunstruct.UnstructAdapter to yaml.RNode as the core
// representation of KRM objects in kustomize.
//
// It's got a silly name because we don't want it around for long,
// and want its use to be obvious.
type WNode struct {
node *yaml.RNode
}
var _ ifc.Kunstructured = (*WNode)(nil)
func NewWNode() *WNode {
return FromRNode(yaml.NewRNode(nil))
}
func FromRNode(node *yaml.RNode) *WNode {
return &WNode{node: node}
}
func (wn *WNode) demandMetaData(label string) yaml.ResourceMeta {
meta, err := wn.node.GetMeta()
if err != nil {
// Log and die since interface doesn't allow error.
log.Fatalf("for %s', expected valid resource: %v", label, err)
}
return meta
}
// Copy implements ifc.Kunstructured.
func (wn *WNode) Copy() ifc.Kunstructured {
return &WNode{node: wn.node.Copy()}
}
// GetAnnotations implements ifc.Kunstructured.
func (wn *WNode) GetAnnotations() map[string]string {
return wn.demandMetaData("GetAnnotations").Annotations
}
// GetFieldValue implements ifc.Kunstructured.
func (wn *WNode) GetFieldValue(path string) (interface{}, error) {
// The argument is a json path, e.g. "metadata.name"
// fields := strings.Split(path, ".")
// return wn.node.Pipe(yaml.Lookup(fields...))
panic("TODO(#WNode): GetFieldValue; implement or drop from API")
}
// GetGvk implements ifc.Kunstructured.
func (wn *WNode) GetGvk() resid.Gvk {
meta := wn.demandMetaData("GetGvk")
g, v := resid.ParseGroupVersion(meta.APIVersion)
return resid.Gvk{Group: g, Version: v, Kind: meta.Kind}
}
// GetKind implements ifc.Kunstructured.
func (wn *WNode) GetKind() string {
return wn.demandMetaData("GetKind").Kind
}
// GetLabels implements ifc.Kunstructured.
func (wn *WNode) GetLabels() map[string]string {
return wn.demandMetaData("GetLabels").Labels
}
// GetName implements ifc.Kunstructured.
func (wn *WNode) GetName() string {
return wn.demandMetaData("GetName").Name
}
// GetSlice implements ifc.Kunstructured.
func (wn *WNode) GetSlice(string) ([]interface{}, error) {
panic("TODO(#WNode) GetSlice; implement or drop from API")
}
// GetSlice implements ifc.Kunstructured.
func (wn *WNode) GetString(string) (string, error) {
panic("TODO(#WNode) GetString; implement or drop from API")
}
// Map implements ifc.Kunstructured.
func (wn *WNode) Map() map[string]interface{} {
panic("TODO(#WNode) Map; implement or drop from API")
}
// MarshalJSON implements ifc.Kunstructured.
func (wn *WNode) MarshalJSON() ([]byte, error) {
return wn.node.MarshalJSON()
}
// MatchesAnnotationSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesAnnotationSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesAnnotationSelector; implement or drop from API")
}
// MatchesLabelSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesLabelSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesLabelSelector; implement or drop from API")
}
// SetAnnotations implements ifc.Kunstructured.
func (wn *WNode) SetAnnotations(map[string]string) {
panic("TODO(#WNode) SetAnnotations; implement or drop from API")
}
// SetGvk implements ifc.Kunstructured.
func (wn *WNode) SetGvk(resid.Gvk) {
panic("TODO(#WNode) SetGvk; implement or drop from API")
}
// SetLabels implements ifc.Kunstructured.
func (wn *WNode) SetLabels(map[string]string) {
panic("TODO(#WNode) SetLabels; implement or drop from API")
}
// SetName implements ifc.Kunstructured.
func (wn *WNode) SetName(string) {
panic("TODO(#WNode) SetName; implement or drop from API")
}
// SetNamespace implements ifc.Kunstructured.
func (wn *WNode) SetNamespace(string) {
panic("TODO(#WNode) SetNamespace; implement or drop from API")
}
// UnmarshalJSON implements ifc.Kunstructured.
func (wn *WNode) UnmarshalJSON(data []byte) error {
return wn.node.UnmarshalJSON(data)
}

View File

@@ -0,0 +1,339 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package wrappy_test
import (
"strings"
"testing"
"gopkg.in/yaml.v3"
. "sigs.k8s.io/kustomize/api/internal/wrappy"
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
)
const (
deploymentLittleJson = `{"apiVersion":"apps/v1","kind":"Deployment",` +
`"metadata":{"name":"homer","namespace":"simpsons"}}`
deploymentBiggerJson = `
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "homer",
"namespace": "simpsons",
"labels": {
"fruit": "apple",
"veggie": "carrot"
},
"annotations": {
"area": "51",
"greeting": "Take me to your leader."
}
}
}
`
bigMapYaml = `Kind: Service
complextree:
- field1:
- boolfield: true
floatsubfield: 1.01
intsubfield: 1010
stringsubfield: idx1010
- boolfield: false
floatsubfield: 1.011
intsubfield: 1011
stringsubfield: idx1011
field2:
- boolfield: true
floatsubfield: 1.02
intsubfield: 1020
stringsubfield: idx1020
- boolfield: false
floatsubfield: 1.021
intsubfield: 1021
stringsubfield: idx1021
- field1:
- boolfield: true
floatsubfield: 1.11
intsubfield: 1110
stringsubfield: idx1110
- boolfield: false
floatsubfield: 1.111
intsubfield: 1111
stringsubfield: idx1111
field2:
- boolfield: true
floatsubfield: 1.112
intsubfield: 1120
stringsubfield: idx1120
- boolfield: false
floatsubfield: 1.1121
intsubfield: 1121
stringsubfield: idx1121
metadata:
labels:
app: application-name
name: service-name
spec:
ports:
port: 80
that:
- idx0
- idx1
- idx2
- idx3
these:
- field1:
- idx010
- idx011
field2:
- idx020
- idx021
- field1:
- idx110
- idx111
field2:
- idx120
- idx121
- field1:
- idx210
- idx211
field2:
- idx220
- idx221
this:
is:
aBool: true
aFloat: 1.001
aNilValue: null
aNumber: 1000
anEmptyMap: {}
anEmptySlice: []
those:
- field1: idx0foo
field2: idx0bar
- field1: idx1foo
field2: idx1bar
- field1: idx2foo
field2: idx2bar
`
)
func makeBigMap() map[string]interface{} {
return map[string]interface{}{
"Kind": "Service",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"app": "application-name",
},
"name": "service-name",
},
"spec": map[string]interface{}{
"ports": map[string]interface{}{
"port": int64(80),
},
},
"this": map[string]interface{}{
"is": map[string]interface{}{
"aNumber": int64(1000),
"aFloat": float64(1.001),
"aNilValue": nil,
"aBool": true,
"anEmptyMap": map[string]interface{}{},
"anEmptySlice": []interface{}{},
/*
TODO: test for unrecognizable (e.g. a function)
"unrecognizable": testing.InternalExample{
Name: "fooBar",
},
*/
},
},
"that": []interface{}{
"idx0",
"idx1",
"idx2",
"idx3",
},
"those": []interface{}{
map[string]interface{}{
"field1": "idx0foo",
"field2": "idx0bar",
},
map[string]interface{}{
"field1": "idx1foo",
"field2": "idx1bar",
},
map[string]interface{}{
"field1": "idx2foo",
"field2": "idx2bar",
},
},
"these": []interface{}{
map[string]interface{}{
"field1": []interface{}{"idx010", "idx011"},
"field2": []interface{}{"idx020", "idx021"},
},
map[string]interface{}{
"field1": []interface{}{"idx110", "idx111"},
"field2": []interface{}{"idx120", "idx121"},
},
map[string]interface{}{
"field1": []interface{}{"idx210", "idx211"},
"field2": []interface{}{"idx220", "idx221"},
},
},
"complextree": []interface{}{
map[string]interface{}{
"field1": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1010",
"intsubfield": int64(1010),
"floatsubfield": float64(1.010),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1011",
"intsubfield": int64(1011),
"floatsubfield": float64(1.011),
"boolfield": false,
},
},
"field2": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1020",
"intsubfield": int64(1020),
"floatsubfield": float64(1.020),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1021",
"intsubfield": int64(1021),
"floatsubfield": float64(1.021),
"boolfield": false,
},
},
},
map[string]interface{}{
"field1": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1110",
"intsubfield": int64(1110),
"floatsubfield": float64(1.110),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1111",
"intsubfield": int64(1111),
"floatsubfield": float64(1.111),
"boolfield": false,
},
},
"field2": []interface{}{
map[string]interface{}{
"stringsubfield": "idx1120",
"intsubfield": int64(1120),
"floatsubfield": float64(1.1120),
"boolfield": true,
},
map[string]interface{}{
"stringsubfield": "idx1121",
"intsubfield": int64(1121),
"floatsubfield": float64(1.1121),
"boolfield": false,
},
},
},
},
}
}
func TestBasicYamlOperationFromMap(t *testing.T) {
bytes, err := yaml.Marshal(makeBigMap())
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
if string(bytes) != bigMapYaml {
t.Fatalf("unexpected string equality")
}
rNode, err := kyaml.Parse(string(bytes))
if err != nil {
t.Fatalf("unexpected yaml.Marshal err: %v", err)
}
rNodeString := rNode.MustString()
// The result from MustString has more indentation
// than bigMapYaml.
rNodeStrings := strings.Split(rNodeString, "\n")
bigMapStrings := strings.Split(bigMapYaml, "\n")
if len(rNodeStrings) != len(bigMapStrings) {
t.Fatalf("line count mismatch")
}
for i := range rNodeStrings {
s1 := strings.TrimSpace(rNodeStrings[i])
s2 := strings.TrimSpace(bigMapStrings[i])
if s1 != s2 {
t.Fatalf("expected '%s'=='%s'", s1, s2)
}
}
}
func TestRoundTripJSON(t *testing.T) {
wn := NewWNode()
err := wn.UnmarshalJSON([]byte(deploymentLittleJson))
if err != nil {
t.Fatalf("unexpected UnmarshalJSON err: %v", err)
}
data, err := wn.MarshalJSON()
if err != nil {
t.Fatalf("unexpected MarshalJSON err: %v", err)
}
actual := string(data)
if actual != deploymentLittleJson {
t.Fatalf("expected %s, got %s", deploymentLittleJson, actual)
}
}
func TestGettingFields(t *testing.T) {
wn := NewWNode()
err := wn.UnmarshalJSON([]byte(deploymentBiggerJson))
if err != nil {
t.Fatalf("unexpected unmarshaljson err: %v", err)
}
gvk := wn.GetGvk()
expected := "apps"
actual := gvk.Group
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
expected = "v1"
actual = gvk.Version
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
expected = "Deployment"
actual = gvk.Kind
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
actual = wn.GetKind()
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
expected = "homer"
actual = wn.GetName()
if expected != actual {
t.Fatalf("expected '%s', got '%s'", expected, actual)
}
actualMap := wn.GetLabels()
v, ok := actualMap["fruit"]
if !ok || v != "apple" {
t.Fatalf("unexpected labels '%v'", actualMap)
}
actualMap = wn.GetAnnotations()
v, ok = actualMap["greeting"]
if !ok || v != "Take me to your leader." {
t.Fatalf("unexpected annotations '%v'", actualMap)
}
}