Merge pull request #99362 from deads2k/confirm-beta

Use a versioner to convert an internal type into an external type for beta serving
This commit is contained in:
Kubernetes Prow Robot 2021-03-04 06:42:09 -08:00 committed by GitHub
commit 0f109b6958
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 2572 deletions

File diff suppressed because it is too large Load Diff

View File

@ -603,7 +603,7 @@ func (m *Instance) InstallAPIs(apiResourceConfigSource serverstorage.APIResource
// Remove resources that serving kinds that are removed.
// We do this here so that we don't accidentally serve versions without resources or openapi information that for kinds we don't serve.
// This is a spot above the construction of individual storage handlers so that no sig accidentally forgets to check.
resourceExpirationEvaluator.RemoveDeletedKinds(groupName, apiGroupInfo.VersionedResourcesStorageMap)
resourceExpirationEvaluator.RemoveDeletedKinds(groupName, apiGroupInfo.Scheme, apiGroupInfo.VersionedResourcesStorageMap)
if len(apiGroupInfo.VersionedResourcesStorageMap) == 0 {
klog.V(1).Infof("Removing API group %v because it is time to stop serving it because it has no versions per APILifecycle.", groupName)
continue

View File

@ -53,17 +53,22 @@ const PostStartHookName = "priority-and-fairness-config-producer"
func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(flowcontrol.GroupName, legacyscheme.Scheme, legacyscheme.ParameterCodec, legacyscheme.Codecs)
// Flow control storage is shared across different versions.
flowControlStorage, err := p.storage(apiResourceConfigSource, restOptionsGetter)
if err != nil {
return genericapiserver.APIGroupInfo{}, false, err
}
if apiResourceConfigSource.VersionEnabled(flowcontrolapisv1alpha1.SchemeGroupVersion) {
flowControlStorage, err := p.storage(apiResourceConfigSource, restOptionsGetter)
if err != nil {
return genericapiserver.APIGroupInfo{}, false, err
}
apiGroupInfo.VersionedResourcesStorageMap[flowcontrolapisv1alpha1.SchemeGroupVersion.Version] = flowControlStorage
}
if apiResourceConfigSource.VersionEnabled(flowcontrolapisv1beta1.SchemeGroupVersion) {
flowControlStorage, err := p.storage(apiResourceConfigSource, restOptionsGetter)
if err != nil {
return genericapiserver.APIGroupInfo{}, false, err
}
apiGroupInfo.VersionedResourcesStorageMap[flowcontrolapisv1beta1.SchemeGroupVersion.Version] = flowControlStorage
}
return apiGroupInfo, true, nil
}

View File

@ -21,6 +21,9 @@ import (
"strconv"
"strings"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
apimachineryversion "k8s.io/apimachinery/pkg/version"
"k8s.io/apiserver/pkg/registry/rest"
@ -45,7 +48,7 @@ type resourceExpirationEvaluator struct {
type ResourceExpirationEvaluator interface {
// RemoveDeletedKinds inspects the storage map and modifies it in place by removing storage for kinds that have been deleted.
// versionedResourcesStorageMap mirrors the field on APIGroupInfo, it's a map from version to resource to the storage.
RemoveDeletedKinds(groupName string, versionedResourcesStorageMap map[string]map[string]rest.Storage)
RemoveDeletedKinds(groupName string, versioner runtime.ObjectVersioner, versionedResourcesStorageMap map[string]map[string]rest.Storage)
// ShouldServeForVersion returns true if a particular version cut off is after the current version
ShouldServeForVersion(majorRemoved, minorRemoved int) bool
}
@ -91,8 +94,21 @@ func NewResourceExpirationEvaluator(currentVersion apimachineryversion.Info) (Re
return ret, nil
}
func (e *resourceExpirationEvaluator) shouldServe(resourceServingInfo rest.Storage) bool {
versionedPtr := resourceServingInfo.New()
func (e *resourceExpirationEvaluator) shouldServe(gv schema.GroupVersion, versioner runtime.ObjectVersioner, resourceServingInfo rest.Storage) bool {
internalPtr := resourceServingInfo.New()
target := gv
// honor storage that overrides group version (used for things like scale subresources)
if versionProvider, ok := resourceServingInfo.(rest.GroupVersionKindProvider); ok {
target = versionProvider.GroupVersionKind(target).GroupVersion()
}
versionedPtr, err := versioner.ConvertToVersion(internalPtr, target)
if err != nil {
utilruntime.HandleError(err)
return false
}
removed, ok := versionedPtr.(removedInterface)
if !ok {
return true
@ -135,12 +151,13 @@ type removedInterface interface {
// removeDeletedKinds inspects the storage map and modifies it in place by removing storage for kinds that have been deleted.
// versionedResourcesStorageMap mirrors the field on APIGroupInfo, it's a map from version to resource to the storage.
func (e *resourceExpirationEvaluator) RemoveDeletedKinds(groupName string, versionedResourcesStorageMap map[string]map[string]rest.Storage) {
func (e *resourceExpirationEvaluator) RemoveDeletedKinds(groupName string, versioner runtime.ObjectVersioner, versionedResourcesStorageMap map[string]map[string]rest.Storage) {
versionsToRemove := sets.NewString()
for apiVersion, versionToResource := range versionedResourcesStorageMap {
for apiVersion := range sets.StringKeySet(versionedResourcesStorageMap) {
versionToResource := versionedResourcesStorageMap[apiVersion]
resourcesToRemove := sets.NewString()
for resourceName, resourceServingInfo := range versionToResource {
if !e.shouldServe(resourceServingInfo) {
if !e.shouldServe(schema.GroupVersion{Group: groupName, Version: apiVersion}, versioner, resourceServingInfo) {
resourcesToRemove.Insert(resourceName)
}
}
@ -151,8 +168,9 @@ func (e *resourceExpirationEvaluator) RemoveDeletedKinds(groupName string, versi
}
klog.V(1).Infof("Removing resource %v.%v.%v because it is time to stop serving it per APILifecycle.", resourceName, apiVersion, groupName)
delete(versionedResourcesStorageMap[apiVersion], resourceName)
delete(versionToResource, resourceName)
}
versionedResourcesStorageMap[apiVersion] = versionToResource
if len(versionedResourcesStorageMap[apiVersion]) == 0 {
versionsToRemove.Insert(apiVersion)

View File

@ -221,13 +221,27 @@ func Test_resourceExpirationEvaluator_shouldServe(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if actual := tt.resourceExpirationEvaluator.shouldServe(tt.restStorage); actual != tt.expected {
gv := schema.GroupVersion{Group: "mygroup", Version: "myversion"}
convertor := &dummyConvertor{}
if actual := tt.resourceExpirationEvaluator.shouldServe(gv, convertor, tt.restStorage); actual != tt.expected {
t.Errorf("shouldServe() = %v, want %v", actual, tt.expected)
}
if !reflect.DeepEqual(convertor.called, gv) {
t.Errorf("expected converter to be called with %#v, got %#v", gv, convertor.called)
}
})
}
}
type dummyConvertor struct {
called runtime.GroupVersioner
}
func (d *dummyConvertor) ConvertToVersion(in runtime.Object, gv runtime.GroupVersioner) (runtime.Object, error) {
d.called = gv
return in, nil
}
func checkErr(t *testing.T, actual error, expected string) {
t.Helper()
switch {
@ -309,7 +323,8 @@ func Test_removeDeletedKinds(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.resourceExpirationEvaluator.RemoveDeletedKinds("group.name", tt.versionedResourcesStorageMap)
convertor := &dummyConvertor{}
tt.resourceExpirationEvaluator.RemoveDeletedKinds("group.name", convertor, tt.versionedResourcesStorageMap)
if !reflect.DeepEqual(tt.expectedStorage, tt.versionedResourcesStorageMap) {
t.Fatal(spew.Sdump(tt.versionedResourcesStorageMap))
}