Merge pull request #17796 from deads2k/gv-object-typer

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2015-12-07 12:34:55 -08:00
commit ec1ba7438f
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 // if we are building an object reference to something not yet persisted, we should fallback to scheme
kind := meta.Kind() kind := meta.Kind()
if kind == "" { if kind == "" {
_, kind, err = Scheme.ObjectVersionAndKind(obj) gvk, err := Scheme.ObjectKind(obj)
if err != nil { if err != nil {
return nil, err return nil, err
} }
kind = gvk.Kind
} }
// 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

View File

@ -111,9 +111,9 @@ func objectMetaAndKind(typer runtime.ObjectTyper, obj runtime.Object) (*api.Obje
if err != nil { if err != nil {
return nil, "", errors.NewInternalError(err) return nil, "", errors.NewInternalError(err)
} }
_, kind, err := typer.ObjectVersionAndKind(obj) gvk, err := typer.ObjectKind(obj)
if err != nil { if err != nil {
return nil, "", errors.NewInternalError(err) 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) { func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) {
printer := spew.ConfigState{DisableMethods: true} 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() name := reflect.TypeOf(item).Elem().Name()
data, err := codec.Encode(item) data, err := codec.Encode(item)
if err != nil { 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) { func roundTripSame(t *testing.T, item runtime.Object, except ...string) {
set := sets.NewString(except...) set := sets.NewString(except...)
seed := rand.Int63() seed := rand.Int63()
fuzzInternalObject(t, "", item, seed) fuzzInternalObject(t, testapi.Default.InternalGroupVersion().String(), item, seed)
version := testapi.Default.VersionUnderTest version := testapi.Default.VersionUnderTest
codecs := []runtime.Codec{} codecs := []runtime.Codec{}
@ -154,6 +157,7 @@ func TestRoundTripTypes(t *testing.T) {
// defer api.Scheme.Log(nil) // defer api.Scheme.Log(nil)
for kind := range api.Scheme.KnownTypes(testapi.Default.InternalGroupVersion()) { for kind := range api.Scheme.KnownTypes(testapi.Default.InternalGroupVersion()) {
t.Logf("working on %v in %v", kind, testapi.Default.InternalGroupVersion())
if nonRoundTrippableTypes.Has(kind) { if nonRoundTrippableTypes.Has(kind) {
continue continue
} }
@ -168,18 +172,18 @@ func TestRoundTripTypes(t *testing.T) {
} }
func doRoundTripTest(kind string, 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 { if err != nil {
t.Fatalf("Couldn't make a %v? %v", kind, err) t.Fatalf("Couldn't make a %v? %v", kind, err)
} }
if _, err := meta.TypeAccessor(item); err != nil { 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) 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]...) roundTripSame(t, item, nonRoundTrippableTypesByVersion[kind]...)
} }
if !nonInternalRoundTrippableTypes.Has(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 // Get codec based on runtime.Object
func GetCodecForObject(obj runtime.Object) (runtime.Codec, error) { func GetCodecForObject(obj runtime.Object) (runtime.Codec, error) {
_, kind, err := api.Scheme.ObjectVersionAndKind(obj) gvk, err := api.Scheme.ObjectKind(obj)
if err != nil { if err != nil {
return nil, fmt.Errorf("unexpected encoding error: %v", err) 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 { 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 return group.Codec(), nil
} }
} }
// Codec used for unversioned types // Codec used for unversioned types
if api.Scheme.Recognizes("", kind) { if api.Scheme.Recognizes(gvk) {
return api.Codec, nil 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 // TODO: uncomment when round trip starts from a versioned object
if true { //c.RandBool() { if true { //c.RandBool() {
*j = &runtime.Unknown{ *j = &runtime.Unknown{
TypeMeta: runtime.TypeMeta{Kind: "Something", APIVersion: "unknown"}, // apiVersion has rules now. Since it includes <group>/<version> and only `v1` can be bare,
RawJSON: []byte(`{"apiVersion":"unknown","kind":"Something","someKey":"someValue"}`), // 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 { } else {
types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}} types := []runtime.Object{&api.Pod{}, &api.ReplicationController{}}

View File

@ -93,7 +93,7 @@ func (gvk GroupVersionKind) GroupVersion() GroupVersion {
return GroupVersion{Group: gvk.Group, Version: gvk.Version} 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 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 hasSubresource := len(subresource) > 0
object := storage.New() object := storage.New()
_, kind, err := a.group.Typer.ObjectVersionAndKind(object) fqKinds, err := a.group.Typer.ObjectKinds(object)
if err != nil { if err != nil {
return nil, err 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) versionedPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), kind)
if err != nil { if err != nil {
@ -134,7 +154,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
} }
versionedObject := indirectArbitraryPointer(versionedPtr) 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 { if err != nil {
return nil, err 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) return nil, fmt.Errorf("subresources can only be declared when the parent is also registered: %s needs %s", path, resource)
} }
parentObject := parentStorage.New() parentObject := parentStorage.New()
_, parentKind, err := a.group.Typer.ObjectVersionAndKind(parentObject)
parentFQKinds, err := a.group.Typer.ObjectKinds(parentObject)
if err != nil { if err != nil {
return nil, err 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 { if err != nil {
return nil, err return nil, err
} }
@ -184,8 +216,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
var versionedList interface{} var versionedList interface{}
if isLister { if isLister {
list := lister.NewList() list := lister.NewList()
_, listKind, err := a.group.Typer.ObjectVersionAndKind(list) listGVK, err := a.group.Typer.ObjectKind(list)
versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), listKind) versionedListPtr, err := a.group.Creater.New(a.group.GroupVersion.String(), listGVK.Kind)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -225,19 +257,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
) )
if isGetterWithOptions { if isGetterWithOptions {
getOptions, getSubpath, getSubpathKey = getterWithOptions.NewGetOptions() getOptions, getSubpath, getSubpathKey = getterWithOptions.NewGetOptions()
getOptionsGVString, getOptionsKind, err := a.group.Typer.ObjectVersionAndKind(getOptions) getOptionsInternalKind, err = a.group.Typer.ObjectKind(getOptions)
if err != nil { if err != nil {
return nil, err 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 // 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 { if err != nil {
return nil, err return nil, err
} }
@ -255,19 +282,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
if isConnecter { if isConnecter {
connectOptions, connectSubpath, connectSubpathKey = connecter.NewConnectOptions() connectOptions, connectSubpath, connectSubpathKey = connecter.NewConnectOptions()
if connectOptions != nil { if connectOptions != nil {
connectOptionsGVString, connectOptionsKind, err := a.group.Typer.ObjectVersionAndKind(connectOptions) connectOptionsInternalKind, err = a.group.Typer.ObjectKind(connectOptions)
if err != nil { if err != nil {
return nil, err 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 // 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. // transformDecodeError adds additional information when a decode fails.
func transformDecodeError(typer runtime.ObjectTyper, baseErr error, into runtime.Object, body []byte) error { 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 { if err != nil {
return err return err
} }
if version, dataKind, err := typer.DataVersionAndKind(body); err == nil && len(dataKind) > 0 { if dataGroupVersionKind, err := typer.DataKind(body); err == nil && len(dataGroupVersionKind.Kind) > 0 {
return errors.NewBadRequest(fmt.Sprintf("%s in version %s cannot be handled as a %s: %v", dataKind, version, kind, baseErr)) 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 // 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 continue
} }
version, kind, err := api.Scheme.DataVersionAndKind(b) dataKind, err := api.Scheme.DataKind(b)
if err != nil { if err != nil {
return nil, policyLoadError{path, i, b, err} return nil, policyLoadError{path, i, b, err}
} }
if version == "" && kind == "" { if dataKind.IsEmpty() {
unversionedLines++ unversionedLines++
// Migrate unversioned policy object // Migrate unversioned policy object
oldPolicy := &v0.Policy{} oldPolicy := &v0.Policy{}

View File

@ -208,7 +208,7 @@ func validateFields(a, b string) bool {
func body(t *testing.T, obj runtime.Object, raw *string) *string { func body(t *testing.T, obj runtime.Object, raw *string) *string {
if obj != nil { if obj != nil {
_, kind, err := api.Scheme.ObjectVersionAndKind(obj) fqKind, err := api.Scheme.ObjectKind(obj)
if err != nil { if err != nil {
t.Errorf("unexpected encoding error: %v", err) t.Errorf("unexpected encoding error: %v", err)
} }
@ -217,18 +217,18 @@ func body(t *testing.T, obj runtime.Object, raw *string) *string {
// split the schemes for internal objects. // split the schemes for internal objects.
// TODO: caesarxuchao: we should add a map from kind to group in Scheme. // TODO: caesarxuchao: we should add a map from kind to group in Scheme.
var bs []byte 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) bs, err = testapi.Default.Codec().Encode(obj)
if err != nil { if err != nil {
t.Errorf("unexpected encoding error: %v", err) 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) bs, err = testapi.Extensions.Codec().Encode(obj)
if err != nil { if err != nil {
t.Errorf("unexpected encoding error: %v", err) t.Errorf("unexpected encoding error: %v", err)
} }
} else { } else {
t.Errorf("unexpected kind: %v", kind) t.Errorf("unexpected kind: %v", fqKind.Kind)
} }
body := string(bs) body := string(bs)
return &body 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 { func (o objects) Add(obj runtime.Object) error {
_, kind, err := o.scheme.ObjectVersionAndKind(obj) gvk, err := o.scheme.ObjectKind(obj)
if err != nil { if err != nil {
return err return err
} }
kind := gvk.Kind
switch { switch {
case meta.IsListType(obj): case meta.IsListType(obj):

View File

@ -27,28 +27,27 @@ import (
) )
func (s *Scheme) DecodeToVersionedObject(data []byte) (interface{}, string, string, error) { func (s *Scheme) DecodeToVersionedObject(data []byte) (interface{}, string, string, error) {
version, kind, err := s.DataVersionAndKind(data) gvk, err := s.DataKind(data)
if err != nil { if err != nil {
return nil, "", "", err return nil, "", "", err
} }
gv, err := unversioned.ParseGroupVersion(version) internalGV, exists := s.InternalVersions[gvk.Group]
if err != nil {
return nil, "", "", err
}
internalGV, exists := s.InternalVersions[gv.Group]
if !exists { 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)) 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)) 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 { if err != nil {
return nil, "", "", err 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 { if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(obj); err != nil {
return nil, "", "", err 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. // 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 { if err != nil {
return nil, err 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 { if err := s.converter.Convert(obj, objOut, flags, meta); err != nil {
return nil, err return nil, err
} }
@ -135,46 +134,54 @@ func (s *Scheme) DecodeIntoWithSpecifiedVersionKind(data []byte, obj interface{}
if len(data) == 0 { if len(data) == 0 {
return errors.New("empty input") return errors.New("empty input")
} }
dataVersion, dataKind, err := s.DataVersionAndKind(data) dataGVK, err := s.DataKind(data)
if err != nil { if err != nil {
return err return err
} }
if dataVersion == "" { if len(dataGVK.Group) == 0 {
dataVersion = requestedGVK.GroupVersion().String() dataGVK.Group = requestedGVK.Group
} }
if dataKind == "" { if len(dataGVK.Version) == 0 {
dataKind = requestedGVK.Kind dataGVK.Version = requestedGVK.Version
} }
if (len(requestedGVK.Group) > 0 || len(requestedGVK.Version) > 0) && (dataVersion != requestedGVK.GroupVersion().String()) { if len(dataGVK.Kind) == 0 {
return errors.New(fmt.Sprintf("The apiVersion in the data (%s) does not match the specified apiVersion(%v)", dataVersion, requestedGVK.GroupVersion())) dataGVK.Kind = requestedGVK.Kind
}
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))
} }
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 { if err != nil {
return err return err
} }
if dataKind == "" { // Assume objects with unset fields are being unmarshalled into the
// Assume objects with unset Kind fields are being unmarshalled into the // correct type.
// correct type. if len(dataGVK.Group) == 0 {
dataKind = objKind dataGVK.Group = objGVK.Group
} }
if dataVersion == "" { if len(dataGVK.Version) == 0 {
// Assume objects with unset Version fields are being unmarshalled into the dataGVK.Version = objGVK.Version
// correct type. }
dataVersion = objVersion 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 { if err != nil {
return err return err
} }
if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(external); err != nil { if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(external); err != nil {
return err 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 { if err := s.converter.Convert(external, obj, flags, meta); err != nil {
return err return err
} }

View File

@ -22,6 +22,8 @@ import (
"fmt" "fmt"
"io" "io"
"path" "path"
"k8s.io/kubernetes/pkg/api/unversioned"
) )
// EncodeToVersion turns the given api object into an appropriate JSON string. // 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) 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 { if err != nil {
return err return err
} }
// Perform a conversion if necessary. // Perform a conversion if necessary.
if objVersion != destVersion { if objGVK.GroupVersion().String() != destVersion {
objOut, err := s.NewObject(destVersion, objKind) objOut, err := s.NewObject(destVersion, objGVK.Kind)
if err != nil { if err != nil {
return err 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) err = s.converter.Convert(obj, objOut, flags, meta)
if err != nil { if err != nil {
return err return err
} }
obj = objOut obj = objOut
}
// ensure the output object name comes from the destination type // ensure the output object name comes from the destination type
_, objKind, err = s.ObjectVersionAndKind(obj) newGroupVersionKind, err := s.ObjectKind(obj)
if err != nil { if err != nil {
return err return err
}
objGVK.Kind = newGroupVersionKind.Kind
} }
// Version and Kind should be set on the wire. // 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 { if err != nil {
return err 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) { func (s *Scheme) encodeUnversionedObject(obj interface{}) (data []byte, err error) {
_, objKind, err := s.ObjectVersionAndKind(obj) objGVK, err := s.ObjectKind(obj)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err = s.SetVersionAndKind("", objKind, obj); err != nil { if err = s.SetVersionAndKind("", objGVK.Kind, obj); err != nil {
return nil, err return nil, err
} }
data, err = json.Marshal(obj) data, err = json.Marshal(obj)

View File

@ -21,6 +21,8 @@ import (
"fmt" "fmt"
"path" "path"
"reflect" "reflect"
"k8s.io/kubernetes/pkg/api/unversioned"
) )
// MetaFactory is used to store and retrieve the version and kind // MetaFactory is used to store and retrieve the version and kind
@ -28,9 +30,9 @@ import (
type MetaFactory interface { type MetaFactory interface {
// Update sets the given version and kind onto the object. // Update sets the given version and kind onto the object.
Update(version, kind string, obj interface{}) error 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. // 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 // DefaultMetaFactory is a default factory for versioning objects in JSON. The object
@ -51,18 +53,23 @@ type SimpleMetaFactory struct {
BaseFields []string 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. // 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 { findKind := struct {
APIVersion string `json:"apiVersion,omitempty"` APIVersion string `json:"apiVersion,omitempty"`
Kind string `json:"kind,omitempty"` Kind string `json:"kind,omitempty"`
}{} }{}
err = json.Unmarshal(data, &findKind) err := json.Unmarshal(data, &findKind)
if err != nil { 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 { func (f SimpleMetaFactory) Update(version, kind string, obj interface{}) error {

View File

@ -26,25 +26,26 @@ import (
func TestSimpleMetaFactoryInterpret(t *testing.T) { func TestSimpleMetaFactoryInterpret(t *testing.T) {
factory := SimpleMetaFactory{} 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 { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
if version != "1" || kind != "object" { expectedFQKind := unversioned.GroupVersionKind{Group: "g", Version: "1", Kind: "object"}
t.Errorf("unexpected interpret: %s %s", version, kind) if expectedFQKind != fqKind {
t.Errorf("unexpected interpret: %s %s", expectedFQKind, fqKind)
} }
// no kind or version // no kind or version
version, kind, err = factory.Interpret([]byte(`{}`)) fqKind, err = factory.Interpret([]byte(`{}`))
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
if version != "" || kind != "" { if !fqKind.IsEmpty() {
t.Errorf("unexpected interpret: %s %s", version, kind) t.Errorf("unexpected interpret: %s %s", fqKind)
} }
// unparsable // unparsable
version, kind, err = factory.Interpret([]byte(`{`)) fqKind, err = factory.Interpret([]byte(`{`))
if err == nil { if err == nil {
t.Errorf("unexpected non-error") t.Errorf("unexpected non-error")
} }
@ -237,10 +238,10 @@ 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 Scope) error { 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) 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) t.Fatalf("Expected '%v', got '%v'", e, a)
} }
scope.Convert(&in.TestString, &out.TestString, 0) scope.Convert(&in.TestString, &out.TestString, 0)

View File

@ -281,15 +281,9 @@ func (s *Scheme) AddDefaultingFuncs(defaultingFuncs ...interface{}) error {
return nil 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. // of an object.
func (s *Scheme) Recognizes(gvString, kind string) bool { func (s *Scheme) Recognizes(gvk unversioned.GroupVersionKind) bool {
gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil {
return false
}
gvk := gv.WithKind(kind)
_, exists := s.gvkToType[gvk] _, exists := s.gvkToType[gvk]
return exists 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 // that case, the conversion.Scope object passed to your conversion functions won't
// have SrcVersion or DestVersion fields set correctly in Meta(). // have SrcVersion or DestVersion fields set correctly in Meta().
func (s *Scheme) Convert(in, out interface{}) error { func (s *Scheme) Convert(in, out interface{}) error {
inVersion := "unknown" inVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
outVersion := "unknown" outVersion := unversioned.GroupVersion{Group: "unknown", Version: "unknown"}
if v, _, err := s.ObjectVersionAndKind(in); err == nil { if gvk, err := s.ObjectKind(in); err == nil {
inVersion = v inVersion = gvk.GroupVersion()
} }
if v, _, err := s.ObjectVersionAndKind(out); err == nil { if gvk, err := s.ObjectKind(out); err == nil {
outVersion = v outVersion = gvk.GroupVersion()
} }
flags, meta := s.generateConvertMeta(inVersion, outVersion, in) flags, meta := s.generateConvertMeta(inVersion, outVersion, in)
if flags == 0 { if flags == 0 {
@ -346,27 +340,36 @@ func (s *Scheme) ConvertToVersion(in interface{}, outVersion string) (interface{
if !ok { if !ok {
return nil, fmt.Errorf("%v cannot be converted into version %q", t, outVersion) 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 { if err != nil {
return nil, err return nil, err
} }
out, err := s.NewObject(outVersion, outKind.Kind) out, err := s.NewObject(outGV.String(), outGVK.Kind)
if err != nil { if err != nil {
return nil, err 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 { if err := s.converter.Convert(in, out, flags, meta); err != nil {
return nil, err return nil, err
} }
if len(outVersion) != 0 { // <<<<<<< HEAD
if err := s.SetVersionAndKind(outVersion, outKind.Kind, out); err != nil { // if len(outVersion) != 0 {
return nil, err // 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 return out, nil
@ -378,37 +381,46 @@ func (s *Scheme) Converter() *Converter {
} }
// generateConvertMeta constructs the meta value we pass to Convert. // 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) t := reflect.TypeOf(in)
return s.converter.inputDefaultFlags[t], &Meta{ return s.converter.inputDefaultFlags[t], &Meta{
SrcVersion: srcVersion, SrcVersion: srcGroupVersion.String(),
DestVersion: destVersion, DestVersion: destGroupVersion.String(),
KeyNameMapping: s.converter.inputFieldMappingFuncs[t], 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. // 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) 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. // 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) v, err := EnforcePtr(obj)
if err != nil { if err != nil {
return "", "", err return []unversioned.GroupVersionKind{}, err
} }
t := v.Type() t := v.Type()
gvks, ok := s.typeToGVK[t] gvks, ok := s.typeToGVK[t]
if !ok { if !ok {
return "", "", &notRegisteredErr{t: t} return []unversioned.GroupVersionKind{}, &notRegisteredErr{t: t}
} }
apiVersion = gvks[0].GroupVersion().String() return gvks, nil
kind = gvks[0].Kind
return
} }
// SetVersionAndKind sets the version and kind fields (with help from // SetVersionAndKind sets the version and kind fields (with help from

View File

@ -128,18 +128,22 @@ func GetTestScheme() *Scheme {
type testMetaFactory struct{} type testMetaFactory struct{}
func (testMetaFactory) Interpret(data []byte) (version, kind string, err error) { func (testMetaFactory) Interpret(data []byte) (unversioned.GroupVersionKind, error) {
findKind := struct { findKind := struct {
APIVersion string `json:"myVersionKey,omitempty"` APIVersion string `json:"myVersionKey,omitempty"`
ObjectKind string `json:"myKindKey,omitempty"` ObjectKind string `json:"myKindKey,omitempty"`
}{} }{}
// yaml is a superset of json, so we use it to decode here. That way, // yaml is a superset of json, so we use it to decode here. That way,
// we understand both. // we understand both.
err = yaml.Unmarshal(data, &findKind) err := yaml.Unmarshal(data, &findKind)
if err != nil { 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 { 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 return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil
default: default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object) fqKind, err := api.Scheme.ObjectKind(object)
if err != nil { if err != nil {
return nil, err 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) newRc, ok = obj.(*api.ReplicationController)
if !ok { if !ok {
if _, kind, err := typer.ObjectVersionAndKind(obj); err == nil { if gvk, err := typer.ObjectKind(obj); err == nil {
return cmdutil.UsageError(cmd, "%s contains a %s not a ReplicationController", filename, kind) return cmdutil.UsageError(cmd, "%s contains a %v not a ReplicationController", filename, gvk)
} }
glog.V(4).Infof("Object %#v is not a ReplicationController", obj) glog.V(4).Infof("Object %#v is not a ReplicationController", obj)
return cmdutil.UsageError(cmd, "%s does not specify a valid ReplicationController", filename) 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 != "" { if outputFormat != "" {
return f.PrintObject(cmd, newRc, out) return f.PrintObject(cmd, newRc, out)
} }
_, kind, err := api.Scheme.ObjectVersionAndKind(newRc) gvk, err := api.Scheme.ObjectKind(newRc)
if err != nil { if err != nil {
return err return err
} }
_, res := meta.KindToResource(kind, false) _, res := meta.KindToResource(gvk.Kind, false)
cmdutil.PrintSuccess(mapper, false, out, res, oldName, message) cmdutil.PrintSuccess(mapper, false, out, res, oldName, message)
return nil return nil
} }

View File

@ -25,7 +25,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/unversioned"
client "k8s.io/kubernetes/pkg/client/unversioned" client "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" 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() mapper, typer := f.Object()
gvString, kind, err := typer.ObjectVersionAndKind(obj) groupVersionKind, err := typer.ObjectKind(obj)
if err != nil { if err != nil {
return nil, "", nil, nil, err 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 { if len(overrides) > 0 {
obj, err = cmdutil.Merge(obj, overrides, kind) obj, err = cmdutil.Merge(obj, overrides, groupVersionKind.Kind)
if err != nil { if err != nil {
return nil, "", nil, nil, err return nil, "", nil, nil, err
} }
} }
mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version) mapping, err := mapper.RESTMapping(groupVersionKind.GroupKind(), groupVersionKind.Version)
if err != nil { if err != nil {
return nil, "", nil, nil, err 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 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 return kubectl.MakeLabels(t.Spec.Selector), nil
default: default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object) gvk, err := api.Scheme.ObjectKind(object)
if err != nil { if err != nil {
return "", err 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) { PortsForObject: func(object runtime.Object) ([]string, error) {
@ -216,11 +216,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
case *api.Service: case *api.Service:
return getServicePorts(t.Spec), nil return getServicePorts(t.Spec), nil
default: default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object) gvk, err := api.Scheme.ObjectKind(object)
if err != nil { if err != nil {
return nil, err 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) { 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 return c.Pods(t.Namespace).GetLogs(t.Name, opts), nil
default: default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object) gvk, err := api.Scheme.ObjectKind(object)
if err != nil { if err != nil {
return nil, err 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) { Scaler: func(mapping *meta.RESTMapping) (kubectl.Scaler, error) {
@ -323,11 +323,11 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
case *api.Pod: case *api.Pod:
return t, nil return t, nil
default: default:
_, kind, err := api.Scheme.ObjectVersionAndKind(object) gvk, err := api.Scheme.ObjectKind(object)
if err != nil { if err != nil {
return nil, err 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 { EditorEnvs: func() []string {
@ -489,29 +489,20 @@ func getSchemaAndValidate(c schemaClient, data []byte, prefix, groupVersion, cac
} }
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error { func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
version, kind, err := runtime.UnstructuredJSONScheme.DataVersionAndKind(data) gvk, err := runtime.UnstructuredJSONScheme.DataKind(data)
if err != nil { if err != nil {
return err return err
} }
gv, err := unversioned.ParseGroupVersion(version) if ok := registered.IsRegisteredAPIGroupVersion(gvk.GroupVersion()); !ok {
if err != nil { return fmt.Errorf("API version %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), registered.RegisteredGroupVersions)
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 gvk.Group == "extensions" { if gvk.Group == "extensions" {
if c.c.ExtensionsClient == nil { if c.c.ExtensionsClient == nil {
return errors.New("unable to validate: no experimental client") 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: // 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 // 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 { func (f *Factory) PrintObject(cmd *cobra.Command, obj runtime.Object, out io.Writer) error {
mapper, _ := f.Object() mapper, _ := f.Object()
gvString, kind, err := api.Scheme.ObjectVersionAndKind(obj) gvk, err := api.Scheme.ObjectKind(obj)
if err != nil {
return err
}
gv, err := unversioned.ParseGroupVersion(gvString)
if err != nil { if err != nil {
return err return err
} }
mapping, err := mapper.RESTMapping(unversioned.GroupKind{Group: gv.Group, Kind: kind}) mapping, err := mapper.RESTMapping(gvk.GroupKind())
if err != nil { if err != nil {
return err return err
} }

View File

@ -23,7 +23,6 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta" "k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/registered" "k8s.io/kubernetes/pkg/api/registered"
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/yaml" "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) return nil, fmt.Errorf("unable to parse %q: %v", source, err)
} }
data = json data = json
version, kind, err := runtime.UnstructuredJSONScheme.DataVersionAndKind(data) gvk, err := runtime.UnstructuredJSONScheme.DataKind(data)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get type info from %q: %v", source, err) return nil, fmt.Errorf("unable to get type info from %q: %v", source, err)
} }
gv, err := unversioned.ParseGroupVersion(version) if ok := registered.IsRegisteredAPIGroupVersion(gvk.GroupVersion()); !ok {
if err != nil { return nil, fmt.Errorf("API version %q in %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), source, registered.RegisteredGroupVersions)
return nil, fmt.Errorf("unable to parse group/version from %q: %v", version, err)
} }
if ok := registered.IsRegisteredAPIGroupVersion(gv); !ok { if gvk.Kind == "" {
return nil, fmt.Errorf("API version %q in %q isn't supported, only supports API versions %q", version, source, registered.RegisteredGroupVersions)
}
if kind == "" {
return nil, fmt.Errorf("kind not set in %q", source) 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 { if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", source, err) 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 object cannot be introspected. Name and namespace will be set into Info
// if the mapping's MetadataAccessor can retrieve them. // if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForObject(obj runtime.Object) (*Info, error) { func (m *Mapper) InfoForObject(obj runtime.Object) (*Info, error) {
gvString, kind, err := m.ObjectVersionAndKind(obj) groupVersionKind, err := m.ObjectKind(obj)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err) 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 { if err != nil {
return nil, fmt.Errorf("unable to parse group/version from %q: %v", gvString, err) return nil, fmt.Errorf("unable to recognize %v: %v", groupVersionKind, 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)
} }
client, err := m.ClientForMapping(mapping) client, err := m.ClientForMapping(mapping)
if err != nil { 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 // 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 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. // TODO: ideally this would encode to version, but we don't expose multiple codecs here.
data, err := info.Mapping.Codec.Encode(info.Object) data, err := info.Mapping.Codec.Encode(info.Object)
if err != nil { 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++ { for i := 0; i < items.Len(); i++ {
rawObj := items.Index(i).FieldByName("RawJSON").Interface().([]byte) rawObj := items.Index(i).FieldByName("RawJSON").Interface().([]byte)
scheme := api.Scheme scheme := api.Scheme
version, kind, err := scheme.DataVersionAndKind(rawObj) groupVersionKind, err := scheme.DataKind(rawObj)
if err != nil { if err != nil {
return err return err
} }
@ -222,8 +222,8 @@ func (p *NamePrinter) PrintObj(obj runtime.Object, w io.Writer) error {
return err return err
} }
tpmeta := unversioned.TypeMeta{ tpmeta := unversioned.TypeMeta{
APIVersion: version, APIVersion: groupVersionKind.GroupVersion().String(),
Kind: kind, Kind: groupVersionKind.Kind,
} }
s := reflect.ValueOf(decodedObj).Elem() s := reflect.ValueOf(decodedObj).Elem()
s.FieldByName("TypeMeta").Set(reflect.ValueOf(tpmeta)) 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 // get codec based on runtime.Object
func getCodec(obj runtime.Object) (runtime.Codec, error) { func getCodec(obj runtime.Object) (runtime.Codec, error) {
_, kind, err := api.Scheme.ObjectVersionAndKind(obj) fqKind, err := api.Scheme.ObjectKind(obj)
if err != nil { if err != nil {
return nil, fmt.Errorf("unexpected encoding error: %v", err) 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. // split the schemes for internal objects.
// TODO: caesarxuchao: we should add a map from kind to group in Scheme. // TODO: caesarxuchao: we should add a map from kind to group in Scheme.
var codec runtime.Codec 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() 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() codec = testapi.Extensions.Codec()
} else { } else {
return nil, fmt.Errorf("unexpected kind: %v", kind) return nil, fmt.Errorf("unexpected kind: %v", fqKind)
} }
return codec, nil return codec, nil
} }

View File

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

View File

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

View File

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

View File

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

View File

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