mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-14 05:36:12 +00:00
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:
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user