99 "context"
1010 "fmt"
1111 "io"
12+ "net"
1213 "net/http"
1314 "net/url"
1415 "strings"
@@ -20,6 +21,7 @@ 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"
@@ -170,6 +172,29 @@ func EnsureLoadBalancerService(
170172 }
171173 output := testServiceLoadBalancer (ctx , getClientIPURL , input .ServiceIntervals )
172174 Expect (output ).ToNot (BeEmpty ())
175+ klog .Infof ("Kubernetes Service LoadBalancer output: %q" , output )
176+
177+ By ("Verifying that the source IP is not part of the Cluster's Service subnet" )
178+ // It is not simple to get the source IP of the runner because its possible connect through a VPN.
179+ //
180+ // When source IP preservation is not enabled,
181+ // the source IP that the LoadBalancer Service responds with would be part of the Cluster's Service subnet.
182+ // In this case we test the source IP is different from the Service IP.
183+ // The output will be something like:
184+ // 192.168.1.141:32768 - when source IP preservation is not enabled.
185+ // 10.22.24.12:32768 - when source IP preservation is enabled.
186+ // Get the source IP from the output.
187+ sourceIPStr := strings .Split (output , ":" )[0 ]
188+ sourceIP := net .ParseIP (sourceIPStr )
189+ Expect (sourceIP ).ToNot (BeNil ())
190+ // Get the Cluster's Service subnet.
191+ serviceCIDRStr := input .WorkloadCluster .Spec .ClusterNetwork .Services .CIDRBlocks [0 ]
192+ _ , serviceCIDR , err := net .ParseCIDR (serviceCIDRStr )
193+ Expect (err ).ToNot (HaveOccurred ())
194+ Expect (sourceIP ).ToNot (BeNil ())
195+ // Verify that the source IP is not part of the Cluster's Service subnet,
196+ // i.e. it will be the external client's IP.
197+ Expect (serviceCIDR .Contains (sourceIP )).To (BeFalse ())
173198}
174199
175200func createTestService (
0 commit comments