Add integration test to promote serviceloadbalancerclass feature to beta.

This commit is contained in:
Xudong Liu 2021-06-23 16:18:58 -07:00
parent b4dddbafa2
commit fe161579e2
2 changed files with 132 additions and 2 deletions

View File

@ -649,9 +649,10 @@ const (
// Allow specifying NamespaceSelector in PodAffinityTerm.
PodAffinityNamespaceSelector featuregate.Feature = "PodAffinityNamespaceSelector"
// owner: @andrewsykim @xudongliuharold
// owner: @andrewsykim @XudongLiuHarold
// kep: http://kep.k8s.io/1959
// alpha: v1.21
// beta: v1.22
//
// Enable support multiple Service "type: LoadBalancer" implementations in a cluster by specifying LoadBalancerClass
ServiceLoadBalancerClass featuregate.Feature = "ServiceLoadBalancerClass"
@ -816,7 +817,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
PodDeletionCost: {Default: true, PreRelease: featuregate.Beta},
TopologyAwareHints: {Default: false, PreRelease: featuregate.Alpha},
PodAffinityNamespaceSelector: {Default: true, PreRelease: featuregate.Beta},
ServiceLoadBalancerClass: {Default: false, PreRelease: featuregate.Alpha},
ServiceLoadBalancerClass: {Default: true, PreRelease: featuregate.Beta},
LogarithmicScaleDown: {Default: false, PreRelease: featuregate.Alpha},
IngressClassNamespacedParams: {Default: false, PreRelease: featuregate.Alpha},
ServiceInternalTrafficPolicy: {Default: false, PreRelease: featuregate.Alpha},

View File

@ -23,8 +23,11 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
servicecontroller "k8s.io/cloud-provider/controllers/service"
fakecloud "k8s.io/cloud-provider/fake"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/test/integration/framework"
@ -138,3 +141,129 @@ func serviceHasNodePorts(svc *corev1.Service) bool {
return false
}
// Test_ServiceLoadBalancerEnableLoadBalancerClass tests that when a LoadBalancer
// type of service has spec.LoadBalancerClass set, cloud provider should not create default load balancer.
func Test_ServiceLoadBalancerEnableLoadBalancerClass(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLoadBalancerClass, true)()
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig()
_, server, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
defer closeFn()
config := restclient.Config{Host: server.URL}
client, err := clientset.NewForConfig(&config)
if err != nil {
t.Fatalf("Error creating clientset: %v", err)
}
ns := framework.CreateTestingNamespace("test-service-load-balancer-class", server, t)
defer framework.DeleteTestingNamespace(ns, server, t)
controller, cloud, informer := newCloudProviderController(t, client)
stopCh := make(chan struct{})
informer.Start(stopCh)
go controller.Run(stopCh, 1)
defer close(stopCh)
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-load-balancer-class",
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
Ports: []corev1.ServicePort{{
Port: int32(80),
}},
LoadBalancerClass: utilpointer.StringPtr("test.com/test"),
},
}
_, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Error creating test service: %v", err)
}
if len(cloud.Calls) > 0 {
t.Errorf("Unexpected cloud provider calls: %v", cloud.Calls)
}
}
// Test_ServiceLoadBalancerEnableLoadBalancerClassThenUpdateLoadBalancerClass tests that when a LoadBalancer
// type of service has spec.LoadBalancerClass set, it should be immutable as long as the service type
// is still LoadBalancer.
func Test_ServiceLoadBalancerEnableLoadBalancerClassThenUpdateLoadBalancerClass(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServiceLoadBalancerClass, true)()
controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig()
_, server, closeFn := framework.RunAnAPIServer(controlPlaneConfig)
defer closeFn()
config := restclient.Config{Host: server.URL}
client, err := clientset.NewForConfig(&config)
if err != nil {
t.Fatalf("Error creating clientset: %v", err)
}
ns := framework.CreateTestingNamespace("test-service-immutable-load-balancer-class", server, t)
defer framework.DeleteTestingNamespace(ns, server, t)
controller, cloud, informer := newCloudProviderController(t, client)
stopCh := make(chan struct{})
informer.Start(stopCh)
go controller.Run(stopCh, 1)
defer close(stopCh)
service := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-load-balancer-class",
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
Ports: []corev1.ServicePort{{
Port: int32(80),
}},
LoadBalancerClass: utilpointer.StringPtr("test.com/test"),
},
}
service, err = client.CoreV1().Services(ns.Name).Create(context.TODO(), service, metav1.CreateOptions{})
if err != nil {
t.Fatalf("Error creating test service: %v", err)
}
if len(cloud.Calls) > 0 {
t.Errorf("Unexpected cloud provider calls: %v", cloud.Calls)
}
service.Spec.LoadBalancerClass = utilpointer.StringPtr("test.com/update")
_, err = client.CoreV1().Services(ns.Name).Update(context.TODO(), service, metav1.UpdateOptions{})
if err == nil {
t.Fatal("Error updating test service load balancer class should throw error")
}
if len(cloud.Calls) > 0 {
t.Errorf("Unexpected cloud provider calls: %v", cloud.Calls)
}
}
func newCloudProviderController(t *testing.T, client *clientset.Clientset) (*servicecontroller.Controller, *fakecloud.Cloud, informers.SharedInformerFactory) {
cloud := &fakecloud.Cloud{}
informerFactory := informers.NewSharedInformerFactory(client, 0)
serviceInformer := informerFactory.Core().V1().Services()
nodeInformer := informerFactory.Core().V1().Nodes()
controller, err := servicecontroller.New(cloud,
client,
serviceInformer,
nodeInformer,
"test-cluster",
utilfeature.DefaultFeatureGate)
if err != nil {
t.Fatalf("Error creating cloud provider controller: %v", err)
}
cloud.Calls = nil // ignore any cloud calls made in init()
return controller, cloud, informerFactory
}