Skip to content

Commit 7ca9715

Browse files
gcs278claude
andcommitted
OCPBUGS-63219: Add E2E tests for clientIPPreservationMode
Add two E2E tests: TestAWSNLBClientIPPreservationMode creates an NLB with ProxyProtocol, verifies the target-group-attributes annotation, router env var, and status are correct, tests connectivity, then switches to Native and verifies the annotation and env var are removed. TestAWSNLBDefaultClientIPPreservationMode creates an NLB without specifying clientIPPreservationMode and verifies the controller defaults it to ProxyProtocol. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent c3b1e27 commit 7ca9715

1 file changed

Lines changed: 192 additions & 0 deletions

File tree

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//go:build e2e
2+
// +build e2e
3+
4+
package e2e
5+
6+
import (
7+
"context"
8+
"testing"
9+
"time"
10+
11+
configv1 "github.com/openshift/api/config/v1"
12+
operatorv1 "github.com/openshift/api/operator/v1"
13+
"github.com/openshift/cluster-ingress-operator/pkg/operator/controller"
14+
15+
appsv1 "k8s.io/api/apps/v1"
16+
"k8s.io/apimachinery/pkg/types"
17+
"k8s.io/apimachinery/pkg/util/wait"
18+
"k8s.io/apiserver/pkg/storage/names"
19+
)
20+
21+
const (
22+
awsLBTargetGroupAttributesAnnotation = "service.beta.kubernetes.io/aws-load-balancer-target-group-attributes"
23+
)
24+
25+
// TestAWSNLBClientIPPreservationMode verifies that the clientIPPreservationMode
26+
// field on AWSNetworkLoadBalancerParameters correctly configures the NLB target
27+
// group attributes and router proxy protocol settings.
28+
func TestAWSNLBClientIPPreservationMode(t *testing.T) {
29+
t.Parallel()
30+
if infraConfig.Status.PlatformStatus == nil {
31+
t.Skip("test skipped on nil platform")
32+
}
33+
if infraConfig.Status.PlatformStatus.Type != configv1.AWSPlatformType {
34+
t.Skipf("test skipped on platform %q", infraConfig.Status.PlatformStatus.Type)
35+
}
36+
37+
name := types.NamespacedName{Namespace: operatorNamespace, Name: "nlb-pp-test"}
38+
domain := name.Name + "." + dnsConfig.Spec.BaseDomain
39+
ic := newLoadBalancerController(name, domain)
40+
ic.Spec.EndpointPublishingStrategy.LoadBalancer = &operatorv1.LoadBalancerStrategy{
41+
Scope: operatorv1.ExternalLoadBalancer,
42+
DNSManagementPolicy: operatorv1.ManagedLoadBalancerDNS,
43+
ProviderParameters: &operatorv1.ProviderLoadBalancerParameters{
44+
Type: operatorv1.AWSLoadBalancerProvider,
45+
AWS: &operatorv1.AWSLoadBalancerParameters{
46+
Type: operatorv1.AWSNetworkLoadBalancer,
47+
NetworkLoadBalancerParameters: &operatorv1.AWSNetworkLoadBalancerParameters{
48+
ClientIPPreservationMode: operatorv1.ClientIPPreservationProxyProtocol,
49+
},
50+
},
51+
},
52+
}
53+
54+
if err := kclient.Create(context.TODO(), ic); err != nil {
55+
t.Fatalf("failed to create ingresscontroller: %v", err)
56+
}
57+
t.Cleanup(func() { assertIngressControllerDeleted(t, kclient, ic) })
58+
59+
if err := waitForIngressControllerCondition(t, kclient, 5*time.Minute, name, availableNotProgressingConditionsForIngressControllerWithLoadBalancer...); err != nil {
60+
t.Fatalf("failed to observe expected conditions: %v", err)
61+
}
62+
63+
// Verify the target-group-attributes annotation is set on the Service.
64+
waitForLBAnnotation(t, ic, awsLBTargetGroupAttributesAnnotation, true, "preserve_client_ip.enabled=false,proxy_protocol_v2.enabled=true")
65+
66+
// Verify the CLB proxy protocol annotation is NOT set.
67+
waitForLBAnnotation(t, ic, "service.beta.kubernetes.io/aws-load-balancer-proxy-protocol", false, "")
68+
69+
// Verify the router deployment has ROUTER_USE_PROXY_PROTOCOL=true.
70+
deployment := &appsv1.Deployment{}
71+
deploymentName := controller.RouterDeploymentName(ic)
72+
if err := kclient.Get(context.TODO(), deploymentName, deployment); err != nil {
73+
t.Fatalf("failed to get router deployment: %v", err)
74+
}
75+
if err := waitForDeploymentEnvVar(t, kclient, deployment, 1*time.Minute, "ROUTER_USE_PROXY_PROTOCOL", "true"); err != nil {
76+
t.Fatalf("expected ROUTER_USE_PROXY_PROTOCOL=true on router deployment: %v", err)
77+
}
78+
79+
// Verify the status has ProxyProtocol.
80+
if err := waitForIngressControllerClientIPPreservationMode(t, name, operatorv1.ClientIPPreservationProxyProtocol); err != nil {
81+
t.Fatalf("expected status clientIPPreservationMode to be ProxyProtocol: %v", err)
82+
}
83+
84+
// Verify connectivity through the NLB.
85+
elbHostname := getIngressControllerLBAddress(t, ic)
86+
namespace := createNamespace(t, names.SimpleNameGenerator.GenerateName("nlb-pp-"))
87+
testPodName := types.NamespacedName{Name: name.Name + "-verify", Namespace: namespace.Name}
88+
testHostname := "apps." + ic.Spec.Domain
89+
t.Logf("verifying external connectivity for ingresscontroller %q with ProxyProtocol", ic.Name)
90+
verifyExternalIngressController(t, testPodName, testHostname, elbHostname)
91+
92+
// Switch to Native and verify the changes.
93+
t.Logf("switching ingresscontroller %q to Native clientIPPreservationMode", ic.Name)
94+
if err := updateIngressControllerWithRetryOnConflict(t, name, 5*time.Minute, func(ic *operatorv1.IngressController) {
95+
ic.Spec.EndpointPublishingStrategy.LoadBalancer.ProviderParameters.AWS.NetworkLoadBalancerParameters.ClientIPPreservationMode = operatorv1.ClientIPPreservationNative
96+
}); err != nil {
97+
t.Fatalf("failed to update ingresscontroller: %v", err)
98+
}
99+
100+
// Verify the target-group-attributes annotation is removed.
101+
waitForLBAnnotation(t, ic, awsLBTargetGroupAttributesAnnotation, false, "")
102+
103+
// Verify ROUTER_USE_PROXY_PROTOCOL is removed.
104+
if err := waitForDeploymentEnvVar(t, kclient, deployment, 1*time.Minute, "ROUTER_USE_PROXY_PROTOCOL", ""); err != nil {
105+
t.Fatalf("expected ROUTER_USE_PROXY_PROTOCOL to be removed from router deployment: %v", err)
106+
}
107+
108+
// Verify the status has Native.
109+
if err := waitForIngressControllerClientIPPreservationMode(t, name, operatorv1.ClientIPPreservationNative); err != nil {
110+
t.Fatalf("expected status clientIPPreservationMode to be Native: %v", err)
111+
}
112+
}
113+
114+
// TestAWSNLBDefaultClientIPPreservationMode verifies that a new NLB
115+
// IngressController defaults to ProxyProtocol for clientIPPreservationMode.
116+
func TestAWSNLBDefaultClientIPPreservationMode(t *testing.T) {
117+
t.Parallel()
118+
if infraConfig.Status.PlatformStatus == nil {
119+
t.Skip("test skipped on nil platform")
120+
}
121+
if infraConfig.Status.PlatformStatus.Type != configv1.AWSPlatformType {
122+
t.Skipf("test skipped on platform %q", infraConfig.Status.PlatformStatus.Type)
123+
}
124+
125+
name := types.NamespacedName{Namespace: operatorNamespace, Name: "nlb-default"}
126+
domain := name.Name + "." + dnsConfig.Spec.BaseDomain
127+
ic := newLoadBalancerController(name, domain)
128+
ic.Spec.EndpointPublishingStrategy.LoadBalancer = &operatorv1.LoadBalancerStrategy{
129+
Scope: operatorv1.ExternalLoadBalancer,
130+
DNSManagementPolicy: operatorv1.ManagedLoadBalancerDNS,
131+
ProviderParameters: &operatorv1.ProviderLoadBalancerParameters{
132+
Type: operatorv1.AWSLoadBalancerProvider,
133+
AWS: &operatorv1.AWSLoadBalancerParameters{
134+
Type: operatorv1.AWSNetworkLoadBalancer,
135+
},
136+
},
137+
}
138+
139+
if err := kclient.Create(context.TODO(), ic); err != nil {
140+
t.Fatalf("failed to create ingresscontroller: %v", err)
141+
}
142+
t.Cleanup(func() { assertIngressControllerDeleted(t, kclient, ic) })
143+
144+
if err := waitForIngressControllerCondition(t, kclient, 5*time.Minute, name, availableNotProgressingConditionsForIngressControllerWithLoadBalancer...); err != nil {
145+
t.Fatalf("failed to observe expected conditions: %v", err)
146+
}
147+
148+
// Verify the status defaults to ProxyProtocol.
149+
if err := waitForIngressControllerClientIPPreservationMode(t, name, operatorv1.ClientIPPreservationProxyProtocol); err != nil {
150+
t.Fatalf("expected new NLB to default to ProxyProtocol: %v", err)
151+
}
152+
153+
// Verify the target-group-attributes annotation is set.
154+
waitForLBAnnotation(t, ic, awsLBTargetGroupAttributesAnnotation, true, "preserve_client_ip.enabled=false,proxy_protocol_v2.enabled=true")
155+
156+
// Verify ROUTER_USE_PROXY_PROTOCOL=true is set.
157+
deployment := &appsv1.Deployment{}
158+
deploymentName := controller.RouterDeploymentName(ic)
159+
if err := kclient.Get(context.TODO(), deploymentName, deployment); err != nil {
160+
t.Fatalf("failed to get router deployment: %v", err)
161+
}
162+
if err := waitForDeploymentEnvVar(t, kclient, deployment, 1*time.Minute, "ROUTER_USE_PROXY_PROTOCOL", "true"); err != nil {
163+
t.Fatalf("expected ROUTER_USE_PROXY_PROTOCOL=true on router deployment: %v", err)
164+
}
165+
}
166+
167+
// waitForIngressControllerClientIPPreservationMode waits for the
168+
// IngressController status to have the expected clientIPPreservationMode.
169+
func waitForIngressControllerClientIPPreservationMode(t *testing.T, name types.NamespacedName, expected operatorv1.ClientIPPreservationMode) error {
170+
t.Helper()
171+
return wait.PollUntilContextTimeout(context.Background(), 5*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) {
172+
ic := &operatorv1.IngressController{}
173+
if err := kclient.Get(ctx, name, ic); err != nil {
174+
t.Logf("failed to get ingresscontroller %s: %v", name.Name, err)
175+
return false, nil
176+
}
177+
if ic.Status.EndpointPublishingStrategy == nil ||
178+
ic.Status.EndpointPublishingStrategy.LoadBalancer == nil ||
179+
ic.Status.EndpointPublishingStrategy.LoadBalancer.ProviderParameters == nil ||
180+
ic.Status.EndpointPublishingStrategy.LoadBalancer.ProviderParameters.AWS == nil ||
181+
ic.Status.EndpointPublishingStrategy.LoadBalancer.ProviderParameters.AWS.NetworkLoadBalancerParameters == nil {
182+
t.Logf("waiting for NLB parameters in status for %s", name.Name)
183+
return false, nil
184+
}
185+
actual := ic.Status.EndpointPublishingStrategy.LoadBalancer.ProviderParameters.AWS.NetworkLoadBalancerParameters.ClientIPPreservationMode
186+
if actual != expected {
187+
t.Logf("expected clientIPPreservationMode %q, got %q for %s", expected, actual, name.Name)
188+
return false, nil
189+
}
190+
return true, nil
191+
})
192+
}

0 commit comments

Comments
 (0)