99 "context"
1010 "fmt"
1111 "io"
12+ "net"
1213 "net/http"
1314 "net/url"
1415 "strings"
@@ -20,12 +21,14 @@ import (
2021 corev1 "k8s.io/api/core/v1"
2122 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2223 "k8s.io/apimachinery/pkg/util/intstr"
24+ "k8s.io/klog/v2"
2325 "k8s.io/utils/ptr"
2426 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
2527 "sigs.k8s.io/cluster-api/test/framework"
2628 "sigs.k8s.io/controller-runtime/pkg/client"
2729
2830 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
31+ capiutils "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/utils"
2932 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/serviceloadbalancer/metallb"
3033)
3134
@@ -170,6 +173,31 @@ func EnsureLoadBalancerService(
170173 }
171174 output := testServiceLoadBalancer (ctx , getClientIPURL , input .ServiceIntervals )
172175 Expect (output ).ToNot (BeEmpty ())
176+ klog .Infof ("Kubernetes Service LoadBalancer output: %q" , output )
177+
178+ By ("Verifying that the source IP is as expected" )
179+ // It is not simple to get the source IP of the runner because its possible connect through a VPN.
180+ //
181+ // When source IP preservation is not enabled,
182+ // the source IP that the LoadBalancer Service responds with an IP from the Cluster's Pod subnet.
183+ // When source IP preservation is enabled, we test the source IP is different from the Pod IP.
184+ // The output will be something like:
185+ // 192.168.1.141:32768 - when source IP preservation is not enabled.
186+ // 10.22.24.12:32768 - when source IP preservation is enabled.
187+ // Get the source IP from the output.
188+ sourceIPStr := strings .Split (output , ":" )[0 ]
189+ sourceIP := net .ParseIP (sourceIPStr )
190+ Expect (sourceIP ).ToNot (BeNil ())
191+ // Get the Cluster's Pod subnet.
192+ podCIDRStr := input .WorkloadCluster .Spec .ClusterNetwork .Pods .CIDRBlocks [0 ]
193+ _ , podCIDR , err := net .ParseCIDR (podCIDRStr )
194+ Expect (err ).ToNot (HaveOccurred ())
195+ Expect (podCIDR ).ToNot (BeNil ())
196+
197+ // When skip kube-proxy is false (i.e. kube-proxy is enabled), sourceIP should be from the Pod subnet.
198+ // Otherwise, sourceIP will be some external IP.
199+ expectIPFromPodSubnet := ! capiutils .ShouldSkipKubeProxy (input .WorkloadCluster )
200+ Expect (podCIDR .Contains (sourceIP )).To (Equal (expectIPFromPodSubnet ))
173201}
174202
175203func createTestService (
0 commit comments