diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go index 37579820a4a..06e0b211897 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/installer.go @@ -381,7 +381,11 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag resourceKind = kind } - tableProvider, _ := storage.(rest.TableConvertor) + tableProvider, isTableProvider := storage.(rest.TableConvertor) + if isLister && !isTableProvider { + // All listers must implement TableProvider + return nil, fmt.Errorf("%q must implement TableConvertor", resource) + } var apiResource metav1.APIResource if utilfeature.DefaultFeatureGate.Enabled(features.StorageVersionHash) && diff --git a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go index 3993bd2366c..edd75bc2af6 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/generic/registry/store.go @@ -1217,6 +1217,10 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { return fmt.Errorf("store for %s must set both KeyRootFunc and KeyFunc or neither", e.DefaultQualifiedResource.String()) } + if e.TableConvertor == nil { + return fmt.Errorf("store for %s must set TableConvertor; rest.NewDefaultTableConvertor(e.DefaultQualifiedResource) can be used to output just name/creation time", e.DefaultQualifiedResource.String()) + } + var isNamespaced bool switch { case e.CreateStrategy != nil: @@ -1377,7 +1381,7 @@ func (e *Store) ConvertToTable(ctx context.Context, object runtime.Object, table if e.TableConvertor != nil { return e.TableConvertor.ConvertToTable(ctx, object, tableOptions) } - return rest.NewDefaultTableConvertor(e.qualifiedResourceFromContext(ctx)).ConvertToTable(ctx, object, tableOptions) + return rest.NewDefaultTableConvertor(e.DefaultQualifiedResource).ConvertToTable(ctx, object, tableOptions) } func (e *Store) StorageVersion() runtime.GroupVersioner { diff --git a/staging/src/k8s.io/apiserver/pkg/registry/rest/table.go b/staging/src/k8s.io/apiserver/pkg/registry/rest/table.go index 31a46c74333..d90ae70762b 100644 --- a/staging/src/k8s.io/apiserver/pkg/registry/rest/table.go +++ b/staging/src/k8s.io/apiserver/pkg/registry/rest/table.go @@ -26,15 +26,17 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" ) type defaultTableConvertor struct { - qualifiedResource schema.GroupResource + defaultQualifiedResource schema.GroupResource } -// NewDefaultTableConvertor creates a default convertor for the provided resource. -func NewDefaultTableConvertor(resource schema.GroupResource) TableConvertor { - return defaultTableConvertor{qualifiedResource: resource} +// NewDefaultTableConvertor creates a default convertor; the provided resource is used for error messages +// if no resource info can be determined from the context passed to ConvertToTable. +func NewDefaultTableConvertor(defaultQualifiedResource schema.GroupResource) TableConvertor { + return defaultTableConvertor{defaultQualifiedResource: defaultQualifiedResource} } var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc() @@ -44,7 +46,11 @@ func (c defaultTableConvertor) ConvertToTable(ctx context.Context, object runtim fn := func(obj runtime.Object) error { m, err := meta.Accessor(obj) if err != nil { - return errNotAcceptable{resource: c.qualifiedResource} + resource := c.defaultQualifiedResource + if info, ok := genericapirequest.RequestInfoFrom(ctx); ok { + resource = schema.GroupResource{Group: info.APIGroup, Resource: info.Resource} + } + return errNotAcceptable{resource: resource} } table.Rows = append(table.Rows, metav1.TableRow{ Cells: []interface{}{m.GetName(), m.GetCreationTimestamp().Time.UTC().Format(time.RFC3339)},