Skip to content

Commit 5b8c8e3

Browse files
committed
OCPBUGS-59176: fix several failing tests in custom-dns jobs
Some e2e tests are failing with the job "gcp-custom-dns" for featuregate "GCPClusterHostedDNSInstall" which is promoted to GA in 4.20. In the "custom-dns" cluster OpenShift will start static CoreDNS pods to provide DNS resolution for API, Internal API and Ingress services that are essential for cluster creation. After cluster deployment is completed, the customer will update their external DNS solution with the same assigned LB IP addresses used for the configuration of the internal CoreDNS instance. The failing tests like http2 and grpc tests use dedicated ingresscontrollers, and gateway also has separated LB and dnsrecord, so the default wildcard created by the new static CoreDNS won't work for those tests. Make below changes to fix the failing tests: - Update makeHTTPClient() DialContext to target LoadBalancer IP address directly when DNS is unmanaged, fixing both http2 and gatewayapi httproute tests. - Update grpc Dial() to target LoadBalancer IP address directly when DNS is unmanaged, fixing the grpc test. - Extract getLoadBalancerAddress() as a reusable helper from assertGatewayLoadbalancerReady() for use across http2, grpc and gatewayapi tests. - Update gatewayapi assertDNSRecordStatus() to check the Published condition per-zone based on whether DNS is managed or unmanaged. - Add isDNSManaged() helper that checks the DNSManaged condition on the default ingresscontroller, defaulting to managed=true when the condition is absent. - Add getClusterBaseDomainName() and update http2/grpc/h2spec shard ingresscontroller to generate domain based on cluster baseDomain instead of ingress domain (e.g. "e2e-test-xxx.apps.baseDomain"), avoiding custom ingresscontroller DNS overlapping with default wildcard "*.apps.baseDomain".
1 parent 954d227 commit 5b8c8e3

7 files changed

Lines changed: 193 additions & 62 deletions

File tree

test/extended/router/gatewayapi_upgrade.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func (t *GatewayAPIUpgradeTest) Setup(ctx context.Context, f *e2e.Framework) {
140140

141141
if t.loadBalancerSupported && t.managedDNS {
142142
g.By("Verifying HTTP connectivity before upgrade")
143-
assertHttpRouteConnection(t.hostname)
143+
assertHttpRouteConnection(t.oc, t.gatewayName+"-openshift-default", t.hostname)
144144
e2e.Logf("HTTPRoute connectivity verified before upgrade")
145145
}
146146
}
@@ -184,7 +184,7 @@ func (t *GatewayAPIUpgradeTest) Test(ctx context.Context, f *e2e.Framework, done
184184

185185
if t.loadBalancerSupported && t.managedDNS {
186186
g.By("Verifying HTTP connectivity after upgrade")
187-
assertHttpRouteConnection(t.hostname)
187+
assertHttpRouteConnection(t.oc, t.gatewayName+"-openshift-default", t.hostname)
188188
}
189189

190190
if migrationOccurred {

test/extended/router/gatewayapicontroller.go

Lines changed: 78 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package router
22

33
import (
44
"context"
5-
"crypto/tls"
65
"errors"
76
"fmt"
87
"net"
@@ -404,9 +403,7 @@ var _ = g.Describe("[sig-network-edge][OCPFeatureGate:GatewayAPIController][Feat
404403
assertHttpRouteSuccessful(oc, gw, "test-httproute")
405404

406405
g.By("Validating the http connectivity to the backend application")
407-
if loadBalancerSupported && managedDNS {
408-
assertHttpRouteConnection(defaultRoutename)
409-
}
406+
assertHttpRouteConnection(oc, gw+"-openshift-default", defaultRoutename)
410407
})
411408

412409
g.It("Ensure GIE is enabled after creating an inferencePool CRD", func() {
@@ -612,20 +609,14 @@ func getPlatformCapabilities(oc *exutil.CLI) (loadBalancerSupported bool, manage
612609
loadBalancerSupported = false
613610
}
614611

615-
managedDNS = isDNSManaged(oc)
612+
var err error
613+
managedDNS, err = isDNSManaged(oc, time.Minute)
614+
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to check if DNS is managed")
616615

617616
e2e.Logf("Platform: %s, LoadBalancer supported: %t, DNS managed: %t", infra.Status.PlatformStatus.Type, loadBalancerSupported, managedDNS)
618617
return loadBalancerSupported, managedDNS
619618
}
620619

621-
// isDNSManaged checks if the cluster has DNS zones configured (public or private).
622-
// On platforms like vSphere without external DNS, DNS records cannot be managed.
623-
func isDNSManaged(oc *exutil.CLI) bool {
624-
dnsConfig, err := oc.AdminConfigClient().ConfigV1().DNSes().Get(context.Background(), "cluster", metav1.GetOptions{})
625-
o.Expect(err).NotTo(o.HaveOccurred(), "Failed to get DNS config")
626-
return dnsConfig.Spec.PrivateZone != nil || dnsConfig.Spec.PublicZone != nil
627-
}
628-
629620
// isIPv6OrDualStack checks if the cluster is using IPv6 or dual-stack networking.
630621
// Returns true if any ServiceNetwork CIDR is IPv6 (indicates IPv6-only or dual-stack).
631622
func isIPv6OrDualStack(oc *exutil.CLI) (bool, error) {
@@ -753,18 +744,17 @@ func buildGateway(name, namespace, gcname, fromNs, domain string) *gatewayapiv1.
753744
}
754745
}
755746

756-
// assertGatewayLoadbalancerReady verifies that the given gateway has the service's load balancer address assigned.
757-
func assertGatewayLoadbalancerReady(oc *exutil.CLI, gwName, gwServiceName string) {
758-
// check gateway LB service, note that External-IP might be hostname (AWS) or IP (Azure/GCP)
747+
// return LoadBalancer service address, note that External-IP might be hostname (AWS) or IP (Azure/GCP)
748+
func getLoadBalancerAddress(oc *exutil.CLI, serviceName string) string {
759749
var lbAddress string
760750
err := wait.PollUntilContextTimeout(context.Background(), 1*time.Second, loadBalancerReadyTimeout, false, func(context context.Context) (bool, error) {
761-
lbService, err := oc.AdminKubeClient().CoreV1().Services(ingressNamespace).Get(context, gwServiceName, metav1.GetOptions{})
751+
lbService, err := oc.AdminKubeClient().CoreV1().Services(ingressNamespace).Get(context, serviceName, metav1.GetOptions{})
762752
if err != nil {
763-
e2e.Logf("Failed to get service %q: %v, retrying...", gwServiceName, err)
753+
e2e.Logf("Failed to get service %q: %v, retrying...", serviceName, err)
764754
return false, nil
765755
}
766756
if len(lbService.Status.LoadBalancer.Ingress) == 0 {
767-
e2e.Logf("Service %q has no load balancer; retrying...", gwServiceName)
757+
e2e.Logf("Service %q has no load balancer; retrying...", serviceName)
768758
return false, nil
769759
}
770760
if lbService.Status.LoadBalancer.Ingress[0].Hostname != "" {
@@ -773,11 +763,20 @@ func assertGatewayLoadbalancerReady(oc *exutil.CLI, gwName, gwServiceName string
773763
lbAddress = lbService.Status.LoadBalancer.Ingress[0].IP
774764
}
775765
if lbAddress == "" {
776-
e2e.Logf("No load balancer address for service %q, retrying", gwServiceName)
766+
e2e.Logf("No load balancer address for service %q, retrying", serviceName)
777767
return false, nil
778768
}
779-
e2e.Logf("Got load balancer address for service %q: %v", gwServiceName, lbAddress)
769+
return true, nil
770+
})
771+
o.Expect(err).NotTo(o.HaveOccurred(), "Timed out to get load balancer address of service %q", serviceName)
772+
e2e.Logf("Got load balancer address for service %q: %v", serviceName, lbAddress)
773+
return lbAddress
774+
}
780775

776+
// assertGatewayLoadbalancerReady verifies that the given gateway has the service's load balancer address assigned.
777+
func assertGatewayLoadbalancerReady(oc *exutil.CLI, gwName, gwServiceName string) {
778+
lbAddress := getLoadBalancerAddress(oc, gwServiceName)
779+
err := wait.PollUntilContextTimeout(context.Background(), 1*time.Second, loadBalancerReadyTimeout, false, func(context context.Context) (bool, error) {
781780
gw, err := oc.AdminGatewayApiClient().GatewayV1().Gateways(ingressNamespace).Get(context, gwName, metav1.GetOptions{})
782781
if err != nil {
783782
e2e.Logf("Failed to get gateway %q: %v; retrying...", err, gwName)
@@ -795,10 +794,17 @@ func assertGatewayLoadbalancerReady(oc *exutil.CLI, gwName, gwServiceName string
795794
o.Expect(err).NotTo(o.HaveOccurred(), "Timed out waiting for gateway %q to get load balancer address of service %q", gwName, gwServiceName)
796795
}
797796

798-
// assertDNSRecordStatus polls until the DNSRecord's status in the default operand namespace is True.
797+
// assertDNSRecordStatus polls until the DNSRecord's status in the default operand namespace is ready.
798+
// When DNS is managed, it waits for all zones to have Published=True.
799+
// When DNS is unmanaged, it waits for all zones to have Published!=True (expected in custom-dns clusters).
799800
func assertDNSRecordStatus(oc *exutil.CLI, gatewayName string) {
800-
// find the DNS Record and confirm its zone status is True
801-
err := wait.PollUntilContextTimeout(context.Background(), 2*time.Second, 10*time.Minute, false, func(context context.Context) (bool, error) {
801+
dnsManaged, err := isDNSManaged(oc, time.Minute)
802+
if err != nil {
803+
e2e.Failf("Failed to get default ingresscontroller DNSManaged status: %v", err)
804+
}
805+
806+
// find the DNS Record and confirm its zone status
807+
err = wait.PollUntilContextTimeout(context.Background(), 2*time.Second, 10*time.Minute, false, func(context context.Context) (bool, error) {
802808
gatewayDNSRecord := &operatoringressv1.DNSRecord{}
803809
gatewayDNSRecords, err := oc.AdminIngressClient().IngressV1().DNSRecords(ingressNamespace).List(context, metav1.ListOptions{})
804810
if err != nil {
@@ -810,20 +816,43 @@ func assertDNSRecordStatus(oc *exutil.CLI, gatewayName string) {
810816
for _, record := range gatewayDNSRecords.Items {
811817
if record.Labels["gateway.networking.k8s.io/gateway-name"] == gatewayName {
812818
gatewayDNSRecord = &record
819+
e2e.Logf("Found the desired dnsrecord and spec is: %v", gatewayDNSRecord.Spec)
813820
break
814821
}
815822
}
816823

817-
// checking the gateway DNS record status
824+
if len(gatewayDNSRecord.Status.Zones) == 0 {
825+
e2e.Logf("DNS record %q has no zones yet, retrying...", gatewayDNSRecord.Name)
826+
return false, nil
827+
}
828+
829+
// Check the Published condition for each zone
818830
for _, zone := range gatewayDNSRecord.Status.Zones {
831+
published := false
819832
for _, condition := range zone.Conditions {
820-
if condition.Type == "Published" && condition.Status == "True" {
821-
return true, nil
833+
if condition.Type != "Published" {
834+
continue
835+
}
836+
e2e.Logf("The published status is %v for zone %v", condition.Status, zone.DNSZone)
837+
if dnsManaged && condition.Status != "True" {
838+
e2e.Logf("DNS record %q zone %v is not published yet, retrying...", gatewayDNSRecord.Name, zone.DNSZone)
839+
return false, nil
840+
}
841+
if !dnsManaged && condition.Status == "True" {
842+
e2e.Logf("DNS record %q zone %v is unexpectedly published for unmanaged DNS, retrying...", gatewayDNSRecord.Name, zone.DNSZone)
843+
return false, nil
822844
}
845+
published = true
846+
break
847+
}
848+
if !published {
849+
e2e.Logf("DNS record %q zone %v has no Published condition, retrying...", gatewayDNSRecord.Name, zone.DNSZone)
850+
return false, nil
823851
}
824852
}
825-
e2e.Logf("DNS record %q is not ready, retrying...", gatewayDNSRecord.Name)
826-
return false, nil
853+
854+
e2e.Logf("All zones are checked and DNS record %q is ready", gatewayDNSRecord.Name)
855+
return true, nil
827856
})
828857
o.Expect(err).NotTo(o.HaveOccurred(), "Timed out waiting for gateway %q DNSRecord to become ready", gatewayName)
829858
}
@@ -1041,24 +1070,28 @@ func assertHttpRouteSuccessful(oc *exutil.CLI, gwName, name string) (*gatewayapi
10411070

10421071
// assertHttpRouteConnection checks if the http route of the given name replies successfully,
10431072
// and returns an error if not
1044-
func assertHttpRouteConnection(hostname string) {
1045-
// Create the http client to check the response status code.
1046-
client := &http.Client{
1047-
Timeout: 10 * time.Second,
1048-
Transport: &http.Transport{
1049-
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
1050-
},
1073+
func assertHttpRouteConnection(oc *exutil.CLI, gwServiceName, hostname string) {
1074+
isDNSManaged, err := isDNSManaged(oc, time.Minute)
1075+
if err != nil {
1076+
e2e.Failf("Failed to get default ingresscontroller DNSManaged status: %v", err)
1077+
}
1078+
lbAddress := ""
1079+
if isDNSManaged {
1080+
err := wait.PollUntilContextTimeout(context.Background(), 20*time.Second, dnsResolutionTimeout, false, func(context context.Context) (bool, error) {
1081+
_, err := net.LookupHost(hostname)
1082+
if err != nil {
1083+
e2e.Logf("[%v] Failed to resolve HTTP route's hostname %q: %v, retrying...", time.Now(), hostname, err)
1084+
return false, nil
1085+
}
1086+
return true, nil
1087+
})
1088+
o.Expect(err).NotTo(o.HaveOccurred(), "Timed out waiting for HTTP route's hostname %q to be resolved: %v", hostname, err)
1089+
} else {
1090+
lbAddress = getLoadBalancerAddress(oc, gwServiceName)
10511091
}
10521092

1053-
err := wait.PollUntilContextTimeout(context.Background(), 20*time.Second, dnsResolutionTimeout, false, func(context context.Context) (bool, error) {
1054-
_, err := net.LookupHost(hostname)
1055-
if err != nil {
1056-
e2e.Logf("[%v] Failed to resolve HTTP route's hostname %q: %v, retrying...", time.Now(), hostname, err)
1057-
return false, nil
1058-
}
1059-
return true, nil
1060-
})
1061-
o.Expect(err).NotTo(o.HaveOccurred(), "Timed out waiting for HTTP route's hostname %q to be resolved: %v", hostname, err)
1093+
// Create the http client to check the response status code.
1094+
client := makeHTTPClient(false, 10*time.Second, lbAddress)
10621095

10631096
// Wait for http route to respond, and when it does, check for the status code.
10641097
err = wait.PollUntilContextTimeout(context.Background(), 5*time.Second, 5*time.Minute, false, func(context context.Context) (bool, error) {

test/extended/router/grpc-interop.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ var _ = g.Describe("[sig-network-edge][Conformance][Area:Networking][Feature:Rou
5353
g.Skip("Skip on platforms where the default router is not exposed by a load balancer service.")
5454
}
5555

56-
defaultDomain, err := getDefaultIngressClusterDomainName(oc, time.Minute)
57-
o.Expect(err).NotTo(o.HaveOccurred(), "failed to find default domain name")
56+
baseDomain, err := getClusterBaseDomainName(oc, time.Minute)
57+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to find base domain name")
5858

5959
g.By("Locating the canary image reference")
6060
image, err := getCanaryImage(oc)
@@ -196,7 +196,7 @@ var _ = g.Describe("[sig-network-edge][Conformance][Area:Networking][Feature:Rou
196196
pemCrt2, err := certgen.MarshalCertToPEMString(tlsCrt2Data)
197197
o.Expect(err).NotTo(o.HaveOccurred())
198198

199-
shardFQDN := oc.Namespace() + "." + defaultDomain
199+
shardFQDN := oc.Namespace() + "." + baseDomain
200200

201201
g.By("Creating routes to test for gRPC interoperability")
202202
routeType := oc.Namespace()
@@ -330,6 +330,15 @@ var _ = g.Describe("[sig-network-edge][Conformance][Area:Networking][Feature:Rou
330330
o.Expect(shardService).NotTo(o.BeNil())
331331
o.Expect(shardService.Status.LoadBalancer.Ingress).To(o.Not(o.BeEmpty()))
332332

333+
isDNSManaged, err := isDNSManaged(oc, time.Minute)
334+
if err != nil {
335+
e2e.Failf("Failed to get default ingresscontroller DNSManaged status: %v", err)
336+
}
337+
lbAddress := ""
338+
if !isDNSManaged {
339+
lbAddress = getLoadBalancerAddress(oc, "router-"+oc.Namespace())
340+
}
341+
333342
testCases := []string{
334343
"cancel_after_begin",
335344
"cancel_after_first_response",
@@ -352,15 +361,15 @@ var _ = g.Describe("[sig-network-edge][Conformance][Area:Networking][Feature:Rou
352361
routev1.TLSTerminationReencrypt,
353362
routev1.TLSTerminationPassthrough,
354363
} {
355-
err := grpcExecTestCases(oc, routeType, 5*time.Minute, testCases...)
364+
err := grpcExecTestCases(oc, routeType, 5*time.Minute, lbAddress, testCases...)
356365
o.Expect(err).NotTo(o.HaveOccurred())
357366
}
358367
})
359368
})
360369
})
361370

362371
// grpcExecTestCases run gRPC interop test cases.
363-
func grpcExecTestCases(oc *exutil.CLI, routeType routev1.TLSTerminationType, timeout time.Duration, testCases ...string) error {
372+
func grpcExecTestCases(oc *exutil.CLI, routeType routev1.TLSTerminationType, timeout time.Duration, lbAddress string, testCases ...string) error {
364373
host, err := getHostnameForRoute(oc, fmt.Sprintf("grpc-interop-%s", routeType))
365374
if err != nil {
366375
return err
@@ -371,6 +380,7 @@ func grpcExecTestCases(oc *exutil.CLI, routeType routev1.TLSTerminationType, tim
371380
Port: 443,
372381
UseTLS: true,
373382
Insecure: true,
383+
Target: lbAddress,
374384
}
375385

376386
if routeType == "h2c" {

test/extended/router/grpc-interop/clientconn.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package grpc_interop
22

33
import (
4+
"context"
45
"crypto/tls"
56
"crypto/x509"
67
"errors"
8+
"fmt"
79
"net"
810
"strconv"
911

@@ -17,6 +19,8 @@ type DialParams struct {
1719
Host string
1820
Port int
1921
Insecure bool
22+
// Target is the actual IP you want to dial instead of resolving hostname
23+
Target string
2024
}
2125

2226
func Dial(cfg DialParams) (*grpc.ClientConn, error) {
@@ -44,5 +48,18 @@ func Dial(cfg DialParams) (*grpc.ClientConn, error) {
4448
opts = append(opts, grpc.WithInsecure())
4549
}
4650

51+
if cfg.Target != "" {
52+
dialer := func(ctx context.Context, addr string) (net.Conn, error) {
53+
_, port, err := net.SplitHostPort(addr)
54+
if err != nil {
55+
return nil, fmt.Errorf("failed to split host:port from %q: %w", addr, err)
56+
}
57+
// Connect to targetIP:port regardless of hostname
58+
dest := net.JoinHostPort(cfg.Target, port)
59+
return (&net.Dialer{}).DialContext(ctx, "tcp", dest)
60+
}
61+
opts = append(opts, grpc.WithContextDialer(dialer))
62+
}
63+
4764
return grpc.Dial(net.JoinHostPort(cfg.Host, strconv.Itoa(cfg.Port)), append(opts, grpc.WithBlock())...)
4865
}

test/extended/router/h2spec.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ var _ = g.Describe("[sig-network-edge][Conformance][Area:Networking][Feature:Rou
8080
}
8181
}
8282

83-
g.By("Getting the default domain")
84-
defaultDomain, err := getDefaultIngressClusterDomainName(oc, time.Minute)
85-
o.Expect(err).NotTo(o.HaveOccurred(), "failed to find default domain name")
83+
g.By("Getting the base domain")
84+
baseDomain, err := getClusterBaseDomainName(oc, time.Minute)
85+
o.Expect(err).NotTo(o.HaveOccurred(), "failed to find base domain name")
8686

8787
g.By("Locating the router image reference")
8888
routerImage, err := exutil.FindRouterImage(oc)
@@ -409,7 +409,7 @@ BFNBRELPe53ZdLKWpf2Sr96vRPRNw
409409
e2e.ExpectNoError(e2epod.WaitForPodNameRunningInNamespace(context.TODO(), oc.KubeClient(), "h2spec-haproxy", oc.KubeFramework().Namespace.Name))
410410
e2e.ExpectNoError(e2epod.WaitForPodNameRunningInNamespace(context.TODO(), oc.KubeClient(), "h2spec", oc.KubeFramework().Namespace.Name))
411411

412-
shardFQDN := oc.Namespace() + "." + defaultDomain
412+
shardFQDN := oc.Namespace() + "." + baseDomain
413413

414414
// The new router shard is using a namespace
415415
// selector so label this test namespace to

0 commit comments

Comments
 (0)