diff --git a/pkg/gvk/gvk.go b/pkg/gvk/gvk.go index 43ef3fbf5..3ed72fe1d 100644 --- a/pkg/gvk/gvk.go +++ b/pkg/gvk/gvk.go @@ -35,6 +35,29 @@ func FromKind(k string) Gvk { } } +// FromString makes a Gvk with a string, +// which is constructed by String() function +func FromString(s string) Gvk { + values := strings.Split(s, separator) + g := values[0] + if g == noGroup { + g = "" + } + v := values[1] + if v == noVersion { + v = "" + } + k := values[2] + if k == noKind { + k = "" + } + return Gvk{ + Group: g, + Version: v, + Kind: k, + } +} + // Values that are brief but meaningful in logs. const ( noGroup = "~G" diff --git a/pkg/resid/itemid.go b/pkg/resid/itemid.go new file mode 100644 index 000000000..dfbcd6a01 --- /dev/null +++ b/pkg/resid/itemid.go @@ -0,0 +1,81 @@ +/* +Copyright 2019 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 resid + +import ( + "strings" + + "sigs.k8s.io/kustomize/pkg/gvk" +) + +// ItemId contains the group, version, kind, namespace +// and name of a resource +type ItemId struct { + // Gvk of the resource. + gvk.Gvk `json:",inline,omitempty" yaml:",inline,omitempty"` + + // Name of the resource before transformation. + Name string `json:"name,omitempty" yaml:"name,omitempty"` + + // Namespace the resource belongs to. + // An untransformed resource has no namespace. + // A fully transformed resource has the namespace + // from the top most overlay. + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` +} + +// String of ItemId based on GVK, name and namespace +func (i ItemId) String() string { + ns := i.Namespace + if ns == "" { + ns = noNamespace + } + nm := i.Name + if nm == "" { + nm = noName + } + + return strings.Join( + []string{i.Gvk.String(), ns, nm}, separator) +} + +func New(g gvk.Gvk, ns, nm string) ItemId { + return ItemId{ + Gvk: g, + Namespace: ns, + Name: nm, + } +} + +func FromString(s string) ItemId { + values := strings.Split(s, separator) + g := gvk.FromString(values[0]) + + ns := values[1] + if ns == noNamespace { + ns = "" + } + nm := values[2] + if nm == noName { + nm = "" + } + return ItemId{ + Gvk: g, + Namespace: ns, + Name: nm, + } +} diff --git a/pkg/resid/itemid_test.go b/pkg/resid/itemid_test.go new file mode 100644 index 000000000..8b3ce4a0a --- /dev/null +++ b/pkg/resid/itemid_test.go @@ -0,0 +1,66 @@ +/* +Copyright 2019 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 resid + +import ( + "testing" + + "sigs.k8s.io/kustomize/pkg/gvk" +) + +var itemIds = []ItemId{ + { + Namespace: "ns", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + { + Namespace: "ns", + Gvk: gvk.Gvk{Version: "v", Kind: "k"}, + Name: "nm", + }, + { + Namespace: "ns", + Gvk: gvk.Gvk{Kind: "k"}, + Name: "nm", + }, + { + Namespace: "ns", + Gvk: gvk.Gvk{}, + Name: "nm", + }, + { + Gvk: gvk.Gvk{}, + Name: "nm", + }, + { + Gvk: gvk.Gvk{}, + Name: "nm", + }, + { + Gvk: gvk.Gvk{}, + }, +} + +func TestItemIds(t *testing.T) { + for _, item := range itemIds { + newItem := FromString(item.String()) + if newItem != item { + t.Fatalf("Actual: %v, Expected: '%s'", newItem, item) + } + } +} diff --git a/pkg/resid/resid.go b/pkg/resid/resid.go index dbf9a3e92..68d92e345 100644 --- a/pkg/resid/resid.go +++ b/pkg/resid/resid.go @@ -24,12 +24,7 @@ import ( // ResId is an immutable identifier of a k8s resource object. type ResId struct { - // Gvk of the resource. - gvKind gvk.Gvk - - // name of the resource before transformation. - name string - + ItemId // namePrefix of the resource. // An untransformed resource has no prefix. // A fully transformed resource has an arbitrary @@ -41,42 +36,36 @@ type ResId struct { // A fully transformed resource has an arbitrary // number of suffixes concatenated together. suffix string - - // Namespace the resource belongs to. - // An untransformed resource has no namespace. - // A fully transformed resource has the namespace - // from the top most overlay. - namespace string } // NewResIdWithPrefixSuffixNamespace creates new resource identifier with a prefix, suffix and a namespace func NewResIdWithPrefixSuffixNamespace(k gvk.Gvk, n, p, s, ns string) ResId { - return ResId{gvKind: k, name: n, prefix: p, suffix: s, namespace: ns} + return ResId{ItemId: ItemId{Gvk: k, Name: n, Namespace: ns}, prefix: p, suffix: s} } // 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} + return ResId{ItemId: ItemId{Gvk: k, Name: n, Namespace: ns}, prefix: p} } // NewResIdWithSuffixNamespace creates new resource identifier with a suffix and a namespace func NewResIdWithSuffixNamespace(k gvk.Gvk, n, s, ns string) ResId { - return ResId{gvKind: k, name: n, suffix: s, namespace: ns} + return ResId{ItemId: ItemId{Gvk: k, Name: n, Namespace: ns}, suffix: s} } // NewResIdWithPrefixSuffix creates new resource identifier with a prefix and suffix func NewResIdWithPrefixSuffix(k gvk.Gvk, n, p, s string) ResId { - return ResId{gvKind: k, name: n, prefix: p, suffix: s} + return ResId{ItemId: ItemId{Gvk: k, Name: n}, prefix: p, suffix: s} } // NewResId creates new resource identifier func NewResId(k gvk.Gvk, n string) ResId { - return ResId{gvKind: k, name: n} + return ResId{ItemId: ItemId{Gvk: k, Name: n}} } // NewResIdKindOnly creates new resource identifier func NewResIdKindOnly(k string, n string) ResId { - return ResId{gvKind: gvk.FromKind(k), name: n} + return ResId{ItemId: ItemId{Gvk: gvk.FromKind(k), Name: n}} } const ( @@ -89,7 +78,7 @@ const ( // String of ResId based on GVK, name and prefix func (n ResId) String() string { - ns := n.namespace + ns := n.ItemId.Namespace if ns == "" { ns = noNamespace } @@ -97,7 +86,7 @@ func (n ResId) String() string { if p == "" { p = noPrefix } - nm := n.name + nm := n.ItemId.Name if nm == "" { nm = noName } @@ -107,39 +96,39 @@ func (n ResId) String() string { } return strings.Join( - []string{n.gvKind.String(), ns, p, nm, s}, separator) + []string{n.ItemId.Gvk.String(), ns, p, nm, s}, separator) } // GvknString of ResId based on GVK and name func (n ResId) GvknString() string { - return n.gvKind.String() + separator + n.name + return n.ItemId.Gvk.String() + separator + n.ItemId.Name } // GvknEquals returns true if the other id matches // Group/Version/Kind/name. func (n ResId) GvknEquals(id ResId) bool { - return n.name == id.name && n.gvKind.Equals(id.gvKind) + return n.ItemId.Name == id.ItemId.Name && n.ItemId.Gvk.Equals(id.ItemId.Gvk) } // NsGvknEquals returns true if the other id matches // namespace/Group/Version/Kind/name. func (n ResId) NsGvknEquals(id ResId) bool { - return n.namespace == id.namespace && n.GvknEquals(id) + return n.ItemId.Namespace == id.ItemId.Namespace && n.GvknEquals(id) } // Gvk returns Group/Version/Kind of the resource. func (n ResId) Gvk() gvk.Gvk { - return n.gvKind + return n.ItemId.Gvk } // Name returns resource name. func (n ResId) Name() string { - return n.name + return n.ItemId.Name } // Namespace returns resource namespace. func (n ResId) Namespace() string { - return n.namespace + return n.ItemId.Namespace } // CopyWithNewPrefixSuffix make a new copy from current ResId @@ -158,7 +147,7 @@ func (n ResId) CopyWithNewPrefixSuffix(p, s string) ResId { // CopyWithNewNamespace make a new copy from current ResId and set a new namespace func (n ResId) CopyWithNewNamespace(ns string) ResId { result := n - result.namespace = ns + result.ItemId.Namespace = ns return result } diff --git a/pkg/resid/resid_test.go b/pkg/resid/resid_test.go index cf3d46a82..748cdb384 100644 --- a/pkg/resid/resid_test.go +++ b/pkg/resid/resid_test.go @@ -12,48 +12,58 @@ var stringTests = []struct { }{ { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "p", - suffix: "s", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "p", + suffix: "s", }, "g_v_k|ns|p|nm|s", }, { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{Version: "v", Kind: "k"}, - name: "nm", - prefix: "p", - suffix: "s", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "p", + suffix: "s", }, "~G_v_k|ns|p|nm|s", }, { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{Kind: "k"}, - name: "nm", - prefix: "p", - suffix: "s", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{Kind: "k"}, + Name: "nm", + }, + prefix: "p", + suffix: "s", }, "~G_~V_k|ns|p|nm|s", }, { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{}, - name: "nm", - prefix: "p", - suffix: "s", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{}, + Name: "nm", + }, + prefix: "p", + suffix: "s", }, "~G_~V_~K|ns|p|nm|s", }, { ResId{ - gvKind: gvk.Gvk{}, - name: "nm", + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + Name: "nm", + }, prefix: "p", suffix: "s", }, @@ -61,22 +71,28 @@ var stringTests = []struct { }, { ResId{ - gvKind: gvk.Gvk{}, - name: "nm", + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + Name: "nm", + }, suffix: "s", }, "~G_~V_~K|~X|~P|nm|s", }, { ResId{ - gvKind: gvk.Gvk{}, + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + }, suffix: "s", }, "~G_~V_~K|~X|~P|~N|s", }, { ResId{ - gvKind: gvk.Gvk{}, + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + }, }, "~G_~V_~K|~X|~P|~N|~S", }, @@ -100,48 +116,47 @@ var gvknStringTests = []struct { }{ { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "p", - suffix: "s", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "p", + suffix: "s", }, "g_v_k|nm", }, { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{Version: "v", Kind: "k"}, - name: "nm", - prefix: "p", - suffix: "s", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "p", + suffix: "s", }, "~G_v_k|nm", }, { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{Kind: "k"}, - name: "nm", - prefix: "p", - suffix: "s", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{Kind: "k"}, + Name: "nm", + }, + prefix: "p", + suffix: "s", }, "~G_~V_k|nm", }, { ResId{ - namespace: "ns", - gvKind: gvk.Gvk{}, - name: "nm", - prefix: "p", - suffix: "s", - }, - "~G_~V_~K|nm", - }, - { - ResId{ - gvKind: gvk.Gvk{}, - name: "nm", + ItemId: ItemId{ + Namespace: "ns", + Gvk: gvk.Gvk{}, + Name: "nm", + }, prefix: "p", suffix: "s", }, @@ -149,22 +164,39 @@ var gvknStringTests = []struct { }, { ResId{ - gvKind: gvk.Gvk{}, - name: "nm", + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + Name: "nm", + }, + prefix: "p", suffix: "s", }, "~G_~V_~K|nm", }, { ResId{ - gvKind: gvk.Gvk{}, + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + Name: "nm", + }, + suffix: "s", + }, + "~G_~V_~K|nm", + }, + { + ResId{ + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + }, suffix: "s", }, "~G_~V_~K|", }, { ResId{ - gvKind: gvk.Gvk{}, + ItemId: ItemId{ + Gvk: gvk.Gvk{}, + }, }, "~G_~V_~K|", }, @@ -190,51 +222,42 @@ var GvknEqualsTest = []struct { }{ { id1: ResId{ - namespace: "X", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "AA", - suffix: "aa", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "AA", + suffix: "aa", }, id2: ResId{ - namespace: "X", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "BB", - suffix: "bb", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "BB", + suffix: "bb", }, gVknResult: true, nSgVknResult: true, }, { id1: ResId{ - namespace: "X", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "AA", - suffix: "aa", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "AA", + suffix: "aa", }, id2: ResId{ - namespace: "Z", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "BB", - suffix: "bb", - }, - gVknResult: true, - nSgVknResult: false, - }, - { - id1: ResId{ - namespace: "X", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "AA", - suffix: "aa", - }, - id2: ResId{ - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", + ItemId: ItemId{ + Namespace: "Z", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, prefix: "BB", suffix: "bb", }, @@ -243,52 +266,85 @@ var GvknEqualsTest = []struct { }, { id1: ResId{ - namespace: "X", - gvKind: gvk.Gvk{Version: "v", Kind: "k"}, - name: "nm", - prefix: "AA", - suffix: "aa", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "AA", + suffix: "aa", }, id2: ResId{ - namespace: "Z", - gvKind: gvk.Gvk{Version: "v", Kind: "k"}, - name: "nm", - prefix: "BB", - suffix: "bb", + ItemId: ItemId{ + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "BB", + suffix: "bb", }, gVknResult: true, nSgVknResult: false, }, { id1: ResId{ - namespace: "X", - gvKind: gvk.Gvk{Kind: "k"}, - name: "nm", - prefix: "AA", - suffix: "aa", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "AA", + suffix: "aa", }, id2: ResId{ - namespace: "Z", - gvKind: gvk.Gvk{Kind: "k"}, - name: "nm", - prefix: "BB", - suffix: "bb", + ItemId: ItemId{ + Namespace: "Z", + Gvk: gvk.Gvk{Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "BB", + suffix: "bb", }, gVknResult: true, nSgVknResult: false, }, { id1: ResId{ - namespace: "X", - name: "nm", - prefix: "AA", - suffix: "aa", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Kind: "k"}, + Name: "nm", + }, + prefix: "AA", + suffix: "aa", }, id2: ResId{ - namespace: "Z", - name: "nm", - prefix: "BB", - suffix: "bb", + ItemId: ItemId{ + Namespace: "Z", + Gvk: gvk.Gvk{Kind: "k"}, + Name: "nm", + }, + prefix: "BB", + suffix: "bb", + }, + gVknResult: true, + nSgVknResult: false, + }, + { + id1: ResId{ + ItemId: ItemId{ + Namespace: "X", + Name: "nm", + }, + prefix: "AA", + suffix: "aa", + }, + id2: ResId{ + ItemId: ItemId{ + Namespace: "Z", + Name: "nm", + }, + prefix: "BB", + suffix: "bb", }, gVknResult: true, nSgVknResult: false, @@ -310,19 +366,23 @@ func TestEquals(t *testing.T) { func TestCopyWithNewPrefixSuffix(t *testing.T) { r1 := ResId{ - namespace: "X", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "a", - suffix: "b", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "a", + suffix: "b", } r2 := r1.CopyWithNewPrefixSuffix("p-", "-s") expected := ResId{ - namespace: "X", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "p-a", - suffix: "b-s", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "p-a", + suffix: "b-s", } if !r2.GvknEquals(expected) { t.Fatalf("%v should equal %v", r2, expected) @@ -331,19 +391,23 @@ func TestCopyWithNewPrefixSuffix(t *testing.T) { func TestCopyWithNewNamespace(t *testing.T) { r1 := ResId{ - namespace: "X", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "a", - suffix: "b", + ItemId: ItemId{ + Namespace: "X", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "a", + suffix: "b", } r2 := r1.CopyWithNewNamespace("zzz") expected := ResId{ - namespace: "zzz", - gvKind: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, - name: "nm", - prefix: "a", - suffix: "b", + ItemId: ItemId{ + Namespace: "zzz", + Gvk: gvk.Gvk{Group: "g", Version: "v", Kind: "k"}, + Name: "nm", + }, + prefix: "a", + suffix: "b", } if !r2.GvknEquals(expected) { t.Fatalf("%v should equal %v", r2, expected)