internal versions

This commit is contained in:
deads2k 2015-11-17 13:21:32 -05:00
parent 6231404682
commit 68b0572974
17 changed files with 222 additions and 108 deletions

View File

@ -41,7 +41,7 @@ func BenchmarkPodConversion(b *testing.B) {
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.ConvertToVersion(versionedObj, scheme.InternalVersion)
obj, err := scheme.ConvertToVersion(versionedObj, scheme.InternalVersions[testapi.Default.Group].String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
@ -69,7 +69,7 @@ func BenchmarkNodeConversion(b *testing.B) {
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.ConvertToVersion(versionedObj, scheme.InternalVersion)
obj, err := scheme.ConvertToVersion(versionedObj, scheme.InternalVersions[testapi.Default.Group].String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
@ -97,7 +97,7 @@ func BenchmarkReplicationControllerConversion(b *testing.B) {
if err != nil {
b.Fatalf("Conversion error: %v", err)
}
obj, err := scheme.ConvertToVersion(versionedObj, scheme.InternalVersion)
obj, err := scheme.ConvertToVersion(versionedObj, scheme.InternalVersions[testapi.Default.Group].String())
if err != nil {
b.Fatalf("Conversion error: %v", err)
}

View File

@ -49,11 +49,15 @@ type GroupVersion struct {
Version string
}
func (gv GroupVersion) IsEmpty() bool {
return len(gv.Group) == 0 && len(gv.Version) == 0
}
// String puts "group" and "version" into a single "group/version" string. For the legacy v1
// it returns "v1".
func (gv GroupVersion) String() string {
// special case the internal apiVersion for kube
if len(gv.Group) == 0 && len(gv.Version) == 0 {
if gv.IsEmpty() {
return ""
}

View File

@ -25,7 +25,8 @@ func init() {
}
func addKnownTypes() {
api.Scheme.AddKnownTypes("",
// TODO this will get cleaned up with the scheme types are fixed
api.Scheme.AddKnownTypes("componentconfig/",
&KubeProxyConfiguration{},
)
}

View File

@ -27,7 +27,8 @@ func init() {
// Adds the list of known types to api.Scheme.
func addKnownTypes() {
api.Scheme.AddKnownTypes("",
// TODO this gets cleaned up when the types are fixed
api.Scheme.AddKnownTypes("extensions/",
&ClusterAutoscaler{},
&ClusterAutoscalerList{},
&Deployment{},

View File

@ -27,7 +27,8 @@ func init() {
// Adds the list of known types to api.Scheme.
func addKnownTypes() {
api.Scheme.AddKnownTypes("",
// TODO this will get cleaned up with the scheme types are fixed
api.Scheme.AddKnownTypes("metrics/",
&RawNode{},
&RawPod{},
)

View File

@ -375,11 +375,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
// test/integration/auth_test.go is currently the most comprehensive status code test
reqScope := RequestScope{
ContextFunc: ctxFn,
Creater: a.group.Creater,
Convertor: a.group.Convertor,
Codec: mapping.Codec,
APIVersion: a.group.GroupVersion.String(),
ContextFunc: ctxFn,
Creater: a.group.Creater,
Convertor: a.group.Convertor,
Codec: mapping.Codec,
APIVersion: a.group.GroupVersion.String(),
// TODO, this internal version needs to plumbed through from the caller
// this works in all the cases we have now
InternalVersion: unversioned.GroupVersion{Group: a.group.GroupVersion.Group},
ServerAPIVersion: serverGroupVersion.String(),
Resource: resource,
Subresource: subresource,

View File

@ -58,6 +58,7 @@ func convert(obj runtime.Object) (runtime.Object, error) {
// This creates fake API versions, similar to api/latest.go.
var testAPIGroup = "test.group"
var testInternalGroupVersion = unversioned.GroupVersion{Group: testAPIGroup, Version: ""}
var testGroupVersion = unversioned.GroupVersion{Group: testAPIGroup, Version: "version"}
var newGroupVersion = unversioned.GroupVersion{Group: testAPIGroup, Version: "version2"}
var prefix = "apis"
@ -136,8 +137,9 @@ func init() {
// "internal" version
api.Scheme.AddKnownTypes(
"", &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
testInternalGroupVersion.String(), &apiservertesting.Simple{}, &apiservertesting.SimpleList{}, &unversioned.Status{},
&unversioned.ListOptions{}, &apiservertesting.SimpleGetOptions{}, &apiservertesting.SimpleRoot{})
api.Scheme.AddInternalGroupVersion(testInternalGroupVersion)
addGrouplessTypes()
addTestTypes()
addNewTestTypes()
@ -1630,7 +1632,7 @@ func TestConnectWithOptions(t *testing.T) {
}
opts, ok := connectStorage.receivedConnectOptions.(*apiservertesting.SimpleGetOptions)
if !ok {
t.Errorf("Unexpected options type: %#v", connectStorage.receivedConnectOptions)
t.Fatalf("Unexpected options type: %#v", connectStorage.receivedConnectOptions)
}
if opts.Param1 != "value1" && opts.Param2 != "value2" {
t.Errorf("Unexpected options value: %#v", opts)
@ -1677,7 +1679,7 @@ func TestConnectWithOptionsAndPath(t *testing.T) {
}
opts, ok := connectStorage.receivedConnectOptions.(*apiservertesting.SimpleGetOptions)
if !ok {
t.Errorf("Unexpected options type: %#v", connectStorage.receivedConnectOptions)
t.Fatalf("Unexpected options type: %#v", connectStorage.receivedConnectOptions)
}
if opts.Param1 != "value1" && opts.Param2 != "value2" {
t.Errorf("Unexpected options value: %#v", opts)

View File

@ -73,10 +73,11 @@ type RequestScope struct {
Creater runtime.ObjectCreater
Convertor runtime.ObjectConvertor
Resource string
Subresource string
Kind string
APIVersion string
Resource string
Subresource string
Kind string
APIVersion string
InternalVersion unversioned.GroupVersion
// The version of apiserver resources to use
ServerAPIVersion string
@ -156,7 +157,7 @@ func getRequestOptions(req *restful.Request, scope RequestScope, kind string, su
if err := scope.Codec.DecodeParametersInto(query, versioned); err != nil {
return nil, errors.NewBadRequest(err.Error())
}
out, err := scope.Convertor.ConvertToVersion(versioned, "")
out, err := scope.Convertor.ConvertToVersion(versioned, scope.InternalVersion.String())
if err != nil {
// programmer error
return nil, err

View File

@ -26,18 +26,29 @@ import (
"k8s.io/kubernetes/pkg/api/unversioned"
)
func (s *Scheme) DecodeToVersionedObject(data []byte) (obj interface{}, version, kind string, err error) {
version, kind, err = s.DataVersionAndKind(data)
func (s *Scheme) DecodeToVersionedObject(data []byte) (interface{}, string, string, error) {
version, kind, err := s.DataVersionAndKind(data)
if err != nil {
return
return nil, "", "", err
}
if version == "" && s.InternalVersion != "" {
gv, err := unversioned.ParseGroupVersion(version)
if err != nil {
return nil, "", "", err
}
internalGV, exists := s.InternalVersions[gv.Group]
if !exists {
return nil, "", "", fmt.Errorf("no internalVersion specified for %v", gv)
}
if len(gv.Version) == 0 && len(internalGV.Version) != 0 {
return nil, "", "", fmt.Errorf("version not set in '%s'", string(data))
}
if kind == "" {
return nil, "", "", fmt.Errorf("kind not set in '%s'", string(data))
}
obj, err = s.NewObject(version, kind)
obj, err := s.NewObject(version, kind)
if err != nil {
return nil, "", "", err
}
@ -45,7 +56,7 @@ func (s *Scheme) DecodeToVersionedObject(data []byte) (obj interface{}, version,
if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(obj); err != nil {
return nil, "", "", err
}
return
return obj, version, kind, nil
}
// Decode converts a JSON string back into a pointer to an api object.
@ -54,8 +65,7 @@ func (s *Scheme) DecodeToVersionedObject(data []byte) (obj interface{}, version,
// s.InternalVersion type before being returned. Decode will not decode
// objects without version set unless InternalVersion is also "".
func (s *Scheme) Decode(data []byte) (interface{}, error) {
// TODO this is cleaned up when internal types are fixed
return s.DecodeToVersion(data, unversioned.ParseGroupVersionOrDie(s.InternalVersion))
return s.DecodeToVersion(data, unversioned.GroupVersion{})
}
// DecodeToVersion converts a JSON string back into a pointer to an api object.
@ -63,6 +73,8 @@ func (s *Scheme) Decode(data []byte) (interface{}, error) {
// technique. The object will be converted, if necessary, into the versioned
// type before being returned. Decode will not decode objects without version
// set unless version is also "".
// a GroupVersion with .IsEmpty() == true is means "use the internal version for
// the object's group"
func (s *Scheme) DecodeToVersion(data []byte, gv unversioned.GroupVersion) (interface{}, error) {
obj, sourceVersion, kind, err := s.DecodeToVersionedObject(data)
if err != nil {
@ -73,8 +85,23 @@ func (s *Scheme) DecodeToVersion(data []byte, gv unversioned.GroupVersion) (inte
return nil, err
}
sourceGV, err := unversioned.ParseGroupVersion(sourceVersion)
if err != nil {
return nil, err
}
// if the gv is empty, then we want the internal version, but the internal version varies by
// group. We can lookup the group now because we have knowledge of the group
if gv.IsEmpty() {
exists := false
gv, exists = s.InternalVersions[sourceGV.Group]
if !exists {
return nil, fmt.Errorf("no internalVersion specified for %v", gv)
}
}
// Convert if needed.
if gv.String() != sourceVersion {
if gv != sourceGV {
objOut, err := s.NewObject(gv.String(), kind)
if err != nil {
return nil, err
@ -118,7 +145,7 @@ func (s *Scheme) DecodeIntoWithSpecifiedVersionKind(data []byte, obj interface{}
if dataKind == "" {
dataKind = gvk.Kind
}
if (len(gvk.GroupVersion().Group) > 0 || len(gvk.GroupVersion().Version) > 0) && (dataVersion != gvk.GroupVersion().String()) {
if (len(gvk.Group) > 0 || len(gvk.Version) > 0) && (dataVersion != gvk.GroupVersion().String()) {
return errors.New(fmt.Sprintf("The apiVersion in the data (%s) does not match the specified apiVersion(%v)", dataVersion, gvk.GroupVersion()))
}
if len(gvk.Kind) > 0 && (dataKind != gvk.Kind) {

View File

@ -19,25 +19,27 @@ package conversion
import (
"fmt"
"reflect"
"k8s.io/kubernetes/pkg/api/unversioned"
)
type notRegisteredErr struct {
kind string
version string
t reflect.Type
gvk unversioned.GroupVersionKind
t reflect.Type
}
func (k *notRegisteredErr) Error() string {
if k.t != nil {
return fmt.Sprintf("no kind is registered for the type %v", k.t)
}
if len(k.kind) == 0 {
return fmt.Sprintf("no version %q has been registered", k.version)
if len(k.gvk.Kind) == 0 {
return fmt.Sprintf("no version %q has been registered", k.gvk.GroupVersion())
}
if len(k.version) == 0 {
return fmt.Sprintf("no kind %q is registered for the default version", k.kind)
if len(k.gvk.Version) == 0 {
return fmt.Sprintf("no kind %q is registered for the default version of group %q", k.gvk.Kind, k.gvk.Group)
}
return fmt.Sprintf("no kind %q is registered for version %q", k.kind, k.version)
return fmt.Sprintf("no kind %q is registered for version %q", k.gvk.Kind, k.gvk.GroupVersion())
}
// IsNotRegisteredError returns true if the error indicates the provided

View File

@ -125,9 +125,13 @@ func TestMetaValues(t *testing.T) {
Kind string `json:"kind,omitempty"`
TestString string `json:"testString"`
}
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "externalVersion"}
s := NewScheme()
s.AddKnownTypeWithName("", "Simple", &InternalSimple{})
s.AddKnownTypeWithName("externalVersion", "Simple", &ExternalSimple{})
s.InternalVersions[internalGV.Group] = internalGV
s.AddKnownTypeWithName(internalGV.String(), "Simple", &InternalSimple{})
s.AddKnownTypeWithName(externalGV.String(), "Simple", &ExternalSimple{})
internalToExternalCalls := 0
externalToInternalCalls := 0
@ -136,10 +140,10 @@ func TestMetaValues(t *testing.T) {
err := s.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope Scope) error {
t.Logf("internal -> external")
if e, a := "", scope.Meta().SrcVersion; e != a {
if e, a := internalGV.String(), scope.Meta().SrcVersion; e != a {
t.Fatalf("Expected '%v', got '%v'", e, a)
}
if e, a := "externalVersion", scope.Meta().DestVersion; e != a {
if e, a := externalGV.String(), scope.Meta().DestVersion; e != a {
t.Fatalf("Expected '%v', got '%v'", e, a)
}
scope.Convert(&in.TestString, &out.TestString, 0)
@ -148,10 +152,10 @@ func TestMetaValues(t *testing.T) {
},
func(in *ExternalSimple, out *InternalSimple, scope Scope) error {
t.Logf("external -> internal")
if e, a := "externalVersion", scope.Meta().SrcVersion; e != a {
if e, a := externalGV.String(), scope.Meta().SrcVersion; e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
if e, a := "", scope.Meta().DestVersion; e != a {
if e, a := internalGV.String(), scope.Meta().DestVersion; e != a {
t.Fatalf("Expected '%v', got '%v'", e, a)
}
scope.Convert(&in.TestString, &out.TestString, 0)
@ -169,7 +173,7 @@ func TestMetaValues(t *testing.T) {
s.Log(t)
// Test Encode, Decode, and DecodeInto
data, err := s.EncodeToVersion(simple, "externalVersion")
data, err := s.EncodeToVersion(simple, externalGV.String())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -226,7 +230,6 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
TestString string `json:"testString"`
}
s := NewScheme()
s.InternalVersion = ""
// We deliberately don't register the types.
internalToExternalCalls := 0

View File

@ -19,6 +19,8 @@ package conversion
import (
"fmt"
"reflect"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// Scheme defines an entire encoding and decoding scheme.
@ -50,7 +52,9 @@ type Scheme struct {
// InternalVersion is the default internal version. It is recommended that
// you use "" for the internal version.
InternalVersion string
// TODO logically the InternalVersion is different for every Group, so this structure
// must be map
InternalVersions map[string]unversioned.GroupVersion
// MetaInsertionFactory is used to create an object to store and retrieve
// the version and kind information for all objects. The default uses the
@ -61,13 +65,19 @@ type Scheme struct {
// NewScheme manufactures a new scheme.
func NewScheme() *Scheme {
s := &Scheme{
versionMap: map[string]map[string]reflect.Type{},
typeToVersion: map[reflect.Type]string{},
typeToKind: map[reflect.Type][]string{},
converter: NewConverter(),
cloner: NewCloner(),
InternalVersion: "",
MetaFactory: DefaultMetaFactory,
versionMap: map[string]map[string]reflect.Type{},
typeToVersion: map[reflect.Type]string{},
typeToKind: map[reflect.Type][]string{},
converter: NewConverter(),
cloner: NewCloner(),
// TODO remove this hard coded list. As step one, hardcode it here so this pull doesn't become even bigger
InternalVersions: map[string]unversioned.GroupVersion{
"": unversioned.GroupVersion{},
"componentconfig": unversioned.GroupVersion{Group: "componentconfig"},
"extensions": unversioned.GroupVersion{Group: "extensions"},
"metrics": unversioned.GroupVersion{Group: "metrics"},
},
MetaFactory: DefaultMetaFactory,
}
s.converter.nameFunc = s.nameFunc
return s
@ -159,13 +169,21 @@ func (s *Scheme) KnownTypes(version string) map[string]reflect.Type {
// NewObject returns a new object of the given version and name,
// or an error if it hasn't been registered.
func (s *Scheme) NewObject(gvString, kind string) (interface{}, error) {
gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil {
return nil, err
}
gvk := gv.WithKind(kind)
if types, ok := s.versionMap[gvString]; ok {
if t, ok := types[kind]; ok {
return reflect.New(t).Interface(), nil
}
return nil, &notRegisteredErr{kind: kind, version: gvString}
return nil, &notRegisteredErr{gvk: gvk}
}
return nil, &notRegisteredErr{kind: kind, version: gvString}
return nil, &notRegisteredErr{gvk: gvk}
}
// AddConversionFuncs adds functions to the list of conversion functions. The given

View File

@ -23,6 +23,7 @@ import (
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/util"
"github.com/ghodss/yaml"
@ -118,7 +119,6 @@ func GetTestScheme() *Scheme {
s.AddKnownTypeWithName("v1", "TestType2", &ExternalTestType2{})
s.AddKnownTypeWithName("", "TestType3", &TestType1{})
s.AddKnownTypeWithName("v1", "TestType3", &ExternalTestType1{})
s.InternalVersion = ""
s.MetaFactory = testMetaFactory{}
return s
}
@ -361,7 +361,7 @@ func TestBadJSONRejection(t *testing.T) {
func TestBadJSONRejectionForSetInternalVersion(t *testing.T) {
s := GetTestScheme()
s.InternalVersion = "v1"
s.InternalVersions[""] = unversioned.GroupVersion{Version: "v1"}
badJSONs := [][]byte{
[]byte(`{"myKindKey":"TestType1"}`), // Missing version
}

View File

@ -88,7 +88,8 @@ func (g *conversionGenerator) AddImport(pkg string) string {
func (g *conversionGenerator) GenerateConversionsForType(version string, reflection reflect.Type) error {
kind := reflection.Name()
internalObj, err := g.scheme.NewObject(g.scheme.InternalVersion, kind)
// TODO this is equivalent to what it did before, but it needs to be fixed for the proper group
internalObj, err := g.scheme.NewObject(g.scheme.InternalVersions[""].String(), kind)
if err != nil {
return fmt.Errorf("cannot create an object of type %v in internal version", kind)
}

View File

@ -23,6 +23,7 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util"
)
@ -61,11 +62,15 @@ func (*EmbeddedTest) IsAnAPIObject() {}
func (*EmbeddedTestExternal) IsAnAPIObject() {}
func TestDecodeEmptyRawExtensionAsObject(t *testing.T) {
s := runtime.NewScheme()
s.AddKnownTypes("", &ObjectTest{})
s.AddKnownTypeWithName("v1test", "ObjectTest", &ObjectTestExternal{})
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGVK := unversioned.GroupVersionKind{Group: "test.group", Version: "v1test", Kind: "ObjectTest"}
obj, err := s.Decode([]byte(`{"kind":"ObjectTest","apiVersion":"v1test","items":[{}]}`))
s := runtime.NewScheme()
s.AddInternalGroupVersion(internalGV)
s.AddKnownTypes(internalGV.String(), &ObjectTest{})
s.AddKnownTypeWithName(externalGVK.GroupVersion().String(), externalGVK.Kind, &ObjectTestExternal{})
obj, err := s.Decode([]byte(`{"kind":"` + externalGVK.Kind + `","apiVersion":"` + externalGVK.GroupVersion().String() + `","items":[{}]}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -74,7 +79,7 @@ func TestDecodeEmptyRawExtensionAsObject(t *testing.T) {
t.Fatalf("unexpected object: %#v", test.Items[0])
}
obj, err = s.Decode([]byte(`{"kind":"ObjectTest","apiVersion":"v1test","items":[{"kind":"Other","apiVersion":"v1"}]}`))
obj, err = s.Decode([]byte(`{"kind":"` + externalGVK.Kind + `","apiVersion":"` + externalGVK.GroupVersion().String() + `","items":[{"kind":"Other","apiVersion":"v1"}]}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -85,11 +90,15 @@ func TestDecodeEmptyRawExtensionAsObject(t *testing.T) {
}
func TestArrayOfRuntimeObject(t *testing.T) {
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"}
s := runtime.NewScheme()
s.AddKnownTypes("", &EmbeddedTest{})
s.AddKnownTypeWithName("v1test", "EmbeddedTest", &EmbeddedTestExternal{})
s.AddKnownTypes("", &ObjectTest{})
s.AddKnownTypeWithName("v1test", "ObjectTest", &ObjectTestExternal{})
s.AddInternalGroupVersion(internalGV)
s.AddKnownTypes(internalGV.String(), &EmbeddedTest{})
s.AddKnownTypeWithName(externalGV.String(), "EmbeddedTest", &EmbeddedTestExternal{})
s.AddKnownTypes(internalGV.String(), &ObjectTest{})
s.AddKnownTypeWithName(externalGV.String(), "ObjectTest", &ObjectTestExternal{})
internal := &ObjectTest{
Items: []runtime.Object{
@ -104,7 +113,7 @@ func TestArrayOfRuntimeObject(t *testing.T) {
},
},
}
wire, err := s.EncodeToVersion(internal, "v1test")
wire, err := s.EncodeToVersion(internal, externalGV.String())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -147,9 +156,14 @@ func TestArrayOfRuntimeObject(t *testing.T) {
}
func TestEmbeddedObject(t *testing.T) {
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"}
embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest")
s := runtime.NewScheme()
s.AddKnownTypes("", &EmbeddedTest{})
s.AddKnownTypeWithName("v1test", "EmbeddedTest", &EmbeddedTestExternal{})
s.AddInternalGroupVersion(internalGV)
s.AddKnownTypes(internalGV.String(), &EmbeddedTest{})
s.AddKnownTypeWithName(externalGV.String(), embeddedTestExternalGVK.Kind, &EmbeddedTestExternal{})
outer := &EmbeddedTest{
ID: "outer",
@ -160,7 +174,7 @@ func TestEmbeddedObject(t *testing.T) {
},
}
wire, err := s.EncodeToVersion(outer, "v1test")
wire, err := s.EncodeToVersion(outer, externalGV.String())
if err != nil {
t.Fatalf("Unexpected encode error '%v'", err)
}
@ -206,9 +220,14 @@ func TestEmbeddedObject(t *testing.T) {
// TestDeepCopyOfEmbeddedObject checks to make sure that EmbeddedObject's can be passed through DeepCopy with fidelity
func TestDeepCopyOfEmbeddedObject(t *testing.T) {
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"}
embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest")
s := runtime.NewScheme()
s.AddKnownTypes("", &EmbeddedTest{})
s.AddKnownTypeWithName("v1test", "EmbeddedTest", &EmbeddedTestExternal{})
s.AddInternalGroupVersion(internalGV)
s.AddKnownTypes(internalGV.String(), &EmbeddedTest{})
s.AddKnownTypeWithName(externalGV.String(), embeddedTestExternalGVK.Kind, &EmbeddedTestExternal{})
original := &EmbeddedTest{
ID: "outer",
@ -219,7 +238,7 @@ func TestDeepCopyOfEmbeddedObject(t *testing.T) {
},
}
originalData, err := s.EncodeToVersion(original, "v1test")
originalData, err := s.EncodeToVersion(original, externalGV.String())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@ -230,7 +249,7 @@ func TestDeepCopyOfEmbeddedObject(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
copiedData, err := s.EncodeToVersion(copyOfOriginal.(runtime.Object), "v1test")
copiedData, err := s.EncodeToVersion(copyOfOriginal.(runtime.Object), externalGV.String())
if err != nil {
t.Errorf("unexpected error: %v", err)
}

View File

@ -181,8 +181,16 @@ func (self *Scheme) runtimeObjectToRawExtensionArray(in *[]Object, out *[]RawExt
default:
version := outVersion
// if the object exists
if inVersion, _, err := scheme.ObjectVersionAndKind(src[i]); err == nil && len(inVersion) != 0 {
version = inVersion
// this code is try to set the outputVersion, but only if the object has a non-internal group version
if inGVString, _, err := scheme.ObjectVersionAndKind(src[i]); err == nil && len(inGVString) != 0 {
inGV, err := unversioned.ParseGroupVersion(inGVString)
if err != nil {
return err
}
if self.raw.InternalVersions[inGV.Group] != inGV {
version = inGV.String()
}
}
data, err := scheme.EncodeToVersion(src[i], version)
if err != nil {
@ -222,9 +230,13 @@ func (self *Scheme) rawExtensionToRuntimeObjectArray(in *[]RawExtension, out *[]
}
// NewScheme creates a new Scheme. This scheme is pluggable by default.
func NewScheme() *Scheme {
func NewScheme(internalGroupVersions ...unversioned.GroupVersion) *Scheme {
s := &Scheme{conversion.NewScheme(), map[string]map[string]FieldLabelConversionFunc{}}
s.raw.InternalVersion = ""
for _, internalGV := range internalGroupVersions {
s.raw.InternalVersions[internalGV.Group] = internalGV
}
s.raw.MetaFactory = conversion.SimpleMetaFactory{BaseFields: []string{"TypeMeta"}, VersionField: "APIVersion", KindField: "Kind"}
if err := s.raw.AddConversionFuncs(
s.embeddedObjectToRawExtension,
@ -247,6 +259,10 @@ func NewScheme() *Scheme {
return s
}
func (s *Scheme) AddInternalGroupVersion(gv unversioned.GroupVersion) {
s.raw.InternalVersions[gv.Group] = gv
}
// AddKnownTypes registers the types of the arguments to the marshaller of the package api.
// Encode() refuses the object unless its type is registered with AddKnownTypes.
func (s *Scheme) AddKnownTypes(version string, types ...Object) {

View File

@ -44,12 +44,15 @@ func (*InternalSimple) IsAnAPIObject() {}
func (*ExternalSimple) IsAnAPIObject() {}
func TestScheme(t *testing.T) {
internalGVK := unversioned.GroupVersionKind{Group: "test.group", Version: "", Kind: "Simple"}
externalGVK := unversioned.GroupVersionKind{Group: "test.group", Version: "externalVersion", Kind: "Simple"}
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"}
internalGVK := internalGV.WithKind("Simple")
externalGVK := externalGV.WithKind("Simple")
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName(internalGVK.GroupVersion().String(), internalGVK.Kind, &InternalSimple{})
scheme.AddKnownTypeWithName(externalGVK.GroupVersion().String(), externalGVK.Kind, &ExternalSimple{})
scheme.AddInternalGroupVersion(internalGV)
scheme.AddKnownTypeWithName(internalGV.String(), internalGVK.Kind, &InternalSimple{})
scheme.AddKnownTypeWithName(externalGV.String(), externalGVK.Kind, &ExternalSimple{})
// test that scheme is an ObjectTyper
var _ runtime.ObjectTyper = scheme
@ -60,10 +63,10 @@ func TestScheme(t *testing.T) {
// Register functions to verify that scope.Meta() gets set correctly.
err := scheme.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
if e, a := internalGVK.GroupVersion().String(), scope.Meta().SrcVersion; e != a {
if e, a := internalGV.String(), scope.Meta().SrcVersion; e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
if e, a := externalGVK.GroupVersion().String(), scope.Meta().DestVersion; e != a {
if e, a := externalGV.String(), scope.Meta().DestVersion; e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
@ -72,10 +75,10 @@ func TestScheme(t *testing.T) {
return nil
},
func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error {
if e, a := externalGVK.GroupVersion().String(), scope.Meta().SrcVersion; e != a {
if e, a := externalGV.String(), scope.Meta().SrcVersion; e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
if e, a := internalGVK.GroupVersion().String(), scope.Meta().DestVersion; e != a {
if e, a := internalGV.String(), scope.Meta().DestVersion; e != a {
t.Errorf("Expected '%v', got '%v'", e, a)
}
scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
@ -93,11 +96,11 @@ func TestScheme(t *testing.T) {
// Test Encode, Decode, DecodeInto, and DecodeToVersion
obj := runtime.Object(simple)
data, err := scheme.EncodeToVersion(obj, "externalVersion")
data, err := scheme.EncodeToVersion(obj, externalGV.String())
obj2, err2 := scheme.Decode(data)
obj3 := &InternalSimple{}
err3 := scheme.DecodeInto(data, obj3)
obj4, err4 := scheme.DecodeToVersion(data, externalGVK.GroupVersion())
obj4, err4 := scheme.DecodeToVersion(data, externalGV)
if err != nil || err2 != nil || err3 != nil || err4 != nil {
t.Fatalf("Failure: '%v' '%v' '%v' '%v'", err, err2, err3, err4)
}
@ -202,9 +205,13 @@ func (*ExternalOptionalExtensionType) IsAnAPIObject() {}
func (*InternalOptionalExtensionType) IsAnAPIObject() {}
func TestExternalToInternalMapping(t *testing.T) {
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"}
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName("", "OptionalExtensionType", &InternalOptionalExtensionType{})
scheme.AddKnownTypeWithName("testExternal", "OptionalExtensionType", &ExternalOptionalExtensionType{})
scheme.AddInternalGroupVersion(internalGV)
scheme.AddKnownTypeWithName(internalGV.String(), "OptionalExtensionType", &InternalOptionalExtensionType{})
scheme.AddKnownTypeWithName(externalGV.String(), "OptionalExtensionType", &ExternalOptionalExtensionType{})
table := []struct {
obj runtime.Object
@ -212,7 +219,7 @@ func TestExternalToInternalMapping(t *testing.T) {
}{
{
&InternalOptionalExtensionType{Extension: runtime.EmbeddedObject{Object: nil}},
`{"kind":"OptionalExtensionType","apiVersion":"testExternal"}`,
`{"kind":"OptionalExtensionType","apiVersion":"` + externalGV.String() + `"}`,
},
}
@ -234,15 +241,19 @@ func TestExternalToInternalMapping(t *testing.T) {
}
func TestExtensionMapping(t *testing.T) {
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"}
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName("", "ExtensionType", &InternalExtensionType{})
scheme.AddKnownTypeWithName("", "OptionalExtensionType", &InternalOptionalExtensionType{})
scheme.AddKnownTypeWithName("", "A", &ExtensionA{})
scheme.AddKnownTypeWithName("", "B", &ExtensionB{})
scheme.AddKnownTypeWithName("testExternal", "ExtensionType", &ExternalExtensionType{})
scheme.AddKnownTypeWithName("testExternal", "OptionalExtensionType", &ExternalOptionalExtensionType{})
scheme.AddKnownTypeWithName("testExternal", "A", &ExtensionA{})
scheme.AddKnownTypeWithName("testExternal", "B", &ExtensionB{})
scheme.AddInternalGroupVersion(internalGV)
scheme.AddKnownTypeWithName(internalGV.String(), "ExtensionType", &InternalExtensionType{})
scheme.AddKnownTypeWithName(internalGV.String(), "OptionalExtensionType", &InternalOptionalExtensionType{})
scheme.AddKnownTypeWithName(internalGV.String(), "A", &ExtensionA{})
scheme.AddKnownTypeWithName(internalGV.String(), "B", &ExtensionB{})
scheme.AddKnownTypeWithName(externalGV.String(), "ExtensionType", &ExternalExtensionType{})
scheme.AddKnownTypeWithName(externalGV.String(), "OptionalExtensionType", &ExternalOptionalExtensionType{})
scheme.AddKnownTypeWithName(externalGV.String(), "A", &ExtensionA{})
scheme.AddKnownTypeWithName(externalGV.String(), "B", &ExtensionB{})
table := []struct {
obj runtime.Object
@ -250,21 +261,21 @@ func TestExtensionMapping(t *testing.T) {
}{
{
&InternalExtensionType{Extension: runtime.EmbeddedObject{Object: &ExtensionA{TestString: "foo"}}},
`{"kind":"ExtensionType","apiVersion":"testExternal","extension":{"kind":"A","testString":"foo"}}
`{"kind":"ExtensionType","apiVersion":"` + externalGV.String() + `","extension":{"kind":"A","testString":"foo"}}
`,
}, {
&InternalExtensionType{Extension: runtime.EmbeddedObject{Object: &ExtensionB{TestString: "bar"}}},
`{"kind":"ExtensionType","apiVersion":"testExternal","extension":{"kind":"B","testString":"bar"}}
`{"kind":"ExtensionType","apiVersion":"` + externalGV.String() + `","extension":{"kind":"B","testString":"bar"}}
`,
}, {
&InternalExtensionType{Extension: runtime.EmbeddedObject{Object: nil}},
`{"kind":"ExtensionType","apiVersion":"testExternal","extension":null}
`{"kind":"ExtensionType","apiVersion":"` + externalGV.String() + `","extension":null}
`,
},
}
for _, item := range table {
gotEncoded, err := scheme.EncodeToVersion(item.obj, "testExternal")
gotEncoded, err := scheme.EncodeToVersion(item.obj, externalGV.String())
if err != nil {
t.Errorf("unexpected error '%v' (%#v)", err, item.obj)
} else if e, a := item.encoded, string(gotEncoded); e != a {
@ -288,10 +299,14 @@ func TestExtensionMapping(t *testing.T) {
}
func TestEncode(t *testing.T) {
internalGV := unversioned.GroupVersion{Group: "test.group", Version: ""}
externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"}
scheme := runtime.NewScheme()
scheme.AddKnownTypeWithName("", "Simple", &InternalSimple{})
scheme.AddKnownTypeWithName("externalVersion", "Simple", &ExternalSimple{})
codec := runtime.CodecFor(scheme, "externalVersion")
scheme.AddInternalGroupVersion(internalGV)
scheme.AddKnownTypeWithName(internalGV.String(), "Simple", &InternalSimple{})
scheme.AddKnownTypeWithName(externalGV.String(), "Simple", &ExternalSimple{})
codec := runtime.CodecFor(scheme, externalGV.String())
test := &InternalSimple{
TestString: "I'm the same",
}