Skip to content

Commit dc8b57d

Browse files
authored
Merge pull request kubernetes#121283 from tnqn/cleanup-unregistered-group
Unregister group path from apiserver when the group no longer exists
2 parents 1cb6793 + 0cda42a commit dc8b57d

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

staging/src/k8s.io/kube-aggregator/pkg/apiserver/apiserver.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,9 @@ type APIAggregator struct {
144144

145145
// proxyHandlers are the proxy handlers that are currently registered, keyed by apiservice.name
146146
proxyHandlers map[string]*proxyHandler
147-
// handledGroups are the groups that already have routes
148-
handledGroups sets.String
147+
// handledGroupVersions contain the groups that already have routes. The key is the name of the group and the value
148+
// is the versions for the group.
149+
handledGroupVersions map[string]sets.Set[string]
149150

150151
// lister is used to add group handling for /apis/<group> aggregator lookups based on
151152
// controller state
@@ -235,7 +236,7 @@ func (c completedConfig) NewWithDelegate(delegationTarget genericapiserver.Deleg
235236
delegateHandler: delegationTarget.UnprotectedHandler(),
236237
proxyTransportDial: proxyTransportDial,
237238
proxyHandlers: map[string]*proxyHandler{},
238-
handledGroups: sets.String{},
239+
handledGroupVersions: map[string]sets.Set[string]{},
239240
lister: informerFactory.Apiregistration().V1().APIServices().Lister(),
240241
APIRegistrationInformers: informerFactory,
241242
serviceResolver: c.ExtraConfig.ServiceResolver,
@@ -524,7 +525,9 @@ func (s *APIAggregator) AddAPIService(apiService *v1.APIService) error {
524525
}
525526

526527
// if we've already registered the path with the handler, we don't want to do it again.
527-
if s.handledGroups.Has(apiService.Spec.Group) {
528+
versions, exist := s.handledGroupVersions[apiService.Spec.Group]
529+
if exist {
530+
versions.Insert(apiService.Spec.Version)
528531
return nil
529532
}
530533

@@ -539,7 +542,7 @@ func (s *APIAggregator) AddAPIService(apiService *v1.APIService) error {
539542
// aggregation is protected
540543
s.GenericAPIServer.Handler.NonGoRestfulMux.Handle(groupPath, groupDiscoveryHandler)
541544
s.GenericAPIServer.Handler.NonGoRestfulMux.UnlistedHandle(groupPath+"/", groupDiscoveryHandler)
542-
s.handledGroups.Insert(apiService.Spec.Group)
545+
s.handledGroupVersions[apiService.Spec.Group] = sets.New[string](apiService.Spec.Version)
543546
return nil
544547
}
545548

@@ -568,8 +571,18 @@ func (s *APIAggregator) RemoveAPIService(apiServiceName string) {
568571
}
569572
delete(s.proxyHandlers, apiServiceName)
570573

571-
// TODO unregister group level discovery when there are no more versions for the group
572-
// We don't need this right away because the handler properly delegates when no versions are present
574+
versions, exist := s.handledGroupVersions[version.Group]
575+
if !exist {
576+
return
577+
}
578+
versions.Delete(version.Version)
579+
if versions.Len() > 0 {
580+
return
581+
}
582+
delete(s.handledGroupVersions, version.Group)
583+
groupPath := "/apis/" + version.Group
584+
s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(groupPath)
585+
s.GenericAPIServer.Handler.NonGoRestfulMux.Unregister(groupPath + "/")
573586
}
574587

575588
// DefaultAPIResourceConfigSource returns default configuration for an APIResource.

test/e2e/apimachinery/aggregator.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import (
5252
admissionapi "k8s.io/pod-security-admission/api"
5353
samplev1alpha1 "k8s.io/sample-apiserver/pkg/apis/wardle/v1alpha1"
5454
"k8s.io/utils/pointer"
55+
"k8s.io/utils/strings/slices"
5556

5657
"github.com/onsi/ginkgo/v2"
5758
"github.com/onsi/gomega"
@@ -560,7 +561,6 @@ func TestSampleAPIServer(ctx context.Context, f *framework.Framework, aggrclient
560561
ginkgo.By("Adding a label to the APIService")
561562
apiServiceClient := aggrclient.ApiregistrationV1().APIServices()
562563
apiServiceLabel := map[string]string{"e2e-apiservice": "patched"}
563-
apiServiceLabelSelector := labels.SelectorFromSet(apiServiceLabel).String()
564564
apiServicePatch, err := json.Marshal(map[string]interface{}{
565565
"metadata": map[string]interface{}{
566566
"labels": apiServiceLabel,
@@ -641,7 +641,7 @@ func TestSampleAPIServer(ctx context.Context, f *framework.Framework, aggrclient
641641
framework.Logf("Found updated apiService label for %q", apiServiceName)
642642

643643
// kubectl delete flunder test-flunder
644-
ginkgo.By(fmt.Sprintf("Delete APIService %q", flunderName))
644+
ginkgo.By(fmt.Sprintf("Delete flunders resource %q", flunderName))
645645
err = dynamicClient.Delete(ctx, flunderName, metav1.DeleteOptions{})
646646
validateErrorWithDebugInfo(ctx, f, err, pods, "deleting flunders(%v) using dynamic client", unstructuredList.Items)
647647

@@ -724,6 +724,7 @@ func TestSampleAPIServer(ctx context.Context, f *framework.Framework, aggrclient
724724
}
725725
framework.Logf("Found patched status condition for %s", wardle.ObjectMeta.Name)
726726

727+
apiServiceLabelSelector := labels.SelectorFromSet(updatedApiService.Labels).String()
727728
ginkgo.By(fmt.Sprintf("APIService deleteCollection with labelSelector: %q", apiServiceLabelSelector))
728729

729730
err = aggrclient.ApiregistrationV1().APIServices().DeleteCollection(ctx,
@@ -736,6 +737,24 @@ func TestSampleAPIServer(ctx context.Context, f *framework.Framework, aggrclient
736737
framework.ExpectNoError(err, "failed to count the required APIServices")
737738
framework.Logf("APIService %s has been deleted.", apiServiceName)
738739

740+
ginkgo.By("Confirm that the group path of " + apiServiceName + " was removed from root paths")
741+
groupPath := "/apis/" + apiServiceGroupName
742+
err = wait.PollUntilContextTimeout(ctx, apiServiceRetryPeriod, apiServiceRetryTimeout, true, func(ctx context.Context) (done bool, err error) {
743+
rootPaths := metav1.RootPaths{}
744+
statusContent, err = restClient.Get().
745+
AbsPath("/").
746+
SetHeader("Accept", "application/json").DoRaw(ctx)
747+
if err != nil {
748+
return false, err
749+
}
750+
err = json.Unmarshal(statusContent, &rootPaths)
751+
if err != nil {
752+
return false, err
753+
}
754+
return !slices.Contains(rootPaths.Paths, groupPath), nil
755+
})
756+
framework.ExpectNoError(err, "Expected to not find %s from root paths", groupPath)
757+
739758
cleanupSampleAPIServer(ctx, client, aggrclient, n, apiServiceName)
740759
}
741760

0 commit comments

Comments
 (0)