diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go b/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go index ef1b3c888e0..f0d7e9f82b1 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/codec.go @@ -19,13 +19,17 @@ package runtime import ( "bytes" "encoding/base64" + "encoding/json" "fmt" "io" "net/url" "reflect" + "strconv" + "strings" "k8s.io/apimachinery/pkg/conversion/queryparams" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog" ) // codec binds an encoder and decoder. @@ -238,6 +242,11 @@ var ( DisabledGroupVersioner GroupVersioner = disabledGroupVersioner{} ) +const ( + internalGroupVersionerIdentifier = "internal" + disabledGroupVersionerIdentifier = "disabled" +) + type internalGroupVersioner struct{} // KindForGroupVersionKinds returns an internal Kind if one is found, or converts the first provided kind to the internal version. @@ -253,6 +262,11 @@ func (internalGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersi return schema.GroupVersionKind{}, false } +// Identifier implements GroupVersioner interface. +func (internalGroupVersioner) Identifier() string { + return internalGroupVersionerIdentifier +} + type disabledGroupVersioner struct{} // KindForGroupVersionKinds returns false for any input. @@ -260,6 +274,11 @@ func (disabledGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersi return schema.GroupVersionKind{}, false } +// Identifier implements GroupVersioner interface. +func (disabledGroupVersioner) Identifier() string { + return disabledGroupVersionerIdentifier +} + // Assert that schema.GroupVersion and GroupVersions implement GroupVersioner var _ GroupVersioner = schema.GroupVersion{} var _ GroupVersioner = schema.GroupVersions{} @@ -315,3 +334,22 @@ func (v multiGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersio } return schema.GroupVersionKind{}, false } + +// Identifier implements GroupVersioner interface. +func (v multiGroupVersioner) Identifier() string { + groupKinds := make([]string, 0, len(v.acceptedGroupKinds)) + for _, gk := range v.acceptedGroupKinds { + groupKinds = append(groupKinds, gk.String()) + } + result := map[string]string{ + "name": "multi", + "target": v.target.String(), + "accepted": strings.Join(groupKinds, ","), + "coerce": strconv.FormatBool(v.coerce), + } + identifier, err := json.Marshal(result) + if err != nil { + klog.Fatalf("Failed marshaling Identifier for %#v: %v", v, err) + } + return string(identifier) +} diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/codec_test.go b/staging/src/k8s.io/apimachinery/pkg/runtime/codec_test.go index be169f781ac..ee0939a5706 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/codec_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/codec_test.go @@ -39,6 +39,7 @@ func TestCoercingMultiGroupVersioner(t *testing.T) { preferredKinds []schema.GroupKind kinds []schema.GroupVersionKind expectKind schema.GroupVersionKind + expectedId string }{ { name: "matched preferred group/kind", @@ -46,6 +47,7 @@ func TestCoercingMultiGroupVersioner(t *testing.T) { preferredKinds: []schema.GroupKind{gk("mygroup", "Foo"), gk("anothergroup", "Bar")}, kinds: []schema.GroupVersionKind{gvk("yetanother", "v1", "Baz"), gvk("anothergroup", "v1", "Bar")}, expectKind: gvk("mygroup", "__internal", "Bar"), + expectedId: "{\"accepted\":\"Foo.mygroup,Bar.anothergroup\",\"coerce\":\"true\",\"name\":\"multi\",\"target\":\"mygroup/__internal\"}", }, { name: "matched preferred group", @@ -53,6 +55,7 @@ func TestCoercingMultiGroupVersioner(t *testing.T) { preferredKinds: []schema.GroupKind{gk("mygroup", ""), gk("anothergroup", "")}, kinds: []schema.GroupVersionKind{gvk("yetanother", "v1", "Baz"), gvk("anothergroup", "v1", "Bar")}, expectKind: gvk("mygroup", "__internal", "Bar"), + expectedId: "{\"accepted\":\".mygroup,.anothergroup\",\"coerce\":\"true\",\"name\":\"multi\",\"target\":\"mygroup/__internal\"}", }, { name: "no preferred group/kind match, uses first kind in list", @@ -60,6 +63,7 @@ func TestCoercingMultiGroupVersioner(t *testing.T) { preferredKinds: []schema.GroupKind{gk("mygroup", ""), gk("anothergroup", "")}, kinds: []schema.GroupVersionKind{gvk("yetanother", "v1", "Baz"), gvk("yetanother", "v1", "Bar")}, expectKind: gvk("mygroup", "__internal", "Baz"), + expectedId: "{\"accepted\":\".mygroup,.anothergroup\",\"coerce\":\"true\",\"name\":\"multi\",\"target\":\"mygroup/__internal\"}", }, } @@ -73,6 +77,9 @@ func TestCoercingMultiGroupVersioner(t *testing.T) { if kind != tc.expectKind { t.Errorf("expected %#v, got %#v", tc.expectKind, kind) } + if e, a := tc.expectedId, v.Identifier(); e != a { + t.Errorf("unexpected identifier: %s, expected: %s", a, e) + } }) } } diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/interfaces.go b/staging/src/k8s.io/apimachinery/pkg/runtime/interfaces.go index acb0d24e7c7..33c377c3eec 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/interfaces.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/interfaces.go @@ -37,6 +37,10 @@ type GroupVersioner interface { // Scheme.New(target) and then perform a conversion between the current Go type and the destination Go type. // Sophisticated implementations may use additional information about the input kinds to pick a destination kind. KindForGroupVersionKinds(kinds []schema.GroupVersionKind) (target schema.GroupVersionKind, ok bool) + // Identifier returns string representation of the object. + // Identifiers of two different encoders should be equal only if for every input + // kinds they return the same result. + Identifier() string } // Identifier represents an identifier. diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/schema/group_version.go b/staging/src/k8s.io/apimachinery/pkg/runtime/schema/group_version.go index 4c67ed59801..636103312f0 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/schema/group_version.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/schema/group_version.go @@ -191,6 +191,11 @@ func (gv GroupVersion) String() string { return gv.Version } +// Identifier implements runtime.GroupVersioner interface. +func (gv GroupVersion) Identifier() string { + return gv.String() +} + // KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false // if none of the options match the group. It prefers a match to group and version over just group. // TODO: Move GroupVersion to a package under pkg/runtime, since it's used by scheme. @@ -246,6 +251,15 @@ func (gv GroupVersion) WithResource(resource string) GroupVersionResource { // in fewer places. type GroupVersions []GroupVersion +// Identifier implements runtime.GroupVersioner interface. +func (gv GroupVersions) Identifier() string { + groupVersions := make([]string, 0, len(gv)) + for i := range gv { + groupVersions = append(groupVersions, gv[i].String()) + } + return fmt.Sprintf("[%s]", strings.Join(groupVersions, ",")) +} + // KindForGroupVersionKinds identifies the preferred GroupVersionKind out of a list. It returns ok false // if none of the options match the group. func (gvs GroupVersions) KindForGroupVersionKinds(kinds []GroupVersionKind) (GroupVersionKind, bool) { diff --git a/staging/src/k8s.io/apimachinery/pkg/runtime/scheme_test.go b/staging/src/k8s.io/apimachinery/pkg/runtime/scheme_test.go index aef8f7ea87f..d4881fe5c86 100644 --- a/staging/src/k8s.io/apimachinery/pkg/runtime/scheme_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/runtime/scheme_test.go @@ -610,6 +610,10 @@ func (m testGroupVersioner) KindForGroupVersionKinds(kinds []schema.GroupVersion return m.target, m.ok } +func (m testGroupVersioner) Identifier() string { + return "testGroupVersioner" +} + func TestConvertToVersion(t *testing.T) { testCases := []struct { scheme *runtime.Scheme