List output with differing types should be more resilient

kubectl get can output a series of objects as a List in versioned
form, but not all API objects are available in the same schema.
Make the act of converting a []runtime.Object to api.List more
robust and add a test to verify its behavior in Get.

Makes it easier for client code to output unified objects.
This commit is contained in:
Clayton Coleman
2015-04-16 19:21:13 -04:00
parent 7f75c982ce
commit 545a5a865f
9 changed files with 255 additions and 29 deletions

View File

@@ -21,6 +21,7 @@ import (
"reflect"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
@@ -200,3 +201,67 @@ func (r *Result) Watch(resourceVersion string) (watch.Interface, error) {
}
return w.Watch(resourceVersion)
}
// AsVersionedObject converts a list of infos into a single object - either a List containing
// the objects as children, or if only a single Object is present, as that object. The provided
// version will be preferred as the conversion target, but the Object's mapping version will be
// used if that version is not present.
func AsVersionedObject(infos []*Info, forceList bool, version string) (runtime.Object, error) {
objects := []runtime.Object{}
for _, info := range infos {
if info.Object == nil {
continue
}
// 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) {
// 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 {
return nil, err
}
objects = append(objects, &runtime.Unknown{RawJSON: data})
continue
}
}
converted, err := tryConvert(info.Mapping.ObjectConvertor, info.Object, version, info.Mapping.APIVersion)
if err != nil {
return nil, err
}
objects = append(objects, converted)
}
var object runtime.Object
if len(objects) == 1 && !forceList {
object = objects[0]
} else {
object = &api.List{Items: objects}
converted, err := tryConvert(api.Scheme, object, version, latest.Version)
if err != nil {
return nil, err
}
object = converted
}
return object, nil
}
// tryConvert attempts to convert the given object to the provided versions in order. This function assumes
// the object is in internal version.
func tryConvert(convertor runtime.ObjectConvertor, object runtime.Object, versions ...string) (runtime.Object, error) {
var last error
for _, version := range versions {
if len(version) == 0 {
return object, nil
}
obj, err := convertor.ConvertToVersion(object, version)
if err != nil {
last = err
continue
}
return obj, nil
}
return nil, last
}