Update ObjectTyper to GroupVersion

pull/6/head
deads2k 2015-11-20 07:38:32 -05:00
parent 33eda2ffb5
commit f764e0099c
31 changed files with 339 additions and 274 deletions

View File

@ -53,10 +53,11 @@ func GetReference(obj runtime.Object) (*ObjectReference, error) {
// if we are building an object reference to something not yet persisted, we should fallback to scheme
kind := meta.Kind()
if kind == "" {
_, kind, err = Scheme.ObjectVersionAndKind(obj)
gvk, err := Scheme.ObjectKind(obj)
if err != nil {
return nil, err
}
kind = gvk.Kind
}
// if the object referenced is actually persisted, we can also get version from meta

View File

@ -111,9 +111,9 @@ func objectMetaAndKind(typer runtime.ObjectTyper, obj runtime.Object) (*api.Obje
if err != nil {
return nil, "", errors.NewInternalError(err)
}
_, kind, err := typer.ObjectVersionAndKind(obj)
gvk, err := typer.ObjectKind(obj)
if err != nil {
return nil, "", errors.NewInternalError(err)
}
return objectMeta, kind, nil
return objectMeta, gvk.Kind, nil
}

View File

@ -63,6 +63,9 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se
func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) {
printer := spew.ConfigState{DisableMethods: true}
gvk, err := api.Scheme.ObjectKind(item)
t.Logf("fully qualified kind for %v is %v with codec %v", reflect.TypeOf(item), gvk, codec)
name := reflect.TypeOf(item).Elem().Name()
data, err := codec.Encode(item)
if err != nil {
@ -96,7 +99,7 @@ func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) {
func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
set := sets.NewString(except...)
seed := rand.Int63()
fuzzInternalObject(t, "", item, seed)
fuzzInternalObject(t, testapi.Default.InternalGroupVersion().String(), item, seed)
version := testapi.Default.VersionUnderTest
codecs := []runtime.Codec{}
@ -154,6 +157,7 @@ func TestRoundTripTypes(t *testing.T) {
// defer api.Scheme.Log(nil)
for kind := range api.Scheme.KnownTypes(testapi.Default.InternalGroupVersion()) {
t.Logf("working on %v in %v", kind, testapi.Default.InternalGroupVersion())
if nonRoundTrippableTypes.Has(kind) {
continue
}
@ -168,18 +172,18 @@ func TestRoundTripTypes(t *testing.T) {
}
func doRoundTripTest(kind string, t *testing.T) {
item, err := api.Scheme.New("", kind)
item, err := api.Scheme.New(testapi.Default.InternalGroupVersion().String(), kind)
if err != nil {
t.Fatalf("Couldn't make a %v? %v", kind, err)
}
if _, err := meta.TypeAccessor(item); err != nil {
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableTypes: %v", kind, err)
}
if api.Scheme.Recognizes(testapi.Default.VersionUnderTest, kind) {
if api.Scheme.Recognizes(testapi.Default.GroupVersion().WithKind(kind)) {
roundTripSame(t, item, nonRoundTrippableTypesByVersion[kind]...)
}
if !nonInternalRoundTrippableTypes.Has(kind) {
roundTrip(t, api.Codec, fuzzInternalObject(t, "", item, rand.Int63()))
roundTrip(t, api.Codec, fuzzInternalObject(t, testapi.Default.InternalGroupVersion().String(), item, rand.Int63()))
}
}

View File

@ -214,22 +214,23 @@ func (g TestGroup) RESTMapper() meta.RESTMapper {
// Get codec based on runtime.Object
func GetCodecForObject(obj runtime.Object) (runtime.Codec, error) {
_, kind, err := api.Scheme.ObjectVersionAndKind(obj)
gvk, err := api.Scheme.ObjectKind(obj)
if err != nil {
return nil, fmt.Errorf("unexpected encoding error: %v", err)
}
// TODO: caesarxuchao: we should detect which group an object belongs to
// by using the version returned by Schem.ObjectVersionAndKind() once we
// split the schemes for internal objects.
// TODO: caesarxuchao: we should add a map from kind to group in Scheme.
for _, group := range Groups {
if api.Scheme.Recognizes(group.GroupAndVersion(), kind) {
if group.GroupVersion().Group != gvk.Group {
continue
}
if api.Scheme.Recognizes(gvk) {
return group.Codec(), nil
}
}
// Codec used for unversioned types
if api.Scheme.Recognizes("", kind) {
if api.Scheme.Recognizes(gvk) {
return api.Codec, nil
}
return nil, fmt.Errorf("unexpected kind: %v", kind)
return nil, fmt.Errorf("unexpected kind: %v", gvk)
}

View File

@ -175,8 +175,10 @@ func FuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
// TODO: uncomment when round trip starts from a versioned object
if true { //c.RandBool() {
*j = &runtime.Unknown{
TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"},
RawJSON: []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`),
// apiVersion has rules now. Since it includes <group>/<version> and only `v1` can be bare,
// then this must choose a valid format to deserialize
TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown.group/unknown"},
RawJSON: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`),
}
} else {
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}

View File

@ -78,7 +78,7 @@ func (gvk GroupVersionKind) GroupVersion() GroupVersion {
return GroupVersion{Group: gvk.Group, Version: gvk.Version}
}
func (gvk *GroupVersionKind) String() string {
func (gvk GroupVersionKind) String() string {
return gvk.Group + "/" + gvk.Version + ", Kind=" + gvk.Kind
}

View File

@ -122,11 +122,31 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
hasSubresource := len(subresource) > 0
object := storage.New()
_, kind, err := a.group.Typer.ObjectVersionAndKind(object)
fqKinds, err := a.group.Typer.ObjectKinds(object)
if err != nil {
return nil, err
}
gvk := a.group.GroupVersion.WithKind(kind)
// a given go type can have multiple potential fully qualified kinds. Find the one that corresponds with the group
// we're trying to register here
fqKindToRegister := unversioned.GroupVersionKind{}
for _, fqKind := range fqKinds {
if fqKind.Group == a.group.GroupVersion.Group {
fqKindToRegister = fqKind
break
}
// TODO This keeps it doing what it was doing before, but it doesn't feel right.
if fqKind.Group == "extensions" && fqKind.Kind == "ThirdPartyResourceData" {
fqKindToRegister = fqKind
fqKindToRegister.Group = a.group.GroupVersion.Group
fqKindToRegister.Version = a.group.GroupVersion.Version
}
}
if fqKindToRegister.IsEmpty() {
return nil, fmt.Errorf("unable to locate fully qualified kind for %v: found %v when registering for %v", reflect.TypeOf(object), fqKinds, a.group.GroupVersion)
}
kind := fqKindToRegister.Kind
versionedPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), kind)
if err != nil {
@ -134,7 +154,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
}
versionedObject := indirectArbitraryPointer(versionedPtr)
mapping, err := a.group.Mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
mapping, err := a.group.Mapper.RESTMapping(fqKindToRegister.GroupKind(), a.group.GroupVersion.Version)
if err != nil {
return nil, err
}
@ -146,13 +166,25 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
return nil, fmt.Errorf("subresources can only be declared when the parent is also registered: %s needs %s", path, resource)
}
parentObject := parentStorage.New()
_, parentKind, err := a.group.Typer.ObjectVersionAndKind(parentObject)
parentFQKinds, err := a.group.Typer.ObjectKinds(parentObject)
if err != nil {
return nil, err
}
parentGVK := a.group.GroupVersion.WithKind(parentKind)
// a given go type can have multiple potential fully qualified kinds. Find the one that corresponds with the group
// we're trying to register here
parentFQKindToRegister := unversioned.GroupVersionKind{}
for _, fqKind := range parentFQKinds {
if fqKind.Group == a.group.GroupVersion.Group {
parentFQKindToRegister = fqKind
break
}
}
if parentFQKindToRegister.IsEmpty() {
return nil, fmt.Errorf("unable to locate fully qualified kind for %v: found %v when registering for %v", reflect.TypeOf(object), fqKinds, a.group.GroupVersion)
}
parentMapping, err := a.group.Mapper.RESTMapping(parentGVK.GroupKind(), parentGVK.Version)
parentMapping, err := a.group.Mapper.RESTMapping(parentFQKindToRegister.GroupKind(), a.group.GroupVersion.Version)
if err != nil {
return nil, err
}
@ -184,8 +216,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
var versionedList interface{}
if isLister {
list := lister.NewList()
_, listKind, err := a.group.Typer.ObjectVersionAndKind(list)
versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), listKind)
listGVK, err := a.group.Typer.ObjectKind(list)
versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), listGVK.Kind)
if err != nil {
return nil, err
}
@ -225,19 +257,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
)
if isGetterWithOptions {
getOptions, getSubpath, getSubpathKey = getterWithOptions.NewGetOptions()
getOptionsGVString, getOptionsKind, err := a.group.Typer.ObjectVersionAndKind(getOptions)
getOptionsInternalKind, err = a.group.Typer.ObjectKind(getOptions)
if err != nil {
return nil, err
}
gv, err := unversioned.ParseGroupVersion(getOptionsGVString)
if err != nil {
return nil, err
}
getOptionsInternalKind = gv.WithKind(getOptionsKind)
// TODO this should be a list of all the different external versions we can coerce into the internalKind
getOptionsExternalKind = serverGroupVersion.WithKind(getOptionsKind)
getOptionsExternalKind = serverGroupVersion.WithKind(getOptionsInternalKind.Kind)
versionedGetOptions, err = a.group.Creater.New(serverGroupVersion.String(), getOptionsKind)
versionedGetOptions, err = a.group.Creater.New(serverGroupVersion.String(), getOptionsInternalKind.Kind)
if err != nil {
return nil, err
}
@ -255,19 +282,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if isConnecter {
connectOptions, connectSubpath, connectSubpathKey = connecter.NewConnectOptions()
if connectOptions != nil {
connectOptionsGVString, connectOptionsKind, err := a.group.Typer.ObjectVersionAndKind(connectOptions)
connectOptionsInternalKind, err = a.group.Typer.ObjectKind(connectOptions)
if err != nil {
return nil, err
}
gv, err := unversioned.ParseGroupVersion(connectOptionsGVString)
if err != nil {
return nil, err
}
connectOptionsInternalKind = gv.WithKind(connectOptionsKind)
// TODO this should be a list of all the different external versions we can coerce into the internalKind
connectOptionsExternalKind = serverGroupVersion.WithKind(connectOptionsKind)
connectOptionsExternalKind = serverGroupVersion.WithKind(connectOptionsInternalKind.Kind)
versionedConnectOptions, err = a.group.Creater.New(serverGroupVersion.String(), connectOptionsKind)
versionedConnectOptions, err = a.group.Creater.New(serverGroupVersion.String(), connectOptionsInternalKind.Kind)
}
}

View File

@ -745,14 +745,14 @@ func finishRequest(timeout time.Duration, fn resultFunc) (result runtime.Object,
// transformDecodeError adds additional information when a decode fails.
func transformDecodeError(typer runtime.ObjectTyper, baseErr error, into runtime.Object, body []byte) error {
_, kind, err := typer.ObjectVersionAndKind(into)
objectGroupVersionKind, err := typer.ObjectKind(into)
if err != nil {
return err
}
if version, dataKind, err := typer.DataVersionAndKind(body); err == nil && len(dataKind) > 0 {
return errors.NewBadRequest(fmt.Sprintf("%s in version %s cannot be handled as a %s: %v", dataKind, version, kind, baseErr))
if dataGroupVersionKind, err := typer.DataKind(body); err == nil && len(dataGroupVersionKind.Kind) > 0 {
return errors.NewBadRequest(fmt.Sprintf("%s in version %v cannot be handled as a %s: %v", dataGroupVersionKind.Kind, dataGroupVersionKind.GroupVersion(), objectGroupVersionKind.Kind, baseErr))
}
return errors.NewBadRequest(fmt.Sprintf("the object provided is unrecognized (must be of type %s): %v", kind, baseErr))
return errors.NewBadRequest(fmt.Sprintf("the object provided is unrecognized (must be of type %s): %v", objectGroupVersionKind.Kind, baseErr))
}
// setSelfLink sets the self link of an object (or the child items in a list) to the base URL of the request

View File

@ -77,12 +77,12 @@ func NewFromFile(path string) (policyList, error) {
continue
}
version, kind, err := api.Scheme.DataVersionAndKind(b)
dataKind, err := api.Scheme.DataKind(b)
if err != nil {
return nil, policyLoadError{path, i, b, err}
}
if version == "" && kind == "" {
if dataKind.IsEmpty() {
unversionedLines++
// Migrate unversioned policy object
oldPolicy := &v0.Policy{}

View File

@ -207,7 +207,7 @@ func validateFields(a, b string) bool {
func body(t *testing.T, obj runtime.Object, raw *string) *string {
if obj != nil {
_, kind, err := api.Scheme.ObjectVersionAndKind(obj)
fqKind, err := api.Scheme.ObjectKind(obj)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
@ -216,18 +216,18 @@ func body(t *testing.T, obj runtime.Object, raw *string) *string {
// split the schemes for internal objects.
// TODO: caesarxuchao: we should add a map from kind to group in Scheme.
var bs []byte
if api.Scheme.Recognizes(testapi.Default.GroupAndVersion(), kind) {
if api.Scheme.Recognizes(testapi.Default.GroupVersion().WithKind(fqKind.Kind)) {
bs, err = testapi.Default.Codec().Encode(obj)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
} else if api.Scheme.Recognizes(testapi.Extensions.GroupAndVersion(), kind) {
} else if api.Scheme.Recognizes(testapi.Extensions.GroupVersion().WithKind(fqKind.Kind)) {
bs, err = testapi.Extensions.Codec().Encode(obj)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
}
} else {
t.Errorf("unexpected kind: %v", kind)
t.Errorf("unexpected kind: %v", fqKind.Kind)
}
body := string(bs)
return &body

View File

@ -210,10 +210,11 @@ func (o objects) Kind(gvk unversioned.GroupVersionKind, name string) (runtime.Ob
}
func (o objects) Add(obj runtime.Object) error {
_, kind, err := o.scheme.ObjectVersionAndKind(obj)
gvk, err := o.scheme.ObjectKind(obj)
if err != nil {
return err
}
kind := gvk.Kind
switch {
case meta.IsListType(obj):

View File

@ -27,28 +27,27 @@ import (
)
func (s *Scheme) DecodeToVersionedObject(data []byte) (interface{}, string, string, error) {
version, kind, err := s.DataVersionAndKind(data)
gvk, err := s.DataKind(data)
if err != nil {
return nil, "", "", err
}
gv, err := unversioned.ParseGroupVersion(version)
if err != nil {
return nil, "", "", err
}
internalGV, exists := s.InternalVersions[gv.Group]
internalGV, exists := s.InternalVersions[gvk.Group]
if !exists {
return nil, "", "", fmt.Errorf("no internalVersion specified for %v", gv)
return nil, "", "", fmt.Errorf("no internalVersion specified for %v", gvk)
}
if len(gv.Version) == 0 && len(internalGV.Version) != 0 {
if len(gvk.Group) == 0 && len(internalGV.Group) != 0 {
return nil, "", "", fmt.Errorf("group not set in '%s'", string(data))
}
if len(gvk.Version) == 0 && len(internalGV.Version) != 0 {
return nil, "", "", fmt.Errorf("version not set in '%s'", string(data))
}
if kind == "" {
if gvk.Kind == "" {
return nil, "", "", fmt.Errorf("kind not set in '%s'", string(data))
}
obj, err := s.NewObject(version, kind)
obj, err := s.NewObject(gvk.GroupVersion().String(), gvk.Kind)
if err != nil {
return nil, "", "", err
}
@ -56,7 +55,7 @@ func (s *Scheme) DecodeToVersionedObject(data []byte) (interface{}, string, stri
if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(obj); err != nil {
return nil, "", "", err
}
return obj, version, kind, nil
return obj, gvk.GroupVersion().String(), gvk.Kind, nil
}
// Decode converts a JSON string back into a pointer to an api object.
@ -106,7 +105,7 @@ func (s *Scheme) DecodeToVersion(data []byte, gv unversioned.GroupVersion) (inte
if err != nil {
return nil, err
}
flags, meta := s.generateConvertMeta(sourceVersion, gv.String(), obj)
flags, meta := s.generateConvertMeta(sourceGV, gv, obj)
if err := s.converter.Convert(obj, objOut, flags, meta); err != nil {
return nil, err
}
@ -135,46 +134,54 @@ func (s *Scheme) DecodeIntoWithSpecifiedVersionKind(data []byte, obj interface{}
if len(data) == 0 {
return errors.New("empty input")
}
dataVersion, dataKind, err := s.DataVersionAndKind(data)
dataGVK, err := s.DataKind(data)
if err != nil {
return err
}
if dataVersion == "" {
dataVersion = requestedGVK.GroupVersion().String()
if len(dataGVK.Group) == 0 {
dataGVK.Group = requestedGVK.Group
}
if dataKind == "" {
dataKind = requestedGVK.Kind
if len(dataGVK.Version) == 0 {
dataGVK.Version = requestedGVK.Version
}
if (len(requestedGVK.Group) > 0 || len(requestedGVK.Version) > 0) && (dataVersion != requestedGVK.GroupVersion().String()) {
return errors.New(fmt.Sprintf("The apiVersion in the data (%s) does not match the specified apiVersion(%v)", dataVersion, requestedGVK.GroupVersion()))
}
if len(requestedGVK.Kind) > 0 && (dataKind != requestedGVK.Kind) {
return errors.New(fmt.Sprintf("The kind in the data (%s) does not match the specified kind(%v)", dataKind, requestedGVK))
if len(dataGVK.Kind) == 0 {
dataGVK.Kind = requestedGVK.Kind
}
objVersion, objKind, err := s.ObjectVersionAndKind(obj)
if len(requestedGVK.Group) > 0 && requestedGVK.Group != dataGVK.Group {
return errors.New(fmt.Sprintf("The fully qualified kind in the data (%v) does not match the specified apiVersion(%v)", dataGVK, requestedGVK))
}
if len(requestedGVK.Version) > 0 && requestedGVK.Version != dataGVK.Version {
return errors.New(fmt.Sprintf("The fully qualified kind in the data (%v) does not match the specified apiVersion(%v)", dataGVK, requestedGVK))
}
if len(requestedGVK.Kind) > 0 && requestedGVK.Kind != dataGVK.Kind {
return errors.New(fmt.Sprintf("The fully qualified kind in the data (%v) does not match the specified apiVersion(%v)", dataGVK, requestedGVK))
}
objGVK, err := s.ObjectKind(obj)
if err != nil {
return err
}
if dataKind == "" {
// Assume objects with unset Kind fields are being unmarshalled into the
// correct type.
dataKind = objKind
// Assume objects with unset fields are being unmarshalled into the
// correct type.
if len(dataGVK.Group) == 0 {
dataGVK.Group = objGVK.Group
}
if dataVersion == "" {
// Assume objects with unset Version fields are being unmarshalled into the
// correct type.
dataVersion = objVersion
if len(dataGVK.Version) == 0 {
dataGVK.Version = objGVK.Version
}
if len(dataGVK.Kind) == 0 {
dataGVK.Kind = objGVK.Kind
}
external, err := s.NewObject(dataVersion, dataKind)
external, err := s.NewObject(dataGVK.GroupVersion().String(), dataGVK.Kind)
if err != nil {
return err
}
if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(external); err != nil {
return err
}
flags, meta := s.generateConvertMeta(dataVersion, objVersion, external)
flags, meta := s.generateConvertMeta(dataGVK.GroupVersion(), objGVK.GroupVersion(), external)
if err := s.converter.Convert(external, obj, flags, meta); err != nil {
return err
}

View File

@ -22,6 +22,8 @@ import (
"fmt"
"io"
"path"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// EncodeToVersion turns the given api object into an appropriate JSON string.
@ -81,33 +83,34 @@ func (s *Scheme) EncodeToVersionStream(obj interface{}, destVersion string, stre
return fmt.Errorf("type %v is not registered for %q and it will be impossible to Decode it, therefore Encode will refuse to encode it.", v.Type(), destVersion)
}
objVersion, objKind, err := s.ObjectVersionAndKind(obj)
objGVK, err := s.ObjectKind(obj)
if err != nil {
return err
}
// Perform a conversion if necessary.
if objVersion != destVersion {
objOut, err := s.NewObject(destVersion, objKind)
if objGVK.GroupVersion().String() != destVersion {
objOut, err := s.NewObject(destVersion, objGVK.Kind)
if err != nil {
return err
}
flags, meta := s.generateConvertMeta(objVersion, destVersion, obj)
flags, meta := s.generateConvertMeta(objGVK.GroupVersion(), unversioned.ParseGroupVersionOrDie(destVersion), obj)
err = s.converter.Convert(obj, objOut, flags, meta)
if err != nil {
return err
}
obj = objOut
}
// ensure the output object name comes from the destination type
_, objKind, err = s.ObjectVersionAndKind(obj)
if err != nil {
return err
// ensure the output object name comes from the destination type
newGroupVersionKind, err := s.ObjectKind(obj)
if err != nil {
return err
}
objGVK.Kind = newGroupVersionKind.Kind
}
// Version and Kind should be set on the wire.
err = s.SetVersionAndKind(destVersion, objKind, obj)
err = s.SetVersionAndKind(destVersion, objGVK.Kind, obj)
if err != nil {
return err
}
@ -129,11 +132,11 @@ func (s *Scheme) EncodeToVersionStream(obj interface{}, destVersion string, stre
}
func (s *Scheme) encodeUnversionedObject(obj interface{}) (data []byte, err error) {
_, objKind, err := s.ObjectVersionAndKind(obj)
objGVK, err := s.ObjectKind(obj)
if err != nil {
return nil, err
}
if err = s.SetVersionAndKind("", objKind, obj); err != nil {
if err = s.SetVersionAndKind("", objGVK.Kind, obj); err != nil {
return nil, err
}
data, err = json.Marshal(obj)

View File

@ -21,6 +21,8 @@ import (
"fmt"
"path"
"reflect"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// MetaFactory is used to store and retrieve the version and kind
@ -28,9 +30,9 @@ import (
type MetaFactory interface {
// Update sets the given version and kind onto the object.
Update(version, kind string, obj interface{}) error
// Interpret should return the version and kind of the wire-format of
// Interpret should return the group,version,kind of the wire-format of
// the object.
Interpret(data []byte) (version, kind string, err error)
Interpret(data []byte) (gvk unversioned.GroupVersionKind, err error)
}
// DefaultMetaFactory is a default factory for versioning objects in JSON. The object
@ -51,18 +53,23 @@ type SimpleMetaFactory struct {
BaseFields []string
}
// Interpret will return the APIVersion and Kind of the JSON wire-format
// Interpret will return the group,version,kind of the JSON wire-format
// encoding of an object, or an error.
func (SimpleMetaFactory) Interpret(data []byte) (version, kind string, err error) {
func (SimpleMetaFactory) Interpret(data []byte) (unversioned.GroupVersionKind, error) {
findKind := struct {
APIVersion string `json:"apiVersion,omitempty"`
Kind string `json:"kind,omitempty"`
}{}
err = json.Unmarshal(data, &findKind)
err := json.Unmarshal(data, &findKind)
if err != nil {
return "", "", fmt.Errorf("couldn't get version/kind; json parse error: %v", err)
return unversioned.GroupVersionKind{}, fmt.Errorf("couldn't get version/kind; json parse error: %v", err)
}
return findKind.APIVersion, findKind.Kind, nil
gv, err := unversioned.ParseGroupVersion(findKind.APIVersion)
if err != nil {
return unversioned.GroupVersionKind{}, fmt.Errorf("couldn't parse apiVersion: %v", err)
}
return gv.WithKind(findKind.Kind), nil
}
func (f SimpleMetaFactory) Update(version, kind string, obj interface{}) error {

View File

@ -26,25 +26,26 @@ import (
func TestSimpleMetaFactoryInterpret(t *testing.T) {
factory := SimpleMetaFactory{}
version, kind, err := factory.Interpret([]byte(`{"apiVersion":"1","kind":"object"}`))
fqKind, err := factory.Interpret([]byte(`{"apiVersion":"g/1","kind":"object"}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "1" || kind != "object" {
t.Errorf("unexpected interpret: %s %s", version, kind)
expectedFQKind := unversioned.GroupVersionKind{Group: "g", Version: "1", Kind: "object"}
if expectedFQKind != fqKind {
t.Errorf("unexpected interpret: %s %s", expectedFQKind, fqKind)
}
// no kind or version
version, kind, err = factory.Interpret([]byte(`{}`))
fqKind, err = factory.Interpret([]byte(`{}`))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if version != "" || kind != "" {
t.Errorf("unexpected interpret: %s %s", version, kind)
if !fqKind.IsEmpty() {
t.Errorf("unexpected interpret: %s %s", fqKind)
}
// unparsable
version, kind, err = factory.Interpret([]byte(`{`))
fqKind, err = factory.Interpret([]byte(`{`))
if err == nil {
t.Errorf("unexpected non-error")
}
@ -237,10 +238,10 @@ func TestMetaValuesUnregisteredConvert(t *testing.T) {
// Register functions to verify that scope.Meta() gets set correctly.
err := s.AddConversionFuncs(
func(in *InternalSimple, out *ExternalSimple, scope Scope) error {
if e, a := "unknown", scope.Meta().SrcVersion; e != a {
if e, a := "unknown/unknown", scope.Meta().SrcVersion; e != a {
t.Fatalf("Expected '%v', got '%v'", e, a)
}
if e, a := "unknown", scope.Meta().DestVersion; 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)

View File

@ -281,15 +281,9 @@ func (s *Scheme) AddDefaultingFuncs(defaultingFuncs ...interface{}) error {
return nil
}
// Recognizes returns true if the scheme is able to handle the provided version and kind
// Recognizes returns true if the scheme is able to handle the provided group,version,kind
// of an object.
func (s *Scheme) Recognizes(gvString, kind string) bool {
gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil {
return false
}
gvk := gv.WithKind(kind)
func (s *Scheme) Recognizes(gvk unversioned.GroupVersionKind) bool {
_, exists := s.gvkToType[gvk]
return exists
}
@ -314,13 +308,13 @@ func (s *Scheme) DeepCopy(in interface{}) (interface{}, error) {
// that case, the conversion.Scope object passed to your conversion functions won't
// have SrcVersion or DestVersion fields set correctly in Meta().
func (s *Scheme) Convert(in, out interface{}) error {
inVersion := "unknown"
outVersion := "unknown"
if v, _, err := s.ObjectVersionAndKind(in); err == nil {
inVersion = v
inVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
outVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
if gvk, err := s.ObjectKind(in); err == nil {
inVersion = gvk.GroupVersion()
}
if v, _, err := s.ObjectVersionAndKind(out); err == nil {
outVersion = v
if gvk, err := s.ObjectKind(out); err == nil {
outVersion = gvk.GroupVersion()
}
flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
if flags == 0 {
@ -346,27 +340,36 @@ func (s *Scheme) ConvertToVersion(in interface{}, outVersion string) (interface{
if !ok {
return nil, fmt.Errorf("%v cannot be converted into version %q", t, outVersion)
}
outKind := gvks[0]
outGV, err := unversioned.ParseGroupVersion(outVersion)
if err != nil {
return nil, err
}
outGVK := outGV.WithKind(gvks[0].Kind)
inVersion, _, err := s.ObjectVersionAndKind(in)
inGVK, err := s.ObjectKind(in)
if err != nil {
return nil, err
}
out, err := s.NewObject(outVersion, outKind.Kind)
out, err := s.NewObject(outGV.String(), outGVK.Kind)
if err != nil {
return nil, err
}
flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
flags, meta := s.generateConvertMeta(inGVK.GroupVersion(), outGV, in)
if err := s.converter.Convert(in, out, flags, meta); err != nil {
return nil, err
}
if len(outVersion) != 0 {
if err := s.SetVersionAndKind(outVersion, outKind.Kind, out); err != nil {
return nil, err
}
// <<<<<<< HEAD
// if len(outVersion) != 0 {
// if err := s.SetVersionAndKind(outVersion, outKind.Kind, out); err != nil {
// return nil, err
// }
// =======
if err := s.SetVersionAndKind(outGV.String(), outGVK.Kind, out); err != nil {
return nil, err
// >>>>>>> Update ObjectTyper to GroupVersion
}
return out, nil
@ -378,37 +381,46 @@ func (s *Scheme) Converter() *Converter {
}
// generateConvertMeta constructs the meta value we pass to Convert.
func (s *Scheme) generateConvertMeta(srcVersion, destVersion string, in interface{}) (FieldMatchingFlags, *Meta) {
func (s *Scheme) generateConvertMeta(srcGroupVersion, destGroupVersion unversioned.GroupVersion, in interface{}) (FieldMatchingFlags, *Meta) {
t := reflect.TypeOf(in)
return s.converter.inputDefaultFlags[t], &Meta{
SrcVersion: srcVersion,
DestVersion: destVersion,
SrcVersion: srcGroupVersion.String(),
DestVersion: destGroupVersion.String(),
KeyNameMapping: s.converter.inputFieldMappingFuncs[t],
}
}
// DataVersionAndKind will return the APIVersion and Kind of the given wire-format
// DataKind will return the group,version,kind of the given wire-format
// encoding of an API Object, or an error.
func (s *Scheme) DataVersionAndKind(data []byte) (version, kind string, err error) {
func (s *Scheme) DataKind(data []byte) (unversioned.GroupVersionKind, error) {
return s.MetaFactory.Interpret(data)
}
// ObjectVersionAndKind returns the API version and kind of the go object,
// ObjectKind returns the group,version,kind of the go object,
// or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectVersionAndKind(obj interface{}) (apiVersion, kind string, err error) {
func (s *Scheme) ObjectKind(obj interface{}) (unversioned.GroupVersionKind, error) {
gvks, err := s.ObjectKinds(obj)
if err != nil {
return unversioned.GroupVersionKind{}, err
}
return gvks[0], nil
}
// ObjectKinds returns all possible group,version,kind of the go object,
// or an error if it's not a pointer or is unregistered.
func (s *Scheme) ObjectKinds(obj interface{}) ([]unversioned.GroupVersionKind, error) {
v, err := EnforcePtr(obj)
if err != nil {
return "", "", err
return []unversioned.GroupVersionKind{}, err
}
t := v.Type()
gvks, ok := s.typeToGVK[t]
if !ok {
return "", "", &notRegisteredErr{t: t}
return []unversioned.GroupVersionKind{}, &notRegisteredErr{t: t}
}
apiVersion = gvks[0].GroupVersion().String()
kind = gvks[0].Kind
return
return gvks, nil
}
// SetVersionAndKind sets the version and kind fields (with help from

View File

@ -128,18 +128,22 @@ func GetTestScheme() *Scheme {
type testMetaFactory struct{}
func (testMetaFactory) Interpret(data []byte) (version, kind string, err error) {
func (testMetaFactory) Interpret(data []byte) (unversioned.GroupVersionKind, error) {
findKind := struct {
APIVersion string `json:"myVersionKey,omitempty"`
ObjectKind string `json:"myKindKey,omitempty"`
}{}
// yaml is a superset of json, so we use it to decode here. That way,
// we understand both.
err = yaml.Unmarshal(data, &findKind)
err := yaml.Unmarshal(data, &findKind)
if err != nil {
return "", "", fmt.Errorf("couldn't get version/kind: %v", err)
return unversioned.GroupVersionKind{}, fmt.Errorf("couldn't get version/kind: %v", err)
}
return findKind.APIVersion, findKind.ObjectKind, nil
gv, err := unversioned.ParseGroupVersion(findKind.APIVersion)
if err != nil {
return unversioned.GroupVersionKind{}, err
}
return gv.WithKind(findKind.ObjectKind), nil
}
func (testMetaFactory) Update(version, kind string, obj interface{}) error {

View File

@ -253,11 +253,11 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec) {
}
return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil
default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object)
fqKind, err := api.Scheme.ObjectKind(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot get the logs from %s", kind)
return nil, fmt.Errorf("cannot get the logs from %v", fqKind)
}
},
}

View File

@ -216,8 +216,8 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
}
newRc, ok = obj.(*api.ReplicationController)
if !ok {
if _, kind, err := typer.ObjectVersionAndKind(obj); err == nil {
return cmdutil.UsageError(cmd, "%s contains a %s not a ReplicationController", filename, kind)
if gvk, err := typer.ObjectKind(obj); err == nil {
return cmdutil.UsageError(cmd, "%s contains a %v not a ReplicationController", filename, gvk)
}
glog.V(4).Infof("Object %#v is not a ReplicationController", obj)
return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename)
@ -358,11 +358,11 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
if outputFormat != "" {
return f.PrintObject(cmd, newRc, out)
}
_, kind, err := api.Scheme.ObjectVersionAndKind(newRc)
gvk, err := api.Scheme.ObjectKind(newRc)
if err != nil {
return err
}
_, res := meta.KindToResource(kind, false)
_, res := meta.KindToResource(gvk.Kind, false)
cmdutil.PrintSuccess(mapper, false, out, res, oldName, message)
return nil
}

View File

@ -25,7 +25,6 @@ import (
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -371,24 +370,19 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
}
mapper, typer := f.Object()
gvString, kind, err := typer.ObjectVersionAndKind(obj)
groupVersionKind, err := typer.ObjectKind(obj)
if err != nil {
return nil, "", nil, nil, err
}
gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil {
return nil, "", nil, nil, err
}
gvk := gv.WithKind(kind)
if len(overrides) > 0 {
obj, err = cmdutil.Merge(obj, overrides, kind)
obj, err = cmdutil.Merge(obj, overrides, groupVersionKind.Kind)
if err != nil {
return nil, "", nil, nil, err
}
}
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
mapping, err := mapper.RESTMapping(groupVersionKind.GroupKind(), groupVersionKind.Version)
if err != nil {
return nil, "", nil, nil, err
}
@ -414,5 +408,5 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
return nil, "", nil, nil, err
}
}
return obj, kind, mapper, mapping, err
return obj, groupVersionKind.Kind, mapper, mapping, err
}

View File

@ -199,11 +199,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
}
return kubectl.MakeLabels(t.Spec.Selector), nil
default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object)
gvk, err := api.Scheme.ObjectKind(object)
if err != nil {
return "", err
}
return "", fmt.Errorf("cannot extract pod selector from %s", kind)
return "", fmt.Errorf("cannot extract pod selector from %v", gvk)
}
},
PortsForObject: func(object runtime.Object) ([]string, error) {
@ -216,11 +216,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
case *api.Service:
return getServicePorts(t.Spec), nil
default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object)
gvk, err := api.Scheme.ObjectKind(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot extract ports from %s", kind)
return nil, fmt.Errorf("cannot extract ports from %v", gvk)
}
},
LabelsForObject: func(object runtime.Object) (map[string]string, error) {
@ -240,11 +240,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
}
return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil
default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object)
gvk, err := api.Scheme.ObjectKind(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot get the logs from %s", kind)
return nil, fmt.Errorf("cannot get the logs from %v", gvk)
}
},
Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) {
@ -323,11 +323,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
case *api.Pod:
return t, nil
default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object)
gvk, err := api.Scheme.ObjectKind(object)
if err != nil {
return nil, err
}
return nil, fmt.Errorf("cannot attach to %s: not implemented", kind)
return nil, fmt.Errorf("cannot attach to %v: not implemented", gvk)
}
},
EditorEnvs: func() []string {
@ -489,29 +489,20 @@ func getSchemaAndValidate(c schemaClient, data []byte, prefix, groupVersion, cac
}
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
version, kind, err := runtime.UnstructuredJSONScheme.DataVersionAndKind(data)
gvk, err := runtime.UnstructuredJSONScheme.DataKind(data)
if err != nil {
return err
}
gv, err := unversioned.ParseGroupVersion(version)
if err != nil {
return fmt.Errorf("unable to parse group/version from %q: %v", version, err)
}
if ok := registered.IsRegisteredAPIGroupVersion(gv); !ok {
return fmt.Errorf("API version %q isn't supported, only supports API versions %q", version, registered.RegisteredGroupVersions)
}
resource, _ := meta.KindToResource(kind, false)
gvk, err := c.mapper.KindFor(resource)
if err != nil {
return fmt.Errorf("could not find api group for %s: %v", kind, err)
if ok := registered.IsRegisteredAPIGroupVersion(gvk.GroupVersion()); !ok {
return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.RegisteredGroupVersions)
}
if gvk.Group == "extensions" {
if c.c.ExtensionsClient == nil {
return errors.New("unable to validate: no experimental client")
}
return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", version, c.cacheDir)
return getSchemaAndValidate(c.c.ExtensionsClient.RESTClient, data, "apis/", gvk.GroupVersion().String(), c.cacheDir)
}
return getSchemaAndValidate(c.c.RESTClient, data, "api", version, c.cacheDir)
return getSchemaAndValidate(c.c.RESTClient, data, "api", gvk.GroupVersion().String(), c.cacheDir)
}
// DefaultClientConfig creates a clientcmd.ClientConfig with the following hierarchy:
@ -571,16 +562,12 @@ func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig {
// PrintObject prints an api object given command line flags to modify the output format
func (f *Factory) PrintObject(cmd *cobra.Command, obj runtime.Object, out io.Writer) error {
mapper, _ := f.Object()
gvString, kind, err := api.Scheme.ObjectVersionAndKind(obj)
if err != nil {
return err
}
gv, err := unversioned.ParseGroupVersion(gvString)
gvk, err := api.Scheme.ObjectKind(obj)
if err != nil {
return err
}
mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: kind})
mapping, err := mapper.RESTMapping(gvk.GroupKind())
if err != nil {
return err
}

View File

@ -23,7 +23,6 @@ import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/registered"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/yaml"
)
@ -45,21 +44,17 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
return nil, fmt.Errorf("unable to parse %q: %v", source, err)
}
data = json
version, kind, err := runtime.UnstructuredJSONScheme.DataVersionAndKind(data)
gvk, err := runtime.UnstructuredJSONScheme.DataKind(data)
if err != nil {
return nil, fmt.Errorf("unable to get type info from %q: %v", source, err)
}
gv, err := unversioned.ParseGroupVersion(version)
if err != nil {
return nil, fmt.Errorf("unable to parse group/version from %q: %v", version, err)
if ok := registered.IsRegisteredAPIGroupVersion(gvk.GroupVersion()); !ok {
return nil, fmt.Errorf("API version %q in %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), source, registered.RegisteredGroupVersions)
}
if ok := registered.IsRegisteredAPIGroupVersion(gv); !ok {
return nil, fmt.Errorf("API version %q in %q isn't supported, only supports API versions %q", version, source, registered.RegisteredGroupVersions)
}
if kind == "" {
if gvk.Kind == "" {
return nil, fmt.Errorf("kind not set in %q", source)
}
mapping, err := m.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: kind}, gv.Version)
mapping, err := m.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
}
@ -97,17 +92,13 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
// if the object cannot be introspected. Name and namespace will be set into Info
// if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForObject(obj runtime.Object) (*Info, error) {
gvString, kind, err := m.ObjectVersionAndKind(obj)
groupVersionKind, err := m.ObjectKind(obj)
if err != nil {
return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err)
}
gv, err := unversioned.ParseGroupVersion(gvString)
mapping, err := m.RESTMapping(groupVersionKind.GroupKind(), groupVersionKind.Version)
if err != nil {
return nil, fmt.Errorf("unable to parse group/version from %q: %v", gvString, err)
}
mapping, err := m.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: kind}, gv.Version)
if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", kind, err)
return nil, fmt.Errorf("unable to recognize %v: %v", groupVersionKind, err)
}
client, err := m.ClientForMapping(mapping)
if err != nil {

View File

@ -243,7 +243,7 @@ func AsVersionedObjects(infos []*Info, version string) ([]runtime.Object, error)
// objects that are not part of api.Scheme must be converted to JSON
// TODO: convert to map[string]interface{}, attach to runtime.Unknown?
if len(version) > 0 {
if _, _, err := api.Scheme.ObjectVersionAndKind(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.
data, err := info.Mapping.Codec.Encode(info.Object)
if err != nil {

View File

@ -213,7 +213,7 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
for i := 0; i < items.Len(); i++ {
rawObj := items.Index(i).FieldByName("RawJSON").Interface().([]byte)
scheme := api.Scheme
version, kind, err := scheme.DataVersionAndKind(rawObj)
groupVersionKind, err := scheme.DataKind(rawObj)
if err != nil {
return err
}
@ -222,8 +222,8 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
return err
}
tpmeta := unversioned.TypeMeta{
APIVersion: version,
Kind: kind,
APIVersion: groupVersionKind.GroupVersion().String(),
Kind: groupVersionKind.Kind,
}
s := reflect.ValueOf(decodedObj).Elem()
s.FieldByName("TypeMeta").Set(reflect.ValueOf(tpmeta))

View File

@ -146,7 +146,7 @@ func (t *Tester) TestWatch(valid runtime.Object, labelsPass, labelsFail []labels
// =============================================================================
// get codec based on runtime.Object
func getCodec(obj runtime.Object) (runtime.Codec, error) {
_, kind, err := api.Scheme.ObjectVersionAndKind(obj)
fqKind, err := api.Scheme.ObjectKind(obj)
if err != nil {
return nil, fmt.Errorf("unexpected encoding error: %v", err)
}
@ -155,12 +155,12 @@ func getCodec(obj runtime.Object) (runtime.Codec, error) {
// split the schemes for internal objects.
// TODO: caesarxuchao: we should add a map from kind to group in Scheme.
var codec runtime.Codec
if api.Scheme.Recognizes(testapi.Default.GroupAndVersion(), kind) {
if api.Scheme.Recognizes(testapi.Default.GroupVersion().WithKind(fqKind.Kind)) {
codec = testapi.Default.Codec()
} else if api.Scheme.Recognizes(testapi.Extensions.GroupAndVersion(), kind) {
} else if api.Scheme.Recognizes(testapi.Extensions.GroupVersion().WithKind(fqKind.Kind)) {
codec = testapi.Extensions.Codec()
} else {
return nil, fmt.Errorf("unexpected kind: %v", kind)
return nil, fmt.Errorf("unexpected kind: %v", fqKind)
}
return codec, nil
}

View File

@ -106,7 +106,7 @@ func TestArrayOfRuntimeObject(t *testing.T) {
&EmbeddedTest{ID: "foo"},
&EmbeddedTest{ID: "bar"},
// TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization
&runtime.Unknown{RawJSON: []byte(`{"apiVersion":"unknown","foo":"bar","kind":"OtherTest"}`)},
&runtime.Unknown{RawJSON: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`)},
&ObjectTest{
Items: []runtime.Object{
&EmbeddedTest{ID: "baz"},
@ -150,7 +150,7 @@ func TestArrayOfRuntimeObject(t *testing.T) {
}
internal.Items[2].(*runtime.Unknown).Kind = "OtherTest"
internal.Items[2].(*runtime.Unknown).APIVersion = "unknown"
internal.Items[2].(*runtime.Unknown).APIVersion = "unknown.group/unknown"
if e, a := internal.Items, list; !reflect.DeepEqual(e, a) {
t.Errorf("mismatched decoded: %s", util.ObjectDiff(e, a))
}

View File

@ -20,6 +20,7 @@ import (
"fmt"
"reflect"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/conversion"
)
@ -56,7 +57,13 @@ func DecodeList(objects []Object, decoders ...ObjectDecoder) []error {
switch t := obj.(type) {
case *Unknown:
for _, decoder := range decoders {
if !decoder.Recognizes(t.APIVersion, t.Kind) {
gv, err := unversioned.ParseGroupVersion(t.APIVersion)
if err != nil {
errs = append(errs, err)
break
}
if !decoder.Recognizes(gv.WithKind(t.Kind)) {
continue
}
obj, err := decoder.Decode(t.RawJSON)
@ -77,9 +84,9 @@ type MultiObjectTyper []ObjectTyper
var _ ObjectTyper = MultiObjectTyper{}
func (m MultiObjectTyper) DataVersionAndKind(data []byte) (version, kind string, err error) {
func (m MultiObjectTyper) DataKind(data []byte) (gvk unversioned.GroupVersionKind, err error) {
for _, t := range m {
version, kind, err = t.DataVersionAndKind(data)
gvk, err = t.DataKind(data)
if err == nil {
return
}
@ -87,9 +94,9 @@ func (m MultiObjectTyper) DataVersionAndKind(data []byte) (version, kind string,
return
}
func (m MultiObjectTyper) ObjectVersionAndKind(obj Object) (version, kind string, err error) {
func (m MultiObjectTyper) ObjectKind(obj Object) (gvk unversioned.GroupVersionKind, err error) {
for _, t := range m {
version, kind, err = t.ObjectVersionAndKind(obj)
gvk, err = t.ObjectKind(obj)
if err == nil {
return
}
@ -97,9 +104,19 @@ func (m MultiObjectTyper) ObjectVersionAndKind(obj Object) (version, kind string
return
}
func (m MultiObjectTyper) Recognizes(version, kind string) bool {
func (m MultiObjectTyper) ObjectKinds(obj Object) (gvks []unversioned.GroupVersionKind, err error) {
for _, t := range m {
if t.Recognizes(version, kind) {
gvks, err = t.ObjectKinds(obj)
if err == nil {
return
}
}
return
}
func (m MultiObjectTyper) Recognizes(gvk unversioned.GroupVersionKind) bool {
for _, t := range m {
if t.Recognizes(gvk) {
return true
}
}

View File

@ -69,13 +69,13 @@ type ObjectCodec interface {
// TODO: Consider removing this interface?
type ObjectDecoder interface {
Decoder
// DataVersionAndKind returns the version and kind of the provided data, or an error
// DataVersionAndKind returns the group,version,kind of the provided data, or an error
// if another problem is detected. In many cases this method can be as expensive to
// invoke as the Decode method.
DataVersionAndKind([]byte) (version, kind string, err error)
// Recognizes returns true if the scheme is able to handle the provided version and kind
DataKind([]byte) (unversioned.GroupVersionKind, error)
// Recognizes returns true if the scheme is able to handle the provided group,version,kind
// of an object.
Recognizes(version, kind string) bool
Recognizes(unversioned.GroupVersionKind) bool
}
///////////////////////////////////////////////////////////////////////////////
@ -91,17 +91,20 @@ type ObjectConvertor interface {
// ObjectTyper contains methods for extracting the APIVersion and Kind
// of objects.
type ObjectTyper interface {
// DataVersionAndKind returns the version and kind of the provided data, or an error
// DataKind returns the group,version,kind of the provided data, or an error
// if another problem is detected. In many cases this method can be as expensive to
// invoke as the Decode method.
DataVersionAndKind([]byte) (version, kind string, err error)
// ObjectVersionAndKind returns the version and kind of the provided object, or an
DataKind([]byte) (unversioned.GroupVersionKind, error)
// ObjectKind returns the default group,version,kind of the provided object, or an
// error if the object is not recognized (IsNotRegisteredError will return true).
ObjectVersionAndKind(Object) (version, kind string, err error)
ObjectKind(Object) (unversioned.GroupVersionKind, error)
// ObjectKinds returns the all possible group,version,kind of the provided object, or an
// error if the object is not recognized (IsNotRegisteredError will return true).
ObjectKinds(Object) ([]unversioned.GroupVersionKind, error)
// Recognizes returns true if the scheme is able to handle the provided version and kind,
// or more precisely that the provided version is a possible conversion or decoding
// target.
Recognizes(version, kind string) bool
Recognizes(gvk unversioned.GroupVersionKind) bool
}
// ObjectCreater contains methods for instantiating an object by kind and version.

View File

@ -37,6 +37,7 @@ type Scheme struct {
}
var _ Decoder = &Scheme{}
var _ ObjectTyper = &Scheme{}
// Function to convert a field selector to internal representation.
type FieldLabelConversionFunc func(label, value string) (internalLabel, internalValue string, err error)
@ -70,13 +71,13 @@ func (self *Scheme) embeddedObjectToRawExtension(in *EmbeddedObject, out *RawExt
// Figure out the type and kind of the output object.
_, outVersion, scheme := self.fromScope(s)
_, kind, err := scheme.raw.ObjectVersionAndKind(in.Object)
gvk, err := scheme.raw.ObjectKind(in.Object)
if err != nil {
return err
}
// Manufacture an object of this type and kind.
outObj, err := scheme.New(outVersion, kind)
outObj, err := scheme.New(outVersion, gvk.Kind)
if err != nil {
return err
}
@ -89,7 +90,7 @@ func (self *Scheme) embeddedObjectToRawExtension(in *EmbeddedObject, out *RawExt
// Copy the kind field into the output object.
err = s.Convert(
&emptyPlugin{PluginBase: PluginBase{Kind: kind}},
&emptyPlugin{PluginBase: PluginBase{Kind: gvk.Kind}},
outObj,
conversion.SourceToDest|conversion.IgnoreMissingFields|conversion.AllowDifferentFieldTypeNames,
)
@ -117,14 +118,14 @@ func (self *Scheme) rawExtensionToEmbeddedObject(in *RawExtension, out *Embedded
}
// Figure out the type and kind of the output object.
inVersion, outVersion, scheme := self.fromScope(s)
_, kind, err := scheme.raw.DataVersionAndKind(in.RawJSON)
gvk, err := scheme.raw.DataKind(in.RawJSON)
if err != nil {
return err
}
// We have to make this object ourselves because we don't store the version field for
// plugin objects.
inObj, err := scheme.New(inVersion, kind)
inObj, err := scheme.New(inVersion, gvk.Kind)
if err != nil {
return err
}
@ -135,7 +136,7 @@ func (self *Scheme) rawExtensionToEmbeddedObject(in *RawExtension, out *Embedded
}
// Make the desired internal version, and do the conversion.
outObj, err := scheme.New(outVersion, kind)
outObj, err := scheme.New(outVersion, gvk.Kind)
if err != nil {
return err
}
@ -182,14 +183,9 @@ func (self *Scheme) runtimeObjectToRawExtensionArray(in *[]Object, out *[]RawExt
version := outVersion
// if the object exists
// 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()
if inGVK, err := scheme.ObjectKind(src[i]); err == nil && !inGVK.GroupVersion().IsEmpty() {
if self.raw.InternalVersions[inGVK.Group] != inGVK.GroupVersion() {
version = inGVK.GroupVersion().String()
}
}
data, err := scheme.EncodeToVersion(src[i], version)
@ -213,14 +209,14 @@ func (self *Scheme) rawExtensionToRuntimeObjectArray(in *[]RawExtension, out *[]
for i := range src {
data := src[i].RawJSON
version, kind, err := scheme.raw.DataVersionAndKind(data)
gvk, err := scheme.raw.DataKind(data)
if err != nil {
return err
}
dest[i] = &Unknown{
TypeMeta: TypeMeta{
APIVersion: version,
Kind: kind,
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
},
RawJSON: data,
}
@ -288,21 +284,26 @@ func (s *Scheme) KnownTypes(gv unversioned.GroupVersion) map[string]reflect.Type
return s.raw.KnownTypes(gv)
}
// DataVersionAndKind will return the APIVersion and Kind of the given wire-format
// DataKind will return the group,version,kind of the given wire-format
// encoding of an API Object, or an error.
func (s *Scheme) DataVersionAndKind(data []byte) (version, kind string, err error) {
return s.raw.DataVersionAndKind(data)
func (s *Scheme) DataKind(data []byte) (unversioned.GroupVersionKind, error) {
return s.raw.DataKind(data)
}
// ObjectVersionAndKind returns the version and kind of the given Object.
func (s *Scheme) ObjectVersionAndKind(obj Object) (version, kind string, err error) {
return s.raw.ObjectVersionAndKind(obj)
// ObjectKind returns the default group,version,kind of the given Object.
func (s *Scheme) ObjectKind(obj Object) (unversioned.GroupVersionKind, error) {
return s.raw.ObjectKind(obj)
}
// Recognizes returns true if the scheme is able to handle the provided version and kind
// ObjectKinds returns the all possible group,version,kind of the given Object.
func (s *Scheme) ObjectKinds(obj Object) ([]unversioned.GroupVersionKind, error) {
return s.raw.ObjectKinds(obj)
}
// Recognizes returns true if the scheme is able to handle the provided group,version,kind
// of an object.
func (s *Scheme) Recognizes(version, kind string) bool {
return s.raw.Recognizes(version, kind)
func (s *Scheme) Recognizes(gvk unversioned.GroupVersionKind) bool {
return s.raw.Recognizes(gvk)
}
// New returns a new API object of the given version ("" for internal

View File

@ -144,7 +144,7 @@ func TestInvalidObjectValueKind(t *testing.T) {
embedded := &runtime.EmbeddedObject{}
switch obj := embedded.Object.(type) {
default:
_, _, err := scheme.ObjectVersionAndKind(obj)
_, err := scheme.ObjectKind(obj)
if err == nil {
t.Errorf("Expected error on invalid kind")
}

View File

@ -33,11 +33,12 @@ var UnstructuredJSONScheme ObjectDecoder = unstructuredJSONScheme{}
type unstructuredJSONScheme struct{}
var _ Decoder = unstructuredJSONScheme{}
var _ ObjectDecoder = unstructuredJSONScheme{}
// Recognizes returns true for any version or kind that is specified (internal
// versions are specifically excluded).
func (unstructuredJSONScheme) Recognizes(version, kind string) bool {
return len(version) > 0 && len(kind) > 0
func (unstructuredJSONScheme) Recognizes(gvk unversioned.GroupVersionKind) bool {
return !gvk.GroupVersion().IsEmpty() && len(gvk.Kind) > 0
}
func (s unstructuredJSONScheme) Decode(data []byte) (Object, error) {
@ -90,16 +91,22 @@ func (unstructuredJSONScheme) DecodeParametersInto(paramaters url.Values, obj Ob
return nil
}
func (unstructuredJSONScheme) DataVersionAndKind(data []byte) (version, kind string, err error) {
func (unstructuredJSONScheme) DataKind(data []byte) (unversioned.GroupVersionKind, error) {
obj := TypeMeta{}
if err := json.Unmarshal(data, &obj); err != nil {
return "", "", err
return unversioned.GroupVersionKind{}, err
}
if len(obj.APIVersion) == 0 {
return "", "", conversion.NewMissingVersionErr(string(data))
return unversioned.GroupVersionKind{}, conversion.NewMissingVersionErr(string(data))
}
if len(obj.Kind) == 0 {
return "", "", conversion.NewMissingKindErr(string(data))
return unversioned.GroupVersionKind{}, conversion.NewMissingKindErr(string(data))
}
return obj.APIVersion, obj.Kind, nil
gv, err := unversioned.ParseGroupVersion(obj.APIVersion)
if err != nil {
return unversioned.GroupVersionKind{}, err
}
return gv.WithKind(obj.Kind), nil
}