mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-12-16 21:07:22 +00:00
Merge pull request #99662 from swetharepakula/eps-ga-api-changes
Graduate EndpointSlice API to GA
This commit is contained in:
@@ -19,10 +19,13 @@ package endpointslice
|
||||
import (
|
||||
"context"
|
||||
|
||||
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
@@ -51,6 +54,7 @@ func (endpointSliceStrategy) PrepareForCreate(ctx context.Context, obj runtime.O
|
||||
endpointSlice.Generation = 1
|
||||
|
||||
dropDisabledFieldsOnCreate(endpointSlice)
|
||||
dropTopologyOnV1(ctx, nil, endpointSlice)
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||
@@ -62,8 +66,8 @@ func (endpointSliceStrategy) PrepareForUpdate(ctx context.Context, obj, old runt
|
||||
// This needs to be changed if a status attribute is added to EndpointSlice
|
||||
ogNewMeta := newEPS.ObjectMeta
|
||||
ogOldMeta := oldEPS.ObjectMeta
|
||||
newEPS.ObjectMeta = v1.ObjectMeta{}
|
||||
oldEPS.ObjectMeta = v1.ObjectMeta{}
|
||||
newEPS.ObjectMeta = metav1.ObjectMeta{}
|
||||
oldEPS.ObjectMeta = metav1.ObjectMeta{}
|
||||
|
||||
if !apiequality.Semantic.DeepEqual(newEPS, oldEPS) || !apiequality.Semantic.DeepEqual(ogNewMeta.Labels, ogOldMeta.Labels) {
|
||||
ogNewMeta.Generation = ogOldMeta.Generation + 1
|
||||
@@ -73,6 +77,7 @@ func (endpointSliceStrategy) PrepareForUpdate(ctx context.Context, obj, old runt
|
||||
oldEPS.ObjectMeta = ogOldMeta
|
||||
|
||||
dropDisabledFieldsOnUpdate(oldEPS, newEPS)
|
||||
dropTopologyOnV1(ctx, oldEPS, newEPS)
|
||||
}
|
||||
|
||||
// Validate validates a new EndpointSlice.
|
||||
@@ -139,3 +144,26 @@ func dropDisabledFieldsOnUpdate(oldEPS, newEPS *discovery.EndpointSlice) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dropTopologyOnV1 on V1 request wipes the DeprecatedTopology field and copies
|
||||
// the NodeName value into DeprecatedTopology
|
||||
func dropTopologyOnV1(ctx context.Context, oldEPS, newEPS *discovery.EndpointSlice) {
|
||||
if info, ok := genericapirequest.RequestInfoFrom(ctx); ok {
|
||||
requestGV := schema.GroupVersion{Group: info.APIGroup, Version: info.APIVersion}
|
||||
if requestGV == discoveryv1beta1.SchemeGroupVersion {
|
||||
return
|
||||
}
|
||||
|
||||
// do not drop topology if endpoints have not been changed
|
||||
if oldEPS != nil && apiequality.Semantic.DeepEqual(oldEPS.Endpoints, newEPS.Endpoints) {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range newEPS.Endpoints {
|
||||
ep := &newEPS.Endpoints[i]
|
||||
|
||||
//Silently clear out DeprecatedTopology
|
||||
ep.DeprecatedTopology = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/discovery"
|
||||
@@ -628,3 +630,241 @@ func TestPrepareForUpdate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_dropTopologyOnV1(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
v1Request bool
|
||||
newEPS *discovery.EndpointSlice
|
||||
originalEPS *discovery.EndpointSlice
|
||||
expectedEPS *discovery.EndpointSlice
|
||||
}{
|
||||
{
|
||||
name: "v1 request, without deprecated topology",
|
||||
v1Request: true,
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1beta1 request, without deprecated topology",
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1 request, with deprecated topology",
|
||||
v1Request: true,
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{{}, {}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1beta1 request, with deprecated topology",
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1 request, updated metadata",
|
||||
v1Request: true,
|
||||
originalEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"example": "one"},
|
||||
},
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"example": "one"},
|
||||
},
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1beta1 request, updated metadata",
|
||||
originalEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"example": "one"},
|
||||
},
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"example": "one"},
|
||||
},
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
{
|
||||
NodeName: utilpointer.StringPtr("node-1"),
|
||||
DeprecatedTopology: map[string]string{"key": "value"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1 request, updated endpoints",
|
||||
v1Request: true,
|
||||
originalEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
},
|
||||
},
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
Hostname: utilpointer.StringPtr("hostname-1"),
|
||||
DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
|
||||
},
|
||||
{
|
||||
Hostname: utilpointer.StringPtr("hostname-1"),
|
||||
DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
{Hostname: utilpointer.StringPtr("hostname-1")},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "v1beta1 request, updated endpoints",
|
||||
originalEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
{DeprecatedTopology: map[string]string{"key": "value"}},
|
||||
},
|
||||
},
|
||||
newEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
Hostname: utilpointer.StringPtr("hostname-1"),
|
||||
DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
|
||||
},
|
||||
{
|
||||
Hostname: utilpointer.StringPtr("hostname-1"),
|
||||
DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedEPS: &discovery.EndpointSlice{
|
||||
Endpoints: []discovery.Endpoint{
|
||||
{
|
||||
Hostname: utilpointer.StringPtr("hostname-1"),
|
||||
DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
|
||||
},
|
||||
{
|
||||
Hostname: utilpointer.StringPtr("hostname-1"),
|
||||
DeprecatedTopology: map[string]string{corev1.LabelHostname: "node-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ctx := genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{APIGroup: "discovery.k8s.io", APIVersion: "v1beta1", Resource: "endpointslices"})
|
||||
if tc.v1Request {
|
||||
ctx = genericapirequest.WithRequestInfo(genericapirequest.NewContext(), &genericapirequest.RequestInfo{APIGroup: "discovery.k8s.io", APIVersion: "v1", Resource: "endpointslices"})
|
||||
}
|
||||
|
||||
dropTopologyOnV1(ctx, tc.originalEPS, tc.newEPS)
|
||||
if !apiequality.Semantic.DeepEqual(tc.newEPS, tc.expectedEPS) {
|
||||
t.Logf("actual endpointslice: %v", tc.newEPS)
|
||||
t.Logf("expected endpointslice: %v", tc.expectedEPS)
|
||||
t.Errorf("unexpected EndpointSlice on API topology strategy")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
package rest
|
||||
|
||||
import (
|
||||
discoveryv1alpha1 "k8s.io/api/discovery/v1alpha1"
|
||||
discoveryv1 "k8s.io/api/discovery/v1"
|
||||
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
@@ -37,14 +37,6 @@ func (p StorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.AP
|
||||
// If you add a version here, be sure to add an entry in `k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go with specific priorities.
|
||||
// TODO refactor the plumbing to provide the information in the APIGroupInfo
|
||||
|
||||
if apiResourceConfigSource.VersionEnabled(discoveryv1alpha1.SchemeGroupVersion) {
|
||||
storageMap, err := p.v1alpha1Storage(apiResourceConfigSource, restOptionsGetter)
|
||||
if err != nil {
|
||||
return genericapiserver.APIGroupInfo{}, false, err
|
||||
}
|
||||
apiGroupInfo.VersionedResourcesStorageMap[discoveryv1alpha1.SchemeGroupVersion.Version] = storageMap
|
||||
}
|
||||
|
||||
if apiResourceConfigSource.VersionEnabled(discoveryv1beta1.SchemeGroupVersion) {
|
||||
storageMap, err := p.v1beta1Storage(apiResourceConfigSource, restOptionsGetter)
|
||||
if err != nil {
|
||||
@@ -53,10 +45,18 @@ func (p StorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.AP
|
||||
apiGroupInfo.VersionedResourcesStorageMap[discoveryv1beta1.SchemeGroupVersion.Version] = storageMap
|
||||
}
|
||||
|
||||
if apiResourceConfigSource.VersionEnabled(discoveryv1.SchemeGroupVersion) {
|
||||
storageMap, err := p.v1Storage(apiResourceConfigSource, restOptionsGetter)
|
||||
if err != nil {
|
||||
return genericapiserver.APIGroupInfo{}, false, err
|
||||
}
|
||||
apiGroupInfo.VersionedResourcesStorageMap[discoveryv1.SchemeGroupVersion.Version] = storageMap
|
||||
}
|
||||
|
||||
return apiGroupInfo, true, nil
|
||||
}
|
||||
|
||||
func (p StorageProvider) v1alpha1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
|
||||
func (p StorageProvider) v1beta1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
|
||||
storage := map[string]rest.Storage{}
|
||||
|
||||
endpointSliceStorage, err := endpointslicestorage.NewREST(restOptionsGetter)
|
||||
@@ -68,7 +68,7 @@ func (p StorageProvider) v1alpha1Storage(apiResourceConfigSource serverstorage.A
|
||||
return storage, err
|
||||
}
|
||||
|
||||
func (p StorageProvider) v1beta1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
|
||||
func (p StorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
|
||||
storage := map[string]rest.Storage{}
|
||||
|
||||
endpointSliceStorage, err := endpointslicestorage.NewREST(restOptionsGetter)
|
||||
|
||||
Reference in New Issue
Block a user