API server should offer metav1 Table/Partial transforms

Now that internal types are equivalent, allow the apiserver to serve metav1 and metav1beta1 depending on the client. Test that in the apiserver integration test and ensure we get the appropriate responses. Register the metav1 type in the appropriate external locations.
parent e256c15d
...@@ -57,7 +57,8 @@ import ( ...@@ -57,7 +57,8 @@ import (
func init() { func init() {
// Register external types for Scheme // Register external types for Scheme
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
utilruntime.Must(metav1beta1.AddToScheme(Scheme)) utilruntime.Must(metav1beta1.AddMetaToScheme(Scheme))
utilruntime.Must(metav1.AddMetaToScheme(Scheme))
utilruntime.Must(scheme.AddToScheme(Scheme)) utilruntime.Must(scheme.AddToScheme(Scheme))
utilruntime.Must(Scheme.SetVersionPriority(corev1.SchemeGroupVersion)) utilruntime.Must(Scheme.SetVersionPriority(corev1.SchemeGroupVersion))
......
...@@ -539,12 +539,12 @@ func translateTimestampUntil(timestamp metav1.Time) string { ...@@ -539,12 +539,12 @@ func translateTimestampUntil(timestamp metav1.Time) string {
} }
var ( var (
podSuccessConditions = []metav1beta1.TableRowCondition{{Type: metav1beta1.RowCompleted, Status: metav1beta1.ConditionTrue, Reason: string(api.PodSucceeded), Message: "The pod has completed successfully."}} podSuccessConditions = []metav1.TableRowCondition{{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: string(api.PodSucceeded), Message: "The pod has completed successfully."}}
podFailedConditions = []metav1beta1.TableRowCondition{{Type: metav1beta1.RowCompleted, Status: metav1beta1.ConditionTrue, Reason: string(api.PodFailed), Message: "The pod failed."}} podFailedConditions = []metav1.TableRowCondition{{Type: metav1.RowCompleted, Status: metav1.ConditionTrue, Reason: string(api.PodFailed), Message: "The pod failed."}}
) )
func printPodList(podList *api.PodList, options printers.PrintOptions) ([]metav1beta1.TableRow, error) { func printPodList(podList *api.PodList, options printers.PrintOptions) ([]metav1.TableRow, error) {
rows := make([]metav1beta1.TableRow, 0, len(podList.Items)) rows := make([]metav1.TableRow, 0, len(podList.Items))
for i := range podList.Items { for i := range podList.Items {
r, err := printPod(&podList.Items[i], options) r, err := printPod(&podList.Items[i], options)
if err != nil { if err != nil {
...@@ -555,7 +555,7 @@ func printPodList(podList *api.PodList, options printers.PrintOptions) ([]metav1 ...@@ -555,7 +555,7 @@ func printPodList(podList *api.PodList, options printers.PrintOptions) ([]metav1
return rows, nil return rows, nil
} }
func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1beta1.TableRow, error) { func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1.TableRow, error) {
restarts := 0 restarts := 0
totalContainers := len(pod.Spec.Containers) totalContainers := len(pod.Spec.Containers)
readyContainers := 0 readyContainers := 0
...@@ -565,7 +565,7 @@ func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1beta1.TableR ...@@ -565,7 +565,7 @@ func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1beta1.TableR
reason = pod.Status.Reason reason = pod.Status.Reason
} }
row := metav1beta1.TableRow{ row := metav1.TableRow{
Object: runtime.RawExtension{Object: pod}, Object: runtime.RawExtension{Object: pod},
} }
......
...@@ -148,8 +148,10 @@ func TestTableGet(t *testing.T) { ...@@ -148,8 +148,10 @@ func TestTableGet(t *testing.T) {
codecs := serializer.NewCodecFactory(scheme) codecs := serializer.NewCodecFactory(scheme)
parameterCodec := runtime.NewParameterCodec(scheme) parameterCodec := runtime.NewParameterCodec(scheme)
metav1.AddToGroupVersion(scheme, gv) metav1.AddToGroupVersion(scheme, gv)
scheme.AddKnownTypes(gv, &metav1beta1.Table{}, &metav1beta1.TableOptions{}) scheme.AddKnownTypes(gv, &metav1beta1.TableOptions{})
scheme.AddKnownTypes(gv, &metav1.TableOptions{})
scheme.AddKnownTypes(metav1beta1.SchemeGroupVersion, &metav1beta1.Table{}, &metav1beta1.TableOptions{}) scheme.AddKnownTypes(metav1beta1.SchemeGroupVersion, &metav1beta1.Table{}, &metav1beta1.TableOptions{})
scheme.AddKnownTypes(metav1.SchemeGroupVersion, &metav1.Table{}, &metav1.TableOptions{})
crConfig := *config crConfig := *config
crConfig.GroupVersion = &gv crConfig.GroupVersion = &gv
......
...@@ -42,7 +42,6 @@ go_library( ...@@ -42,7 +42,6 @@ go_library(
importpath = "k8s.io/apimachinery/pkg/api/meta", importpath = "k8s.io/apimachinery/pkg/api/meta",
deps = [ deps = [
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1beta1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/conversion:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
......
...@@ -21,7 +21,6 @@ import ( ...@@ -21,7 +21,6 @@ import (
"reflect" "reflect"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
"k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
...@@ -114,12 +113,12 @@ func Accessor(obj interface{}) (metav1.Object, error) { ...@@ -114,12 +113,12 @@ func Accessor(obj interface{}) (metav1.Object, error) {
// AsPartialObjectMetadata takes the metav1 interface and returns a partial object. // AsPartialObjectMetadata takes the metav1 interface and returns a partial object.
// TODO: consider making this solely a conversion action. // TODO: consider making this solely a conversion action.
func AsPartialObjectMetadata(m metav1.Object) *metav1beta1.PartialObjectMetadata { func AsPartialObjectMetadata(m metav1.Object) *metav1.PartialObjectMetadata {
switch t := m.(type) { switch t := m.(type) {
case *metav1.ObjectMeta: case *metav1.ObjectMeta:
return &metav1beta1.PartialObjectMetadata{ObjectMeta: *t} return &metav1.PartialObjectMetadata{ObjectMeta: *t}
default: default:
return &metav1beta1.PartialObjectMetadata{ return &metav1.PartialObjectMetadata{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: m.GetName(), Name: m.GetName(),
GenerateName: m.GetGenerateName(), GenerateName: m.GetGenerateName(),
......
...@@ -113,7 +113,4 @@ func AddMetaToScheme(scheme *runtime.Scheme) error { ...@@ -113,7 +113,4 @@ func AddMetaToScheme(scheme *runtime.Scheme) error {
return scheme.AddConversionFuncs( return scheme.AddConversionFuncs(
Convert_Slice_string_To_v1_IncludeObjectPolicy, Convert_Slice_string_To_v1_IncludeObjectPolicy,
) )
// register manually. This usually goes through the SchemeBuilder, which we cannot use here.
//scheme.AddGeneratedDeepCopyFuncs(GetGeneratedDeepCopyFuncs()...)
} }
...@@ -49,18 +49,18 @@ func transformObject(ctx context.Context, obj runtime.Object, opts interface{}, ...@@ -49,18 +49,18 @@ func transformObject(ctx context.Context, obj runtime.Object, opts interface{},
case target == nil: case target == nil:
return obj, nil return obj, nil
case target.Kind == "PartialObjectMetadata" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "PartialObjectMetadata":
return asV1Beta1PartialObjectMetadata(obj) return asPartialObjectMetadata(obj, target.GroupVersion())
case target.Kind == "PartialObjectMetadataList" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "PartialObjectMetadataList":
return asV1Beta1PartialObjectMetadataList(obj) return asPartialObjectMetadataList(obj, target.GroupVersion())
case target.Kind == "Table" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "Table":
options, ok := opts.(*metav1beta1.TableOptions) options, ok := opts.(*metav1beta1.TableOptions)
if !ok { if !ok {
return nil, fmt.Errorf("unexpected TableOptions, got %T", opts) return nil, fmt.Errorf("unexpected TableOptions, got %T", opts)
} }
return asV1Beta1Table(ctx, obj, options, scope) return asTable(ctx, obj, options, scope, target.GroupVersion())
default: default:
accepted, _ := negotiation.MediaTypesForSerializer(metainternalversion.Codecs) accepted, _ := negotiation.MediaTypesForSerializer(metainternalversion.Codecs)
...@@ -74,7 +74,7 @@ func transformObject(ctx context.Context, obj runtime.Object, opts interface{}, ...@@ -74,7 +74,7 @@ func transformObject(ctx context.Context, obj runtime.Object, opts interface{},
func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Request) (interface{}, error) { func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Request) (interface{}, error) {
switch target := mediaType.Convert; { switch target := mediaType.Convert; {
case target == nil: case target == nil:
case target.Kind == "Table" && target.GroupVersion() == metav1beta1.SchemeGroupVersion: case target.Kind == "Table" && (target.GroupVersion() == metav1beta1.SchemeGroupVersion || target.GroupVersion() == metav1.SchemeGroupVersion):
opts := &metav1beta1.TableOptions{} opts := &metav1beta1.TableOptions{}
if err := metav1beta1.ParameterCodec.DecodeParameters(req.URL.Query(), metav1beta1.SchemeGroupVersion, opts); err != nil { if err := metav1beta1.ParameterCodec.DecodeParameters(req.URL.Query(), metav1beta1.SchemeGroupVersion, opts); err != nil {
return nil, err return nil, err
...@@ -95,9 +95,8 @@ func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Reque ...@@ -95,9 +95,8 @@ func optionsForTransform(mediaType negotiation.MediaTypeOptions, req *http.Reque
func targetEncodingForTransform(scope *RequestScope, mediaType negotiation.MediaTypeOptions, req *http.Request) (schema.GroupVersionKind, runtime.NegotiatedSerializer, bool) { func targetEncodingForTransform(scope *RequestScope, mediaType negotiation.MediaTypeOptions, req *http.Request) (schema.GroupVersionKind, runtime.NegotiatedSerializer, bool) {
switch target := mediaType.Convert; { switch target := mediaType.Convert; {
case target == nil: case target == nil:
case target.Kind == "PartialObjectMetadata" && target.GroupVersion() == metav1beta1.SchemeGroupVersion, case (target.Kind == "PartialObjectMetadata" || target.Kind == "PartialObjectMetadataList" || target.Kind == "Table") &&
target.Kind == "PartialObjectMetadataList" && target.GroupVersion() == metav1beta1.SchemeGroupVersion, (target.GroupVersion() == metav1beta1.SchemeGroupVersion || target.GroupVersion() == metav1.SchemeGroupVersion):
target.Kind == "Table" && target.GroupVersion() == metav1beta1.SchemeGroupVersion:
return *target, metainternalversion.Codecs, true return *target, metainternalversion.Codecs, true
} }
return scope.Kind, scope.Serializer, false return scope.Kind, scope.Serializer, false
...@@ -142,31 +141,39 @@ func (e errNotAcceptable) Status() metav1.Status { ...@@ -142,31 +141,39 @@ func (e errNotAcceptable) Status() metav1.Status {
} }
} }
func asV1Beta1Table(ctx context.Context, result runtime.Object, opts *metav1beta1.TableOptions, scope *RequestScope) (runtime.Object, error) { func asTable(ctx context.Context, result runtime.Object, opts *metav1beta1.TableOptions, scope *RequestScope, groupVersion schema.GroupVersion) (runtime.Object, error) {
table, err := scope.TableConvertor.ConvertToTable(ctx, result, opts) switch groupVersion {
case metav1beta1.SchemeGroupVersion, metav1.SchemeGroupVersion:
default:
return nil, newNotAcceptableError(fmt.Sprintf("no Table exists in group version %s", groupVersion))
}
obj, err := scope.TableConvertor.ConvertToTable(ctx, result, opts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
table := (*metav1.Table)(obj)
for i := range table.Rows { for i := range table.Rows {
item := &table.Rows[i] item := &table.Rows[i]
switch opts.IncludeObject { switch opts.IncludeObject {
case metav1beta1.IncludeObject: case metav1.IncludeObject:
item.Object.Object, err = scope.Convertor.ConvertToVersion(item.Object.Object, scope.Kind.GroupVersion()) item.Object.Object, err = scope.Convertor.ConvertToVersion(item.Object.Object, scope.Kind.GroupVersion())
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: rely on defaulting for the value here? // TODO: rely on defaulting for the value here?
case metav1beta1.IncludeMetadata, "": case metav1.IncludeMetadata, "":
m, err := meta.Accessor(item.Object.Object) m, err := meta.Accessor(item.Object.Object)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// TODO: turn this into an internal type and do conversion in order to get object kind automatically set? // TODO: turn this into an internal type and do conversion in order to get object kind automatically set?
partial := meta.AsPartialObjectMetadata(m) partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) partial.GetObjectKind().SetGroupVersionKind(groupVersion.WithKind("PartialObjectMetadata"))
item.Object.Object = partial item.Object.Object = partial
case metav1beta1.IncludeNone: case metav1.IncludeNone:
item.Object.Object = nil item.Object.Object = nil
default: default:
err = errors.NewBadRequest(fmt.Sprintf("unrecognized includeObject value: %q", opts.IncludeObject)) err = errors.NewBadRequest(fmt.Sprintf("unrecognized includeObject value: %q", opts.IncludeObject))
...@@ -177,42 +184,74 @@ func asV1Beta1Table(ctx context.Context, result runtime.Object, opts *metav1beta ...@@ -177,42 +184,74 @@ func asV1Beta1Table(ctx context.Context, result runtime.Object, opts *metav1beta
return table, nil return table, nil
} }
func asV1Beta1PartialObjectMetadata(result runtime.Object) (runtime.Object, error) { func asPartialObjectMetadata(result runtime.Object, groupVersion schema.GroupVersion) (runtime.Object, error) {
if meta.IsListType(result) { if meta.IsListType(result) {
err := newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadata, but the requested object is a list (%T)", result)) err := newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadata, but the requested object is a list (%T)", result))
return nil, err return nil, err
} }
switch groupVersion {
case metav1beta1.SchemeGroupVersion, metav1.SchemeGroupVersion:
default:
return nil, newNotAcceptableError(fmt.Sprintf("no PartialObjectMetadataList exists in group version %s", groupVersion))
}
m, err := meta.Accessor(result) m, err := meta.Accessor(result)
if err != nil { if err != nil {
return nil, err return nil, err
} }
partial := meta.AsPartialObjectMetadata(m) partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) partial.GetObjectKind().SetGroupVersionKind(groupVersion.WithKind("PartialObjectMetadata"))
return partial, nil return partial, nil
} }
func asV1Beta1PartialObjectMetadataList(result runtime.Object) (runtime.Object, error) { func asPartialObjectMetadataList(result runtime.Object, groupVersion schema.GroupVersion) (runtime.Object, error) {
if !meta.IsListType(result) { li, ok := result.(metav1.ListInterface)
if !ok {
return nil, newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadataList, but the requested object is not a list (%T)", result)) return nil, newNotAcceptableError(fmt.Sprintf("you requested PartialObjectMetadataList, but the requested object is not a list (%T)", result))
} }
list := &metav1beta1.PartialObjectMetadataList{}
if li, ok := result.(metav1.ListInterface); ok { gvk := groupVersion.WithKind("PartialObjectMetadata")
switch {
case groupVersion == metav1beta1.SchemeGroupVersion:
list := &metav1beta1.PartialObjectMetadataList{}
err := meta.EachListItem(result, func(obj runtime.Object) error {
m, err := meta.Accessor(obj)
if err != nil {
return err
}
partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(gvk)
list.Items = append(list.Items, partial)
return nil
})
if err != nil {
return nil, err
}
list.SelfLink = li.GetSelfLink() list.SelfLink = li.GetSelfLink()
list.ResourceVersion = li.GetResourceVersion() list.ResourceVersion = li.GetResourceVersion()
list.Continue = li.GetContinue() list.Continue = li.GetContinue()
} return list, nil
err := meta.EachListItem(result, func(obj runtime.Object) error {
m, err := meta.Accessor(obj) case groupVersion == metav1.SchemeGroupVersion:
list := &metav1.PartialObjectMetadataList{}
err := meta.EachListItem(result, func(obj runtime.Object) error {
m, err := meta.Accessor(obj)
if err != nil {
return err
}
partial := meta.AsPartialObjectMetadata(m)
partial.GetObjectKind().SetGroupVersionKind(gvk)
list.Items = append(list.Items, partial)
return nil
})
if err != nil { if err != nil {
return err return nil, err
} }
partial := meta.AsPartialObjectMetadata(m) list.SelfLink = li.GetSelfLink()
partial.GetObjectKind().SetGroupVersionKind(metav1beta1.SchemeGroupVersion.WithKind("PartialObjectMetadata")) list.ResourceVersion = li.GetResourceVersion()
list.Items = append(list.Items, partial) list.Continue = li.GetContinue()
return nil return list, nil
})
if err != nil { default:
return nil, err return nil, newNotAcceptableError(fmt.Sprintf("no PartialObjectMetadataList exists in group version %s", groupVersion))
} }
return list, nil
} }
...@@ -78,7 +78,7 @@ func (scope *RequestScope) err(err error, w http.ResponseWriter, req *http.Reque ...@@ -78,7 +78,7 @@ func (scope *RequestScope) err(err error, w http.ResponseWriter, req *http.Reque
func (scope *RequestScope) AllowsConversion(gvk schema.GroupVersionKind, mimeType, mimeSubType string) bool { func (scope *RequestScope) AllowsConversion(gvk schema.GroupVersionKind, mimeType, mimeSubType string) bool {
// TODO: this is temporary, replace with an abstraction calculated at endpoint installation time // TODO: this is temporary, replace with an abstraction calculated at endpoint installation time
if gvk.GroupVersion() == metav1beta1.SchemeGroupVersion { if gvk.GroupVersion() == metav1beta1.SchemeGroupVersion || gvk.GroupVersion() == metav1.SchemeGroupVersion {
switch gvk.Kind { switch gvk.Kind {
case "Table": case "Table":
return scope.TableConvertor != nil && return scope.TableConvertor != nil &&
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment