diff --git a/pkg/api/meta/restmapper_test.go b/pkg/api/meta/restmapper_test.go index 2c748d07c40..ed84849bc29 100644 --- a/pkg/api/meta/restmapper_test.go +++ b/pkg/api/meta/restmapper_test.go @@ -33,6 +33,10 @@ func (fakeCodec) Decode([]byte) (runtime.Object, error) { return nil, nil } +func (fakeCodec) DecodeToVersion([]byte, string) (runtime.Object, error) { + return nil, nil +} + func (fakeCodec) DecodeInto([]byte, runtime.Object) error { return nil } diff --git a/pkg/conversion/decode.go b/pkg/conversion/decode.go index bf099d96737..275b2cd9fff 100644 --- a/pkg/conversion/decode.go +++ b/pkg/conversion/decode.go @@ -50,7 +50,16 @@ 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) { - obj, version, kind, err := s.DecodeToVersionedObject(data) + return s.DecodeToVersion(data, s.InternalVersion) +} + +// DecodeToVersion converts a JSON string back into a pointer to an api object. +// Deduces the type based upon the fields added by the MetaInsertionFactory +// 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 "". +func (s *Scheme) DecodeToVersion(data []byte, version string) (interface{}, error) { + obj, sourceVersion, kind, err := s.DecodeToVersionedObject(data) if err != nil { return nil, err } @@ -60,12 +69,12 @@ func (s *Scheme) Decode(data []byte) (interface{}, error) { } // Convert if needed. - if s.InternalVersion != version { - objOut, err := s.NewObject(s.InternalVersion, kind) + if version != sourceVersion { + objOut, err := s.NewObject(version, kind) if err != nil { return nil, err } - flags, meta := s.generateConvertMeta(version, s.InternalVersion, obj) + flags, meta := s.generateConvertMeta(sourceVersion, version, obj) if err := s.converter.Convert(obj, objOut, flags, meta); err != nil { return nil, err } diff --git a/pkg/runtime/codec.go b/pkg/runtime/codec.go index 8577b02dbbe..93b7102eb69 100644 --- a/pkg/runtime/codec.go +++ b/pkg/runtime/codec.go @@ -77,3 +77,10 @@ type codecWrapper struct { func (c *codecWrapper) Encode(obj Object) ([]byte, error) { return c.EncodeToVersion(obj, c.version) } + +// TODO: Make this behaviour default when we move everyone away from +// the unversioned types. +// +// func (c *codecWrapper) Decode(data []byte) (Object, error) { +// return c.DecodeToVersion(data, c.version) +// } diff --git a/pkg/runtime/interfaces.go b/pkg/runtime/interfaces.go index 3cea83f80dc..51e9a86d79e 100644 --- a/pkg/runtime/interfaces.go +++ b/pkg/runtime/interfaces.go @@ -37,6 +37,7 @@ type ObjectCodec interface { // Decoder defines methods for deserializing API objects into a given type type Decoder interface { Decode(data []byte) (Object, error) + DecodeToVersion(data []byte, version string) (Object, error) DecodeInto(data []byte, obj Object) error DecodeIntoWithSpecifiedVersionKind(data []byte, obj Object, kind, version string) error } diff --git a/pkg/runtime/scheme.go b/pkg/runtime/scheme.go index a5620794c75..c03056a85c2 100644 --- a/pkg/runtime/scheme.go +++ b/pkg/runtime/scheme.go @@ -446,6 +446,19 @@ func (s *Scheme) Decode(data []byte) (Object, error) { return obj.(Object), nil } +// DecodeToVersion converts a YAML or JSON string back into a pointer to an api +// object. Deduces the type based upon the APIVersion and Kind fields, which +// are set by Encode. Only versioned objects (APIVersion != "") are +// accepted. The object will be converted into the in-memory versioned type +// requested before being returned. +func (s *Scheme) DecodeToVersion(data []byte, version string) (Object, error) { + obj, err := s.raw.DecodeToVersion(data, version) + if err != nil { + return nil, err + } + return obj.(Object), nil +} + // DecodeInto parses a YAML or JSON string and stores it in obj. Returns an error // if data.Kind is set and doesn't match the type of obj. Obj should be a // pointer to an api type. diff --git a/pkg/runtime/scheme_test.go b/pkg/runtime/scheme_test.go index 8eaebcfa885..8db2e125995 100644 --- a/pkg/runtime/scheme_test.go +++ b/pkg/runtime/scheme_test.go @@ -87,14 +87,15 @@ func TestScheme(t *testing.T) { TestString: "foo", } - // Test Encode, Decode, and DecodeInto + // Test Encode, Decode, DecodeInto, and DecodeToVersion obj := runtime.Object(simple) data, err := scheme.EncodeToVersion(obj, "externalVersion") obj2, err2 := scheme.Decode(data) obj3 := &InternalSimple{} err3 := scheme.DecodeInto(data, obj3) - if err != nil || err2 != nil { - t.Fatalf("Failure: '%v' '%v' '%v'", err, err2, err3) + obj4, err4 := scheme.DecodeToVersion(data, "externalVersion") + if err != nil || err2 != nil || err3 != nil || err4 != nil { + t.Fatalf("Failure: '%v' '%v' '%v' '%v'", err, err2, err3, err4) } if _, ok := obj2.(*InternalSimple); !ok { t.Fatalf("Got wrong type") @@ -105,6 +106,9 @@ func TestScheme(t *testing.T) { if e, a := simple, obj3; !reflect.DeepEqual(e, a) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", e, a) } + if _, ok := obj4.(*ExternalSimple); !ok { + t.Fatalf("Got wrong type") + } // Test Convert external := &ExternalSimple{} diff --git a/pkg/runtime/unstructured.go b/pkg/runtime/unstructured.go index 737026ea183..303300ccd0f 100644 --- a/pkg/runtime/unstructured.go +++ b/pkg/runtime/unstructured.go @@ -78,6 +78,10 @@ func (unstructuredJSONScheme) DecodeIntoWithSpecifiedVersionKind(data []byte, ob return nil } +func (unstructuredJSONScheme) DecodeToVersion(data []byte, version string) (Object, error) { + return nil, nil +} + func (unstructuredJSONScheme) DataVersionAndKind(data []byte) (version, kind string, err error) { obj := TypeMeta{} if err := json.Unmarshal(data, &obj); err != nil {