WIP residPackage

This commit is contained in:
Jeffrey Regan
2018-10-04 20:24:22 -07:00
parent 239db504ff
commit c9887e8c15
40 changed files with 242 additions and 215 deletions

View File

@@ -1,59 +0,0 @@
/*
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
// GenerationBehavior specifies generation behavior of configmaps, secrets and maybe other resources.
type GenerationBehavior int
const (
// BehaviorUnspecified is an Unspecified behavior; typically treated as a Create.
BehaviorUnspecified GenerationBehavior = iota
// BehaviorCreate makes a new resource.
BehaviorCreate
// BehaviorReplace replaces a resource.
BehaviorReplace
// BehaviorMerge attempts to merge a new resource with an existing resource.
BehaviorMerge
)
// String converts a GenerationBehavior to a string.
func (b GenerationBehavior) String() string {
switch b {
case BehaviorReplace:
return "replace"
case BehaviorMerge:
return "merge"
case BehaviorCreate:
return "create"
default:
return "unspecified"
}
}
// NewGenerationBehavior converts a string to a GenerationBehavior.
func NewGenerationBehavior(s string) GenerationBehavior {
switch s {
case "replace":
return BehaviorReplace
case "merge":
return BehaviorMerge
case "create":
return BehaviorCreate
default:
return BehaviorUnspecified
}
}

View File

@@ -1,148 +0,0 @@
/*
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 (
"strings"
"sigs.k8s.io/kustomize/pkg/gvk"
)
// ResId conflates GroupVersionKind with a textual name to uniquely identify a kubernetes resource (object).
type ResId struct {
// Gvk of the resource.
gvKind gvk.Gvk
// original name of the resource before transformation.
name string
// namePrefix of the resource
// an untransformed resource has no prefix, fully transformed resource has an arbitrary number of prefixes
// concatenated together.
prefix string
// namespace the resource belongs to
// an untransformed resource has no namespace, fully transformed resource has the namespace from
// the top most overlay
namespace string
}
// NewResIdWithPrefixNamespace creates new resource identifier with a prefix and a namespace
func NewResIdWithPrefixNamespace(k gvk.Gvk, n, p, ns string) ResId {
return ResId{gvKind: k, name: n, prefix: p, namespace: ns}
}
// NewResIdWithPrefix creates new resource identifier with a prefix
func NewResIdWithPrefix(k gvk.Gvk, n, p string) ResId {
return ResId{gvKind: k, name: n, prefix: p}
}
// NewResId creates new resource identifier
func NewResId(k gvk.Gvk, n string) ResId {
return ResId{gvKind: k, name: n}
}
// NewResIdKindOnly creates new resource identifier
func NewResIdKindOnly(k string, n string) ResId {
return ResId{gvKind: gvk.FromKind(k), name: n}
}
const (
noNamespace = "noNamespace"
noPrefix = "noPrefix"
noName = "noName"
separator = "|"
)
// String of ResId based on GVK, name and prefix
func (n ResId) String() string {
ns := n.namespace
if ns == "" {
ns = noNamespace
}
p := n.prefix
if p == "" {
p = noPrefix
}
nm := n.name
if nm == "" {
nm = noName
}
return strings.Join(
[]string{n.gvKind.String(), ns, p, nm}, separator)
}
// GvknString of ResId based on GVK and name
func (n ResId) GvknString() string {
return n.gvKind.String() + separator + n.name
}
// GvknEquals return if two ResId have the same Group/Version/Kind and name
// The comparison excludes prefix
func (n ResId) GvknEquals(id ResId) bool {
return n.gvKind.Equals(id.gvKind) && n.name == id.name
}
// Gvk returns Group/Version/Kind of the resource.
func (n ResId) Gvk() gvk.Gvk {
return n.gvKind
}
// Name returns resource name.
func (n ResId) Name() string {
return n.name
}
// Prefix returns name prefix.
func (n ResId) Prefix() string {
return n.prefix
}
// Namespace returns resource namespace.
func (n ResId) Namespace() string {
return n.namespace
}
// CopyWithNewPrefix make a new copy from current ResId and append a new prefix
func (n ResId) CopyWithNewPrefix(p string) ResId {
return ResId{gvKind: n.gvKind, name: n.name, prefix: n.concatPrefix(p), namespace: n.namespace}
}
// CopyWithNewNamespace make a new copy from current ResId and set a new namespace
func (n ResId) CopyWithNewNamespace(ns string) ResId {
return ResId{gvKind: n.gvKind, name: n.name, prefix: n.prefix, namespace: ns}
}
// HasSameLeftmostPrefix check if two ResIds have the same
// left most prefix.
func (n ResId) HasSameLeftmostPrefix(id ResId) bool {
prefixes1 := n.prefixList()
prefixes2 := id.prefixList()
return prefixes1[0] == prefixes2[0]
}
func (n ResId) concatPrefix(p string) string {
if p == "" {
return n.prefix
}
if n.prefix == "" {
return p
}
return p + ":" + n.prefix
}
func (n ResId) prefixList() []string {
return strings.Split(n.prefix, ":")
}

View File

@@ -1,107 +0,0 @@
package resource
import (
"testing"
"sigs.k8s.io/kustomize/pkg/gvk"
)
var stringTests = []struct {
x ResId
s string
}{
{ResId{gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
name: "nm", prefix: "p", namespace: "ns"},
"g_v_k|ns|p|nm"},
{ResId{gvKind: gvk.Gvk{Version: "v", Kind: "k"},
name: "nm", prefix: "p", namespace: "ns"},
"noGroup_v_k|ns|p|nm"},
{ResId{gvKind: gvk.Gvk{Kind: "k"},
name: "nm", prefix: "p", namespace: "ns"},
"noGroup_noVersion_k|ns|p|nm"},
{ResId{gvKind: gvk.Gvk{},
name: "nm", prefix: "p", namespace: "ns"},
"noGroup_noVersion_noKind|ns|p|nm"},
{ResId{gvKind: gvk.Gvk{},
name: "nm", prefix: "p"},
"noGroup_noVersion_noKind|noNamespace|p|nm"},
{ResId{gvKind: gvk.Gvk{},
name: "nm"},
"noGroup_noVersion_noKind|noNamespace|noPrefix|nm"},
{ResId{gvKind: gvk.Gvk{}},
"noGroup_noVersion_noKind|noNamespace|noPrefix|noName"},
{ResId{},
"noGroup_noVersion_noKind|noNamespace|noPrefix|noName"},
}
func TestString(t *testing.T) {
for _, hey := range stringTests {
if hey.x.String() != hey.s {
t.Fatalf("Actual: %v, Expected: '%s'", hey.x, hey.s)
}
}
}
var gvknStringTests = []struct {
x ResId
s string
}{
{ResId{gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
name: "nm", prefix: "p", namespace: "ns"},
"g_v_k|nm"},
{ResId{gvKind: gvk.Gvk{Version: "v", Kind: "k"},
name: "nm", prefix: "p", namespace: "ns"},
"noGroup_v_k|nm"},
{ResId{gvKind: gvk.Gvk{Kind: "k"},
name: "nm", prefix: "p", namespace: "ns"},
"noGroup_noVersion_k|nm"},
{ResId{gvKind: gvk.Gvk{},
name: "nm", prefix: "p", namespace: "ns"},
"noGroup_noVersion_noKind|nm"},
{ResId{gvKind: gvk.Gvk{},
name: "nm", prefix: "p"},
"noGroup_noVersion_noKind|nm"},
{ResId{gvKind: gvk.Gvk{},
name: "nm"},
"noGroup_noVersion_noKind|nm"},
{ResId{gvKind: gvk.Gvk{}},
"noGroup_noVersion_noKind|"},
{ResId{},
"noGroup_noVersion_noKind|"},
}
func TestGvknString(t *testing.T) {
for _, hey := range gvknStringTests {
if hey.x.GvknString() != hey.s {
t.Fatalf("Actual: %s, Expected: '%s'", hey.x.GvknString(), hey.s)
}
}
}
var GvknEqualsTest = []struct {
x1 ResId
x2 ResId
}{
{ResId{gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
name: "nm", prefix: "AA", namespace: "X"},
ResId{gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"},
name: "nm", prefix: "BB", namespace: "Z"}},
{ResId{gvKind: gvk.Gvk{Version: "v", Kind: "k"},
name: "nm", prefix: "AA", namespace: "X"},
ResId{gvKind: gvk.Gvk{Version: "v", Kind: "k"},
name: "nm", prefix: "BB", namespace: "Z"}},
{ResId{gvKind: gvk.Gvk{Kind: "k"},
name: "nm", prefix: "AA", namespace: "X"},
ResId{gvKind: gvk.Gvk{Kind: "k"},
name: "nm", prefix: "BB", namespace: "Z"}},
{ResId{name: "nm", prefix: "AA", namespace: "X"},
ResId{name: "nm", prefix: "BB", namespace: "Z"}},
}
func TestEquals(t *testing.T) {
for _, hey := range GvknEqualsTest {
if !hey.x1.GvknEquals(hey.x2) {
t.Fatalf("%v should equal %v", hey.x1, hey.x2)
}
}
}

View File

@@ -29,19 +29,19 @@ import (
"sigs.k8s.io/kustomize/pkg/gvk"
"sigs.k8s.io/kustomize/pkg/ifc"
internal "sigs.k8s.io/kustomize/pkg/internal/error"
"sigs.k8s.io/kustomize/pkg/loader"
"sigs.k8s.io/kustomize/pkg/patch"
"sigs.k8s.io/kustomize/pkg/resid"
)
// Resource is an "Unstructured" (json/map form) Kubernetes API resource object
// paired with a GenerationBehavior.
type Resource struct {
unstructured.Unstructured
b GenerationBehavior
b ifc.GenerationBehavior
}
// NewResourceWithBehavior returns a new instance of Resource.
func NewResourceWithBehavior(obj runtime.Object, b GenerationBehavior) (*Resource, error) {
func NewResourceWithBehavior(obj runtime.Object, b ifc.GenerationBehavior) (*Resource, error) {
// Convert obj to a byte stream, then convert that to JSON (Unstructured).
marshaled, err := json.Marshal(obj)
if err != nil {
@@ -61,13 +61,13 @@ func NewResourceFromMap(m map[string]interface{}) *Resource {
// NewResourceFromUnstruct returns a new instance of Resource.
func NewResourceFromUnstruct(u unstructured.Unstructured) *Resource {
return &Resource{Unstructured: u, b: BehaviorUnspecified}
return &Resource{Unstructured: u, b: ifc.BehaviorUnspecified}
}
// NewResourceSliceFromPatches returns a slice of resources given a patch path
// slice from a kustomization file.
func NewResourceSliceFromPatches(
ldr loader.Loader, paths []patch.StrategicMerge,
ldr ifc.Loader, paths []patch.StrategicMerge,
decoder ifc.Decoder) ([]*Resource, error) {
var result []*Resource
for _, path := range paths {
@@ -117,24 +117,24 @@ func (r *Resource) String() string {
}
// Behavior returns the behavior for the resource.
func (r *Resource) Behavior() GenerationBehavior {
func (r *Resource) Behavior() ifc.GenerationBehavior {
return r.b
}
// SetBehavior changes the resource to the new behavior
func (r *Resource) SetBehavior(b GenerationBehavior) *Resource {
func (r *Resource) SetBehavior(b ifc.GenerationBehavior) *Resource {
r.b = b
return r
}
// IsGenerated checks if the resource is generated from a generator
func (r *Resource) IsGenerated() bool {
return r.b != BehaviorUnspecified
return r.b != ifc.BehaviorUnspecified
}
// Id returns the ResId for the resource.
func (r *Resource) Id() ResId {
return NewResId(gvk.FromSchemaGvk(r.GroupVersionKind()), r.GetName())
func (r *Resource) Id() resid.ResId {
return resid.NewResId(gvk.FromSchemaGvk(r.GroupVersionKind()), r.GetName())
}
// Merge performs merge with other resource.