remove rootscopedkinds from groupmeta
Kubernetes-commit: 8ae62517da5eff6d6bad21badfd39ee88463ad42
This commit is contained in:
parent
bd62696dfb
commit
b7f90743d0
|
@ -20,7 +20,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver"
|
||||
"k8s.io/apiserver/pkg/apis/apiserver/v1alpha1"
|
||||
)
|
||||
|
@ -30,7 +29,6 @@ func Install(registry *registered.APIRegistrationManager, scheme *runtime.Scheme
|
|||
if err := announced.NewGroupMetaFactory(
|
||||
&announced.GroupMetaFactoryArgs{
|
||||
GroupName: apiserver.GroupName,
|
||||
RootScopedKinds: sets.NewString("AdmissionConfiguration"),
|
||||
VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version},
|
||||
AddInternalObjectsToScheme: apiserver.AddToScheme,
|
||||
},
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/apis/audit"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1alpha1"
|
||||
"k8s.io/apiserver/pkg/apis/audit/v1beta1"
|
||||
|
@ -32,10 +31,8 @@ import (
|
|||
func Install(registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
|
||||
if err := announced.NewGroupMetaFactory(
|
||||
&announced.GroupMetaFactoryArgs{
|
||||
GroupName: audit.GroupName,
|
||||
VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version, v1alpha1.SchemeGroupVersion.Version},
|
||||
// Any Kind that is not namespaced must be cluster scoped.
|
||||
RootScopedKinds: sets.NewString("Event", "Policy"),
|
||||
GroupName: audit.GroupName,
|
||||
VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version, v1alpha1.SchemeGroupVersion.Version},
|
||||
AddInternalObjectsToScheme: audit.AddToScheme,
|
||||
},
|
||||
announced.VersionToSchemeFunc{
|
||||
|
|
|
@ -347,6 +347,10 @@ type SimpleRESTStorage struct {
|
|||
injectedFunction func(obj runtime.Object) (returnObj runtime.Object, err error)
|
||||
}
|
||||
|
||||
func (storage *SimpleRESTStorage) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (storage *SimpleRESTStorage) Export(ctx context.Context, name string, opts metav1.ExportOptions) (runtime.Object, error) {
|
||||
obj, err := storage.Get(ctx, name, &metav1.GetOptions{})
|
||||
if err != nil {
|
||||
|
@ -615,6 +619,10 @@ type GetWithOptionsRootRESTStorage struct {
|
|||
takesPath string
|
||||
}
|
||||
|
||||
func (r *GetWithOptionsRootRESTStorage) NamespaceScoped() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *GetWithOptionsRootRESTStorage) Get(ctx context.Context, name string, options runtime.Object) (runtime.Object, error) {
|
||||
if _, ok := options.(*genericapitesting.SimpleGetOptions); !ok {
|
||||
return nil, fmt.Errorf("Unexpected options object: %#v", options)
|
||||
|
@ -801,6 +809,10 @@ func TestNotFound(t *testing.T) {
|
|||
|
||||
type UnimplementedRESTStorage struct{}
|
||||
|
||||
func (UnimplementedRESTStorage) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (UnimplementedRESTStorage) New() runtime.Object {
|
||||
return &genericapitesting.Simple{}
|
||||
}
|
||||
|
@ -3774,10 +3786,6 @@ func (storage *SimpleXGSubresourceRESTStorage) GroupVersionKind(containingGV sch
|
|||
return storage.itemGVK
|
||||
}
|
||||
|
||||
func (*SimpleXGSubresourceRESTStorage) ClusterScoped() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func TestXGSubresource(t *testing.T) {
|
||||
container := restful.NewContainer()
|
||||
container.Router(restful.CurlyRouter{})
|
||||
|
|
|
@ -132,18 +132,18 @@ func (a *APIInstaller) newWebService() *restful.WebService {
|
|||
}
|
||||
|
||||
// getResourceKind returns the external group version kind registered for the given storage
|
||||
// object and whether or not the kind is cluster scoped. If the storage object is a subresource and has an override supplied for it, it returns
|
||||
// object. If the storage object is a subresource and has an override supplied for it, it returns
|
||||
// the group version kind supplied in the override.
|
||||
func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schema.GroupVersionKind, bool, error) {
|
||||
func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schema.GroupVersionKind, error) {
|
||||
// Let the storage tell us exactly what GVK it has
|
||||
if gvkProvider, ok := storage.(rest.GroupVersionKindProvider); ok {
|
||||
return gvkProvider.GroupVersionKind(a.group.GroupVersion), gvkProvider.ClusterScoped(), nil
|
||||
return gvkProvider.GroupVersionKind(a.group.GroupVersion), nil
|
||||
}
|
||||
|
||||
object := storage.New()
|
||||
fqKinds, _, err := a.group.Typer.ObjectKinds(object)
|
||||
if err != nil {
|
||||
return schema.GroupVersionKind{}, false, err
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
|
||||
// a given go type can have multiple potential fully qualified kinds. Find the one that corresponds with the group
|
||||
|
@ -156,11 +156,11 @@ func (a *APIInstaller) getResourceKind(path string, storage rest.Storage) (schem
|
|||
}
|
||||
}
|
||||
if fqKindToRegister.Empty() {
|
||||
return schema.GroupVersionKind{}, false, fmt.Errorf("unable to locate fully qualified kind for %v: found %v when registering for %v", reflect.TypeOf(object), fqKinds, a.group.GroupVersion)
|
||||
return schema.GroupVersionKind{}, fmt.Errorf("unable to locate fully qualified kind for %v: found %v when registering for %v", reflect.TypeOf(object), fqKinds, a.group.GroupVersion)
|
||||
}
|
||||
|
||||
// group is guaranteed to match based on the check above
|
||||
return fqKindToRegister, a.group.RootScopedKinds.Has(fqKindToRegister.Kind), nil
|
||||
return fqKindToRegister, nil
|
||||
}
|
||||
|
||||
func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storage, ws *restful.WebService) (*metav1.APIResource, error) {
|
||||
|
@ -176,7 +176,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
return nil, err
|
||||
}
|
||||
|
||||
fqKindToRegister, clusterScoped, err := a.getResourceKind(path, storage)
|
||||
fqKindToRegister, err := a.getResourceKind(path, storage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -187,7 +187,28 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
}
|
||||
defaultVersionedObject := indirectArbitraryPointer(versionedPtr)
|
||||
kind := fqKindToRegister.Kind
|
||||
hasSubresource := len(subresource) > 0
|
||||
isSubresource := len(subresource) > 0
|
||||
|
||||
// If there is a subresource, namespace scoping is defined by the parent resource
|
||||
namespaceScoped := true
|
||||
if isSubresource {
|
||||
parentStorage, ok := a.group.Storage[resource]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing parent storage: %q", resource)
|
||||
}
|
||||
scoper, ok := parentStorage.(rest.Scoper)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%q must implement scoper", resource)
|
||||
}
|
||||
namespaceScoped = scoper.NamespaceScoped()
|
||||
|
||||
} else {
|
||||
scoper, ok := storage.(rest.Scoper)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%q must implement scoper", resource)
|
||||
}
|
||||
namespaceScoped = scoper.NamespaceScoped()
|
||||
}
|
||||
|
||||
// what verbs are supported by the storage, used to know what verbs we support per path
|
||||
creater, isCreater := storage.(rest.Creater)
|
||||
|
@ -330,7 +351,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
var apiResource metav1.APIResource
|
||||
// Get the list of actions for the given scope.
|
||||
switch {
|
||||
case clusterScoped:
|
||||
case !namespaceScoped:
|
||||
// Handle non-namespace scoped resources like nodes.
|
||||
resourcePath := resource
|
||||
resourceParams := params
|
||||
|
@ -338,7 +359,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
nameParams := append(params, nameParam)
|
||||
proxyParams := append(nameParams, pathParam)
|
||||
suffix := ""
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
suffix = "/" + subresource
|
||||
itemPath = itemPath + suffix
|
||||
resourcePath = itemPath
|
||||
|
@ -387,7 +408,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
nameParams := append(namespaceParams, nameParam)
|
||||
proxyParams := append(nameParams, pathParam)
|
||||
itemPathSuffix := ""
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
itemPathSuffix = "/" + subresource
|
||||
itemPath = itemPath + itemPathSuffix
|
||||
resourcePath = itemPath
|
||||
|
@ -423,7 +444,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
// list or post across namespace.
|
||||
// For ex: LIST all pods in all namespaces by sending a LIST request at /api/apiVersion/pods.
|
||||
// TODO: more strongly type whether a resource allows these actions on "all namespaces" (bulk delete)
|
||||
if !hasSubresource {
|
||||
if !isSubresource {
|
||||
actions = appendIf(actions, action{"LIST", resource, params, namer, true}, isLister)
|
||||
actions = appendIf(actions, action{"WATCHLIST", "watch/" + resource, params, namer, true}, allowWatchList)
|
||||
}
|
||||
|
@ -509,12 +530,13 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
routes := []*restful.RouteBuilder{}
|
||||
|
||||
// If there is a subresource, kind should be the parent's kind.
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
parentStorage, ok := a.group.Storage[resource]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing parent storage: %q", resource)
|
||||
}
|
||||
fqParentKind, _, err := a.getResourceKind(resource, parentStorage)
|
||||
|
||||
fqParentKind, err := a.getResourceKind(resource, parentStorage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -527,7 +549,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
case "GET": // Get a resource.
|
||||
var handler restful.RouteFunction
|
||||
if isGetterWithOptions {
|
||||
handler = restfulGetResourceWithOptions(getterWithOptions, reqScope, hasSubresource)
|
||||
handler = restfulGetResourceWithOptions(getterWithOptions, reqScope, isSubresource)
|
||||
} else {
|
||||
handler = restfulGetResource(getter, exporter, reqScope)
|
||||
}
|
||||
|
@ -543,7 +565,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
handler = genericfilters.RestfulWithCompression(handler)
|
||||
}
|
||||
doc := "read the specified " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "read " + subresource + " of the specified " + kind
|
||||
}
|
||||
route := ws.GET(action.Path).To(handler).
|
||||
|
@ -567,7 +589,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
routes = append(routes, route)
|
||||
case "LIST": // List all resources of a kind.
|
||||
doc := "list objects of kind " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "list " + subresource + " of objects of kind " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulListResource(lister, watcher, reqScope, false, a.minRequestTimeout))
|
||||
|
@ -587,13 +609,13 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
switch {
|
||||
case isLister && isWatcher:
|
||||
doc := "list or watch objects of kind " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "list or watch " + subresource + " of objects of kind " + kind
|
||||
}
|
||||
route.Doc(doc)
|
||||
case isWatcher:
|
||||
doc := "watch objects of kind " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "watch " + subresource + "of objects of kind " + kind
|
||||
}
|
||||
route.Doc(doc)
|
||||
|
@ -602,7 +624,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
routes = append(routes, route)
|
||||
case "PUT": // Update a resource.
|
||||
doc := "replace the specified " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "replace " + subresource + " of the specified " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulUpdateResource(updater, reqScope, admit))
|
||||
|
@ -621,7 +643,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
routes = append(routes, route)
|
||||
case "PATCH": // Partially update a resource
|
||||
doc := "partially update the specified " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "partially update " + subresource + " of the specified " + kind
|
||||
}
|
||||
supportedTypes := []string{
|
||||
|
@ -651,7 +673,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
handler = metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, handler)
|
||||
article := getArticleForNoun(kind, " ")
|
||||
doc := "create" + article + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "create " + subresource + " of" + article + kind
|
||||
}
|
||||
route := ws.POST(action.Path).To(handler).
|
||||
|
@ -671,7 +693,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
case "DELETE": // Delete a resource.
|
||||
article := getArticleForNoun(kind, " ")
|
||||
doc := "delete" + article + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "delete " + subresource + " of" + article + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulDeleteResource(gracefulDeleter, isGracefulDeleter, reqScope, admit))
|
||||
|
@ -692,7 +714,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
routes = append(routes, route)
|
||||
case "DELETECOLLECTION":
|
||||
doc := "delete collection of " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "delete collection of " + subresource + " of a " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulDeleteCollection(collectionDeleter, isCollectionDeleter, reqScope, admit))
|
||||
|
@ -711,7 +733,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
// TODO: deprecated
|
||||
case "WATCH": // Watch a resource.
|
||||
doc := "watch changes to an object of kind " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "watch changes to " + subresource + " of an object of kind " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||
|
@ -730,7 +752,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
// TODO: deprecated
|
||||
case "WATCHLIST": // Watch all resources of a kind.
|
||||
doc := "watch individual changes to a list of " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "watch individual changes to a list of " + subresource + " of " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulListResource(lister, watcher, reqScope, true, a.minRequestTimeout))
|
||||
|
@ -753,10 +775,10 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
|||
connectProducedObject = "string"
|
||||
}
|
||||
doc := "connect " + method + " requests to " + kind
|
||||
if hasSubresource {
|
||||
if isSubresource {
|
||||
doc = "connect " + method + " requests to " + subresource + " of " + kind
|
||||
}
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulConnectResource(connecter, reqScope, admit, path, hasSubresource))
|
||||
handler := metrics.InstrumentRouteFunc(action.Verb, resource, subresource, requestScope, restfulConnectResource(connecter, reqScope, admit, path, isSubresource))
|
||||
route := ws.Method(method).Path(action.Path).
|
||||
To(handler).
|
||||
Doc(doc).
|
||||
|
|
|
@ -242,6 +242,18 @@ func (e *Store) NewList() runtime.Object {
|
|||
return e.NewListFunc()
|
||||
}
|
||||
|
||||
// NamespaceScoped indicates whether the resource is namespaced
|
||||
func (e *Store) NamespaceScoped() bool {
|
||||
if e.CreateStrategy != nil {
|
||||
return e.CreateStrategy.NamespaceScoped()
|
||||
}
|
||||
if e.UpdateStrategy != nil {
|
||||
return e.UpdateStrategy.NamespaceScoped()
|
||||
}
|
||||
|
||||
panic("programmer error: no CRUD for resource, you're crazy, override NamespaceScoped too")
|
||||
}
|
||||
|
||||
// GetCreateStrategy implements GenericStore.
|
||||
func (e *Store) GetCreateStrategy() rest.RESTCreateStrategy {
|
||||
return e.CreateStrategy
|
||||
|
|
|
@ -58,6 +58,13 @@ type Storage interface {
|
|||
New() runtime.Object
|
||||
}
|
||||
|
||||
// Scoper indicates what scope the resource is at. It must be specified.
|
||||
// It is usually provided automatically based on your strategy.
|
||||
type Scoper interface {
|
||||
// NamespaceScoped returns true if the storage is namespaced
|
||||
NamespaceScoped() bool
|
||||
}
|
||||
|
||||
// KindProvider specifies a different kind for its API than for its internal storage. This is necessary for external
|
||||
// objects that are not compiled into the api server. For such objects, there is no in-memory representation for
|
||||
// the object, so they must be represented as generic objects (e.g. runtime.Unknown), but when we present the object as part of
|
||||
|
@ -83,7 +90,6 @@ type CategoriesProvider interface {
|
|||
// TODO KindProvider (only used by federation) should be removed and replaced with this, but that presents greater risk late in 1.8.
|
||||
type GroupVersionKindProvider interface {
|
||||
GroupVersionKind(containingGV schema.GroupVersion) schema.GroupVersionKind
|
||||
ClusterScoped() bool
|
||||
}
|
||||
|
||||
// Lister is an object that can retrieve resources that match the provided field and label criteria.
|
||||
|
|
|
@ -424,7 +424,6 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
|
|||
Defaulter: apiGroupInfo.Scheme,
|
||||
Typer: apiGroupInfo.Scheme,
|
||||
Linker: runtime.SelfLinker(meta.NewAccessor()),
|
||||
RootScopedKinds: apiGroupInfo.GroupMeta.RootScopedKinds,
|
||||
|
||||
Admit: s.admissionControl,
|
||||
MinRequestTimeout: s.minRequestTimeout,
|
||||
|
|
|
@ -43,7 +43,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/version"
|
||||
"k8s.io/apiserver/pkg/apis/example"
|
||||
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/endpoints/discovery"
|
||||
genericapifilters "k8s.io/apiserver/pkg/endpoints/filters"
|
||||
|
@ -416,34 +415,14 @@ func (authz *mockAuthorizer) Authorize(a authorizer.Attributes) (authorized auth
|
|||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
type mockAuthenticator struct {
|
||||
lastURI string
|
||||
}
|
||||
|
||||
func (authn *mockAuthenticator) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||
authn.lastURI = req.RequestURI
|
||||
return &user.DefaultInfo{
|
||||
Name: "foo",
|
||||
}, true, nil
|
||||
}
|
||||
|
||||
func decodeResponse(resp *http.Response, obj interface{}) error {
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(data, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type testGetterStorage struct {
|
||||
Version string
|
||||
}
|
||||
|
||||
func (p *testGetterStorage) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *testGetterStorage) New() runtime.Object {
|
||||
return &metav1.APIGroup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
@ -461,6 +440,10 @@ type testNoVerbsStorage struct {
|
|||
Version string
|
||||
}
|
||||
|
||||
func (p *testNoVerbsStorage) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *testNoVerbsStorage) New() runtime.Object {
|
||||
return &metav1.APIGroup{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
|
|
Loading…
Reference in New Issue