From ee55200440c8236248f47cbe2dd783ba1a717614 Mon Sep 17 00:00:00 2001 From: Mangirdas Judeikis Date: Sat, 21 Sep 2024 18:43:56 +0300 Subject: [PATCH] Add GroupLister interface to discovery GroupManager Signed-off-by: Mangirdas Judeikis --- .../apiserver/pkg/endpoints/discovery/root.go | 34 ++++++++++++++++--- .../pkg/endpoints/discovery/root_test.go | 8 +++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root.go b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root.go index 24f0a34526d..8cc52e05fbd 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root.go @@ -17,6 +17,7 @@ limitations under the License. package discovery import ( + "context" "net/http" "sync" @@ -33,12 +34,21 @@ import ( // GroupManager is an interface that allows dynamic mutation of the existing webservice to handle // API groups being added or removed. type GroupManager interface { + GroupLister + AddGroup(apiGroup metav1.APIGroup) RemoveGroup(groupName string) ServeHTTP(resp http.ResponseWriter, req *http.Request) WebService() *restful.WebService } +// GroupLister knows how to list APIGroups for discovery. +type GroupLister interface { + // Groups returns APIGroups for discovery, filling in ServerAddressByClientCIDRs + // based on data in req. + Groups(ctx context.Context, req *http.Request) ([]metav1.APIGroup, error) +} + // rootAPIsHandler creates a webservice serving api group discovery. // The list of APIGroups may change while the server is running because additional resources // are registered or removed. It is not safe to cache the values. @@ -94,24 +104,40 @@ func (s *rootAPIsHandler) RemoveGroup(groupName string) { } } -func (s *rootAPIsHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { +func (s *rootAPIsHandler) Groups(ctx context.Context, req *http.Request) ([]metav1.APIGroup, error) { s.lock.RLock() defer s.lock.RUnlock() + return s.groupsLocked(ctx, req), nil +} + +// groupsLocked returns the APIGroupList discovery information for this handler. +// The caller must hold the lock before invoking this method to avoid data races. +func (s *rootAPIsHandler) groupsLocked(ctx context.Context, req *http.Request) []metav1.APIGroup { + clientIP := utilnet.GetClientIP(req) + serverCIDR := s.addresses.ServerAddressByClientCIDRs(clientIP) + orderedGroups := []metav1.APIGroup{} for _, groupName := range s.apiGroupNames { orderedGroups = append(orderedGroups, s.apiGroups[groupName]) } - clientIP := utilnet.GetClientIP(req) - serverCIDR := s.addresses.ServerAddressByClientCIDRs(clientIP) groups := make([]metav1.APIGroup, len(orderedGroups)) for i := range orderedGroups { groups[i] = orderedGroups[i] groups[i].ServerAddressByClientCIDRs = serverCIDR } - responsewriters.WriteObjectNegotiated(s.serializer, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, resp, req, http.StatusOK, &metav1.APIGroupList{Groups: groups}, false) + return groups +} + +func (s *rootAPIsHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { + s.lock.RLock() + defer s.lock.RUnlock() + + groupList := metav1.APIGroupList{Groups: s.groupsLocked(req.Context(), req)} + + responsewriters.WriteObjectNegotiated(s.serializer, negotiation.DefaultEndpointRestrictions, schema.GroupVersion{}, resp, req, http.StatusOK, &groupList, false) } func (s *rootAPIsHandler) restfulHandle(req *restful.Request, resp *restful.Response) { diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root_test.go b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root_test.go index a4467aed136..fce52cead4a 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root_test.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/discovery/root_test.go @@ -17,6 +17,7 @@ limitations under the License. package discovery import ( + "context" "encoding/json" "fmt" "io/ioutil" @@ -173,6 +174,13 @@ func TestDiscoveryOrdering(t *testing.T) { t.Fatalf("unexpected error: %v", err) } + // Check if internal groups listers returns the same group. + groups, err := handler.Groups(context.TODO(), &http.Request{}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + assert.Len(t, groups, 6) + assert.Len(t, groupList.Groups, 6) assert.Equal(t, "x", groupList.Groups[0].Name) assert.Equal(t, "y", groupList.Groups[1].Name)