diff --git a/pkg/apiserver/registry/clusterpedia/resources/rest.go b/pkg/apiserver/registry/clusterpedia/resources/rest.go index 899458f2c..cbca236e0 100644 --- a/pkg/apiserver/registry/clusterpedia/resources/rest.go +++ b/pkg/apiserver/registry/clusterpedia/resources/rest.go @@ -30,7 +30,7 @@ var _ genericrest.SingularNameProvider = &REST{} // NewREST returns a RESTStorage object that will work against API services func NewREST(resourceHandler http.Handler, methods []string) *REST { if len(methods) == 0 { - methods = []string{"Get"} + methods = []string{"GET"} } return &REST{ methods: methods, diff --git a/pkg/kubeapiserver/apiserver.go b/pkg/kubeapiserver/apiserver.go index 3b16d9094..68d4741d4 100644 --- a/pkg/kubeapiserver/apiserver.go +++ b/pkg/kubeapiserver/apiserver.go @@ -143,16 +143,18 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget) controller := NewClusterResourceController(restManager, discoveryManager, c.ExtraConfig.InformerFactory.Cluster().V1alpha2().PediaClusters()) - methodSet := sets.Set[string]{} + methodSet := sets.New("GET") for _, rest := range proxyrest.GetSubresourceRESTs(controller) { - restManager.preRegisterSubresource(subresource{ + if err := restManager.preRegisterSubresource(subresource{ gr: rest.ParentGroupResource(), kind: rest.ParentKind(), namespaced: rest.Namespaced(), name: rest.Subresource(), connecter: rest, - }) + }); err != nil { + return nil, nil, err + } methodSet.Insert(rest.ConnectMethods()...) } diff --git a/pkg/kubeapiserver/resourcerest/proxy/subresource.go b/pkg/kubeapiserver/resourcerest/proxy/subresource.go index 42437c0b3..957d5224c 100644 --- a/pkg/kubeapiserver/resourcerest/proxy/subresource.go +++ b/pkg/kubeapiserver/resourcerest/proxy/subresource.go @@ -60,7 +60,7 @@ func GetSubresourceRESTs(connGetter ClusterConnectionGetter) []*PodSubresourceRe parent: schema.GroupResource{Group: "", Resource: "pods"}, parentKind: "Pod", namespaced: true, - methods: []string{"GET"}, + methods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"}, upgradeRequired: false, options: &api.PodProxyOptions{}, connGetter: connGetter, diff --git a/pkg/kubeapiserver/restmanager.go b/pkg/kubeapiserver/restmanager.go index 0fcb8eaf2..395b6e1e7 100644 --- a/pkg/kubeapiserver/restmanager.go +++ b/pkg/kubeapiserver/restmanager.go @@ -1,6 +1,7 @@ package kubeapiserver import ( + "fmt" "strings" "sync" "sync/atomic" @@ -34,6 +35,21 @@ import ( "github.com/clusterpedia-io/clusterpedia/pkg/storage" ) +// toDiscoveryKubeVerb maps an action.Verb to the logical kube verb, used for discovery +var toDiscoveryKubeVerb = map[string]string{ + "CONNECT": "", // do not list in discovery. + "DELETE": "delete", + "DELETECOLLECTION": "deletecollection", + "GET": "get", + "LIST": "list", + "PATCH": "patch", + "POST": "create", + "PROXY": "proxy", + "PUT": "update", + "WATCH": "watch", + "WATCHLIST": "watch", +} + type RESTManager struct { serializer runtime.NegotiatedSerializer storageFactory storage.StorageFactory @@ -116,12 +132,22 @@ type subresource struct { } // preRegisterSubresource is non-concurrently safe and only called at initialization time -func (m *RESTManager) preRegisterSubresource(subresource subresource) { +func (m *RESTManager) preRegisterSubresource(subresource subresource) error { + var verbs []string + for _, method := range subresource.connecter.ConnectMethods() { + if verb := toDiscoveryKubeVerb[method]; verb != "" { + verbs = append(verbs, verb) + } + } + if len(verbs) == 0 { + return fmt.Errorf("resource['%s/%s'] available verbs are empty", subresource.gr.String(), subresource.name) + } + objGVK := subresource.connecter.(rest.Storage).New().GetObjectKind().GroupVersionKind() apiResource := metav1.APIResource{ Name: subresource.gr.Resource + "/" + subresource.name, Namespaced: subresource.namespaced, - Verbs: subresource.connecter.ConnectMethods(), + Verbs: verbs, Kind: objGVK.Kind, } @@ -143,6 +169,7 @@ func (m *RESTManager) preRegisterSubresource(subresource subresource) { RequestScope: requestScope, Storage: subresource.connecter, } + return nil } func (m *RESTManager) GetAPIGroups() map[string]metav1.APIGroup {