diff --git a/internal/gatewayapi/contexts.go b/internal/gatewayapi/contexts.go index 38edbc3917..e6641b3837 100644 --- a/internal/gatewayapi/contexts.go +++ b/internal/gatewayapi/contexts.go @@ -6,6 +6,8 @@ package gatewayapi import ( + "math" + certificatesv1b1 "k8s.io/api/certificates/v1beta1" corev1 "k8s.io/api/core/v1" discoveryv1 "k8s.io/api/discovery/v1" @@ -114,12 +116,17 @@ func (g *GatewayContext) attachEnvoyProxy(resources *resource.Resources, epMap m } } -func (g *GatewayContext) IncreaseAttachedListenerSets() { +func (g *GatewayContext) IncreaseAttachedListenerSets(count uint32) { if g.Status.AttachedListenerSets == nil { - g.Status.AttachedListenerSets = ptr.To[int32](1) - } else { - *g.Status.AttachedListenerSets++ + if count > 0 { + g.Status.AttachedListenerSets = new(int32(min(int64(count), math.MaxInt32))) + } + return } + + // Check for potential overflow before adding + newValue := int64(*g.Status.AttachedListenerSets) + int64(count) + *g.Status.AttachedListenerSets = int32(min(newValue, math.MaxInt32)) } // ListenerContext wraps a Listener and provides helper methods for @@ -138,6 +145,10 @@ type ListenerContext struct { namespaceSelector labels.Selector + // specValid indicates whether per-listener spec validation succeeded. + // Conflict detection should only consider listeners with specValid=true. + specValid bool + tls ListenerTLSConfig httpIR *ir.HTTPListener diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go index 3b44fd9f66..cefb4b678d 100644 --- a/internal/gatewayapi/helpers.go +++ b/internal/gatewayapi/helpers.go @@ -423,24 +423,24 @@ func wildcardHostnameMatchesHostname(wildcardHostname, hostname string) bool { func containsPort(ports []*protocolPort, port *protocolPort) bool { for _, protocolPort := range ports { - curProtocol, curLevel := layer4Protocol(protocolPort) - myProtocol, myLevel := layer4Protocol(port) - if protocolPort.port == port.port && (curProtocol == myProtocol && curLevel == myLevel) { + curProtocol := layer4Protocol(protocolPort) + myProtocol := layer4Protocol(port) + if protocolPort.port == port.port && curProtocol == myProtocol { return true } } return false } -// layer4Protocol returns listener L4 protocol and listen protocol level -func layer4Protocol(protocolPort *protocolPort) (string, string) { +// layer4Protocol returns listener L4 protocol +func layer4Protocol(protocolPort *protocolPort) string { switch protocolPort.protocol { case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType: - return TCPProtocol, L7Protocol + return TCPProtocol case gwapiv1.TCPProtocolType: - return TCPProtocol, L4Protocol + return TCPProtocol default: - return UDPProtocol, L4Protocol + return UDPProtocol } } diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 5861da7ad1..8d73feffbd 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -17,6 +17,7 @@ import ( "github.com/google/cel-go/cel" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/utils/ptr" @@ -214,9 +215,110 @@ func validClientCertificateRef(ref *gwapiv1.SecretObjectReference) error { return nil } +// allowedRouteKindsForProtocol returns the route kinds supported by the given listener protocol. +func allowedRouteKindsForProtocol(protocol gwapiv1.ProtocolType, tlsMode *gwapiv1.TLSModeType) []gwapiv1.Kind { + switch protocol { + case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType: + return []gwapiv1.Kind{resource.KindHTTPRoute, resource.KindGRPCRoute} + case gwapiv1.TLSProtocolType: + if tlsMode != nil && *tlsMode == gwapiv1.TLSModePassthrough { + return []gwapiv1.Kind{resource.KindTLSRoute} + } + // Terminate mode or unspecified defaults to accept both TCP and TLS routes + return []gwapiv1.Kind{resource.KindTCPRoute, resource.KindTLSRoute} + case gwapiv1.TCPProtocolType: + return []gwapiv1.Kind{resource.KindTCPRoute} + case gwapiv1.UDPProtocolType: + return []gwapiv1.Kind{resource.KindUDPRoute} + default: + return nil + } +} + +// validateProtocolRules validates protocol-specific constraints (hostname, TLS requirements). +// Returns true if all constraints are satisfied, false otherwise. +func validateProtocolRules(listener *ListenerContext) bool { + switch listener.Protocol { + case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType, + gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType: + // All supported protocols pass basic validation here. + // Protocol-specific constraints (TLS, hostname) are validated in + // validateTLSConfiguration and validateHostName respectively, + // where they can set proper conditions. + return true + + default: + // Unsupported protocol handled separately + return false + } +} + +func (t *Translator) validateListenerSpec(listener *ListenerContext, resources *resource.Resources) bool { + // Validate listener spec directly without relying on conditions. + // Start with valid assumption and invalidate on failures. + + // Phase 1: Validate fundamental rules + specValid := t.validateAllowedNamespaces(listener) + if !validateProtocolRules(listener) { + specValid = false + } + + // Phase 2: Validate allowed routes based on protocol + if listener.Protocol == gwapiv1.HTTPProtocolType || + listener.Protocol == gwapiv1.HTTPSProtocolType || + listener.Protocol == gwapiv1.TCPProtocolType || + listener.Protocol == gwapiv1.UDPProtocolType || + listener.Protocol == gwapiv1.TLSProtocolType { + var tlsMode *gwapiv1.TLSModeType + if listener.TLS != nil { + tlsMode = listener.TLS.Mode + } + allowedKinds := allowedRouteKindsForProtocol(listener.Protocol, tlsMode) + if !t.validateAllowedRoutes(listener, allowedKinds...) { + specValid = false + } + } else { + // Unsupported protocol + specValid = false + listener.SetSupportedKinds() + listener.SetCondition( + gwapiv1.ListenerConditionAccepted, + metav1.ConditionFalse, + gwapiv1.ListenerReasonUnsupportedProtocol, + fmt.Sprintf("Protocol %s is unsupported, must be %s, %s, %s or %s.", listener.Protocol, + gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType), + ) + } + + // Phase 3: Validate TLS configuration details + if !t.validateTLSConfiguration(listener, resources) { + specValid = false + } + + // Phase 4: Validate Hostname configuration + if !t.validateHostName(listener) { + specValid = false + } + + return specValid +} + func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource.XdsIRMap, infraIR resource.InfraIRMap, resources *resource.Resources) { // Infra IR proxy ports must be unique. foundPorts := make(map[string][]*protocolPort) + + // Phase 1: Validate each listener's spec independently. + // This must happen before conflict resolution so that invalid listeners + // don't block valid ones during conflict detection. + for _, gateway := range gateways { + for _, listener := range gateway.listeners { + listener.specValid = t.validateListenerSpec(listener, resources) + } + } + + // Phase 2: Run conflict detection. + // Only listeners that haven't been marked as invalid will participate in conflict resolution. + t.validateConflictedProtocolsListeners(gateways) t.validateConflictedLayer7Listeners(gateways) t.validateConflictedLayer4Listeners(gateways, gwapiv1.TCPProtocolType) t.validateConflictedLayer4Listeners(gateways, gwapiv1.UDPProtocolType) @@ -224,9 +326,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource t.validateConflictedMergedListeners(gateways) } - // Iterate through all listeners to validate spec - // and compute status for each, and add valid ones - // to the Xds IR. + // Phase 3: Build IR for valid listeners. for _, gateway := range gateways { irKey := t.getIRKey(gateway.Gateway) @@ -235,57 +335,27 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource } t.processProxyReadyListener(xdsIR[irKey], gateway.envoyProxy) t.processProxyObservability(gateway, xdsIR[irKey], infraIR[irKey].Proxy, resources) - + gatewayAttachedListenerSets := sets.New[string]() for _, listener := range gateway.listeners { - // Process protocol & supported kinds - switch listener.Protocol { - case gwapiv1.TLSProtocolType: - if listener.TLS != nil { - switch *listener.TLS.Mode { - case gwapiv1.TLSModePassthrough: - t.validateAllowedRoutes(listener, resource.KindTLSRoute) - case gwapiv1.TLSModeTerminate: - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - default: - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - } - } else { - t.validateAllowedRoutes(listener, resource.KindTCPRoute, resource.KindTLSRoute) - } - case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType: - t.validateAllowedRoutes(listener, resource.KindHTTPRoute, resource.KindGRPCRoute) - case gwapiv1.TCPProtocolType: - t.validateAllowedRoutes(listener, resource.KindTCPRoute) - case gwapiv1.UDPProtocolType: - t.validateAllowedRoutes(listener, resource.KindUDPRoute) - default: - listener.SetSupportedKinds() - listener.SetCondition( - gwapiv1.ListenerConditionAccepted, - metav1.ConditionFalse, - gwapiv1.ListenerReasonUnsupportedProtocol, - fmt.Sprintf("Protocol %s is unsupported, must be %s, %s, %s or %s.", listener.Protocol, - gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType), - ) - } - - // Validate allowed namespaces - t.validateAllowedNamespaces(listener) - - // Process TLS configuration - t.validateTLSConfiguration(listener, resources) - - // Process Hostname configuration - t.validateHostName(listener) - - // Process conditions and check if the listener is ready + // Finalize listener conditions and check readiness. t.validateListenerConditions(listener) + if !listener.IsReady() { + // Skip invalid listeners from IR building + continue + } // Skip listeners with invalid frontend TLS validation as they are not functional. if listener.frontendTLSValidationInvalid() { continue } + if listener.isFromListenerSet() { + gatewayAttachedListenerSets.Insert(types.NamespacedName{ + Namespace: listener.listenerSet.Namespace, + Name: listener.listenerSet.Name, + }.String()) + } + address := netutils.IPv4ListenerAddress ipFamily := getEnvoyIPFamily(gateway.envoyProxy) if ipFamily != nil && (*ipFamily == egv1a1.IPv6 || *ipFamily == egv1a1.DualStack) { @@ -365,11 +435,35 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR resource foundPorts[irKey] = append(foundPorts[irKey], servicePort) } } + gateway.IncreaseAttachedListenerSets(uint32(len(gatewayAttachedListenerSets))) } t.checkOverlappingTLSConfig(gateways) } +// isListenerReady returns true if the listener is ready (Accepted=True and Programmed=True or no conditions yet). +// A listener is not ready if it has Accepted=False or Programmed=False. +func isListenerReady(listener *ListenerContext) bool { + conditions := listener.GetConditions() + + // No conditions yet means it will be set to ready during validation. + if len(conditions) == 0 { + return true + } + + // Check if Accepted=False or Programmed=False exists. + for _, cond := range conditions { + if cond.Type == string(gwapiv1.ListenerConditionAccepted) && cond.Status == metav1.ConditionFalse { + return false + } + if cond.Type == string(gwapiv1.ListenerConditionProgrammed) && cond.Status == metav1.ConditionFalse { + return false + } + } + + return true +} + // checkOverlappingTLSConfig checks for overlapping hostnames and certificates between listeners and sets // the `OverlappingTLSConfig` condition if there are overlapping hostnames or certificates. func (t *Translator) checkOverlappingTLSConfig(gateways []*GatewayContext) { @@ -378,7 +472,7 @@ func (t *Translator) checkOverlappingTLSConfig(gateways []*GatewayContext) { httpsListeners := []*ListenerContext{} for _, gateway := range gateways { for _, listener := range gateway.listeners { - if listener.Protocol == gwapiv1.HTTPSProtocolType { + if listener.Protocol == gwapiv1.HTTPSProtocolType && isListenerReady(listener) { httpsListeners = append(httpsListeners, listener) } } @@ -393,7 +487,7 @@ func (t *Translator) checkOverlappingTLSConfig(gateways []*GatewayContext) { for _, gateway := range gateways { httpsListeners := []*ListenerContext{} for _, listener := range gateway.listeners { - if listener.Protocol == gwapiv1.HTTPSProtocolType { + if listener.Protocol == gwapiv1.HTTPSProtocolType && isListenerReady(listener) { httpsListeners = append(httpsListeners, listener) } } @@ -422,10 +516,18 @@ func checkOverlappingHostnames(httpsListeners []*ListenerContext) { if overlappingListeners[i] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[i]) { + continue + } for j := i + 1; j < len(httpsListeners); j++ { if overlappingListeners[j] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[j]) { + continue + } if httpsListeners[i].Port != httpsListeners[j].Port { continue } @@ -504,10 +606,18 @@ func checkOverlappingCertificates(httpsListeners []*ListenerContext) { if overlappingListeners[i] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[i]) { + continue + } for j := i + 1; j < len(httpsListeners); j++ { if overlappingListeners[j] != nil { continue } + // Skip listeners that are already marked as invalid from per-listener validation + if hasInvalidCondition(httpsListeners[j]) { + continue + } if httpsListeners[i].Port != httpsListeners[j].Port { continue } diff --git a/internal/gatewayapi/listenerset.go b/internal/gatewayapi/listenerset.go index 68cdb575ed..2fd10d1196 100644 --- a/internal/gatewayapi/listenerset.go +++ b/internal/gatewayapi/listenerset.go @@ -93,7 +93,6 @@ func (t *Translator) processListenerSet(ls *gwapiv1.ListenerSet, gatewayMap map[ } gatewayCtx.listeners = append(gatewayCtx.listeners, listenerCtx) } - gatewayCtx.IncreaseAttachedListenerSets() } // ProcessListenerSetStatus computes the status of ListenerSets after their listeners have been processed. diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index 56fcaf5aa7..d3c15834d2 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -2282,7 +2282,7 @@ func (t *Translator) processAllowedListenersForParentRefs( } parentRefCtx.SetListeners(allowedListeners...) - if !HasReadyListener(selectedListeners) { + if !HasReadyListener(allowedListeners) { routeStatus := GetRouteStatus(routeContext) status.SetRouteStatusCondition(routeStatus, parentRefCtx.routeParentStatusIdx, diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml index 863fde4c1d..5bbba87e2a 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml @@ -176,6 +176,10 @@ gateways: allowedRoutes: namespaces: from: Same + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 - name: tcp protocol: TCP port: 53 @@ -222,7 +226,16 @@ services: - name: http protocol: TCP port: 8080 - +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K endpointslices: - apiVersion: discovery.k8s.io/v1 kind: EndpointSlice diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml index af39245f4e..3048d4dd49 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml @@ -250,6 +250,10 @@ gateways: name: https port: 443 protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate - allowedRoutes: namespaces: from: Same @@ -284,10 +288,15 @@ gateways: - attachedRoutes: 1 conditions: - lastTransitionTime: null - message: Listener must have TLS set when protocol is HTTPS. - reason: Invalid - status: "False" + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -737,6 +746,9 @@ xdsIR: traffic: {} - address: 0.0.0.0 externalPort: 443 + grpc: + enableGRPCStats: true + enableGRPCWeb: true hostnames: - '*' metadata: @@ -749,6 +761,48 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10443 + routes: + - destination: + metadata: + kind: GRPCRoute + name: grpcroute-1 + namespace: envoy-gateway + name: grpcroute/envoy-gateway/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: envoy-gateway + sectionName: "8080" + name: grpcroute/envoy-gateway/grpcroute-1/rule/0/backend/0 + protocol: GRPC + weight: 1 + headerMatches: + - distinct: false + exact: foo + name: magic + hostname: '*' + isHTTP2: true + metadata: + kind: GRPCRoute + name: grpcroute-1 + namespace: envoy-gateway + policies: + - kind: BackendTrafficPolicy + name: target-grpcroute-in-gateway-2 + namespace: envoy-gateway + name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/* + traffic: {} + tls: + alpnProtocols: null + certificates: + - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + name: envoy-gateway/tls-secret-1 + privateKey: '[redacted]' readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml index a29dfb9785..41827b1006 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-routing-type-listener.out.yaml @@ -218,12 +218,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-1/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -309,20 +303,6 @@ xdsIR: name: "" prefix: /foo traffic: {} - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-1/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.in.yaml index eab52dcef7..bdaf427072 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.in.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.in.yaml @@ -128,6 +128,10 @@ gateways: allowedRoutes: namespaces: from: Same + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 - name: tcp protocol: TCP port: 53 @@ -162,3 +166,13 @@ gateways: allowedRoutes: namespaces: from: Same +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml index 6fa616eead..e5b60bfc2c 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-status-conditions.out.yaml @@ -277,6 +277,10 @@ gateways: name: https port: 443 protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate - allowedRoutes: namespaces: from: Same @@ -311,10 +315,15 @@ gateways: - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: Listener must have TLS set when protocol is HTTPS. - reason: Invalid - status: "False" + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -610,6 +619,14 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10443 + tls: + alpnProtocols: null + certificates: + - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + name: envoy-gateway/tls-secret-1 + privateKey: '[redacted]' + maxVersion: "1.3" + minVersion: "1.2" readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml index 2554c33cbe..4a89e8ad27 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml @@ -176,6 +176,10 @@ gateways: allowedRoutes: namespaces: from: Same + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 - name: tcp protocol: TCP port: 53 @@ -196,6 +200,16 @@ gateways: allowedRoutes: namespaces: from: Same +secrets: +- apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K services: - apiVersion: v1 kind: Service diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml index 081fd59005..75dc766fcd 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml @@ -250,6 +250,10 @@ gateways: name: https port: 443 protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate - allowedRoutes: namespaces: from: Same @@ -284,10 +288,15 @@ gateways: - attachedRoutes: 1 conditions: - lastTransitionTime: null - message: Listener must have TLS set when protocol is HTTPS. - reason: Invalid - status: "False" + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -729,6 +738,9 @@ xdsIR: name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/* - address: 0.0.0.0 externalPort: 443 + grpc: + enableGRPCStats: true + enableGRPCWeb: true hostnames: - '*' metadata: @@ -741,6 +753,44 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10443 + routes: + - destination: + metadata: + kind: GRPCRoute + name: grpcroute-1 + namespace: envoy-gateway + name: grpcroute/envoy-gateway/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: envoy-gateway + sectionName: "8080" + name: grpcroute/envoy-gateway/grpcroute-1/rule/0/backend/0 + protocol: GRPC + weight: 1 + envoyExtensions: {} + headerMatches: + - distinct: false + exact: foo + name: magic + hostname: '*' + isHTTP2: true + metadata: + kind: GRPCRoute + name: grpcroute-1 + namespace: envoy-gateway + name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/* + tls: + alpnProtocols: null + certificates: + - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A4QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + name: envoy-gateway/tls-secret-1 + privateKey: '[redacted]' readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml index c2ac20067f..f11b451baf 100644 --- a/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-attached-routes.out.yaml @@ -326,13 +326,6 @@ infraIR: namespace: envoy-gateway-system envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route: proxy: - listeners: - - name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: unresolved-gateway-with-one-attached-unresolved-route @@ -487,21 +480,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: unresolved-gateway-with-one-attached-unresolved-route - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/unresolved-gateway-with-one-attached-unresolved-route/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml new file mode 100644 index 0000000000..1b0dfa84fc --- /dev/null +++ b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.in.yaml @@ -0,0 +1,64 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + # This listener has an invalid certificate reference (secret does not exist) + # It should have ResolvedRefs=False with InvalidCertificateRef + # and should be skipped during conflict resolution + - name: invalid-https + protocol: HTTPS + port: 443 + hostname: "*.example.com" + allowedRoutes: + namespaces: + from: All + tls: + mode: Terminate + certificateRefs: + - name: non-existent-secret + # This listener has valid configuration and should be accepted + # even though it's on the same port/hostname as the invalid listener + - name: valid-https + protocol: HTTPS + port: 443 + hostname: "*.example.com" + allowedRoutes: + namespaces: + from: All + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 +secrets: + - apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR3RENDQXFpZ0F3SUJBZ0lVVDRyelIreStHd1VzMm9ydExIZ0k1MzBKeG9Fd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkpibU11TVJRd0VnWURWUVFEREF0bGVHRnRjR3hsTG1OdgpiVEFlRncweU5UQTBNakl3TWpVNU1UQmFGdzB6TlRBME1qQXdNalU1TVRCYU1EVXhGREFTQmdOVkJBTU1DMlp2CmJ5NWlZWEl1WTI5dE1SMHdHd1lEVlFRS0RCUmxlR0Z0Y0d4bElHOXlaMkZ1YVhwaGRHbHZiakNDQVNJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTE4wbnJNR1NZNjBPT0JuTFVaSGpCRFkxazhqWHA2RwppeG1RaFNOK3lZUi9VQWVqSmhCOVI3S2RuT3d0eGljTnozdUFtL0p0UTFKRUU0dW5xQnhVTU8ydWpvVXl4ZisrCjRnb2tFYmVpTlhNN0ptaklPOGxEWlJjcEhFTlE3eUNJL3d1cEZBcHgwNnVrNUtBSlpRMUlmVXhZWS9RRkJsc3cKdUx0TWozVlB6eDBJYjRIV1lHdGhXcDIzUWduMUdGUWVTOGMwZHdqWWNBTGtrTFdwWWdUZTZGT0VhR3hvUzdwTQpGbitvZnRFUjlxZCtDcnRDSXM5TzFtOW5MUU9UWGJDNU5nSzR1ZFdhMFBuYjJ6TEk4WjZsVHFRSTNSODE2NkxKCkVDQi9ZSlYzVmtMb2cxUmx0d0FrM3hrWHFnbVhTZUxILzY3MHh6MEx5OGZHQVpmejFMQVpkSXNDQXdFQUFhT0IKenpDQnpEQWRCZ05WSFE0RUZnUVUzbVFodVB2dVl1K0lmN0ZaM010eU9jMWdjQ1V3YUFZRFZSMGpCR0V3WDRBVQpXWmxKWFQ1bXlEVnlsUjlSS2JQQTAxTkVlcytoTWFRdk1DMHhGVEFUQmdOVkJBb01ER1Y0WVcxd2JHVWdTVzVqCkxqRVVNQklHQTFVRUF3d0xaWGhoYlhCc1pTNWpiMjJDRkJuNktuTlBhbm1Db1daVStNYmtwKzJScmN4dU1Bc0cKQTFVZER3UUVBd0lDL0RBcEJnTlZIUkVFSWpBZ2dnOW1iMjh1WlhoaGJYQnNaUzVqYjIyQ0RTb3VaWGhoYlhCcwpaUzVqYjIwd0NRWURWUjBTQkFJd0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFIa2xEbzkvNnRLcDNFd3JSCnJjVStKOUtmUkFGajc5YU1DREpVb0NyM2J6RFIycXQ4ZzlsbDdFSzZaeEtFa0xzWkFlYzBxU0Z1QjBvbzVqZFEKM3VvT2hNK1JKTkZoTldFd3dHWmpMb0FlK2oxaXByN1A5ajdmdFNzck8ra3M3TVNMeTE2RW9IV2Q0eG00Rk5QZQpmUVpRYWhpTTdMYVFCdW5wdXlhZWtLdG5tU241RzlkSHpGeTVNelRSbFJyVWxhVzdVbDRUeExlOEROZ2ZpR2ZCCnpjcmpVK2l3RUJXeS94b3B2aDEzNmlybmV3NTg3RWt3dzQ3QXFhc3gvZStMK2NhSlYySGVMd0dSaE5xR2pIcjkKQ2dSVHpud3F5QjdtTVNXYStWaXBNSHlUVmRCNjRvYjZxbkdqTldvWXdRbUUraU0vL0VrTURzd2JVcTc2R1pKMApsWlRkTlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ3pkSjZ6QmttT3REamcKWnkxR1I0d1EyTlpQSTE2ZWhvc1prSVVqZnNtRWYxQUhveVlRZlVleW5aenNMY1luRGM5N2dKdnliVU5TUkJPTApwNmdjVkREdHJvNkZNc1gvdnVJS0pCRzNvalZ6T3lab3lEdkpRMlVYS1J4RFVPOGdpUDhMcVJRS2NkT3JwT1NnCkNXVU5TSDFNV0dQMEJRWmJNTGk3VEk5MVQ4OGRDRytCMW1CcllWcWR0MElKOVJoVUhrdkhOSGNJMkhBQzVKQzEKcVdJRTN1aFRoR2hzYUV1NlRCWi9xSDdSRWZhbmZncTdRaUxQVHRadlp5MERrMTJ3dVRZQ3VMblZtdEQ1MjlzeQp5UEdlcFU2a0NOMGZOZXVpeVJBZ2YyQ1ZkMVpDNklOVVpiY0FKTjhaRjZvSmwwbml4Lyt1OU1jOUM4dkh4Z0dYCjg5U3dHWFNMQWdNQkFBRUNnZ0VBSmYrYW53UEV6WS9CdjFwNWpya1ZvbmVYb1hnMno5QmpZYzFsTTZma0djY3YKZGY2SXo5TUhQSDM5UFZGUDlQTUtyUGNGam1hdWE1djRtNGlyb3h2OHBFZGk3RGRkRDVNbW44a1ZhMUhRaVk3TAp5a0lqenJFVGxiemh2Q3RHQnhpYkVLZ0RrMWFZNEc1dzdxWXVuSXB0NVoyTnhKelB4TDFqVUYyY3Z0VmdZS0FPCjN2TWY1dENWbS9kL2JBT2xvWnVVc3ArSnc1ZTYvSFN3c3lEdjV2Y2dDQkRXRjFkTFFiYUxCelZDZGJBY0Fma1AKbFUzeGhZMVYyMGU2NmhBbU0veE53MzArSUhvTUlTUTFiQW9MOXVzN3NsTlYxT2ZNZk5hWC83WVdKWFVab1MzNwpyY1IvVXYwZlRtQkhPR3pwK25oaWpLRUlYU1ZESjNxK040amM4Ni9IeVFLQmdRRFhWbzNKSmlia0cvY1JBZ2pICkVqdWROMHJMSGJvVldPanN5ekZmaXg1MHJKTTYwMDJKZURicGdQeEt4ZUtFdGl4ZkVWQmU0eHdqNG9oK1ZubEIKT0dMU3BWcHRRVFRnRVprWXFvVU1iUDIyNHQ2cUZuSXZsTkkwZFJGWDUyS3I2L1FCS0EwWEk3K0I1bTV3Z2hLcgo4ZEQrMGRWNkZzMmxFT0NMWUJKck1weFNIUUtCZ1FEVlY0REVaUlFvVUo5UGRkb3IyK2IweFV2Y3JHeUJ1NlM2CjJZOFJuMzdWUVlBSThHUnlYRkcxTGxZaHpMOWNwd0tUR21SMVhPRTVkMC9mMStaU3h5TVc1d2FSaXU1b0dFK2cKUlNsMXBBdTNUdlEzM1BVNUJzNFhhcHBLOC9BZVk3cG1pd1JhYnRPSFlQa0FHMXNzL3k1d1NjVGUxQXZiWlpsTAo1TmgwdHZvZ3h3S0JnUUNtRkFJOFhlbG15czZ0Vm1WUXE1WkF0YkZBb0VleFNTWXo0cTdNb200MXpCZXRLZVRHCkhtb3pneUNSeHJiaVplSW8zQ0NoWGdXSkE2RUQxMHVqYW9xRkxiUmxTUUl2d2tMU1RFbGJBUUJZdWZiRE5aYVIKYmZVRk1qalRGQWo4MFhrYUh6cWhXeGZMWnQ1TWRYVlRHYWgzcjN3MnNqbWVranFzSThkdzE5TEtYUUtCZ0NoMQp3T0QrUG5WcTNOdklBUWxpV2dtL3hTUmp1dXhidHVFTTA1cEhBbG5WWXovT3YyNEUzaVliVkpCeWNUUlVKQ1BiCjFJT0JpdUZJSkdqU1hFY0VwejMzc0lJM3RBRWY0eklGQzlqWXRMUWVFQ2pzQ2NHMzdhdjVOcXZTV1k2WjRVY0QKUkY4V041MnNJVzBJd3lEa2dGMGhVR25tRXgyWHhodmptYjJBMmkwUEFvR0FUV1kzbXZRVWtZcmU5R0J0alVqYgpDWUx5Mm1VVElKbjVDcmhjTHMvMlh5MkNoVSt5MnhsT3pIcm1vanRIaHFFcnVCK0xyZkpBd3B3cGVRNmxyWnFQCjFGazVKT2c2bmV2U3lDcWF4SDZaenZRMXJ6VzAycm1IMUJrV1BiY0NwKy9VRTIrS3JselZtNHkvZ0ZoRGVGZlcKRUc5UzIzYndKME1JUmF0WVpFQm0wcWs9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: valid-https + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 diff --git a/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml new file mode 100644 index 0000000000..663bd2014f --- /dev/null +++ b/internal/gatewayapi/testdata/gateway-with-conflicting-listeners-one-invalid-ref.out.yaml @@ -0,0 +1,213 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: '*.example.com' + name: invalid-https + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - name: non-existent-secret + mode: Terminate + - allowedRoutes: + namespaces: + from: All + hostname: '*.example.com' + name: valid-https + port: 443 + protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: 'No valid secrets exist: certificate refs 0: Secret envoy-gateway/non-existent-secret + does not exist.' + reason: InvalidCertificateRef + status: "False" + type: ResolvedRefs + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: Invalid + status: "False" + type: Programmed + name: invalid-https + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: valid-https + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - name: envoy-gateway/gateway-1/valid-https + ports: + - containerPort: 10443 + name: https-443 + protocol: HTTPS + servicePort: 443 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-1 + namespace: envoy-gateway-system +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-1-196ae069 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-1 + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 443 + hostnames: + - '*.example.com' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: valid-https + name: envoy-gateway/gateway-1/valid-https + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10443 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: '*.example.com' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/*_example_com + pathMatch: + distinct: false + name: "" + prefix: / + tls: + alpnProtocols: null + certificates: + - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR3RENDQXFpZ0F3SUJBZ0lVVDRyelIreStHd1VzMm9ydExIZ0k1MzBKeG9Fd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xURVZNQk1HQTFVRUNnd01aWGhoYlhCc1pTQkpibU11TVJRd0VnWURWUVFEREF0bGVHRnRjR3hsTG1OdgpiVEFlRncweU5UQTBNakl3TWpVNU1UQmFGdzB6TlRBME1qQXdNalU1TVRCYU1EVXhGREFTQmdOVkJBTU1DMlp2CmJ5NWlZWEl1WTI5dE1SMHdHd1lEVlFRS0RCUmxlR0Z0Y0d4bElHOXlaMkZ1YVhwaGRHbHZiakNDQVNJd0RRWUoKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTE4wbnJNR1NZNjBPT0JuTFVaSGpCRFkxazhqWHA2RwppeG1RaFNOK3lZUi9VQWVqSmhCOVI3S2RuT3d0eGljTnozdUFtL0p0UTFKRUU0dW5xQnhVTU8ydWpvVXl4ZisrCjRnb2tFYmVpTlhNN0ptaklPOGxEWlJjcEhFTlE3eUNJL3d1cEZBcHgwNnVrNUtBSlpRMUlmVXhZWS9RRkJsc3cKdUx0TWozVlB6eDBJYjRIV1lHdGhXcDIzUWduMUdGUWVTOGMwZHdqWWNBTGtrTFdwWWdUZTZGT0VhR3hvUzdwTQpGbitvZnRFUjlxZCtDcnRDSXM5TzFtOW5MUU9UWGJDNU5nSzR1ZFdhMFBuYjJ6TEk4WjZsVHFRSTNSODE2NkxKCkVDQi9ZSlYzVmtMb2cxUmx0d0FrM3hrWHFnbVhTZUxILzY3MHh6MEx5OGZHQVpmejFMQVpkSXNDQXdFQUFhT0IKenpDQnpEQWRCZ05WSFE0RUZnUVUzbVFodVB2dVl1K0lmN0ZaM010eU9jMWdjQ1V3YUFZRFZSMGpCR0V3WDRBVQpXWmxKWFQ1bXlEVnlsUjlSS2JQQTAxTkVlcytoTWFRdk1DMHhGVEFUQmdOVkJBb01ER1Y0WVcxd2JHVWdTVzVqCkxqRVVNQklHQTFVRUF3d0xaWGhoYlhCc1pTNWpiMjJDRkJuNktuTlBhbm1Db1daVStNYmtwKzJScmN4dU1Bc0cKQTFVZER3UUVBd0lDL0RBcEJnTlZIUkVFSWpBZ2dnOW1iMjh1WlhoaGJYQnNaUzVqYjIyQ0RTb3VaWGhoYlhCcwpaUzVqYjIwd0NRWURWUjBTQkFJd0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFIa2xEbzkvNnRLcDNFd3JSCnJjVStKOUtmUkFGajc5YU1DREpVb0NyM2J6RFIycXQ4ZzlsbDdFSzZaeEtFa0xzWkFlYzBxU0Z1QjBvbzVqZFEKM3VvT2hNK1JKTkZoTldFd3dHWmpMb0FlK2oxaXByN1A5ajdmdFNzck8ra3M3TVNMeTE2RW9IV2Q0eG00Rk5QZQpmUVpRYWhpTTdMYVFCdW5wdXlhZWtLdG5tU241RzlkSHpGeTVNelRSbFJyVWxhVzdVbDRUeExlOEROZ2ZpR2ZCCnpjcmpVK2l3RUJXeS94b3B2aDEzNmlybmV3NTg3RWt3dzQ3QXFhc3gvZStMK2NhSlYySGVMd0dSaE5xR2pIcjkKQ2dSVHpud3F5QjdtTVNXYStWaXBNSHlUVmRCNjRvYjZxbkdqTldvWXdRbUUraU0vL0VrTURzd2JVcTc2R1pKMApsWlRkTlE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + name: envoy-gateway/tls-secret-1 + privateKey: '[redacted]' + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml index 898c56910c..fb1bca1c0e 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-namespaces-selector.out.yaml @@ -78,13 +78,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -120,21 +113,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml index c1be28da35..d6eddedd1d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-group.out.yaml @@ -69,13 +69,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -111,21 +104,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml index 875e056fd0..ad9f652f5d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind-and-supported.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -113,21 +106,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml index c9e11f45f4..891bdd8a8b 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-routes-kind.out.yaml @@ -69,13 +69,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -111,21 +104,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml index 0127e45fe8..8a474483bb 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-allowed-tls-route-kind.out.yaml @@ -38,13 +38,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10080 - name: tls-80 - protocol: TLS - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -116,13 +109,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml index 4e0b318363..82b7f2918d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-multiple-tls-configuration.out.yaml @@ -158,12 +158,6 @@ infraIR: name: https-8443 protocol: HTTPS servicePort: 8443 - - name: envoy-gateway/gateway-1/tls-all-invalid-cert - ports: - - containerPort: 8444 - name: https-8444 - protocol: HTTPS - servicePort: 8444 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -302,20 +296,6 @@ xdsIR: - certificate: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ2VENDQVVTZ0F3SUJBZ0lVU2l2SkdURHdva1M3aGVZLzJjc1JzejR2SkIwd0NnWUlLb1pJemowRUF3SXcKRmpFVU1CSUdBMVVFQXd3TFptOXZMbUpoY2k1amIyMHdIaGNOTWpRd01qSTVNRGt6TURFd1doY05NelF3TWpJMgpNRGt6TURFd1dqQVdNUlF3RWdZRFZRUUREQXRtYjI4dVltRnlMbU52YlRCMk1CQUdCeXFHU000OUFnRUdCU3VCCkJBQWlBMklBQkZ2cnZSZWJhYVd1UzZNQUVJZDZ3WmZPS3Z1Q1R5VU1PbFpKcUZDRjlUa3pNWWw4Q2lvZnluT3QKQ3JzMHZ2YTlrZC9QMkpNR0JKcWdZZXZid290clJpMTJxTG5IMDQvam9HSWpqVE9LbzNJb2ZyK0ZrOHdMdkFlMwpPMVpLdFI5c3pxTlRNRkV3SFFZRFZSME9CQllFRklLczFRRm5vRHQ5K3Fva1I0T0RXYk16MWYrUE1COEdBMVVkCkl3UVlNQmFBRklLczFRRm5vRHQ5K3Fva1I0T0RXYk16MWYrUE1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0NnWUkKS29aSXpqMEVBd0lEWndBd1pBSXdIMzF0SHlmVVAwNFhIcGJXR2UxWjFJYUJaQndJdGg1NURVNGhqZlB1OG0rSgpXdjdiVzh6VFNnd0xpcW9yZmN1bkFqQTBnaE5KQkExWDJYdElLRG1sM3M3L1Z4OEZKY1MwNHZwQ2hoK2xBYkxTCnZlYWEyOFIzVExFWTNVK1FUWEkvd0lrPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== name: envoy-gateway/tls-secret-ecdsa-2 privateKey: '[redacted]' - - address: 0.0.0.0 - externalPort: 8444 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls-all-invalid-cert - name: envoy-gateway/gateway-1/tls-all-invalid-cert - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8444 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml index f5eb3615ea..d3b527cf81 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-invalid-mode.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml index f0b8e08392..08b2c9ae80 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-no-certificate-refs.out.yaml @@ -72,13 +72,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -114,21 +107,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml index 17179618ef..fdf22c3ae1 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-does-not-exist.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml index 94d6649edd..be22741fa9 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-in-other-namespace.out.yaml @@ -76,13 +76,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -118,21 +111,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml index acfc47f023..5ab341a973 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-invalid-tls-configuration-secret-is-not-valid.out.yaml @@ -75,13 +75,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,21 +110,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml index eb0643097a..ed93a40205 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-missing-allowed-namespaces-selector.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/http - ports: - - containerPort: 10080 - name: http-80 - protocol: HTTP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -113,21 +106,6 @@ xdsIR: sectionName: "8080" name: envoy-gateway/gateway-1 protocol: TCP - http: - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-1/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml index 1e3bf50365..eee30d760d 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-tcp-with-hostname.out.yaml @@ -35,13 +35,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tcp - ports: - - containerPort: 10080 - name: tcp-80 - protocol: TCP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -82,13 +75,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp - name: envoy-gateway/gateway-1/tcp - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml index f3d7139fc7..cdc8155dc4 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-udp-with-hostname.out.yaml @@ -35,13 +35,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/udp - ports: - - containerPort: 10080 - name: udp-80 - protocol: UDP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -82,13 +75,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - udp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: udp - name: envoy-gateway/gateway-1/udp - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml index 4672cbedfb..1765434059 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-unsupported-protocol.out.yaml @@ -71,13 +71,6 @@ httpRoutes: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/unsupported - ports: - - containerPort: 10080 - name: "-80" - protocol: "" - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml index 228b0bf29f..f255acbcf4 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-tcp-or-tls-port.out.yaml @@ -70,12 +70,6 @@ infraIR: name: tcp-162 protocol: TCP servicePort: 162 - - name: envoy-gateway/gateway-1/tcp2 - ports: - - containerPort: 10162 - name: tls-162 - protocol: TLS - servicePort: 162 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -182,12 +176,3 @@ xdsIR: name: tcproute-1 namespace: default name: tcproute/default/tcproute-1 - - address: 0.0.0.0 - externalPort: 162 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp2 - name: envoy-gateway/gateway-1/tcp2 - port: 10162 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml index cac7a60a43..f858c8d772 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-on-same-udp-port.out.yaml @@ -175,12 +175,3 @@ xdsIR: protocol: UDP weight: 1 name: udproute/default/udproute-1 - - address: 0.0.0.0 - externalPort: 162 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: udp2 - name: envoy-gateway/gateway-1/udp2 - port: 10162 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml index 823f9813a5..c8d0bc9210 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-http-and-tlsroute-same-hostname-and-port.out.yaml @@ -28,15 +28,15 @@ gateways: - attachedRoutes: 1 conditions: - lastTransitionTime: null - message: All listeners for a given port must use a unique hostname - reason: HostnameConflict + message: Sending translated listener configuration to the data plane + reason: Programmed status: "True" - type: Conflicted - - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid - status: "False" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -56,8 +56,13 @@ gateways: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict status: "False" type: Programmed - lastTransitionTime: null @@ -90,9 +95,9 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: There are no ready listeners for this parent ref - reason: NoReadyListeners - status: "False" + message: Route is accepted + reason: Accepted + status: "True" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -194,18 +199,39 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: foo.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/foo_com + pathMatch: + distinct: false + name: "" + prefix: / readyListener: address: 0.0.0.0 ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls-1 - name: envoy-gateway/gateway-1/tls-1 - port: 10080 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml index 0df14ad10c..653b286872 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-hostname.out.yaml @@ -26,15 +26,15 @@ gateways: - attachedRoutes: 1 conditions: - lastTransitionTime: null - message: All listeners for a given port must use a unique hostname - reason: HostnameConflict + message: Sending translated listener configuration to the data plane + reason: Programmed status: "True" - type: Conflicted - - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid - status: "False" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -54,8 +54,13 @@ gateways: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict status: "False" type: Programmed - lastTransitionTime: null @@ -90,9 +95,9 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: There are no ready listeners for this parent ref - reason: NoReadyListeners - status: "False" + message: Route is accepted + reason: Accepted + status: "True" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -163,20 +168,37 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - foo.com - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: http-2 - name: envoy-gateway/gateway-1/http-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: foo.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/foo_com + pathMatch: + distinct: false + name: "" + prefix: / readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml index 37c0a342f3..103498cfa7 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.in.yaml @@ -21,6 +21,40 @@ gateways: allowedRoutes: namespaces: from: All + tls: + mode: Terminate + certificateRefs: + - name: tls-secret-1 + - allowedRoutes: + namespaces: + from: All + name: udp-8162 + port: 8162 + protocol: UDP + # This listener(http-8162) is valid because HTTP + UDP are compatible protocols. + - allowedRoutes: + namespaces: + from: All + name: http-8162 + port: 8162 + protocol: HTTP + # This listener(tcp-8162) is invalid because TCP is not compatible with HTTP. + - allowedRoutes: + namespaces: + from: All + name: tcp-8162 + port: 8162 + protocol: TCP +secrets: + - apiVersion: v1 + kind: Secret + metadata: + namespace: envoy-gateway + name: tls-secret-1 + type: kubernetes.io/tls + data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lVRUZNaFA5ZUo5WEFCV3NRNVptNmJSazJjTE5Rd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0ZqRVVNQklHQTFVRUF3d0xabTl2TG1KaGNpNWpiMjB3SGhjTk1qUXdNakk1TURrek1ERXdXaGNOTXpRdwpNakkyTURrek1ERXdXakFXTVJRd0VnWURWUVFEREF0bWIyOHVZbUZ5TG1OdmJUQ0NBU0l3RFFZSktvWklodmNOCkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFKbEk2WXhFOVprQ1BzNnBDUXhickNtZWl4OVA1RGZ4OVJ1NUxENFQKSm1kVzdJS2R0UVYvd2ZMbXRzdTc2QithVGRDaldlMEJUZmVPT1JCYlIzY1BBRzZFbFFMaWNsUVVydW4zcStncwpKcEsrSTdjSStqNXc4STY4WEg1V1E3clZVdGJ3SHBxYncrY1ZuQnFJVU9MaUlhdGpJZjdLWDUxTTF1RjljZkVICkU0RG5jSDZyYnI1OS9SRlpCc2toeHM1T3p3Sklmb2hreXZGd2V1VHd4Sy9WcGpJKzdPYzQ4QUJDWHBOTzlEL3EKRWgrck9hdWpBTWNYZ0hRSVRrQ2lpVVRjVW82TFNIOXZMWlB0YXFmem9acTZuaE1xcFc2NUUxcEF3RjNqeVRUeAphNUk4SmNmU0Zqa2llWjIwTFVRTW43TThVNHhIamFvL2d2SDBDQWZkQjdSTFUyc0NBd0VBQWFOVE1GRXdIUVlEClZSME9CQllFRk9SQ0U4dS8xRERXN2loWnA3Y3g5dFNtUG02T01COEdBMVVkSXdRWU1CYUFGT1JDRTh1LzFERFcKN2loWnA3Y3g5dFNtUG02T01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRnQ1M3pqc3FUYUg1YThFMmNodm1XQWdDcnhSSzhiVkxNeGl3TkdqYm1FUFJ6K3c2TngrazBBOEtFY0lEc0tjClNYY2k1OHU0b1didFZKQmx6YS9adWpIUjZQMUJuT3BsK2FveTc4NGJiZDRQMzl3VExvWGZNZmJCQ20xdmV2aDkKQUpLbncyWnRxcjRta2JMY3hFcWxxM3NCTEZBUzlzUUxuS05DZTJjR0xkVHAyYm9HK3FjZ3lRZ0NJTTZmOEVNdgpXUGlmQ01NR3V6Sy9HUkY0YlBPL1lGNDhld0R1M1VlaWgwWFhkVUFPRTlDdFVhOE5JaGMxVVBhT3pQcnRZVnFyClpPR2t2L0t1K0I3OGg4U0VzTzlYclFjdXdiT25KeDZLdFIrYWV5a3ZBcFhDUTNmWkMvYllLQUFSK1A0QUpvUVoKYndJVW1YaTRnajVtK2JLUGhlK2lyK0U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0= + tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2QwZlBDYWtweE1nUnUKT0VXQjFiQk5FM3ZseW55aTZWbkV2VWF1OUhvakR2UHVPTFJIaGI4MmoyY1ovMHhnL1lKR09LelBuV2JERkxGNApHdWh3dDRENmFUR0xYNklPODEwTDZ0SXZIWGZNUXRJS2VwdTZ3K3p1WVo4bG1yejB1RjZlWEtqamVIbHhyb2ZrCnVNekM3OUVaU0lYZlZlczJ1SmdVRSs4VGFzSDUzQ2Y4MFNSRGlIeEdxckttdVNjWCtwejBreGdCZ1VWYTVVS20KUWdTZDFmVUxLOUEwNXAxOXkrdURPM204bVhRNkxVQ0N1STFwZHNROGFlNS9zamlxa0VjWlJjMTdWYVgxWjVVaQpvcGZnNW9SY05VTG9VTHNiek9aNTR0YlVDUmdSV2VLbGZxaElINEZ6OUlkVlUyR3dFdEdhMmV6TjgyMVBaQ3QzCjZhbVRIelJsQWdNQkFBRUNnZ0VBWTFGTUlLNDVXTkVNUHJ6RTZUY3NNdVV2RkdhQVZ4bVk5NW5SMEtwajdvb3IKY21CVys2ZXN0TTQ4S1AwaitPbXd3VFpMY29Cd3VoWGN0V1Bob1lXcDhteWUxRUlEdjNyaHRHMDdocEQ1NGg2dgpCZzh3ejdFYStzMk9sT0N6UnlKNzBSY281YlhjWDNGaGJjdnFlRWJwaFFyQnpOSEtLMjZ4cmZqNWZIT3p6T1FGCmJHdUZ3SDVic3JGdFhlajJXM3c4eW90N0ZQSDV3S3RpdnhvSWU5RjMyOXNnOU9EQnZqWnpiaG1LVTArckFTK1kKRGVield2bFJyaEUrbXVmQTN6M0N0QXhDOFJpNzNscFNoTDRQQWlvcG1SUXlxZXRXMjYzOFFxcnM0R3hnNzhwbApJUXJXTmNBc2s3Slg5d3RZenV6UFBXSXRWTTFscFJiQVRhNTJqdFl2NVFLQmdRRE5tMTFtZTRYam1ZSFV2cStZCmFTUzdwK2UybXZEMHVaOU9JeFluQnBWMGkrckNlYnFFMkE1Rm5hcDQ5Yld4QTgwUElldlVkeUpCL2pUUkoxcVMKRUpXQkpMWm1LVkg2K1QwdWw1ZUtOcWxFTFZHU0dCSXNpeE9SUXpDZHBoMkx0UmtBMHVjSVUzY3hiUmVMZkZCRQpiSkdZWENCdlNGcWd0VDlvZTFldVpMVmFOd0tCZ1FERWdENzJENk81eGIweEQ1NDQ1M0RPMUJhZmd6aThCWDRTCk1SaVd2LzFUQ0w5N05sRWtoeXovNmtQd1owbXJRcE5CMzZFdkpKZFVteHdkU2MyWDhrOGcxMC85NVlLQkdWQWoKL3d0YVZYbE9WeEFvK0ZSelpZeFpyQ29uWWFSMHVwUzFybDRtenN4REhlZU9mUVZUTUgwUjdZN0pnbTA5dXQ4SwplanAvSXZBb1F3S0JnQjNaRWlRUWhvMVYrWjBTMlpiOG5KS0plMy9zMmxJTXFHM0ZkaS9RS3Q0eWViQWx6OGY5ClBZVXBzRmZEQTg5Z3grSU1nSm5sZVptdTk2ZnRXSjZmdmJSenllN216TG5zZU05TXZua1lHbGFGWmJRWnZubXMKN3ZoRmtzY3dHRlh4d21GMlBJZmU1Z3pNMDRBeVdjeTFIaVhLS2dNOXM3cGsxWUdyZGowZzdacmRBb0dCQUtLNApDR3MrbkRmMEZTMFJYOWFEWVJrRTdBNy9YUFhtSG5YMkRnU1h5N0Q4NTRPaWdTTWNoUmtPNTErbVNJejNQbllvCk41T1FXM2lHVVl1M1YvYmhnc0VSUzM1V2xmRk9BdDBzRUR5bjF5SVdXcDF5dG93d3BUNkVvUXVuZ2NYZjA5RjMKS1NROXowd3M4VmsvRWkvSFVXcU5LOWFXbU51cmFaT0ZqL2REK1ZkOUFvR0FMWFN3dEE3K043RDRkN0VEMURSRQpHTWdZNVd3OHFvdDZSdUNlNkpUY0FnU3B1MkhNU3JVY2dXclpiQnJZb09FUnVNQjFoMVJydk5ybU1qQlM0VW9FClgyZC8vbGhpOG1wL2VESWN3UDNRa2puanBJRFJWMFN1eWxrUkVaZURKZjVZb3R6eDdFdkJhbzFIbkQrWEg4eUIKVUtmWGJTaHZKVUdhRmgxT3Q1Y3JoM1k9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K httpRoutes: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml index 3eab4a3a04..73505b3971 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-and-incompatible-protocol.out.yaml @@ -21,20 +21,42 @@ gateways: name: http-2 port: 80 protocol: HTTPS + tls: + certificateRefs: + - name: tls-secret-1 + mode: Terminate + - allowedRoutes: + namespaces: + from: All + name: udp-8162 + port: 8162 + protocol: UDP + - allowedRoutes: + namespaces: + from: All + name: http-8162 + port: 8162 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + name: tcp-8162 + port: 8162 + protocol: TCP status: listeners: - attachedRoutes: 1 conditions: - lastTransitionTime: null - message: All listeners for a given port must use a compatible protocol - reason: ProtocolConflict + message: Sending translated listener configuration to the data plane + reason: Programmed status: "True" - type: Conflicted - - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid - status: "False" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -54,8 +76,13 @@ gateways: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener must have TLS set when protocol is HTTPS. - reason: Invalid + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict status: "False" type: Programmed - lastTransitionTime: null @@ -69,6 +96,76 @@ gateways: kind: HTTPRoute - group: gateway.networking.k8s.io kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: udp-8162 + supportedKinds: + - group: gateway.networking.k8s.io + kind: UDPRoute + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http-8162 + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: tcp-8162 + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute httpRoutes: - apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -90,9 +187,9 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: There are no ready listeners for this parent ref - reason: NoReadyListeners - status: "False" + message: Route is accepted + reason: Accepted + status: "True" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -113,6 +210,18 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 + - name: envoy-gateway/gateway-1/udp-8162 + ports: + - containerPort: 8162 + name: udp-8162 + protocol: UDP + servicePort: 8162 + - name: envoy-gateway/gateway-1/http-8162 + ports: + - containerPort: 8162 + name: http-8162 + protocol: HTTP + servicePort: 8162 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -163,22 +272,94 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: foo.com + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/foo_com + pathMatch: + distinct: false + name: "" + prefix: / - address: 0.0.0.0 - externalPort: 80 + externalPort: 8162 hostnames: - - bar.com + - '*' metadata: kind: Gateway name: gateway-1 namespace: envoy-gateway - sectionName: http-2 - name: envoy-gateway/gateway-1/http-2 + sectionName: http-8162 + name: envoy-gateway/gateway-1/http-8162 path: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true - port: 10080 + port: 8162 + routes: + - destination: + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + metadata: + kind: Service + name: service-1 + namespace: default + sectionName: "8080" + name: httproute/default/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + hostname: '*' + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/0/* + pathMatch: + distinct: false + name: "" + prefix: / readyListener: address: 0.0.0.0 ipFamily: IPv4 path: /ready port: 19003 + udp: + - address: 0.0.0.0 + externalPort: 8162 + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: udp-8162 + name: envoy-gateway/gateway-1/udp-8162 + port: 8162 diff --git a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml index 476881b619..d660062076 100644 --- a/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-two-listeners-with-same-port-http-tcp-protocol.out.yaml @@ -45,18 +45,23 @@ gateways: kind: HTTPRoute - group: gateway.networking.k8s.io kind: GRPCRoute - - attachedRoutes: 1 + - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: Sending translated listener configuration to the data plane - reason: Programmed + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict status: "True" - type: Programmed + type: Conflicted - lastTransitionTime: null - message: Listener has been successfully translated - reason: Accepted - status: "True" + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Programmed - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -110,12 +115,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-1/tcp - ports: - - containerPort: 10080 - name: tcp-80 - protocol: TCP - servicePort: 80 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -143,9 +142,9 @@ tcpRoutes: parents: - conditions: - lastTransitionTime: null - message: Route is accepted - reason: Accepted - status: "True" + message: There are no ready listeners for this parent ref + reason: NoReadyListeners + status: "False" type: Accepted - lastTransitionTime: null message: Resolved all the Object references for the Route @@ -233,38 +232,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 80 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tcp - name: envoy-gateway/gateway-1/tcp - port: 10080 - routes: - - destination: - metadata: - kind: TCPRoute - name: tcproute-1 - namespace: default - name: tcproute/default/tcproute-1/rule/-1 - settings: - - addressType: IP - endpoints: - - host: 7.7.7.7 - port: 8163 - metadata: - kind: Service - name: service-1 - namespace: default - sectionName: "8163" - name: tcproute/default/tcproute-1/rule/-1/backend/0 - protocol: TCP - weight: 1 - metadata: - kind: TCPRoute - name: tcproute-1 - namespace: default - name: tcproute/default/tcproute-1 diff --git a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml index 736ddb24a9..57d094fad0 100644 --- a/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-conflict-listeners.out.yaml @@ -54,15 +54,15 @@ gateways: - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: All listeners for a given port must use a unique hostname - reason: HostnameConflict + message: Sending translated listener configuration to the data plane + reason: Programmed status: "True" - type: Conflicted - - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: Invalid - status: "False" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs @@ -142,33 +142,38 @@ listenerSets: status: conditions: - lastTransitionTime: null - message: All listeners are invalid + message: Some listeners are invalid reason: ListenersNotValid - status: "False" + status: "True" type: Accepted - lastTransitionTime: null - message: All listeners are invalid - reason: ListenersNotValid - status: "False" + message: Some listeners are invalid + reason: Programmed + status: "True" type: Programmed listeners: - attachedRoutes: 0 conditions: - lastTransitionTime: null - message: All listeners for a given port must use a unique hostname - reason: HostnameConflict + message: Sending translated listener configuration to the data plane + reason: Programmed status: "True" - type: Conflicted - - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: ListenersNotValid - status: "False" type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted - lastTransitionTime: null message: Listener references have been resolved reason: ResolvedRefs status: "True" type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted name: conflict-listener-1 supportedKinds: - group: gateway.networking.k8s.io @@ -183,8 +188,13 @@ listenerSets: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: ListenersNotValid + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict status: "False" type: Programmed - lastTransitionTime: null @@ -240,8 +250,13 @@ listenerSets: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: ListenersNotValid + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict status: "False" type: Programmed - lastTransitionTime: null @@ -325,8 +340,13 @@ listenerSets: status: "True" type: Conflicted - lastTransitionTime: null - message: Listener is invalid, see other Conditions for details. - reason: ListenersNotValid + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict status: "False" type: Programmed - lastTransitionTime: null @@ -437,34 +457,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 8089 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener-2 - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-same-xls/conflict-listener-2 - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - - address: 0.0.0.0 - externalPort: 8089 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/gateway-xls/conflict-listener-from-two-xlss/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8089 - address: 0.0.0.0 externalPort: 8090 hostnames: @@ -479,20 +471,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 8090 - - address: 0.0.0.0 - externalPort: 8888 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway-xls - sectionName: conflict-listener - name: gateway-xls/composite-gateway/gateway-xls/listener-conflict-with-gateway/conflict-listener - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8888 - address: 0.0.0.0 externalPort: 8091 hostnames: diff --git a/internal/gatewayapi/testdata/listenerset-hostname-conflict.in.yaml b/internal/gatewayapi/testdata/listenerset-hostname-conflict.in.yaml new file mode 100644 index 0000000000..17ec739ae1 --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-hostname-conflict.in.yaml @@ -0,0 +1,134 @@ +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + allowedListeners: + namespaces: + from: Same + listeners: + - name: gateway-listener + port: 80 + protocol: HTTP + hostname: "gateway-listener.com" + allowedRoutes: + namespaces: + from: All + # The following listener should be accepted based on listener precedence + - name: hostname-conflict-with-gateway-listener + port: 80 + protocol: HTTP + hostname: "hostname-conflict-with-gateway-listener.com" + allowedRoutes: + namespaces: + from: All +listenerSets: + # The listener `hostname-conflict-with-gateway-listener` should be rejected but the listenerSet should be accepted since it has other valid listeners + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-gateway-1 + namespace: envoy-gateway + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + listeners: + - name: listener-set-1-listener + port: 80 + protocol: HTTP + hostname: "listener-set-1-listener.com" + allowedRoutes: + namespaces: + from: All + # The following listener should be rejected since it conflicts with the gateway listener + - name: hostname-conflict-with-gateway-listener + port: 80 + protocol: HTTP + hostname: "hostname-conflict-with-gateway-listener.com" + allowedRoutes: + namespaces: + from: All + # The following listener should be accepted based on listener precedence + - name: hostname-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + hostname: "hostname-conflict-with-listener-set-listener.com" + allowedRoutes: + namespaces: + from: All + # This listenerSet should not be accepted since its only listener `hostname-conflict-with-gateway-listener` is rejected + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-gateway-2 + namespace: envoy-gateway + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + listeners: + # The following listener should be rejected since it conflicts with the gateway listener + - name: hostname-conflict-with-gateway-listener + port: 80 + protocol: HTTP + hostname: "hostname-conflict-with-gateway-listener.com" + allowedRoutes: + namespaces: + from: All + # The listener `hostname-conflict-with-listener-set-listener` should be rejected but the listenerSet should be accepted since it has other valid listeners + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-listener-set-1 + namespace: envoy-gateway + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + listeners: + - name: listener-set-2-listener + port: 80 + protocol: HTTP + hostname: "listener-set-2-listener.com" + allowedRoutes: + namespaces: + from: All + # The following listener should be rejected since it conflicts with another listenerSet's listener + - name: hostname-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + hostname: "hostname-conflict-with-listener-set-listener.com" + allowedRoutes: + namespaces: + from: All + # This listenerSet should not be accepted since its only listener `hostname-conflict-with-listener-set-listener` is rejected + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-listener-set-2 + namespace: envoy-gateway + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + listeners: + # The following listener should be rejected since it conflicts with another listenerSet's listener + - name: hostname-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + hostname: "hostname-conflict-with-listener-set-listener.com" + allowedRoutes: + namespaces: + from: All diff --git a/internal/gatewayapi/testdata/listenerset-hostname-conflict.out.yaml b/internal/gatewayapi/testdata/listenerset-hostname-conflict.out.yaml new file mode 100644 index 0000000000..48bed5be81 --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-hostname-conflict.out.yaml @@ -0,0 +1,542 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + spec: + allowedListeners: + namespaces: + from: Same + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: gateway-listener.com + name: gateway-listener + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + hostname: hostname-conflict-with-gateway-listener.com + name: hostname-conflict-with-gateway-listener + port: 80 + protocol: HTTP + status: + attachedListenerSets: 2 + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: hostname-conflict-with-gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + envoy-gateway/gateway-with-listenerset-hostname-conflict: + proxy: + listeners: + - name: envoy-gateway/gateway-with-listenerset-hostname-conflict/gateway-listener + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-with-listenerset-hostname-conflict + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway/gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway-system +listenerSets: +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-gateway-1 + namespace: envoy-gateway + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: listener-set-1-listener.com + name: listener-set-1-listener + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + hostname: hostname-conflict-with-gateway-listener.com + name: hostname-conflict-with-gateway-listener + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + hostname: hostname-conflict-with-listener-set-listener.com + name: hostname-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + status: + conditions: + - lastTransitionTime: null + message: Some listeners are invalid + reason: ListenersNotValid + status: "True" + type: Accepted + - lastTransitionTime: null + message: Some listeners are invalid + reason: Programmed + status: "True" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: listener-set-1-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: hostname-conflict-with-gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: hostname-conflict-with-listener-set-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-gateway-2 + namespace: envoy-gateway + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: hostname-conflict-with-gateway-listener.com + name: hostname-conflict-with-gateway-listener + port: 80 + protocol: HTTP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + status: + conditions: + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: hostname-conflict-with-gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-listener-set-1 + namespace: envoy-gateway + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: listener-set-2-listener.com + name: listener-set-2-listener + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + hostname: hostname-conflict-with-listener-set-listener.com + name: hostname-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + status: + conditions: + - lastTransitionTime: null + message: Some listeners are invalid + reason: ListenersNotValid + status: "True" + type: Accepted + - lastTransitionTime: null + message: Some listeners are invalid + reason: Programmed + status: "True" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: listener-set-2-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: hostname-conflict-with-listener-set-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-hostname-conflict-with-listener-set-2 + namespace: envoy-gateway + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: hostname-conflict-with-listener-set-listener.com + name: hostname-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + status: + conditions: + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a unique hostname + reason: HostnameConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: hostname-conflict-with-listener-set-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +xdsIR: + envoy-gateway/gateway-with-listenerset-hostname-conflict: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-with-listenerset-hostname-facad556 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-with-listenerset-hostname-conflict + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-gateway-with-listenerset-hostname-facad556 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway/gateway-with-listenerset-hostname-conflict + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - gateway-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + sectionName: gateway-listener + name: envoy-gateway/gateway-with-listenerset-hostname-conflict/gateway-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - hostname-conflict-with-gateway-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + sectionName: hostname-conflict-with-gateway-listener + name: envoy-gateway/gateway-with-listenerset-hostname-conflict/hostname-conflict-with-gateway-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - listener-set-1-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + sectionName: listener-set-1-listener + name: envoy-gateway/gateway-with-listenerset-hostname-conflict/envoy-gateway/listenerset-with-hostname-conflict-with-gateway-1/listener-set-1-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - hostname-conflict-with-listener-set-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + sectionName: hostname-conflict-with-listener-set-listener + name: envoy-gateway/gateway-with-listenerset-hostname-conflict/envoy-gateway/listenerset-with-hostname-conflict-with-gateway-1/hostname-conflict-with-listener-set-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - listener-set-2-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-hostname-conflict + namespace: envoy-gateway + sectionName: listener-set-2-listener + name: envoy-gateway/gateway-with-listenerset-hostname-conflict/envoy-gateway/listenerset-with-hostname-conflict-with-listener-set-1/listener-set-2-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml index a302de7ee8..22b5ca8df2 100644 --- a/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-https-tls-misuses-gateway-namespace.out.yaml @@ -20,7 +20,6 @@ gateways: port: 80 protocol: HTTP status: - attachedListenerSets: 1 listeners: - attachedRoutes: 0 conditions: @@ -92,12 +91,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway/composite-gateway/xls/https-xls/extra-https-same-ns - ports: - - containerPort: 8443 - name: https-8443 - protocol: HTTPS - servicePort: 8443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: composite-gateway @@ -204,20 +197,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 8443 - hostnames: - - '*' - metadata: - kind: Gateway - name: composite-gateway - namespace: gateway - sectionName: extra-https-same-ns - name: gateway/composite-gateway/xls/https-xls/extra-https-same-ns - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 8443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml index d456feeb28..56eee1bf1e 100644 --- a/internal/gatewayapi/testdata/listenerset-invalid.out.yaml +++ b/internal/gatewayapi/testdata/listenerset-invalid.out.yaml @@ -20,7 +20,7 @@ gateways: port: 80 protocol: HTTP status: - attachedListenerSets: 2 + attachedListenerSets: 1 listeners: - attachedRoutes: 0 conditions: @@ -200,30 +200,12 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-invalid/invalid-one - ports: - - containerPort: 8085 - name: "-8085" - protocol: "" - servicePort: 8085 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-invalid/invalid-two - ports: - - containerPort: 8086 - name: "-8086" - protocol: "" - servicePort: 8086 - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-mixed/mixed-valid ports: - containerPort: 8087 name: http-8087 protocol: HTTP servicePort: 8087 - - name: gateway-xls/composite-gateway/gateway-xls/same-namespace-mixed/mixed-invalid - ports: - - containerPort: 8088 - name: "-8088" - protocol: "" - servicePort: 8088 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: composite-gateway diff --git a/internal/gatewayapi/testdata/listenerset-protocol-conflict.in.yaml b/internal/gatewayapi/testdata/listenerset-protocol-conflict.in.yaml new file mode 100644 index 0000000000..615a57d6dd --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-protocol-conflict.in.yaml @@ -0,0 +1,162 @@ +namespaces: + - apiVersion: v1 + kind: Namespace + metadata: + name: gateway-conformance-infra +gateways: + - apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + spec: + gatewayClassName: envoy-gateway-class + allowedListeners: + namespaces: + from: Same + listeners: + - name: gateway-listener + port: 80 + protocol: HTTP + hostname: "gateway-listener.com" + allowedRoutes: + namespaces: + from: All + # The following listener should be accepted based on listener precedence + - name: protocol-conflict-with-gateway-listener + port: 80 + protocol: HTTP + hostname: "protocol-conflict-with-gateway-listener.com" + allowedRoutes: + namespaces: + from: All +listenerSets: + # The listener `protocol-conflict-with-gateway-listener` should be rejected but the listenerSet should be accepted since it has other valid listeners + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-gateway-1 + namespace: gateway-conformance-infra + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + listeners: + - name: listener-set-1-listener + port: 80 + protocol: HTTP + hostname: "listener-set-1-listener.com" + allowedRoutes: + namespaces: + from: All + # The following listener should be rejected since it conflicts with the gateway listener + - name: protocol-conflict-with-gateway-listener + port: 80 + protocol: TCP + allowedRoutes: + namespaces: + from: All + # The following listener should be accepted based on listener precedence + - name: protocol-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + hostname: "protocol-conflict-with-listener-set-listener.com" + allowedRoutes: + namespaces: + from: All + # This listenerSet should not be accepted since its only listener `protocol-conflict-with-gateway-listener` is rejected + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-gateway-2 + namespace: gateway-conformance-infra + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + listeners: + # The following listener should be rejected since it conflicts with the gateway listener + - name: protocol-conflict-with-gateway-listener + port: 80 + protocol: TCP + allowedRoutes: + namespaces: + from: All + # The listener `protocol-conflict-with-listener-set-listener` should be rejected but the listenerSet should be accepted since it has other valid listeners + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-listener-set-1 + namespace: gateway-conformance-infra + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + listeners: + - name: listener-set-2-listener + port: 80 + protocol: HTTP + hostname: "listener-set-2-listener.com" + allowedRoutes: + namespaces: + from: All + # The following listener should be rejected since it conflicts with another listenerSet's listener + - name: protocol-conflict-with-listener-set-listener + port: 80 + protocol: TCP + allowedRoutes: + namespaces: + from: All + # This listenerSet should not be accepted since its only listener `protocol-conflict-with-listener-set-listener` is rejected + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-listener-set-2 + namespace: gateway-conformance-infra + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + listeners: + # The following listener should be rejected since it conflicts with another listenerSet's listener + - name: protocol-conflict-with-listener-set-listener + port: 80 + protocol: TCP + allowedRoutes: + namespaces: + from: All + # The first listener is invalid due to unsupported protocol and should not block + # the following valid listener on the same port. + - apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-invalid-first-should-not-block-valid + namespace: gateway-conformance-infra + spec: + parentRef: + kind: Gateway + group: gateway.networking.k8s.io + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + listeners: + - name: invalid-unsupported-protocol-first + port: 81 + protocol: SCTP + allowedRoutes: + namespaces: + from: All + - name: valid-http-after-invalid + port: 81 + protocol: HTTP + hostname: "valid-http-after-invalid.com" + allowedRoutes: + namespaces: + from: All diff --git a/internal/gatewayapi/testdata/listenerset-protocol-conflict.out.yaml b/internal/gatewayapi/testdata/listenerset-protocol-conflict.out.yaml new file mode 100644 index 0000000000..36f163a24d --- /dev/null +++ b/internal/gatewayapi/testdata/listenerset-protocol-conflict.out.yaml @@ -0,0 +1,634 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + spec: + allowedListeners: + namespaces: + from: Same + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: gateway-listener.com + name: gateway-listener + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + hostname: protocol-conflict-with-gateway-listener.com + name: protocol-conflict-with-gateway-listener + port: 80 + protocol: HTTP + status: + attachedListenerSets: 3 + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: protocol-conflict-with-gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +infraIR: + gateway-conformance-infra/gateway-with-listenerset-protocol-conflict: + proxy: + listeners: + - name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/gateway-listener + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + - name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/gateway-conformance-infra/listenerset-invalid-first-should-not-block-valid/valid-http-after-invalid + ports: + - containerPort: 10081 + name: http-81 + protocol: HTTP + servicePort: 81 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-with-listenerset-protocol-conflict + gateway.envoyproxy.io/owning-gateway-namespace: gateway-conformance-infra + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict + namespace: envoy-gateway-system +listenerSets: +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-gateway-1 + namespace: gateway-conformance-infra + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: listener-set-1-listener.com + name: listener-set-1-listener + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + name: protocol-conflict-with-gateway-listener + port: 80 + protocol: TCP + - allowedRoutes: + namespaces: + from: All + hostname: protocol-conflict-with-listener-set-listener.com + name: protocol-conflict-with-listener-set-listener + port: 80 + protocol: HTTP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + status: + conditions: + - lastTransitionTime: null + message: Some listeners are invalid + reason: ListenersNotValid + status: "True" + type: Accepted + - lastTransitionTime: null + message: Some listeners are invalid + reason: Programmed + status: "True" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: listener-set-1-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: protocol-conflict-with-gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: protocol-conflict-with-listener-set-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-gateway-2 + namespace: gateway-conformance-infra + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + name: protocol-conflict-with-gateway-listener + port: 80 + protocol: TCP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + status: + conditions: + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Only one TCP listener is allowed in a given port + reason: ProtocolConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: protocol-conflict-with-gateway-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-listener-set-1 + namespace: gateway-conformance-infra + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + hostname: listener-set-2-listener.com + name: listener-set-2-listener + port: 80 + protocol: HTTP + - allowedRoutes: + namespaces: + from: All + name: protocol-conflict-with-listener-set-listener + port: 80 + protocol: TCP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + status: + conditions: + - lastTransitionTime: null + message: Some listeners are invalid + reason: ListenersNotValid + status: "True" + type: Accepted + - lastTransitionTime: null + message: Some listeners are invalid + reason: Programmed + status: "True" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: listener-set-2-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Only one TCP listener is allowed in a given port + reason: ProtocolConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: protocol-conflict-with-listener-set-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-with-protocol-conflict-with-listener-set-2 + namespace: gateway-conformance-infra + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + name: protocol-conflict-with-listener-set-listener + port: 80 + protocol: TCP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + status: + conditions: + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners are invalid + reason: ListenersNotValid + status: "False" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Only one TCP listener is allowed in a given port + reason: ProtocolConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: protocol-conflict-with-listener-set-listener + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute +- apiVersion: gateway.networking.k8s.io/v1 + kind: ListenerSet + metadata: + name: listenerset-invalid-first-should-not-block-valid + namespace: gateway-conformance-infra + spec: + listeners: + - allowedRoutes: + namespaces: + from: All + name: invalid-unsupported-protocol-first + port: 81 + protocol: SCTP + - allowedRoutes: + namespaces: + from: All + hostname: valid-http-after-invalid.com + name: valid-http-after-invalid + port: 81 + protocol: HTTP + parentRef: + group: gateway.networking.k8s.io + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + status: + conditions: + - lastTransitionTime: null + message: Some listeners are invalid + reason: ListenersNotValid + status: "True" + type: Accepted + - lastTransitionTime: null + message: Some listeners are invalid + reason: Programmed + status: "True" + type: Programmed + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Protocol SCTP is unsupported, must be HTTP, HTTPS, TCP or UDP. + reason: UnsupportedProtocol + status: "False" + type: Accepted + - lastTransitionTime: null + message: Listener is invalid, see other Conditions for details. + reason: ListenersNotValid + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: invalid-unsupported-protocol-first + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + - lastTransitionTime: null + message: No conflicts detected + reason: NoConflicts + status: "False" + type: Conflicted + name: valid-http-after-invalid + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +xdsIR: + gateway-conformance-infra/gateway-with-listenerset-protocol-conflict: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-gateway-conformance-infra-gateway-with-listeners-eaf6e342 + namespace: envoy-gateway-system + sectionName: "8080" + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-gateway-conformance-infra-gateway-with-listeners-eaf6e342 + namespace: envoy-gateway-system + sectionName: "8080" + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - gateway-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + sectionName: gateway-listener + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/gateway-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - protocol-conflict-with-gateway-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + sectionName: protocol-conflict-with-gateway-listener + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/protocol-conflict-with-gateway-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - listener-set-1-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + sectionName: listener-set-1-listener + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/gateway-conformance-infra/listenerset-with-protocol-conflict-with-gateway-1/listener-set-1-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - protocol-conflict-with-listener-set-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + sectionName: protocol-conflict-with-listener-set-listener + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/gateway-conformance-infra/listenerset-with-protocol-conflict-with-gateway-1/protocol-conflict-with-listener-set-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - listener-set-2-listener.com + metadata: + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + sectionName: listener-set-2-listener + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/gateway-conformance-infra/listenerset-with-protocol-conflict-with-listener-set-1/listener-set-2-listener + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + - address: 0.0.0.0 + externalPort: 81 + hostnames: + - valid-http-after-invalid.com + metadata: + kind: Gateway + name: gateway-with-listenerset-protocol-conflict + namespace: gateway-conformance-infra + sectionName: valid-http-after-invalid + name: gateway-conformance-infra/gateway-with-listenerset-protocol-conflict/gateway-conformance-infra/listenerset-invalid-first-should-not-block-valid/valid-http-after-invalid + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10081 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways-conflicting-layer4-protocol.in.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways-conflicting-layer4-protocol.in.yaml new file mode 100644 index 0000000000..d8ec5e7ae1 --- /dev/null +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways-conflicting-layer4-protocol.in.yaml @@ -0,0 +1,70 @@ +envoyProxyForGatewayClass: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + namespace: envoy-gateway-system + name: test + spec: + mergeGateways: true +gateways: + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + port: 80 + protocol: HTTP + allowedRoutes: + namespaces: + from: Same + - apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + # This listener conflicts with gateway-1's HTTP/80: both map to the same + # TCP port in the merged infra, but they use incompatible protocols. + - name: tcp + port: 80 + protocol: TCP + allowedRoutes: + namespaces: + from: Same +httpRoutes: + - apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + rules: + - matches: + - path: + value: "/" + backendRefs: + - name: service-1 + port: 8080 +tcpRoutes: + - apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: TCPRoute + metadata: + namespace: default + name: tcproute-1 + spec: + parentRefs: + - namespace: envoy-gateway + name: gateway-2 + rules: + - backendRefs: + - name: service-1 + port: 8163 diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways-conflicting-layer4-protocol.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways-conflicting-layer4-protocol.out.yaml new file mode 100644 index 0000000000..a7ea6fc74c --- /dev/null +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways-conflicting-layer4-protocol.out.yaml @@ -0,0 +1,221 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +- apiVersion: gateway.networking.k8s.io/v1beta1 + kind: Gateway + metadata: + name: gateway-2 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: Same + name: tcp + port: 80 + protocol: TCP + status: + listeners: + - attachedRoutes: 0 + conditions: + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "True" + type: Conflicted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Accepted + - lastTransitionTime: null + message: All listeners for a given port must use a compatible protocol + reason: ProtocolConflict + status: "False" + type: Programmed + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: tcp + supportedKinds: + - group: gateway.networking.k8s.io + kind: TCPRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + name: httproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + rules: + - backendRefs: + - name: service-1 + port: 8080 + matches: + - path: + value: / + status: + parents: + - conditions: + - lastTransitionTime: null + message: No listeners included by this parent ref allowed this attachment. + reason: NotAllowedByListeners + status: "False" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway +infraIR: + envoy-gateway-class: + proxy: + config: + apiVersion: gateway.envoyproxy.io/v1alpha1 + kind: EnvoyProxy + metadata: + name: test + namespace: envoy-gateway-system + spec: + logging: {} + mergeGateways: true + status: {} + listeners: + - name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class + ownerReference: + kind: GatewayClass + name: envoy-gateway-class + name: envoy-gateway-class + namespace: envoy-gateway-system +tcpRoutes: +- apiVersion: gateway.networking.k8s.io/v1alpha2 + kind: TCPRoute + metadata: + name: tcproute-1 + namespace: default + spec: + parentRefs: + - name: gateway-2 + namespace: envoy-gateway + rules: + - backendRefs: + - name: service-1 + port: 8163 + status: + parents: + - conditions: + - lastTransitionTime: null + message: No listeners included by this parent ref allowed this attachment. + reason: NotAllowedByListeners + status: "False" + type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-2 + namespace: envoy-gateway +xdsIR: + envoy-gateway-class: + accessLog: + json: + - path: /dev/stdout + globalResources: + proxyServiceCluster: + metadata: + kind: Service + name: envoy-envoy-gateway-class-3b1df594 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway-class + settings: + - addressType: IP + endpoints: + - host: 7.6.5.4 + port: 8080 + zone: zone1 + metadata: + kind: Service + name: envoy-envoy-gateway-class-3b1df594 + namespace: envoy-gateway-system + sectionName: "8080" + name: envoy-gateway-class + protocol: TCP + http: + - address: 0.0.0.0 + externalPort: 80 + hostnames: + - '*' + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml index 28b1ac3406..f41c3b186d 100644 --- a/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml +++ b/internal/gatewayapi/testdata/merge-invalid-multiple-gateways.out.yaml @@ -170,20 +170,6 @@ xdsIR: escapedSlashesAction: UnescapeAndRedirect mergeSlashes: true port: 10080 - - address: 0.0.0.0 - externalPort: 80 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: http - name: envoy-gateway/gateway-2/http - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10080 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml index c58cf94f48..68afd0fe72 100644 --- a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml @@ -228,12 +228,6 @@ infraIR: name: http-80 protocol: HTTP servicePort: 80 - - name: envoy-gateway/gateway-2/https - ports: - - containerPort: 10443 - name: https-443 - protocol: HTTPS - servicePort: 443 - name: envoy-gateway/gateway-2/tcp ports: - containerPort: 10053 @@ -551,20 +545,6 @@ xdsIR: name: "" safeRegex: http://.*\.example\.com maxAge: 16m40s - - address: 0.0.0.0 - externalPort: 443 - hostnames: - - '*' - metadata: - kind: Gateway - name: gateway-2 - namespace: envoy-gateway - sectionName: https - name: envoy-gateway/gateway-2/https - path: - escapedSlashesAction: UnescapeAndRedirect - mergeSlashes: true - port: 10443 readyListener: address: 0.0.0.0 ipFamily: IPv4 diff --git a/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml b/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml index 70c8273b9f..3ea4f78801 100644 --- a/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-invalid-no-matching-listener.out.yaml @@ -315,13 +315,6 @@ infraIR: namespace: envoy-gateway-system envoy-gateway/gateway-tlsroute-tcproute-only: proxy: - listeners: - - name: envoy-gateway/gateway-tlsroute-tcproute-only/tls-passthrough - ports: - - containerPort: 10443 - name: tls-443 - protocol: TLS - servicePort: 443 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-tlsroute-tcproute-only @@ -743,16 +736,6 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 443 - metadata: - kind: Gateway - name: gateway-tlsroute-tcproute-only - namespace: envoy-gateway - sectionName: tls-passthrough - name: envoy-gateway/gateway-tlsroute-tcproute-only/tls-passthrough - port: 10443 envoy-gateway/gateway-tlsroute-tls-passthrough-only: accessLog: json: diff --git a/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml b/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml index f7221094bd..5a7b2c7289 100644 --- a/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-not-attaching-to-gateway-with-no-mode.out.yaml @@ -36,13 +36,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10090 - name: tls-90 - protocol: TLS - servicePort: 90 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -114,13 +107,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 90 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10090 diff --git a/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml b/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml index eca1a7d9b6..e1f898a957 100644 --- a/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml +++ b/internal/gatewayapi/testdata/tlsroute-with-listener-both-passthrough-and-cert-data.out.yaml @@ -39,13 +39,6 @@ gateways: infraIR: envoy-gateway/gateway-1: proxy: - listeners: - - name: envoy-gateway/gateway-1/tls - ports: - - containerPort: 10090 - name: tls-90 - protocol: TLS - servicePort: 90 metadata: labels: gateway.envoyproxy.io/owning-gateway-name: gateway-1 @@ -117,13 +110,3 @@ xdsIR: ipFamily: IPv4 path: /ready port: 19003 - tcp: - - address: 0.0.0.0 - externalPort: 90 - metadata: - kind: Gateway - name: gateway-1 - namespace: envoy-gateway - sectionName: tls - name: envoy-gateway/gateway-1/tls - port: 10090 diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index ab9d5bc5ee..8c3e169283 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -274,7 +274,7 @@ func (t *Translator) validateBackendRefBackend( return nil } -func (t *Translator) validateListenerConditions(listener *ListenerContext) { +func (t *Translator) validateListenerConditions(listener *ListenerContext) bool { lConditions := listener.GetConditions() if len(lConditions) == 0 { listener.SetCondition(gwapiv1.ListenerConditionProgrammed, metav1.ConditionTrue, gwapiv1.ListenerReasonProgrammed, @@ -287,7 +287,7 @@ func (t *Translator) validateListenerConditions(listener *ListenerContext) { listener.SetCondition(gwapiv1.ListenerConditionConflicted, metav1.ConditionFalse, gwapiv1.ListenerReasonNoConflicts, "No conflicts detected") } - return + return true } // Edge case: only one condition which is ResolvedRefs=False, Reason=PartiallyInvalidCertificateRef @@ -298,7 +298,7 @@ func (t *Translator) validateListenerConditions(listener *ListenerContext) { "Listener has been successfully translated") listener.SetCondition(gwapiv1.ListenerConditionProgrammed, metav1.ConditionTrue, gwapiv1.ListenerReasonProgrammed, "Sending translated listener configuration to the data plane") - return + return true } // Any condition on the listener apart from Programmed=true indicates an error. @@ -334,11 +334,50 @@ func (t *Translator) validateListenerConditions(listener *ListenerContext) { ) } // skip computing IR - return + return false + } + + return true +} + +// hasInvalidCondition checks if a listener has been marked as invalid during per-listener validation. +// A listener is considered invalid if it has Programmed=False, Accepted=False, or ResolvedRefs=False +// (except for the special case of PartiallyInvalidCertificateRef which is allowed). +// This is used during conflict resolution to skip invalid listeners so they don't block valid ones. +func hasInvalidCondition(listener *ListenerContext) bool { + conditions := listener.GetConditions() + for _, cond := range conditions { + if cond.Type == string(gwapiv1.ListenerConditionProgrammed) && cond.Status == metav1.ConditionFalse { + return true + } + if cond.Type == string(gwapiv1.ListenerConditionAccepted) && cond.Status == metav1.ConditionFalse { + return true + } + // ResolvedRefs=False is invalid except for PartiallyInvalidCertificateRef which allows + // the listener to still be programmed with valid certificates + if cond.Type == string(gwapiv1.ListenerConditionResolvedRefs) && + cond.Status == metav1.ConditionFalse && + cond.Reason != string(status.ListenerReasonPartiallyInvalidCertificateRef) { + return true + } } + return false +} + +// isSpecValidForConflictChecks returns whether a listener should participate in +// conflict detection. In the normal translation flow this is driven by +// listener.specValid. The fallback keeps direct unit tests meaningful when they +// invoke conflict checks without running per-listener spec validation first. +func isSpecValidForConflictChecks(listener *ListenerContext) bool { + if listener.specValid { + return true + } + return !hasInvalidCondition(listener) } -func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) { +// validateAllowedNamespaces validates namespace selector configuration. +// Returns true if the namespace spec is valid, false otherwise. +func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) bool { if listener.AllowedRoutes != nil && listener.AllowedRoutes.Namespaces != nil && listener.AllowedRoutes.Namespaces.From != nil && @@ -350,26 +389,28 @@ func (t *Translator) validateAllowedNamespaces(listener *ListenerContext) { gwapiv1.ListenerReasonInvalid, "The allowedRoutes.namespaces.selector field must be specified when allowedRoutes.namespaces.from is set to \"Selector\".", ) - } else { - selector, err := metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) - if err != nil { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - fmt.Sprintf("The allowedRoutes.namespaces.selector could not be parsed: %v.", err), - ) - } - - listener.namespaceSelector = selector + return false + } + selector, err := metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) + if err != nil { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + fmt.Sprintf("The allowedRoutes.namespaces.selector could not be parsed: %v.", err), + ) + return false } + + listener.namespaceSelector = selector } + return true } func (t *Translator) validateTerminateModeAndGetTLSSecrets( listener *ListenerContext, resources *resource.Resources, -) ([]*corev1.Secret, []*x509.Certificate) { +) ([]*corev1.Secret, []*x509.Certificate, bool) { if len(listener.TLS.CertificateRefs) == 0 { listener.SetCondition( gwapiv1.ListenerConditionProgrammed, @@ -377,7 +418,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( gwapiv1.ListenerReasonInvalid, "Listener must have at least 1 TLS certificate ref", ) - return nil, nil + return nil, nil, false } var errs []status.ListenerError @@ -487,7 +528,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( fmt.Sprintf("No valid secrets exist: %v", errors.Join(errList...)), ) - return nil, nil + return nil, nil, false } validSecrets, certs, err := parseCertsFromTLSSecretsData(secrets) @@ -499,7 +540,7 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( err.Reason(), fmt.Sprintf("No valid secrets exist: %v.", err.Error()), ) - return nil, nil + return nil, nil, false } else { errs = append(errs, err) } @@ -518,13 +559,17 @@ func (t *Translator) validateTerminateModeAndGetTLSSecrets( fmt.Sprintf("Some secrets are invalid: %v", errors.Join(errList...)), ) } - return validSecrets, certs + return validSecrets, certs, true } +// validateTLSConfiguration validates TLS configuration per protocol. +// Returns true if the TLS spec is valid, false otherwise. func (t *Translator) validateTLSConfiguration( listener *ListenerContext, resources *resource.Resources, -) { +) bool { + specValid := true + switch listener.Protocol { case gwapiv1.HTTPProtocolType, gwapiv1.UDPProtocolType, gwapiv1.TCPProtocolType: if listener.TLS != nil { @@ -534,6 +579,7 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must not have TLS set when protocol is %s.", listener.Protocol), ) + specValid = false } case gwapiv1.HTTPSProtocolType: if listener.TLS == nil { @@ -543,25 +589,29 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must have TLS set when protocol is %s.", listener.Protocol), ) - break - } - - if listener.TLS.Mode != nil && *listener.TLS.Mode != gwapiv1.TLSModeTerminate { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - "UnsupportedTLSMode", - fmt.Sprintf("TLS %s mode is not supported, TLS mode must be Terminate.", *listener.TLS.Mode), - ) - break - } + specValid = false + } else { + if listener.TLS.Mode != nil && *listener.TLS.Mode != gwapiv1.TLSModeTerminate { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + "UnsupportedTLSMode", + fmt.Sprintf("TLS %s mode is not supported, TLS mode must be Terminate.", *listener.TLS.Mode), + ) + specValid = false + } else { + secrets, certs, ok := t.validateTerminateModeAndGetTLSSecrets(listener, resources) + listener.SetTLSSecrets(secrets) - secrets, certs := t.validateTerminateModeAndGetTLSSecrets(listener, resources) - listener.SetTLSSecrets(secrets) + if !ok { + specValid = false + } - listener.tls.certDNSNames = make([]string, 0) - for _, cert := range certs { - listener.tls.certDNSNames = append(listener.tls.certDNSNames, cert.DNSNames...) + listener.tls.certDNSNames = make([]string, 0) + for _, cert := range certs { + listener.tls.certDNSNames = append(listener.tls.certDNSNames, cert.DNSNames...) + } + } } case gwapiv1.TLSProtocolType: if listener.TLS == nil { @@ -571,33 +621,38 @@ func (t *Translator) validateTLSConfiguration( gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must have TLS set when protocol is %s.", listener.Protocol), ) - break - } - - if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModePassthrough { - if len(listener.TLS.CertificateRefs) > 0 { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - "Listener must not have TLS certificate refs set for TLS mode Passthrough.", - ) - break + specValid = false + } else { + if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModePassthrough { + if len(listener.TLS.CertificateRefs) > 0 { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + "Listener must not have TLS certificate refs set for TLS mode Passthrough.", + ) + specValid = false + } } - } - if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModeTerminate { - if len(listener.TLS.CertificateRefs) == 0 { - listener.SetCondition( - gwapiv1.ListenerConditionProgrammed, - metav1.ConditionFalse, - gwapiv1.ListenerReasonInvalid, - "Listener must have TLS certificate refs set for TLS mode Terminate.", - ) - break + if listener.TLS.Mode != nil && *listener.TLS.Mode == gwapiv1.TLSModeTerminate { + if len(listener.TLS.CertificateRefs) == 0 { + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + "Listener must have TLS certificate refs set for TLS mode Terminate.", + ) + specValid = false + } else { + secrets, _, ok := t.validateTerminateModeAndGetTLSSecrets(listener, resources) + listener.SetTLSSecrets(secrets) + + if !ok { + specValid = false + } + } } - secrets, _ := t.validateTerminateModeAndGetTLSSecrets(listener, resources) - listener.SetTLSSecrets(secrets) } } @@ -631,9 +686,13 @@ func (t *Translator) validateTLSConfiguration( "Listener has invalid CA certificate for frontend TLS validation.", ) } + + return specValid } -func (t *Translator) validateHostName(listener *ListenerContext) { +// validateHostName validates hostname configuration per protocol. +// Returns true if the hostname spec is valid, false otherwise. +func (t *Translator) validateHostName(listener *ListenerContext) bool { if listener.Protocol == gwapiv1.UDPProtocolType || listener.Protocol == gwapiv1.TCPProtocolType { if listener.Hostname != nil { listener.SetCondition( @@ -642,26 +701,30 @@ func (t *Translator) validateHostName(listener *ListenerContext) { gwapiv1.ListenerReasonInvalid, fmt.Sprintf("Listener must not have hostname set when protocol is %s.", listener.Protocol), ) + return false } } + return true } -func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds ...gwapiv1.Kind) { +// validateAllowedRoutes validates allowed route kinds configuration. +// Returns true if the allowed routes spec is valid, false otherwise. +func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds ...gwapiv1.Kind) bool { canSupportKinds := make([]gwapiv1.RouteGroupKind, len(routeKinds)) for i, routeKind := range routeKinds { canSupportKinds[i] = gwapiv1.RouteGroupKind{Group: GroupPtr(gwapiv1.GroupName), Kind: routeKind} } if listener.AllowedRoutes == nil || len(listener.AllowedRoutes.Kinds) == 0 { listener.SetSupportedKinds(canSupportKinds...) - return + return true } + specValid := true supportedRouteKinds := make([]gwapiv1.Kind, 0) supportedKinds := make([]gwapiv1.RouteGroupKind, 0) unSupportedKinds := make([]gwapiv1.RouteGroupKind, 0) for _, kind := range listener.AllowedRoutes.Kinds { - // if there is a group it must match `gateway.networking.k8s.io` if kind.Group != nil && string(*kind.Group) != gwapiv1.GroupName { listener.SetCondition( @@ -670,6 +733,7 @@ func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds gwapiv1.ListenerReasonInvalidRouteKinds, fmt.Sprintf("Group is not supported, group must be %s", gwapiv1.GroupName), ) + specValid = false continue } @@ -701,14 +765,21 @@ func (t *Translator) validateAllowedRoutes(listener *ListenerContext, routeKinds gwapiv1.ListenerReasonInvalidRouteKinds, fmt.Sprintf("%s is not supported, kind must be one of %v", string(kind.Kind), printRouteKinds), ) + specValid = false } - listener.SetSupportedKinds(supportedKinds...) + // If no kinds were explicitly specified but there were no errors, set default supported kinds + if len(supportedKinds) == 0 && specValid { + listener.SetSupportedKinds(canSupportKinds...) + } else { + listener.SetSupportedKinds(supportedKinds...) + } + return specValid } type portListeners struct { listeners []*ListenerContext - protocols sets.Set[string] + protocols map[string]bool hostnames map[string]int } @@ -717,6 +788,11 @@ func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContex listenerSets := sets.Set[string]{} for _, gateway := range gateways { for _, listener := range gateway.listeners { + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } hostname := new(gwapiv1.Hostname) if listener.Hostname != nil { hostname = listener.Hostname @@ -735,6 +811,106 @@ func (t *Translator) validateConflictedMergedListeners(gateways []*GatewayContex } } +// validateConflictedProtocolsListeners checks for listeners that have conflicting protocols on the same port and sets the Conflicted condition on those listeners. +func (t *Translator) validateConflictedProtocolsListeners(gateways []*GatewayContext) { + // Per-gateway check: within each gateway, listeners on the same port must use compatible protocols. + // HTTPS and TLS are considered compatible with each other but not with HTTP or TCP. + for _, gateway := range gateways { + portListenerInfo := collectPortListeners(gateway.listeners) + markProtocolConflicts(portListenerInfo) + } + + // In merge mode, also check for protocol conflicts across all gateways that share + // the same infra port, since they share the same IR key. A Gateway with HTTP/80 + // and another with TCP/80 would each pass the per-gateway check above (single + // listener per gateway), but must still be flagged as conflicted in merge mode. + if t.MergeGateways { + var allListeners []*ListenerContext + for _, gateway := range gateways { + allListeners = append(allListeners, gateway.listeners...) + } + portListenerInfo := collectPortListeners(allListeners) + markProtocolConflicts(portListenerInfo) + } +} + +// collectPortListeners groups the provided listeners by port, skipping any with unsupported protocols. +func collectPortListeners(listeners []*ListenerContext) map[gwapiv1.PortNumber]*portListeners { + portListenerInfo := map[gwapiv1.PortNumber]*portListeners{} + for _, listener := range listeners { + // Skip listeners that already failed per-listener validation. + // This avoids invalid listeners blocking valid listeners in conflict checks. + if !isSpecValidForConflictChecks(listener) { + continue + } + if !isSupportedListenerProtocol(listener.Protocol) { + continue + } + if portListenerInfo[listener.Port] == nil { + portListenerInfo[listener.Port] = &portListeners{ + hostnames: map[string]int{}, + protocols: map[string]bool{}, + } + } + portListenerInfo[listener.Port].listeners = append(portListenerInfo[listener.Port].listeners, listener) + protocol := getProtocolForListener(listener) + portListenerInfo[listener.Port].protocols[protocol] = true + } + return portListenerInfo +} + +// markProtocolConflicts iterates portListenerInfo and marks any listeners whose protocol +// is incompatible with the first non-UDP listener on the same port. +func markProtocolConflicts(portListenerInfo map[gwapiv1.PortNumber]*portListeners) { + for _, info := range portListenerInfo { + // For protocol conflict detection, the first listener on a port wins. + // Subsequent listeners with incompatible protocols are marked as conflicted. + // UDP can coexist with TCP/HTTP/HTTPS/TLS, but TCP/HTTP/HTTPS/TLS cannot mix. + var firstNonUDPProtocol string + seenNonUDPProtocol := false + + for _, listener := range info.listeners { + protocol := getProtocolForListener(listener) + + // UDP listeners can coexist with any other protocol + if protocol == "UDP" { + continue + } + + // This is the first non-UDP listener we've seen on this port + if !seenNonUDPProtocol { + firstNonUDPProtocol = protocol + seenNonUDPProtocol = true + continue + } + + // This is a subsequent non-UDP listener - check if it conflicts + if protocol != firstNonUDPProtocol { + listener.SetCondition( + gwapiv1.ListenerConditionConflicted, + metav1.ConditionTrue, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + // TODO: remove following once https://github.com/kubernetes-sigs/gateway-api/pull/4692 landed, + // we may want to have similar logic when protocol conflict happened. + listener.SetCondition( + gwapiv1.ListenerConditionAccepted, + metav1.ConditionFalse, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonProtocolConflict, + "All listeners for a given port must use a compatible protocol", + ) + } + } + } +} + func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContext) { // Iterate through all layer-7 (HTTP, HTTPS, TLS) listeners and collect info about protocols // and hostnames per port. @@ -744,25 +920,20 @@ func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContex if listener.Protocol == gwapiv1.UDPProtocolType || listener.Protocol == gwapiv1.TCPProtocolType { continue } + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } if portListenerInfo[listener.Port] == nil { portListenerInfo[listener.Port] = &portListeners{ - protocols: sets.Set[string]{}, hostnames: map[string]int{}, + protocols: map[string]bool{}, } } portListenerInfo[listener.Port].listeners = append(portListenerInfo[listener.Port].listeners, listener) - var protocol string - switch listener.Protocol { - // HTTPS and TLS can co-exist on the same port - case gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType: - protocol = "https/tls" - default: - protocol = string(listener.Protocol) - } - portListenerInfo[listener.Port].protocols.Insert(protocol) - var hostname string if listener.Hostname != nil { hostname = string(*listener.Hostname) @@ -773,21 +944,20 @@ func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContex // Set Conflicted conditions for any listeners with conflicting specs. for _, info := range portListenerInfo { + perHostnameListenerFound := map[string]bool{} for _, listener := range info.listeners { - if len(info.protocols) > 1 { - listener.SetCondition( - gwapiv1.ListenerConditionConflicted, - metav1.ConditionTrue, - gwapiv1.ListenerReasonProtocolConflict, - "All listeners for a given port must use a compatible protocol", - ) - } var hostname string if listener.Hostname != nil { hostname = string(*listener.Hostname) } + // the first listener with a given hostname on a given port is allowed to be non-conflicted, + // but any additional listener with the same hostname and port is a conflict + if found := perHostnameListenerFound[hostname]; !found { + perHostnameListenerFound[hostname] = true + continue + } if info.hostnames[hostname] > 1 { listener.SetCondition( gwapiv1.ListenerConditionConflicted, @@ -795,6 +965,19 @@ func (t *Translator) validateConflictedLayer7Listeners(gateways []*GatewayContex gwapiv1.ListenerReasonHostnameConflict, "All listeners for a given port must use a unique hostname", ) + // TODO: remove following once https://github.com/kubernetes-sigs/gateway-api/pull/4692 landed. + listener.SetCondition( + gwapiv1.ListenerConditionAccepted, + metav1.ConditionFalse, + gwapiv1.ListenerReasonHostnameConflict, + "All listeners for a given port must use a unique hostname", + ) + listener.SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonHostnameConflict, + "All listeners for a given port must use a unique hostname", + ) } } } @@ -806,6 +989,11 @@ func (t *Translator) validateConflictedLayer4Listeners(gateways []*GatewayContex for _, gateway := range gateways { portListenerInfo := map[gwapiv1.PortNumber]*portListeners{} for _, listener := range gateway.listeners { + // Skip listeners that are already marked as invalid from per-listener validation. + // This prevents an invalid first listener from blocking valid subsequent listeners. + if !isSpecValidForConflictChecks(listener) { + continue + } for _, protocol := range protocols { if listener.Protocol == protocol { if portListenerInfo[listener.Port] == nil { @@ -832,6 +1020,26 @@ func (t *Translator) validateConflictedLayer4Listeners(gateways []*GatewayContex } } +func getProtocolForListener(listener *ListenerContext) string { + switch listener.Protocol { + // HTTPS and TLS can co-exist on the same port. + case gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType: + return "https/tls" + default: + return string(listener.Protocol) + } +} + +func isSupportedListenerProtocol(protocol gwapiv1.ProtocolType) bool { + switch protocol { + case gwapiv1.HTTPProtocolType, gwapiv1.HTTPSProtocolType, gwapiv1.TLSProtocolType, + gwapiv1.TCPProtocolType, gwapiv1.UDPProtocolType: + return true + default: + return false + } +} + func (t *Translator) validateCrossNamespaceRef(from crossNamespaceFrom, to crossNamespaceTo, referenceGrants []*gwapiv1b1.ReferenceGrant) bool { for _, referenceGrant := range referenceGrants { // The ReferenceGrant must be defined in the namespace of diff --git a/internal/gatewayapi/validate_test.go b/internal/gatewayapi/validate_test.go new file mode 100644 index 0000000000..781ab2ae2b --- /dev/null +++ b/internal/gatewayapi/validate_test.go @@ -0,0 +1,105 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +package gatewayapi + +import ( + "testing" + + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +func TestValidateConflictedProtocolsListenersIgnoresUnsupportedProtocols(t *testing.T) { + unsupported := gwapiv1.ProtocolType("INVALID") + + gateway := &gwapiv1.Gateway{} + gateway.Status.Listeners = []gwapiv1.ListenerStatus{{}, {}} + + gatewayCtx := &GatewayContext{Gateway: gateway} + gatewayCtx.listeners = []*ListenerContext{ + { + Listener: &gwapiv1.Listener{ + Name: "invalid", + Port: 80, + Protocol: unsupported, + }, + gateway: gatewayCtx, + listenerStatusIdx: 0, + }, + { + Listener: &gwapiv1.Listener{ + Name: "http", + Port: 80, + Protocol: gwapiv1.HTTPProtocolType, + }, + gateway: gatewayCtx, + listenerStatusIdx: 1, + }, + } + + translator := &Translator{} + translator.validateConflictedProtocolsListeners([]*GatewayContext{gatewayCtx}) + + httpConds := gatewayCtx.Status.Listeners[1].Conditions + require.False(t, hasListenerCondition(httpConds, gwapiv1.ListenerConditionConflicted, gwapiv1.ListenerReasonProtocolConflict, metav1.ConditionTrue)) + require.False(t, hasListenerCondition(httpConds, gwapiv1.ListenerConditionAccepted, gwapiv1.ListenerReasonProtocolConflict, metav1.ConditionFalse)) + require.False(t, hasListenerCondition(httpConds, gwapiv1.ListenerConditionProgrammed, gwapiv1.ListenerReasonProtocolConflict, metav1.ConditionFalse)) +} + +func TestValidateConflictedProtocolsListenersIgnoresInvalidListeners(t *testing.T) { + gateway := &gwapiv1.Gateway{} + gateway.Status.Listeners = []gwapiv1.ListenerStatus{{}, {}} + + gatewayCtx := &GatewayContext{Gateway: gateway} + gatewayCtx.listeners = []*ListenerContext{ + { + Listener: &gwapiv1.Listener{ + Name: "invalid-tcp", + Port: 80, + Protocol: gwapiv1.TCPProtocolType, + }, + gateway: gatewayCtx, + listenerStatusIdx: 0, + }, + { + Listener: &gwapiv1.Listener{ + Name: "http", + Port: 80, + Protocol: gwapiv1.HTTPProtocolType, + }, + gateway: gatewayCtx, + listenerStatusIdx: 1, + }, + } + + // Mark the first listener invalid. It should be ignored in protocol conflict checks. + gatewayCtx.listeners[0].SetCondition( + gwapiv1.ListenerConditionProgrammed, + metav1.ConditionFalse, + gwapiv1.ListenerReasonInvalid, + "listener is invalid", + ) + + translator := &Translator{} + translator.validateConflictedProtocolsListeners([]*GatewayContext{gatewayCtx}) + + httpConds := gatewayCtx.Status.Listeners[1].Conditions + require.False(t, hasListenerCondition(httpConds, gwapiv1.ListenerConditionConflicted, gwapiv1.ListenerReasonProtocolConflict, metav1.ConditionTrue)) + require.False(t, hasListenerCondition(httpConds, gwapiv1.ListenerConditionAccepted, gwapiv1.ListenerReasonProtocolConflict, metav1.ConditionFalse)) + require.False(t, hasListenerCondition(httpConds, gwapiv1.ListenerConditionProgrammed, gwapiv1.ListenerReasonProtocolConflict, metav1.ConditionFalse)) +} + +// nolint: unparam +func hasListenerCondition(conditions []metav1.Condition, condType gwapiv1.ListenerConditionType, reason gwapiv1.ListenerConditionReason, status metav1.ConditionStatus) bool { + for _, cond := range conditions { + if cond.Type == string(condType) && cond.Reason == string(reason) && cond.Status == status { + return true + } + } + + return false +} diff --git a/test/conformance/suite.go b/test/conformance/suite.go index 9214424884..4239f2aee5 100644 --- a/test/conformance/suite.go +++ b/test/conformance/suite.go @@ -47,8 +47,6 @@ func SkipTests(gatewayNamespaceMode bool) []suite.ConformanceTest { skipTests := []suite.ConformanceTest{ tests.GatewayStaticAddresses, // TODO: fix following conformance tests - tests.ListenerSetHostnameConflict, - tests.ListenerSetProtocolConflict, tests.HTTPRouteHTTPSListenerDetectMisdirectedRequests, }