Commit 5c30f983 authored by k8s-merge-robot's avatar k8s-merge-robot

Merge pull request #25018 from smarterclayton/fast_conversion

Automatic merge from submit-queue Reduce allocations during conversion, enable new UnsafeConvertToVersion path Cleans up the conversion path to avoid a few unnecessary allocations, then creates a new UnsafeConvertToVersion path that will allow encode/decode to bypass copying the object for performance. In that subsequent PR, ConvertToVersion will start to call Copy() and we will refactor conversions to reuse as much of the existing object as possible. Also changes the unversioned.ObjectKind signature to not require allocations - speeds up a few common paths.
parents 08440b5d ea7e7a18
...@@ -50,11 +50,11 @@ func BenchmarkPodConversion(b *testing.B) { ...@@ -50,11 +50,11 @@ func BenchmarkPodConversion(b *testing.B) {
var result *api.Pod var result *api.Pod
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
pod := &items[i%width] pod := &items[i%width]
versionedObj, err := scheme.ConvertToVersion(pod, testapi.Default.GroupVersion().String()) versionedObj, err := scheme.UnsafeConvertToVersion(pod, *testapi.Default.GroupVersion())
if err != nil { if err != nil {
b.Fatalf("Conversion error: %v", err) b.Fatalf("Conversion error: %v", err)
} }
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String()) obj, err := scheme.UnsafeConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion())
if err != nil { if err != nil {
b.Fatalf("Conversion error: %v", err) b.Fatalf("Conversion error: %v", err)
} }
...@@ -76,11 +76,11 @@ func BenchmarkNodeConversion(b *testing.B) { ...@@ -76,11 +76,11 @@ func BenchmarkNodeConversion(b *testing.B) {
scheme := api.Scheme scheme := api.Scheme
var result *api.Node var result *api.Node
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
versionedObj, err := scheme.ConvertToVersion(&node, testapi.Default.GroupVersion().String()) versionedObj, err := scheme.UnsafeConvertToVersion(&node, *testapi.Default.GroupVersion())
if err != nil { if err != nil {
b.Fatalf("Conversion error: %v", err) b.Fatalf("Conversion error: %v", err)
} }
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String()) obj, err := scheme.UnsafeConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion())
if err != nil { if err != nil {
b.Fatalf("Conversion error: %v", err) b.Fatalf("Conversion error: %v", err)
} }
...@@ -104,11 +104,11 @@ func BenchmarkReplicationControllerConversion(b *testing.B) { ...@@ -104,11 +104,11 @@ func BenchmarkReplicationControllerConversion(b *testing.B) {
scheme := api.Scheme scheme := api.Scheme
var result *api.ReplicationController var result *api.ReplicationController
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
versionedObj, err := scheme.ConvertToVersion(&replicationController, testapi.Default.GroupVersion().String()) versionedObj, err := scheme.UnsafeConvertToVersion(&replicationController, *testapi.Default.GroupVersion())
if err != nil { if err != nil {
b.Fatalf("Conversion error: %v", err) b.Fatalf("Conversion error: %v", err)
} }
obj, err := scheme.ConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion().String()) obj, err := scheme.UnsafeConvertToVersion(versionedObj, testapi.Default.InternalGroupVersion())
if err != nil { if err != nil {
b.Fatalf("Conversion error: %v", err) b.Fatalf("Conversion error: %v", err)
} }
......
...@@ -123,33 +123,21 @@ type objectAccessor struct { ...@@ -123,33 +123,21 @@ type objectAccessor struct {
} }
func (obj objectAccessor) GetKind() string { func (obj objectAccessor) GetKind() string {
if gvk := obj.GetObjectKind().GroupVersionKind(); gvk != nil { return obj.GetObjectKind().GroupVersionKind().Kind
return gvk.Kind
}
return ""
} }
func (obj objectAccessor) SetKind(kind string) { func (obj objectAccessor) SetKind(kind string) {
gvk := obj.GetObjectKind().GroupVersionKind() gvk := obj.GetObjectKind().GroupVersionKind()
if gvk == nil {
gvk = &unversioned.GroupVersionKind{}
}
gvk.Kind = kind gvk.Kind = kind
obj.GetObjectKind().SetGroupVersionKind(gvk) obj.GetObjectKind().SetGroupVersionKind(gvk)
} }
func (obj objectAccessor) GetAPIVersion() string { func (obj objectAccessor) GetAPIVersion() string {
if gvk := obj.GetObjectKind().GroupVersionKind(); gvk != nil { return obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
return gvk.GroupVersion().String()
}
return ""
} }
func (obj objectAccessor) SetAPIVersion(version string) { func (obj objectAccessor) SetAPIVersion(version string) {
gvk := obj.GetObjectKind().GroupVersionKind() gvk := obj.GetObjectKind().GroupVersionKind()
if gvk == nil {
gvk = &unversioned.GroupVersionKind{}
}
gv, err := unversioned.ParseGroupVersion(version) gv, err := unversioned.ParseGroupVersion(version)
if err != nil { if err != nil {
gv = unversioned.GroupVersion{Version: version} gv = unversioned.GroupVersion{Version: version}
......
...@@ -253,10 +253,10 @@ type InternalObject struct { ...@@ -253,10 +253,10 @@ type InternalObject struct {
} }
func (obj *InternalObject) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *InternalObject) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *InternalObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *InternalObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind() obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *InternalObject) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *InternalObject) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind) return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
} }
...@@ -610,10 +610,10 @@ type MyAPIObject struct { ...@@ -610,10 +610,10 @@ type MyAPIObject struct {
} }
func (obj *MyAPIObject) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *MyAPIObject) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *MyAPIObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *MyAPIObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind() obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *MyAPIObject) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *MyAPIObject) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind) return unversioned.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
} }
......
...@@ -32,7 +32,7 @@ func (fakeConvertor) Convert(in, out interface{}) error { ...@@ -32,7 +32,7 @@ func (fakeConvertor) Convert(in, out interface{}) error {
return nil return nil
} }
func (fakeConvertor) ConvertToVersion(in runtime.Object, _ string) (runtime.Object, error) { func (fakeConvertor) ConvertToVersion(in runtime.Object, _ unversioned.GroupVersion) (runtime.Object, error) {
return in, nil return in, nil
} }
......
...@@ -54,10 +54,7 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) { ...@@ -54,10 +54,7 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) {
// if the object referenced is actually persisted, we can just get kind from meta // if the object referenced is actually persisted, we can just get kind from meta
// if we are building an object reference to something not yet persisted, we should fallback to scheme // if we are building an object reference to something not yet persisted, we should fallback to scheme
var kind string kind := gvk.Kind
if gvk != nil {
kind = gvk.Kind
}
if len(kind) == 0 { if len(kind) == 0 {
// TODO: this is wrong // TODO: this is wrong
gvk, err := Scheme.ObjectKind(obj) gvk, err := Scheme.ObjectKind(obj)
...@@ -68,10 +65,7 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) { ...@@ -68,10 +65,7 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) {
} }
// if the object referenced is actually persisted, we can also get version from meta // if the object referenced is actually persisted, we can also get version from meta
var version string version := gvk.GroupVersion().String()
if gvk != nil {
version = gvk.GroupVersion().String()
}
if len(version) == 0 { if len(version) == 0 {
selfLink := meta.GetSelfLink() selfLink := meta.GetSelfLink()
if len(selfLink) == 0 { if len(selfLink) == 0 {
...@@ -111,9 +105,9 @@ func GetPartialReference(obj runtime.Object, fieldPath string) (*ObjectReference ...@@ -111,9 +105,9 @@ func GetPartialReference(obj runtime.Object, fieldPath string) (*ObjectReference
// IsAnAPIObject allows clients to preemptively get a reference to an API object and pass it to places that // IsAnAPIObject allows clients to preemptively get a reference to an API object and pass it to places that
// intend only to get a reference to that object. This simplifies the event recording interface. // intend only to get a reference to that object. This simplifies the event recording interface.
func (obj *ObjectReference) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *ObjectReference) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *ObjectReference) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *ObjectReference) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
...@@ -281,7 +281,7 @@ func TestObjectWatchFraming(t *testing.T) { ...@@ -281,7 +281,7 @@ func TestObjectWatchFraming(t *testing.T) {
secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00} secret.Data["binary"] = []byte{0x00, 0x10, 0x30, 0x55, 0xff, 0x00}
secret.Data["utf8"] = []byte("a string with \u0345 characters") secret.Data["utf8"] = []byte("a string with \u0345 characters")
secret.Data["long"] = bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x00}, 1000) secret.Data["long"] = bytes.Repeat([]byte{0x01, 0x02, 0x03, 0x00}, 1000)
converted, _ := api.Scheme.ConvertToVersion(secret, "v1") converted, _ := api.Scheme.ConvertToVersion(secret, v1.SchemeGroupVersion)
v1secret := converted.(*v1.Secret) v1secret := converted.(*v1.Secret)
for _, streamingMediaType := range api.Codecs.SupportedStreamingMediaTypes() { for _, streamingMediaType := range api.Codecs.SupportedStreamingMediaTypes() {
s, _ := api.Codecs.StreamingSerializerForMediaType(streamingMediaType, nil) s, _ := api.Codecs.StreamingSerializerForMediaType(streamingMediaType, nil)
...@@ -358,7 +358,7 @@ func benchmarkItems() []v1.Pod { ...@@ -358,7 +358,7 @@ func benchmarkItems() []v1.Pod {
for i := range items { for i := range items {
var pod api.Pod var pod api.Pod
apiObjectFuzzer.Fuzz(&pod) apiObjectFuzzer.Fuzz(&pod)
out, err := api.Scheme.ConvertToVersion(&pod, "v1") out, err := api.Scheme.ConvertToVersion(&pod, v1.SchemeGroupVersion)
if err != nil { if err != nil {
panic(err) panic(err)
} }
......
...@@ -259,11 +259,11 @@ func (gvk *GroupVersionKind) ToAPIVersionAndKind() (string, string) { ...@@ -259,11 +259,11 @@ func (gvk *GroupVersionKind) ToAPIVersionAndKind() (string, string) {
// do not use TypeMeta. This method exists to support test types and legacy serializations // do not use TypeMeta. This method exists to support test types and legacy serializations
// that have a distinct group and kind. // that have a distinct group and kind.
// TODO: further reduce usage of this method. // TODO: further reduce usage of this method.
func FromAPIVersionAndKind(apiVersion, kind string) *GroupVersionKind { func FromAPIVersionAndKind(apiVersion, kind string) GroupVersionKind {
if gv, err := ParseGroupVersion(apiVersion); err == nil { if gv, err := ParseGroupVersion(apiVersion); err == nil {
return &GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind} return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
} }
return &GroupVersionKind{Kind: kind} return GroupVersionKind{Kind: kind}
} }
// All objects that are serialized from a Scheme encode their type information. This interface is used // All objects that are serialized from a Scheme encode their type information. This interface is used
...@@ -273,10 +273,10 @@ func FromAPIVersionAndKind(apiVersion, kind string) *GroupVersionKind { ...@@ -273,10 +273,10 @@ func FromAPIVersionAndKind(apiVersion, kind string) *GroupVersionKind {
type ObjectKind interface { type ObjectKind interface {
// SetGroupVersionKind sets or clears the intended serialized kind of an object. Passing kind nil // SetGroupVersionKind sets or clears the intended serialized kind of an object. Passing kind nil
// should clear the current setting. // should clear the current setting.
SetGroupVersionKind(kind *GroupVersionKind) SetGroupVersionKind(kind GroupVersionKind)
// GroupVersionKind returns the stored group, version, and kind of an object, or nil if the object does // GroupVersionKind returns the stored group, version, and kind of an object, or nil if the object does
// not expose or provide these fields. // not expose or provide these fields.
GroupVersionKind() *GroupVersionKind GroupVersionKind() GroupVersionKind
} }
// EmptyObjectKind implements the ObjectKind interface as a noop // EmptyObjectKind implements the ObjectKind interface as a noop
...@@ -286,7 +286,7 @@ var EmptyObjectKind = emptyObjectKind{} ...@@ -286,7 +286,7 @@ var EmptyObjectKind = emptyObjectKind{}
type emptyObjectKind struct{} type emptyObjectKind struct{}
// SetGroupVersionKind implements the ObjectKind interface // SetGroupVersionKind implements the ObjectKind interface
func (emptyObjectKind) SetGroupVersionKind(gvk *GroupVersionKind) {} func (emptyObjectKind) SetGroupVersionKind(gvk GroupVersionKind) {}
// GroupVersionKind implements the ObjectKind interface // GroupVersionKind implements the ObjectKind interface
func (emptyObjectKind) GroupVersionKind() *GroupVersionKind { return nil } func (emptyObjectKind) GroupVersionKind() GroupVersionKind { return GroupVersionKind{} }
...@@ -25,12 +25,12 @@ func Kind(kind string) GroupKind { ...@@ -25,12 +25,12 @@ func Kind(kind string) GroupKind {
} }
// SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta // SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
func (obj *TypeMeta) SetGroupVersionKind(gvk *GroupVersionKind) { func (obj *TypeMeta) SetGroupVersionKind(gvk GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
// GroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta // GroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
func (obj *TypeMeta) GroupVersionKind() *GroupVersionKind { func (obj *TypeMeta) GroupVersionKind() GroupVersionKind {
return FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
......
...@@ -149,7 +149,7 @@ func validateOwnerReference(ownerReference api.OwnerReference, fldPath *field.Pa ...@@ -149,7 +149,7 @@ func validateOwnerReference(ownerReference api.OwnerReference, fldPath *field.Pa
if len(ownerReference.UID) == 0 { if len(ownerReference.UID) == 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), ownerReference.UID, "uid must not be empty")) allErrs = append(allErrs, field.Invalid(fldPath.Child("uid"), ownerReference.UID, "uid must not be empty"))
} }
if _, ok := BannedOwners[*gvk]; ok { if _, ok := BannedOwners[gvk]; ok {
allErrs = append(allErrs, field.Invalid(fldPath, ownerReference, fmt.Sprintf("%s is disallowed from being an owner", gvk))) allErrs = append(allErrs, field.Invalid(fldPath, ownerReference, fmt.Sprintf("%s is disallowed from being an owner", gvk)))
} }
return allErrs return allErrs
......
...@@ -264,7 +264,7 @@ func (c stripVersionEncoder) EncodeToStream(obj runtime.Object, w io.Writer, ove ...@@ -264,7 +264,7 @@ func (c stripVersionEncoder) EncodeToStream(obj runtime.Object, w io.Writer, ove
} }
gvk.Group = "" gvk.Group = ""
gvk.Version = "" gvk.Version = ""
roundTrippedObj.GetObjectKind().SetGroupVersionKind(gvk) roundTrippedObj.GetObjectKind().SetGroupVersionKind(*gvk)
return c.serializer.EncodeToStream(roundTrippedObj, w) return c.serializer.EncodeToStream(roundTrippedObj, w)
} }
......
...@@ -459,7 +459,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, typer runtime.ObjectTyper ...@@ -459,7 +459,7 @@ func PatchResource(r rest.Patcher, scope RequestScope, typer runtime.ObjectTyper
ctx := scope.ContextFunc(req) ctx := scope.ContextFunc(req)
ctx = api.WithNamespace(ctx, namespace) ctx = api.WithNamespace(ctx, namespace)
versionedObj, err := converter.ConvertToVersion(r.New(), scope.Kind.GroupVersion().String()) versionedObj, err := converter.ConvertToVersion(r.New(), scope.Kind.GroupVersion())
if err != nil { if err != nil {
scope.err(err, res.ResponseWriter, req.Request) scope.err(err, res.ResponseWriter, req.Request)
return return
......
...@@ -174,7 +174,7 @@ func (tc *patchTestCase) Run(t *testing.T) { ...@@ -174,7 +174,7 @@ func (tc *patchTestCase) Run(t *testing.T) {
namer := &testNamer{namespace, name} namer := &testNamer{namespace, name}
versionedObj, err := api.Scheme.ConvertToVersion(&api.Pod{}, "v1") versionedObj, err := api.Scheme.ConvertToVersion(&api.Pod{}, unversioned.GroupVersion{Version: "v1"})
if err != nil { if err != nil {
t.Errorf("%s: unexpected error: %v", tc.name, err) t.Errorf("%s: unexpected error: %v", tc.name, err)
return return
......
...@@ -35,9 +35,9 @@ func init() { ...@@ -35,9 +35,9 @@ func init() {
} }
func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *Config) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *Config) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *Config) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *Config) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
...@@ -32,9 +32,9 @@ func init() { ...@@ -32,9 +32,9 @@ func init() {
} }
func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *Config) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *Config) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *Config) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *Config) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *Config) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
...@@ -210,9 +210,6 @@ func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs { ...@@ -210,9 +210,6 @@ func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
// Meta is supplied by Scheme, when it calls Convert. // Meta is supplied by Scheme, when it calls Convert.
type Meta struct { type Meta struct {
SrcVersion string
DestVersion string
// KeyNameMapping is an optional function which may map the listed key (field name) // KeyNameMapping is an optional function which may map the listed key (field name)
// into a source and destination value. // into a source and destination value.
KeyNameMapping FieldMappingFunc KeyNameMapping FieldMappingFunc
......
...@@ -611,7 +611,7 @@ func TestConverter_meta(t *testing.T) { ...@@ -611,7 +611,7 @@ func TestConverter_meta(t *testing.T) {
checks := 0 checks := 0
err := c.RegisterConversionFunc( err := c.RegisterConversionFunc(
func(in *Foo, out *Bar, s Scope) error { func(in *Foo, out *Bar, s Scope) error {
if s.Meta() == nil || s.Meta().SrcVersion != "test" || s.Meta().DestVersion != "passes" { if s.Meta() == nil {
t.Errorf("Meta did not get passed!") t.Errorf("Meta did not get passed!")
} }
checks++ checks++
...@@ -624,7 +624,7 @@ func TestConverter_meta(t *testing.T) { ...@@ -624,7 +624,7 @@ func TestConverter_meta(t *testing.T) {
} }
err = c.RegisterConversionFunc( err = c.RegisterConversionFunc(
func(in *string, out *string, s Scope) error { func(in *string, out *string, s Scope) error {
if s.Meta() == nil || s.Meta().SrcVersion != "test" || s.Meta().DestVersion != "passes" { if s.Meta() == nil {
t.Errorf("Meta did not get passed a second time!") t.Errorf("Meta did not get passed a second time!")
} }
checks++ checks++
...@@ -634,7 +634,7 @@ func TestConverter_meta(t *testing.T) { ...@@ -634,7 +634,7 @@ func TestConverter_meta(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{SrcVersion: "test", DestVersion: "passes"}) err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{})
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("Unexpected error: %v", err)
} }
......
...@@ -174,8 +174,6 @@ func DeepCopy_conversion_Equalities(in Equalities, out *Equalities, c *Cloner) e ...@@ -174,8 +174,6 @@ func DeepCopy_conversion_Equalities(in Equalities, out *Equalities, c *Cloner) e
} }
func DeepCopy_conversion_Meta(in Meta, out *Meta, c *Cloner) error { func DeepCopy_conversion_Meta(in Meta, out *Meta, c *Cloner) error {
out.SrcVersion = in.SrcVersion
out.DestVersion = in.DestVersion
if in.KeyNameMapping == nil { if in.KeyNameMapping == nil {
out.KeyNameMapping = nil out.KeyNameMapping = nil
} else if newVal, err := c.DeepCopy(in.KeyNameMapping); err != nil { } else if newVal, err := c.DeepCopy(in.KeyNameMapping); err != nil {
......
...@@ -221,7 +221,7 @@ func (o AnnotateOptions) RunAnnotate() error { ...@@ -221,7 +221,7 @@ func (o AnnotateOptions) RunAnnotate() error {
return err return err
} }
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion().String()) obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
if err != nil { if err != nil {
return err return err
} }
......
...@@ -87,24 +87,24 @@ type ExternalType2 struct { ...@@ -87,24 +87,24 @@ type ExternalType2 struct {
} }
func (obj *internalType) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *internalType) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *internalType) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *internalType) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *internalType) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *internalType) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
func (obj *externalType) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *externalType) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *externalType) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *externalType) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *externalType) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *externalType) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
func (obj *ExternalType2) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *ExternalType2) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *ExternalType2) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *ExternalType2) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
func (obj *ExternalType2) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *ExternalType2) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
......
...@@ -167,7 +167,7 @@ func (o *ConvertOptions) RunConvert() error { ...@@ -167,7 +167,7 @@ func (o *ConvertOptions) RunConvert() error {
} }
infos := []*resource.Info{info} infos := []*resource.Info{info}
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String(), o.encoder) objects, err := resource.AsVersionedObject(infos, false, o.outputVersion, o.encoder)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -182,7 +182,7 @@ func RunEdit(f *cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args ...@@ -182,7 +182,7 @@ func RunEdit(f *cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
if err != nil { if err != nil {
return err return err
} }
objs, err := resource.AsVersionedObjects(infos, defaultVersion.String(), encoder) objs, err := resource.AsVersionedObjects(infos, defaultVersion, encoder)
if err != nil { if err != nil {
return err return err
} }
......
...@@ -246,7 +246,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -246,7 +246,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
if err != nil { if err != nil {
return err return err
} }
obj, err := resource.AsVersionedObject(infos, !singular, version.String(), f.JSONEncoder()) obj, err := resource.AsVersionedObject(infos, !singular, version, f.JSONEncoder())
if err != nil { if err != nil {
return err return err
} }
...@@ -273,7 +273,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string ...@@ -273,7 +273,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
} }
for ix := range infos { for ix := range infos {
objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version.String()) objs[ix], err = infos[ix].Mapping.ConvertToVersion(infos[ix].Object, version)
if err != nil { if err != nil {
allErrs = append(allErrs, err) allErrs = append(allErrs, err)
continue continue
......
...@@ -246,7 +246,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri ...@@ -246,7 +246,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
} }
outputObj = info.Object outputObj = info.Object
} else { } else {
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion().String()) obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
if err != nil { if err != nil {
return err return err
} }
......
...@@ -211,7 +211,7 @@ func (r *Result) Watch(resourceVersion string) (watch.Interface, error) { ...@@ -211,7 +211,7 @@ func (r *Result) Watch(resourceVersion string) (watch.Interface, error) {
// the objects as children, or if only a single Object is present, as that object. The provided // the objects as children, or if only a single Object is present, as that object. The provided
// version will be preferred as the conversion target, but the Object's mapping version will be // version will be preferred as the conversion target, but the Object's mapping version will be
// used if that version is not present. // used if that version is not present.
func AsVersionedObject(infos []*Info, forceList bool, version string, encoder runtime.Encoder) (runtime.Object, error) { func AsVersionedObject(infos []*Info, forceList bool, version unversioned.GroupVersion, encoder runtime.Encoder) (runtime.Object, error) {
objects, err := AsVersionedObjects(infos, version, encoder) objects, err := AsVersionedObjects(infos, version, encoder)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -222,7 +222,7 @@ func AsVersionedObject(infos []*Info, forceList bool, version string, encoder ru ...@@ -222,7 +222,7 @@ func AsVersionedObject(infos []*Info, forceList bool, version string, encoder ru
object = objects[0] object = objects[0]
} else { } else {
object = &api.List{Items: objects} object = &api.List{Items: objects}
converted, err := tryConvert(api.Scheme, object, version, registered.GroupOrDie(api.GroupName).GroupVersion.Version) converted, err := tryConvert(api.Scheme, object, version, registered.GroupOrDie(api.GroupName).GroupVersion)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -234,7 +234,7 @@ func AsVersionedObject(infos []*Info, forceList bool, version string, encoder ru ...@@ -234,7 +234,7 @@ func AsVersionedObject(infos []*Info, forceList bool, version string, encoder ru
// AsVersionedObjects converts a list of infos into versioned objects. The provided // AsVersionedObjects converts a list of infos into versioned objects. The provided
// version will be preferred as the conversion target, but the Object's mapping version will be // version will be preferred as the conversion target, but the Object's mapping version will be
// used if that version is not present. // used if that version is not present.
func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder) ([]runtime.Object, error) { func AsVersionedObjects(infos []*Info, version unversioned.GroupVersion, encoder runtime.Encoder) ([]runtime.Object, error) {
objects := []runtime.Object{} objects := []runtime.Object{}
for _, info := range infos { for _, info := range infos {
if info.Object == nil { if info.Object == nil {
...@@ -250,7 +250,7 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder) ...@@ -250,7 +250,7 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder)
// objects that are not part of api.Scheme must be converted to JSON // objects that are not part of api.Scheme must be converted to JSON
// TODO: convert to map[string]interface{}, attach to runtime.Unknown? // TODO: convert to map[string]interface{}, attach to runtime.Unknown?
if len(version) > 0 { if !version.IsEmpty() {
if _, err := api.Scheme.ObjectKind(info.Object); runtime.IsNotRegisteredError(err) { if _, err := api.Scheme.ObjectKind(info.Object); runtime.IsNotRegisteredError(err) {
// TODO: ideally this would encode to version, but we don't expose multiple codecs here. // TODO: ideally this would encode to version, but we don't expose multiple codecs here.
data, err := runtime.Encode(encoder, info.Object) data, err := runtime.Encode(encoder, info.Object)
...@@ -263,7 +263,7 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder) ...@@ -263,7 +263,7 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder)
} }
} }
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.GroupVersionKind.GroupVersion().String()) converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.GroupVersionKind.GroupVersion())
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -274,10 +274,10 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder) ...@@ -274,10 +274,10 @@ func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder)
// tryConvert attempts to convert the given object to the provided versions in order. This function assumes // tryConvert attempts to convert the given object to the provided versions in order. This function assumes
// the object is in internal version. // the object is in internal version.
func tryConvert(convertor runtime.ObjectConvertor, object runtime.Object, versions ...string) (runtime.Object, error) { func tryConvert(convertor runtime.ObjectConvertor, object runtime.Object, versions ...unversioned.GroupVersion) (runtime.Object, error) {
var last error var last error
for _, version := range versions { for _, version := range versions {
if len(version) == 0 { if version.IsEmpty() {
return object, nil return object, nil
} }
obj, err := convertor.ConvertToVersion(object, version) obj, err := convertor.ConvertToVersion(object, version)
......
...@@ -182,7 +182,7 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error { ...@@ -182,7 +182,7 @@ func (p *VersionedPrinter) PrintObj(obj runtime.Object, w io.Writer) error {
if version.IsEmpty() { if version.IsEmpty() {
continue continue
} }
converted, err := p.convertor.ConvertToVersion(obj, version.String()) converted, err := p.convertor.ConvertToVersion(obj, version)
if runtime.IsNotRegisteredError(err) { if runtime.IsNotRegisteredError(err) {
continue continue
} }
......
...@@ -105,7 +105,7 @@ func TestPrinter(t *testing.T) { ...@@ -105,7 +105,7 @@ func TestPrinter(t *testing.T) {
}, },
} }
emptyListTest := &api.PodList{} emptyListTest := &api.PodList{}
testapi, err := api.Scheme.ConvertToVersion(podTest, testapi.Default.GroupVersion().String()) testapi, err := api.Scheme.ConvertToVersion(podTest, *testapi.Default.GroupVersion())
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
......
...@@ -40,7 +40,7 @@ type thirdPartyObjectConverter struct { ...@@ -40,7 +40,7 @@ type thirdPartyObjectConverter struct {
converter runtime.ObjectConvertor converter runtime.ObjectConvertor
} }
func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersion string) (out runtime.Object, err error) { func (t *thirdPartyObjectConverter) ConvertToVersion(in runtime.Object, outVersion unversioned.GroupVersion) (out runtime.Object, err error) {
switch in.(type) { switch in.(type) {
// This seems weird, but in this case the ThirdPartyResourceData is really just a wrapper on the raw 3rd party data. // This seems weird, but in this case the ThirdPartyResourceData is really just a wrapper on the raw 3rd party data.
// The actual thing printed/sent to server is the actual raw third party resource data, which only has one version. // The actual thing printed/sent to server is the actual raw third party resource data, which only has one version.
......
...@@ -162,7 +162,7 @@ func (c *parameterCodec) EncodeParameters(obj Object, to unversioned.GroupVersio ...@@ -162,7 +162,7 @@ func (c *parameterCodec) EncodeParameters(obj Object, to unversioned.GroupVersio
return nil, err return nil, err
} }
if to != gvk.GroupVersion() { if to != gvk.GroupVersion() {
out, err := c.convertor.ConvertToVersion(obj, to.String()) out, err := c.convertor.ConvertToVersion(obj, to)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -43,10 +43,31 @@ func (t objectTyperToTyper) ObjectKind(obj Object) (*unversioned.GroupVersionKin ...@@ -43,10 +43,31 @@ func (t objectTyperToTyper) ObjectKind(obj Object) (*unversioned.GroupVersionKin
return &gvk, unversionedType, nil return &gvk, unversionedType, nil
} }
// ObjectTyperToTyper casts the old typer interface to the new typer interface
func ObjectTyperToTyper(typer ObjectTyper) Typer { func ObjectTyperToTyper(typer ObjectTyper) Typer {
return objectTyperToTyper{typer: typer} return objectTyperToTyper{typer: typer}
} }
// unsafeObjectConvertor implements ObjectConvertor using the unsafe conversion path.
type unsafeObjectConvertor struct {
*Scheme
}
var _ ObjectConvertor = unsafeObjectConvertor{}
// ConvertToVersion converts in to the provided outVersion without copying the input first, which
// is only safe if the output object is not mutated or reused.
func (c unsafeObjectConvertor) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
return c.Scheme.UnsafeConvertToVersion(in, outVersion)
}
// UnsafeObjectConvertor performs object conversion without copying the object structure,
// for use when the converted object will not be reused or mutated. Primarily for use within
// versioned codecs, which use the external object for serialization but do not return it.
func UnsafeObjectConvertor(scheme *Scheme) ObjectConvertor {
return unsafeObjectConvertor{scheme}
}
// fieldPtr puts the address of fieldName, which must be a member of v, // fieldPtr puts the address of fieldName, which must be a member of v,
// into dest, which must be an address of a variable to which this field's // into dest, which must be an address of a variable to which this field's
// address can be assigned. // address can be assigned.
......
...@@ -161,7 +161,7 @@ type StorageSerializer interface { ...@@ -161,7 +161,7 @@ type StorageSerializer interface {
// Non-codec interfaces // Non-codec interfaces
type ObjectVersioner interface { type ObjectVersioner interface {
ConvertToVersion(in Object, outVersion string) (out Object, err error) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (out Object, err error)
} }
// ObjectConvertor converts an object to a different version. // ObjectConvertor converts an object to a different version.
...@@ -171,7 +171,7 @@ type ObjectConvertor interface { ...@@ -171,7 +171,7 @@ type ObjectConvertor interface {
Convert(in, out interface{}) error Convert(in, out interface{}) error
// ConvertToVersion takes the provided object and converts it the provided version. This // ConvertToVersion takes the provided object and converts it the provided version. This
// method does not guarantee that the in object is not mutated. // method does not guarantee that the in object is not mutated.
ConvertToVersion(in Object, outVersion string) (out Object, err error) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (out Object, err error)
ConvertFieldLabel(version, kind, label, value string) (string, string, error) ConvertFieldLabel(version, kind, label, value string) (string, string, error)
} }
......
...@@ -21,12 +21,12 @@ import ( ...@@ -21,12 +21,12 @@ import (
) )
// SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta // SetGroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
func (obj *TypeMeta) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *TypeMeta) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
} }
// GroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta // GroupVersionKind satisfies the ObjectKind interface for all objects that embed TypeMeta
func (obj *TypeMeta) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *TypeMeta) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
} }
......
...@@ -124,11 +124,8 @@ func (s *Scheme) nameFunc(t reflect.Type) string { ...@@ -124,11 +124,8 @@ func (s *Scheme) nameFunc(t reflect.Type) string {
// fromScope gets the input version, desired output version, and desired Scheme // fromScope gets the input version, desired output version, and desired Scheme
// from a conversion.Scope. // from a conversion.Scope.
func (s *Scheme) fromScope(scope conversion.Scope) (inVersion, outVersion string, scheme *Scheme) { func (s *Scheme) fromScope(scope conversion.Scope) *Scheme {
scheme = s return s
inVersion = scope.Meta().SrcVersion
outVersion = scope.Meta().DestVersion
return inVersion, outVersion, scheme
} }
// Converter allows access to the converter for the scheme // Converter allows access to the converter for the scheme
...@@ -476,16 +473,12 @@ func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string, ...@@ -476,16 +473,12 @@ func (s *Scheme) ConvertFieldLabel(version, kind, label, value string) (string,
// contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also // contain the inKind (or a mapping by name defined with AddKnownTypeWithName). Will also
// return an error if the conversion does not result in a valid Object being // return an error if the conversion does not result in a valid Object being
// returned. The serializer handles loading/serializing nested objects. // returned. The serializer handles loading/serializing nested objects.
func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error) { func (s *Scheme) ConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
gv, err := unversioned.ParseGroupVersion(outVersion)
if err != nil {
return nil, err
}
switch in.(type) { switch in.(type) {
case *Unknown, *Unstructured, *UnstructuredList: case *Unknown, *Unstructured, *UnstructuredList:
old := in.GetObjectKind().GroupVersionKind() old := in.GetObjectKind().GroupVersionKind()
defer in.GetObjectKind().SetGroupVersionKind(old) defer in.GetObjectKind().SetGroupVersionKind(old)
setTargetVersion(in, s, gv) setTargetVersion(in, s, outVersion)
return in, nil return in, nil
} }
t := reflect.TypeOf(in) t := reflect.TypeOf(in)
...@@ -509,7 +502,7 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error) ...@@ -509,7 +502,7 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error)
kind = kinds[0] kind = kinds[0]
} }
outKind := gv.WithKind(kind.Kind) outKind := outVersion.WithKind(kind.Kind)
inKind, err := s.ObjectKind(in) inKind, err := s.ObjectKind(in)
if err != nil { if err != nil {
...@@ -521,29 +514,106 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error) ...@@ -521,29 +514,106 @@ func (s *Scheme) ConvertToVersion(in Object, outVersion string) (Object, error)
return nil, err return nil, err
} }
flags, meta := s.generateConvertMeta(inKind.GroupVersion(), gv, in) flags, meta := s.generateConvertMeta(inKind.GroupVersion(), outVersion, in)
if err := s.converter.Convert(in, out, flags, meta); err != nil { if err := s.converter.Convert(in, out, flags, meta); err != nil {
return nil, err return nil, err
} }
setTargetVersion(out, s, gv) setTargetVersion(out, s, outVersion)
return out, nil
}
// UnsafeConvertToVersion will convert in to the provided outVersion if such a conversion is possible,
// but does not guarantee the output object does not share fields with the input object. It attempts to be as
// efficient as possible when doing conversion.
func (s *Scheme) UnsafeConvertToVersion(in Object, outVersion unversioned.GroupVersion) (Object, error) {
switch t := in.(type) {
case *Unknown:
t.APIVersion = outVersion.String()
return t, nil
case *Unstructured:
t.SetAPIVersion(outVersion.String())
return t, nil
case *UnstructuredList:
t.SetAPIVersion(outVersion.String())
return t, nil
}
// determine the incoming kinds with as few allocations as possible.
t := reflect.TypeOf(in)
if t.Kind() != reflect.Ptr {
return nil, fmt.Errorf("only pointer types may be converted: %v", t)
}
t = t.Elem()
if t.Kind() != reflect.Struct {
return nil, fmt.Errorf("only pointers to struct types may be converted: %v", t)
}
kinds, ok := s.typeToGVK[t]
if !ok || len(kinds) == 0 {
return nil, fmt.Errorf("%v is not a registered type and cannot be converted into version %q", t, outVersion)
}
// if the Go type is also registered to the destination kind, no conversion is necessary
for i := range kinds {
if kinds[i].Version == outVersion.Version && kinds[i].Group == outVersion.Group {
setTargetKind(in, kinds[i])
return in, nil
}
}
// type is unversioned, no conversion necessary
// it should be possible to avoid this allocation
if unversionedKind, ok := s.unversionedTypes[t]; ok {
kind := unversionedKind
outKind := outVersion.WithKind(kind.Kind)
setTargetKind(in, outKind)
return in, nil
}
// allocate a new object as the target using the target kind
// TODO: this should look in the target group version and find the first kind that matches, rather than the
// first kind registered in typeToGVK
kind := kinds[0]
kind.Version = outVersion.Version
kind.Group = outVersion.Group
out, err := s.New(kind)
if err != nil {
return nil, err
}
// TODO: try to avoid the allocations here - in fast paths we are not likely to need these flags or meta
flags, meta := s.converter.DefaultMeta(t)
if err := s.converter.Convert(in, out, flags, meta); err != nil {
return nil, err
}
setTargetKind(out, kind)
return out, nil return out, nil
} }
// generateConvertMeta constructs the meta value we pass to Convert. // generateConvertMeta constructs the meta value we pass to Convert.
func (s *Scheme) generateConvertMeta(srcGroupVersion, destGroupVersion unversioned.GroupVersion, in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) { func (s *Scheme) generateConvertMeta(srcGroupVersion, destGroupVersion unversioned.GroupVersion, in interface{}) (conversion.FieldMatchingFlags, *conversion.Meta) {
flags, meta := s.converter.DefaultMeta(reflect.TypeOf(in)) return s.converter.DefaultMeta(reflect.TypeOf(in))
meta.SrcVersion = srcGroupVersion.String()
meta.DestVersion = destGroupVersion.String()
return flags, meta
} }
// setTargetVersion is deprecated and should be replaced by use of setTargetKind
func setTargetVersion(obj Object, raw *Scheme, gv unversioned.GroupVersion) { func setTargetVersion(obj Object, raw *Scheme, gv unversioned.GroupVersion) {
if gv.Version == APIVersionInternal { if gv.Version == APIVersionInternal {
// internal is a special case // internal is a special case
obj.GetObjectKind().SetGroupVersionKind(nil) obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{})
} else { return
gvk, _ := raw.ObjectKind(obj) }
obj.GetObjectKind().SetGroupVersionKind(&unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvk.Kind}) gvk, _ := raw.ObjectKind(obj)
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: gvk.Kind})
}
// setTargetKind sets the kind on an object, taking into account whether the target kind is the internal version.
func setTargetKind(obj Object, kind unversioned.GroupVersionKind) {
if kind.Version == APIVersionInternal {
// internal is a special case
// TODO: look at removing the need to special case this
obj.GetObjectKind().SetGroupVersionKind(unversioned.GroupVersionKind{})
return
} }
obj.GetObjectKind().SetGroupVersionKind(kind)
} }
...@@ -65,24 +65,12 @@ func TestScheme(t *testing.T) { ...@@ -65,24 +65,12 @@ func TestScheme(t *testing.T) {
// Register functions to verify that scope.Meta() gets set correctly. // Register functions to verify that scope.Meta() gets set correctly.
err := scheme.AddConversionFuncs( err := scheme.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error { func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
if e, a := internalGV.String(), scope.Meta().SrcVersion; e != a {
t.Errorf("Expected '%v', got '%v'", 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) scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
scope.Convert(&in.TestString, &out.TestString, 0) scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++ internalToExternalCalls++
return nil return nil
}, },
func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error { func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error {
if e, a := externalGV.String(), scope.Meta().SrcVersion; e != a {
t.Errorf("Expected '%v', got '%v'", 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) scope.Convert(&in.TypeMeta, &out.TypeMeta, 0)
scope.Convert(&in.TestString, &out.TestString, 0) scope.Convert(&in.TestString, &out.TestString, 0)
externalToInternalCalls++ externalToInternalCalls++
...@@ -472,10 +460,10 @@ type ExternalInternalSame struct { ...@@ -472,10 +460,10 @@ type ExternalInternalSame struct {
} }
func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind()
} }
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind)
} }
...@@ -542,7 +530,7 @@ func TestKnownTypes(t *testing.T) { ...@@ -542,7 +530,7 @@ func TestKnownTypes(t *testing.T) {
func TestConvertToVersion(t *testing.T) { func TestConvertToVersion(t *testing.T) {
s := GetTestScheme() s := GetTestScheme()
tt := &TestType1{A: "I'm not a pointer object"} tt := &TestType1{A: "I'm not a pointer object"}
other, err := s.ConvertToVersion(tt, "v1") other, err := s.ConvertToVersion(tt, unversioned.GroupVersion{Version: "v1"})
if err != nil { if err != nil {
t.Fatalf("Failure: %v", err) t.Fatalf("Failure: %v", err)
} }
...@@ -570,24 +558,12 @@ func TestMetaValues(t *testing.T) { ...@@ -570,24 +558,12 @@ func TestMetaValues(t *testing.T) {
err := s.AddConversionFuncs( err := s.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error { func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
t.Logf("internal -> external") t.Logf("internal -> external")
if e, a := internalGV.String(), scope.Meta().SrcVersion; e != a {
t.Fatalf("Expected '%v', got '%v'", 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) scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++ internalToExternalCalls++
return nil return nil
}, },
func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error { func(in *ExternalSimple, out *InternalSimple, scope conversion.Scope) error {
t.Logf("external -> internal") t.Logf("external -> internal")
if e, a := externalGV.String(), scope.Meta().SrcVersion; e != a {
t.Errorf("Expected '%v', got '%v'", 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) scope.Convert(&in.TestString, &out.TestString, 0)
externalToInternalCalls++ externalToInternalCalls++
return nil return nil
...@@ -602,12 +578,12 @@ func TestMetaValues(t *testing.T) { ...@@ -602,12 +578,12 @@ func TestMetaValues(t *testing.T) {
s.Log(t) s.Log(t)
out, err := s.ConvertToVersion(simple, externalGV.String()) out, err := s.ConvertToVersion(simple, externalGV)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
internal, err := s.ConvertToVersion(out, internalGV.String()) internal, err := s.ConvertToVersion(out, internalGV)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
...@@ -643,12 +619,6 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) { ...@@ -643,12 +619,6 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
// Register functions to verify that scope.Meta() gets set correctly. // Register functions to verify that scope.Meta() gets set correctly.
err := s.AddConversionFuncs( err := s.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error { func(in *InternalSimple, out *ExternalSimple, scope conversion.Scope) error {
if e, a := "unknown/unknown", scope.Meta().SrcVersion; e != a {
t.Fatalf("Expected '%v', got '%v'", e, a)
}
if e, a := "unknown/unknown", scope.Meta().DestVersion; e != a {
t.Fatalf("Expected '%v', got '%v'", e, a)
}
scope.Convert(&in.TestString, &out.TestString, 0) scope.Convert(&in.TestString, &out.TestString, 0)
internalToExternalCalls++ internalToExternalCalls++
return nil return nil
......
...@@ -129,10 +129,10 @@ var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs( ...@@ -129,10 +129,10 @@ var TestObjectFuzzer = fuzz.New().NilChance(.5).NumElements(1, 100).Funcs(
) )
func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() unversioned.ObjectKind { return obj } func (obj *MyWeirdCustomEmbeddedVersionKindField) GetObjectKind() unversioned.ObjectKind { return obj }
func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (obj *MyWeirdCustomEmbeddedVersionKindField) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind() obj.APIVersion, obj.ObjectKind = gvk.ToAPIVersionAndKind()
} }
func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() *unversioned.GroupVersionKind { func (obj *MyWeirdCustomEmbeddedVersionKindField) GroupVersionKind() unversioned.GroupVersionKind {
return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind) return unversioned.FromAPIVersionAndKind(obj.APIVersion, obj.ObjectKind)
} }
......
...@@ -111,7 +111,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi ...@@ -111,7 +111,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
if unk, ok := into.(*runtime.Unknown); ok && unk != nil { if unk, ok := into.(*runtime.Unknown); ok && unk != nil {
unk.Raw = originalData unk.Raw = originalData
unk.ContentType = runtime.ContentTypeJSON unk.ContentType = runtime.ContentTypeJSON
unk.GetObjectKind().SetGroupVersionKind(actual) unk.GetObjectKind().SetGroupVersionKind(*actual)
return unk, actual, nil return unk, actual, nil
} }
......
...@@ -31,12 +31,12 @@ import ( ...@@ -31,12 +31,12 @@ import (
type testDecodable struct { type testDecodable struct {
Other string Other string
Value int `json:"value"` Value int `json:"value"`
gvk *unversioned.GroupVersionKind gvk unversioned.GroupVersionKind
} }
func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d } func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
func (d *testDecodable) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { d.gvk = gvk } func (d *testDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
func (d *testDecodable) GroupVersionKind() *unversioned.GroupVersionKind { return d.gvk } func (d *testDecodable) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
func TestDecode(t *testing.T) { func TestDecode(t *testing.T) {
testCases := []struct { testCases := []struct {
...@@ -76,34 +76,28 @@ func TestDecode(t *testing.T) { ...@@ -76,34 +76,28 @@ func TestDecode(t *testing.T) {
errFn: func(err error) bool { return err.Error() == "fake error" }, errFn: func(err error) bool { return err.Error() == "fake error" },
}, },
{ {
data: []byte("{}"), data: []byte("{}"),
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
creater: &mockCreater{obj: &testDecodable{}}, creater: &mockCreater{obj: &testDecodable{}},
expectedObject: &testDecodable{ expectedObject: &testDecodable{},
gvk: nil, // json serializer does NOT set GVK expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
},
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
}, },
// version without group is not defaulted // version without group is not defaulted
{ {
data: []byte(`{"apiVersion":"blah"}`), data: []byte(`{"apiVersion":"blah"}`),
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
creater: &mockCreater{obj: &testDecodable{}}, creater: &mockCreater{obj: &testDecodable{}},
expectedObject: &testDecodable{ expectedObject: &testDecodable{},
gvk: nil, // json serializer does NOT set GVK expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
},
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "", Version: "blah"},
}, },
// group without version is defaulted // group without version is defaulted
{ {
data: []byte(`{"apiVersion":"other/"}`), data: []byte(`{"apiVersion":"other/"}`),
defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}, defaultGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
creater: &mockCreater{obj: &testDecodable{}}, creater: &mockCreater{obj: &testDecodable{}},
expectedObject: &testDecodable{ expectedObject: &testDecodable{},
gvk: nil, // json serializer does NOT set GVK expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
},
expectedGVK: &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"},
}, },
// accept runtime.Unknown as into and bypass creator // accept runtime.Unknown as into and bypass creator
......
...@@ -120,14 +120,14 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi ...@@ -120,14 +120,14 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
} }
actual := unk.GroupVersionKind() actual := unk.GroupVersionKind()
copyKindDefaults(actual, gvk) copyKindDefaults(&actual, gvk)
if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil { if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil {
*intoUnknown = unk *intoUnknown = unk
if len(intoUnknown.ContentType) == 0 { if len(intoUnknown.ContentType) == 0 {
intoUnknown.ContentType = s.contentType intoUnknown.ContentType = s.contentType
} }
return intoUnknown, actual, nil return intoUnknown, &actual, nil
} }
if into != nil { if into != nil {
...@@ -136,16 +136,16 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi ...@@ -136,16 +136,16 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
case runtime.IsNotRegisteredError(err): case runtime.IsNotRegisteredError(err):
pb, ok := into.(proto.Message) pb, ok := into.(proto.Message)
if !ok { if !ok {
return nil, actual, errNotMarshalable{reflect.TypeOf(into)} return nil, &actual, errNotMarshalable{reflect.TypeOf(into)}
} }
if err := proto.Unmarshal(unk.Raw, pb); err != nil { if err := proto.Unmarshal(unk.Raw, pb); err != nil {
return nil, actual, err return nil, &actual, err
} }
return into, actual, nil return into, &actual, nil
case err != nil: case err != nil:
return nil, actual, err return nil, &actual, err
default: default:
copyKindDefaults(actual, typed) copyKindDefaults(&actual, typed)
// if the result of defaulting did not set a version or group, ensure that at least group is set // if the result of defaulting did not set a version or group, ensure that at least group is set
// (copyKindDefaults will not assign Group if version is already set). This guarantees that the group // (copyKindDefaults will not assign Group if version is already set). This guarantees that the group
// of into is set if there is no better information from the caller or object. // of into is set if there is no better information from the caller or object.
...@@ -156,25 +156,24 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi ...@@ -156,25 +156,24 @@ func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKi
} }
if len(actual.Kind) == 0 { if len(actual.Kind) == 0 {
return nil, actual, runtime.NewMissingKindErr(fmt.Sprintf("%#v", unk.TypeMeta)) return nil, &actual, runtime.NewMissingKindErr(fmt.Sprintf("%#v", unk.TypeMeta))
} }
if len(actual.Version) == 0 { if len(actual.Version) == 0 {
return nil, actual, runtime.NewMissingVersionErr(fmt.Sprintf("%#v", unk.TypeMeta)) return nil, &actual, runtime.NewMissingVersionErr(fmt.Sprintf("%#v", unk.TypeMeta))
} }
return unmarshalToObject(s.typer, s.creater, actual, into, unk.Raw) return unmarshalToObject(s.typer, s.creater, &actual, into, unk.Raw)
} }
// EncodeToStream serializes the provided object to the given writer. Overrides is ignored. // EncodeToStream serializes the provided object to the given writer. Overrides is ignored.
func (s *Serializer) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unversioned.GroupVersion) error { func (s *Serializer) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unversioned.GroupVersion) error {
var unk runtime.Unknown var unk runtime.Unknown
if kind := obj.GetObjectKind().GroupVersionKind(); kind != nil { kind := obj.GetObjectKind().GroupVersionKind()
unk = runtime.Unknown{ unk = runtime.Unknown{
TypeMeta: runtime.TypeMeta{ TypeMeta: runtime.TypeMeta{
Kind: kind.Kind, Kind: kind.Kind,
APIVersion: kind.GroupVersion().String(), APIVersion: kind.GroupVersion().String(),
}, },
}
} }
prefixSize := uint64(len(s.prefix)) prefixSize := uint64(len(s.prefix))
...@@ -334,7 +333,7 @@ func (s *RawSerializer) Decode(originalData []byte, gvk *unversioned.GroupVersio ...@@ -334,7 +333,7 @@ func (s *RawSerializer) Decode(originalData []byte, gvk *unversioned.GroupVersio
intoUnknown.Raw = data intoUnknown.Raw = data
intoUnknown.ContentEncoding = "" intoUnknown.ContentEncoding = ""
intoUnknown.ContentType = s.contentType intoUnknown.ContentType = s.contentType
intoUnknown.SetGroupVersionKind(actual) intoUnknown.SetGroupVersionKind(*actual)
return intoUnknown, actual, nil return intoUnknown, actual, nil
} }
......
...@@ -34,12 +34,12 @@ import ( ...@@ -34,12 +34,12 @@ import (
) )
type testObject struct { type testObject struct {
gvk *unversioned.GroupVersionKind gvk unversioned.GroupVersionKind
} }
func (d *testObject) GetObjectKind() unversioned.ObjectKind { return d } func (d *testObject) GetObjectKind() unversioned.ObjectKind { return d }
func (d *testObject) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { d.gvk = gvk } func (d *testObject) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
func (d *testObject) GroupVersionKind() *unversioned.GroupVersionKind { return d.gvk } func (d *testObject) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
type testMarshalable struct { type testMarshalable struct {
testObject testObject
...@@ -106,7 +106,7 @@ func TestEncode(t *testing.T) { ...@@ -106,7 +106,7 @@ func TestEncode(t *testing.T) {
0x22, 0x00, // content-encoding 0x22, 0x00, // content-encoding
} }
obj2 := &testMarshalable{ obj2 := &testMarshalable{
testObject: testObject{gvk: &unversioned.GroupVersionKind{Kind: "test", Group: "other", Version: "version"}}, testObject: testObject{gvk: unversioned.GroupVersionKind{Kind: "test", Group: "other", Version: "version"}},
data: []byte{0x01, 0x02, 0x03}, data: []byte{0x01, 0x02, 0x03},
} }
wire2 := []byte{ wire2 := []byte{
......
...@@ -71,7 +71,7 @@ func NewCodecForScheme( ...@@ -71,7 +71,7 @@ func NewCodecForScheme(
encodeVersion []unversioned.GroupVersion, encodeVersion []unversioned.GroupVersion,
decodeVersion []unversioned.GroupVersion, decodeVersion []unversioned.GroupVersion,
) runtime.Codec { ) runtime.Codec {
return NewCodec(encoder, decoder, scheme, scheme, scheme, runtime.ObjectTyperToTyper(scheme), encodeVersion, decodeVersion) return NewCodec(encoder, decoder, runtime.UnsafeObjectConvertor(scheme), scheme, scheme, runtime.ObjectTyperToTyper(scheme), encodeVersion, decodeVersion)
} }
// NewCodec takes objects in their internal versions and converts them to external versions before // NewCodec takes objects in their internal versions and converts them to external versions before
...@@ -204,7 +204,7 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in ...@@ -204,7 +204,7 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
} }
// Convert if needed. // Convert if needed.
out, err := c.convertor.ConvertToVersion(obj, targetGV.String()) out, err := c.convertor.ConvertToVersion(obj, targetGV)
if err != nil { if err != nil {
return nil, gvk, err return nil, gvk, err
} }
...@@ -227,10 +227,12 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv ...@@ -227,10 +227,12 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv
} }
if (c.encodeVersion == nil && len(overrides) == 0) || isUnversioned { if (c.encodeVersion == nil && len(overrides) == 0) || isUnversioned {
old := obj.GetObjectKind().GroupVersionKind() objectKind := obj.GetObjectKind()
obj.GetObjectKind().SetGroupVersionKind(gvk) old := objectKind.GroupVersionKind()
defer obj.GetObjectKind().SetGroupVersionKind(old) objectKind.SetGroupVersionKind(*gvk)
return c.encoder.EncodeToStream(obj, w, overrides...) err = c.encoder.EncodeToStream(obj, w, overrides...)
objectKind.SetGroupVersionKind(old)
return err
} }
targetGV, ok := c.encodeVersion[gvk.Group] targetGV, ok := c.encodeVersion[gvk.Group]
...@@ -261,22 +263,21 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv ...@@ -261,22 +263,21 @@ func (c *codec) EncodeToStream(obj runtime.Object, w io.Writer, overrides ...unv
} }
// Perform a conversion if necessary // Perform a conversion if necessary
if gvk.GroupVersion() != targetGV { objectKind := obj.GetObjectKind()
out, err := c.convertor.ConvertToVersion(obj, targetGV.String()) old := objectKind.GroupVersionKind()
if err != nil { out, err := c.convertor.ConvertToVersion(obj, targetGV)
if ok { if err != nil {
return err if ok {
} return err
} else {
obj = out
} }
} else { } else {
old := obj.GetObjectKind().GroupVersionKind() obj = out
defer obj.GetObjectKind().SetGroupVersionKind(old)
obj.GetObjectKind().SetGroupVersionKind(&unversioned.GroupVersionKind{Group: targetGV.Group, Version: targetGV.Version, Kind: gvk.Kind})
} }
// Conversion is responsible for setting the proper group, version, and kind onto the outgoing object
return c.encoder.EncodeToStream(obj, w, overrides...) err = c.encoder.EncodeToStream(obj, w, overrides...)
// restore the old GVK, in case conversion returned the same object
objectKind.SetGroupVersionKind(old)
return err
} }
// promoteOrPrependGroupVersion finds the group version in the provided group versions that has the same group as target. // promoteOrPrependGroupVersion finds the group version in the provided group versions that has the same group as target.
......
...@@ -30,12 +30,12 @@ import ( ...@@ -30,12 +30,12 @@ import (
type testDecodable struct { type testDecodable struct {
Other string Other string
Value int `json:"value"` Value int `json:"value"`
gvk *unversioned.GroupVersionKind gvk unversioned.GroupVersionKind
} }
func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d } func (d *testDecodable) GetObjectKind() unversioned.ObjectKind { return d }
func (d *testDecodable) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { d.gvk = gvk } func (d *testDecodable) SetGroupVersionKind(gvk unversioned.GroupVersionKind) { d.gvk = gvk }
func (d *testDecodable) GroupVersionKind() *unversioned.GroupVersionKind { return d.gvk } func (d *testDecodable) GroupVersionKind() unversioned.GroupVersionKind { return d.gvk }
func TestDecode(t *testing.T) { func TestDecode(t *testing.T) {
gvk1 := &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"} gvk1 := &unversioned.GroupVersionKind{Kind: "Test", Group: "other", Version: "blah"}
...@@ -65,12 +65,12 @@ func TestDecode(t *testing.T) { ...@@ -65,12 +65,12 @@ func TestDecode(t *testing.T) {
}{ }{
{ {
serializer: &mockSerializer{actual: gvk1}, serializer: &mockSerializer{actual: gvk1},
convertor: &checkConvertor{groupVersion: "other/__internal"}, convertor: &checkConvertor{groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1, expectedGVK: gvk1,
}, },
{ {
serializer: &mockSerializer{actual: gvk1, obj: decodable1}, serializer: &mockSerializer{actual: gvk1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1, expectedGVK: gvk1,
sameObject: decodable2, sameObject: decodable2,
}, },
...@@ -78,7 +78,7 @@ func TestDecode(t *testing.T) { ...@@ -78,7 +78,7 @@ func TestDecode(t *testing.T) {
{ {
serializer: &mockSerializer{actual: gvk1, obj: decodable1}, serializer: &mockSerializer{actual: gvk1, obj: decodable1},
defaultGVK: &unversioned.GroupVersionKind{Group: "force"}, defaultGVK: &unversioned.GroupVersionKind{Group: "force"},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "force/__internal"}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "force", Version: "__internal"}},
expectedGVK: gvk1, expectedGVK: gvk1,
sameObject: decodable2, sameObject: decodable2,
}, },
...@@ -118,7 +118,7 @@ func TestDecode(t *testing.T) { ...@@ -118,7 +118,7 @@ func TestDecode(t *testing.T) {
serializer: &mockSerializer{actual: gvk1, obj: decodable1}, serializer: &mockSerializer{actual: gvk1, obj: decodable1},
copier: &checkCopy{in: decodable1, obj: decodable1}, copier: &checkCopy{in: decodable1, obj: decodable1},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1, expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}}, expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
}, },
...@@ -127,7 +127,7 @@ func TestDecode(t *testing.T) { ...@@ -127,7 +127,7 @@ func TestDecode(t *testing.T) {
serializer: &mockSerializer{actual: gvk1, obj: decodable1}, serializer: &mockSerializer{actual: gvk1, obj: decodable1},
copier: &checkCopy{in: decodable1, obj: nil, err: fmt.Errorf("error on copy")}, copier: &checkCopy{in: decodable1, obj: nil, err: fmt.Errorf("error on copy")},
convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: "other/__internal"}, convertor: &checkConvertor{in: decodable1, obj: decodable2, groupVersion: unversioned.GroupVersion{Group: "other", Version: "__internal"}},
expectedGVK: gvk1, expectedGVK: gvk1,
expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}}, expectedObject: &runtime.VersionedObjects{Objects: []runtime.Object{decodable1, decodable2}},
}, },
...@@ -228,7 +228,7 @@ func (c *checkCopy) Copy(obj runtime.Object) (runtime.Object, error) { ...@@ -228,7 +228,7 @@ func (c *checkCopy) Copy(obj runtime.Object) (runtime.Object, error) {
type checkConvertor struct { type checkConvertor struct {
err error err error
in, obj runtime.Object in, obj runtime.Object
groupVersion string groupVersion unversioned.GroupVersion
directConvert bool directConvert bool
} }
...@@ -244,7 +244,7 @@ func (c *checkConvertor) Convert(in, out interface{}) error { ...@@ -244,7 +244,7 @@ func (c *checkConvertor) Convert(in, out interface{}) error {
} }
return c.err return c.err
} }
func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion string) (out runtime.Object, err error) { func (c *checkConvertor) ConvertToVersion(in runtime.Object, outVersion unversioned.GroupVersion) (out runtime.Object, err error) {
if c.directConvert { if c.directConvert {
return nil, fmt.Errorf("unexpected call to ConvertToVersion") return nil, fmt.Errorf("unexpected call to ConvertToVersion")
} }
......
...@@ -301,18 +301,18 @@ func (u *Unstructured) SetAnnotations(annotations map[string]string) { ...@@ -301,18 +301,18 @@ func (u *Unstructured) SetAnnotations(annotations map[string]string) {
u.setNestedMap(annotations, "metadata", "annotations") u.setNestedMap(annotations, "metadata", "annotations")
} }
func (u *Unstructured) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (u *Unstructured) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
u.SetAPIVersion(gvk.GroupVersion().String()) u.SetAPIVersion(gvk.GroupVersion().String())
u.SetKind(gvk.Kind) u.SetKind(gvk.Kind)
} }
func (u *Unstructured) GroupVersionKind() *unversioned.GroupVersionKind { func (u *Unstructured) GroupVersionKind() unversioned.GroupVersionKind {
gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion()) gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion())
if err != nil { if err != nil {
return nil return unversioned.GroupVersionKind{}
} }
gvk := gv.WithKind(u.GetKind()) gvk := gv.WithKind(u.GetKind())
return &gvk return gvk
} }
// UnstructuredList allows lists that do not have Golang structs // UnstructuredList allows lists that do not have Golang structs
...@@ -364,18 +364,18 @@ func (u *UnstructuredList) SetSelfLink(selfLink string) { ...@@ -364,18 +364,18 @@ func (u *UnstructuredList) SetSelfLink(selfLink string) {
u.setNestedField(selfLink, "metadata", "selfLink") u.setNestedField(selfLink, "metadata", "selfLink")
} }
func (u *UnstructuredList) SetGroupVersionKind(gvk *unversioned.GroupVersionKind) { func (u *UnstructuredList) SetGroupVersionKind(gvk unversioned.GroupVersionKind) {
u.SetAPIVersion(gvk.GroupVersion().String()) u.SetAPIVersion(gvk.GroupVersion().String())
u.SetKind(gvk.Kind) u.SetKind(gvk.Kind)
} }
func (u *UnstructuredList) GroupVersionKind() *unversioned.GroupVersionKind { func (u *UnstructuredList) GroupVersionKind() unversioned.GroupVersionKind {
gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion()) gv, err := unversioned.ParseGroupVersion(u.GetAPIVersion())
if err != nil { if err != nil {
return nil return unversioned.GroupVersionKind{}
} }
gvk := gv.WithKind(u.GetKind()) gvk := gv.WithKind(u.GetKind())
return &gvk return gvk
} }
// VersionedObjects is used by Decoders to give callers a way to access all versions // VersionedObjects is used by Decoders to give callers a way to access all versions
......
...@@ -45,10 +45,10 @@ func (s unstructuredJSONScheme) Decode(data []byte, _ *unversioned.GroupVersionK ...@@ -45,10 +45,10 @@ func (s unstructuredJSONScheme) Decode(data []byte, _ *unversioned.GroupVersionK
gvk := obj.GetObjectKind().GroupVersionKind() gvk := obj.GetObjectKind().GroupVersionKind()
if len(gvk.Kind) == 0 { if len(gvk.Kind) == 0 {
return nil, gvk, NewMissingKindErr(string(data)) return nil, &gvk, NewMissingKindErr(string(data))
} }
return obj, gvk, nil return obj, &gvk, nil
} }
func (unstructuredJSONScheme) EncodeToStream(obj Object, w io.Writer, overrides ...unversioned.GroupVersion) error { func (unstructuredJSONScheme) EncodeToStream(obj Object, w io.Writer, overrides ...unversioned.GroupVersion) error {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment