Merge pull request #125237 from aojea/ipmode_integration

improve loadbalancer IPMode testing
This commit is contained in:
Kubernetes Prow Robot
2024-06-24 19:22:43 -07:00
committed by GitHub
2 changed files with 112 additions and 35 deletions

View File

@@ -84,6 +84,7 @@ type Cloud struct {
ClusterList []string ClusterList []string
MasterName string MasterName string
ExternalIP net.IP ExternalIP net.IP
BalancerIPMode *v1.LoadBalancerIPMode
Balancers map[string]Balancer Balancers map[string]Balancer
updateCallLock sync.Mutex updateCallLock sync.Mutex
UpdateCalls []UpdateBalancerCall UpdateCalls []UpdateBalancerCall
@@ -224,7 +225,15 @@ func (f *Cloud) EnsureLoadBalancer(ctx context.Context, clusterName string, serv
f.Balancers[name] = Balancer{name, region, spec.LoadBalancerIP, spec.Ports, nodes} f.Balancers[name] = Balancer{name, region, spec.LoadBalancerIP, spec.Ports, nodes}
status := &v1.LoadBalancerStatus{} status := &v1.LoadBalancerStatus{}
status.Ingress = []v1.LoadBalancerIngress{{IP: f.ExternalIP.String()}} // process Ports
portStatus := []v1.PortStatus{}
for _, port := range spec.Ports {
portStatus = append(portStatus, v1.PortStatus{
Port: port.Port,
Protocol: port.Protocol,
})
}
status.Ingress = []v1.LoadBalancerIngress{{IP: f.ExternalIP.String(), IPMode: f.BalancerIPMode, Ports: portStatus}}
return status, f.Err return status, f.Err
} }

View File

@@ -19,14 +19,15 @@ package service
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"reflect"
"testing" "testing"
"time" "time"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait"
utilfeature "k8s.io/apiserver/pkg/util/feature" utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers" "k8s.io/client-go/informers"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
@@ -39,6 +40,7 @@ import (
"k8s.io/kubernetes/test/integration/framework" "k8s.io/kubernetes/test/integration/framework"
"k8s.io/utils/net" "k8s.io/utils/net"
utilpointer "k8s.io/utils/pointer" utilpointer "k8s.io/utils/pointer"
"k8s.io/utils/ptr"
) )
// Test_ServiceLoadBalancerAllocateNodePorts tests that a Service with spec.allocateLoadBalancerNodePorts=false // Test_ServiceLoadBalancerAllocateNodePorts tests that a Service with spec.allocateLoadBalancerNodePorts=false
@@ -644,21 +646,62 @@ func newServiceController(t *testing.T, client *clientset.Clientset) (*serviceco
// Test_ServiceLoadBalancerIPMode tests whether the cloud provider has correctly updated the ipMode field. // Test_ServiceLoadBalancerIPMode tests whether the cloud provider has correctly updated the ipMode field.
func Test_ServiceLoadBalancerIPMode(t *testing.T) { func Test_ServiceLoadBalancerIPMode(t *testing.T) {
ipModeVIP := corev1.LoadBalancerIPModeVIP baseService := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "test-update-load-balancer-ip-mode",
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
Ports: []corev1.ServicePort{{
Port: int32(80),
}},
},
}
testCases := []struct { testCases := []struct {
ipModeEnabled bool ipModeEnabled bool
externalIP string setIPMode *corev1.LoadBalancerIPMode
expectedIPMode *corev1.LoadBalancerIPMode externalIP string
expectedIngress corev1.LoadBalancerIngress
}{ }{
{ {
ipModeEnabled: false, ipModeEnabled: false,
externalIP: "1.2.3.4", externalIP: "1.2.3.4",
expectedIPMode: nil, expectedIngress: corev1.LoadBalancerIngress{
IP: "1.2.3.4",
IPMode: nil,
Ports: []corev1.PortStatus{{Port: 80, Protocol: corev1.ProtocolTCP}},
},
}, },
{ {
ipModeEnabled: true, ipModeEnabled: true,
externalIP: "1.2.3.5", setIPMode: nil,
expectedIPMode: &ipModeVIP, externalIP: "1.2.3.4",
expectedIngress: corev1.LoadBalancerIngress{
IP: "1.2.3.4",
IPMode: ptr.To(corev1.LoadBalancerIPModeVIP),
Ports: []corev1.PortStatus{{Port: 80, Protocol: corev1.ProtocolTCP}},
},
},
{
ipModeEnabled: true,
setIPMode: ptr.To(corev1.LoadBalancerIPModeVIP),
externalIP: "1.2.3.4",
expectedIngress: corev1.LoadBalancerIngress{
IP: "1.2.3.4",
IPMode: ptr.To(corev1.LoadBalancerIPModeVIP),
Ports: []corev1.PortStatus{{Port: 80, Protocol: corev1.ProtocolTCP}},
},
},
{
ipModeEnabled: true,
setIPMode: ptr.To(corev1.LoadBalancerIPModeProxy),
externalIP: "1.2.3.4",
expectedIngress: corev1.LoadBalancerIngress{
IP: "1.2.3.4",
IPMode: ptr.To(corev1.LoadBalancerIPModeProxy),
Ports: []corev1.PortStatus{{Port: 80, Protocol: corev1.ProtocolTCP}},
},
}, },
} }
@@ -678,43 +721,68 @@ func Test_ServiceLoadBalancerIPMode(t *testing.T) {
controller, cloud, informer := newServiceController(t, client) controller, cloud, informer := newServiceController(t, client)
cloud.ExternalIP = net.ParseIPSloppy(tc.externalIP) cloud.ExternalIP = net.ParseIPSloppy(tc.externalIP)
cloud.BalancerIPMode = tc.expectedIngress.IPMode
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
informer.Start(ctx.Done()) informer.Start(ctx.Done())
go controller.Run(ctx, 1, controllersmetrics.NewControllerManagerMetrics("loadbalancer-test")) go controller.Run(ctx, 1, controllersmetrics.NewControllerManagerMetrics("loadbalancer-test"))
service := &corev1.Service{ service, err := client.CoreV1().Services(ns.Name).Create(ctx, baseService, metav1.CreateOptions{})
ObjectMeta: metav1.ObjectMeta{
Name: "test-update-load-balancer-ip-mode",
},
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeLoadBalancer,
Ports: []corev1.ServicePort{{
Port: int32(80),
}},
},
}
service, err = client.CoreV1().Services(ns.Name).Create(ctx, service, metav1.CreateOptions{})
if err != nil { if err != nil {
t.Fatalf("Error creating test service: %v", err) t.Fatalf("Error creating test service: %v", err)
} }
time.Sleep(5 * time.Second) // sleep 5 second to wait for the service controller reconcile err = wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, 10*time.Second, true, func(_ context.Context) (done bool, err error) {
service, err = client.CoreV1().Services(ns.Name).Get(ctx, service.Name, metav1.GetOptions{}) service, err = client.CoreV1().Services(ns.Name).Get(ctx, service.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("Error getting test service: %v", err)
}
if len(service.Status.LoadBalancer.Ingress) != 1 {
return false, nil
}
return true, nil
})
if err != nil { if err != nil {
t.Fatalf("Error getting test service: %v", err)
}
if len(service.Status.LoadBalancer.Ingress) == 0 {
t.Fatalf("unexpected load balancer status") t.Fatalf("unexpected load balancer status")
} }
gotIngress := service.Status.LoadBalancer.Ingress[0] ingress := service.Status.LoadBalancer.Ingress[0]
if gotIngress.IP != tc.externalIP || !reflect.DeepEqual(gotIngress.IPMode, tc.expectedIPMode) { if !apiequality.Semantic.DeepEqual(&ingress, &tc.expectedIngress) {
t.Errorf("unexpected load balancer ingress, got ingress %v, expected IP %v, expected ipMode %v", t.Errorf("expected Ingress %v, got IP %v",
gotIngress, tc.externalIP, tc.expectedIPMode) ingress, tc.expectedIngress)
if ingress.IPMode != nil && tc.expectedIngress.IPMode != nil {
t.Logf("IPMode %v expected %v", *ingress.IPMode, *tc.expectedIngress.IPMode)
}
}
// mutate the service and check the status is preserved
newService := service.DeepCopy()
newService.Spec.Ports[0].Port = 443
service, err = client.CoreV1().Services(ns.Name).Update(ctx, newService, metav1.UpdateOptions{})
if err != nil {
t.Fatalf("Error updating test service: %v", err)
}
expectedIngress := tc.expectedIngress
expectedIngress.Ports[0].Port = 443
err = wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, 10*time.Second, true, func(_ context.Context) (done bool, err error) {
service, err = client.CoreV1().Services(ns.Name).Get(ctx, service.Name, metav1.GetOptions{})
if err != nil {
t.Fatalf("Error getting test service: %v", err)
}
if len(service.Status.LoadBalancer.Ingress) != 1 {
return false, nil
}
ingress = service.Status.LoadBalancer.Ingress[0]
if !apiequality.Semantic.DeepEqual(&ingress, &expectedIngress) {
t.Logf("Ingress %v Expected %v", ingress, expectedIngress)
return false, nil
}
return true, nil
})
if err != nil {
t.Fatalf("unexpected load balancer status")
} }
}) })
} }