Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

infra: add support for merging gateways on to a single EnvoyProxy #1938

Merged
merged 17 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/gatewayapi/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type AddressesTranslator interface {
func (t *Translator) ProcessAddresses(gateways []*GatewayContext, xdsIR XdsIRMap, infraIR InfraIRMap, resources *Resources) {
for _, gateway := range gateways {
// Infra IR already exist
irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name)
irKey := t.getIRKey(gateway.Gateway)
gwInfraIR := infraIR[irKey]

var ipAddr []string
Expand Down
10 changes: 10 additions & 0 deletions internal/gatewayapi/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,12 @@ func GatewayOwnerLabels(namespace, name string) map[string]string {
}
}

// GatewayClassOwnerLabel returns the GatewayCLass Owner label using
// the provided name as the value.
func GatewayClassOwnerLabel(name string) map[string]string {
return map[string]string{OwningGatewayClassLabel: name}
}

// servicePortToContainerPort translates a service port into an ephemeral
// container port.
func servicePortToContainerPort(servicePort int32) int32 {
Expand Down Expand Up @@ -444,6 +450,10 @@ func irTLSListenerConfigName(secret *v1.Secret) string {
return fmt.Sprintf("%s-%s", secret.Namespace, secret.Name)
}

func isMergeGatewaysEnabled(resources *Resources) bool {
return resources.EnvoyProxy != nil && resources.EnvoyProxy.Spec.MergeGateways != nil && *resources.EnvoyProxy.Spec.MergeGateways
}

func protocolSliceToStringSlice(protocols []gwapiv1.ProtocolType) []string {
var protocolStrings []string
for _, protocol := range protocols {
Expand Down
40 changes: 20 additions & 20 deletions internal/gatewayapi/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,25 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap
t.validateConflictedLayer7Listeners(gateways)
t.validateConflictedLayer4Listeners(gateways, gwapiv1.TCPProtocolType, gwapiv1.TLSProtocolType)
t.validateConflictedLayer4Listeners(gateways, gwapiv1.UDPProtocolType)
if t.MergeGateways {
t.validateConflictedMergedListeners(gateways)
}

// Iterate through all listeners to validate spec
// and compute status for each, and add valid ones
// to the Xds IR.
for _, gateway := range gateways {
// init IR per gateway
irKey := irStringKey(gateway.Gateway.Namespace, gateway.Gateway.Name)
gwXdsIR := &ir.Xds{}
gwInfraIR := ir.NewInfra()
gwInfraIR.Proxy.Name = irKey
gwInfraIR.Proxy.GetProxyMetadata().Labels = GatewayOwnerLabels(gateway.Namespace, gateway.Name)
if resources.EnvoyProxy != nil {
gwInfraIR.Proxy.Config = resources.EnvoyProxy
}

// save the IR references in the map before the translation starts
xdsIR[irKey] = gwXdsIR
infraIR[irKey] = gwInfraIR

// Infra IR proxy ports must be unique.
var foundPorts []*protocolPort
irKey := t.getIRKey(gateway.Gateway)

gwXdsIR.AccessLog = processAccessLog(gwInfraIR.Proxy.Config)
gwXdsIR.Tracing = processTracing(gateway.Gateway, gwInfraIR.Proxy.Config)
gwXdsIR.Metrics = processMetrics(gwInfraIR.Proxy.Config)
if resources.EnvoyProxy != nil {
infraIR[irKey].Proxy.Config = resources.EnvoyProxy
}

xdsIR[irKey].AccessLog = processAccessLog(infraIR[irKey].Proxy.Config)
xdsIR[irKey].Tracing = processTracing(gateway.Gateway, infraIR[irKey].Proxy.Config)
xdsIR[irKey].Metrics = processMetrics(infraIR[irKey].Proxy.Config)

for _, listener := range gateway.listeners {
// Process protocol & supported kinds
Expand Down Expand Up @@ -119,7 +113,7 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap
// see more https://gateway-api.sigs.k8s.io/references/spec/#gateway.networking.k8s.io/gwapiv1.Listener.
irListener.Hostnames = append(irListener.Hostnames, "*")
}
gwXdsIR.HTTP = append(gwXdsIR.HTTP, irListener)
xdsIR[irKey].HTTP = append(xdsIR[irKey].HTTP, irListener)
}

// Add the listener to the Infra IR. Infra IR ports must have a unique port number per layer-4 protocol
Expand All @@ -139,14 +133,20 @@ func (t *Translator) ProcessListeners(gateways []*GatewayContext, xdsIR XdsIRMap
case gwapiv1.UDPProtocolType:
proto = ir.UDPProtocolType
}

infraPortName := string(listener.Name)
if t.MergeGateways {
infraPortName = irHTTPListenerName(listener)
}

infraPort := ir.ListenerPort{
Name: string(listener.Name),
Name: infraPortName,
Protocol: proto,
ServicePort: servicePort.port,
ContainerPort: containerPort,
}
// Only 1 listener is supported.
gwInfraIR.Proxy.Listeners[0].Ports = append(gwInfraIR.Proxy.Listeners[0].Ports, infraPort)
infraIR[irKey].Proxy.Listeners[0].Ports = append(infraIR[irKey].Proxy.Listeners[0].Ports, infraPort)
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
perHostRoutes = append(perHostRoutes, hostRoute)
}
}

irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)
irKey := t.getIRKey(listener.gateway)
irListener := xdsIR[irKey].GetHTTPListener(irHTTPListenerName(listener))
if irListener != nil {
if GetRouteType(route) == KindGRPCRoute {
Expand Down Expand Up @@ -669,7 +668,8 @@ func (t *Translator) processTLSRouteParentRefs(tlsRoute *TLSRouteContext, resour

hasHostnameIntersection = true

irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)
irKey := t.getIRKey(listener.gateway)

containerPort := servicePortToContainerPort(int32(listener.Port))
// Create the TCP Listener while parsing the TLSRoute since
// the listener directly links to a routeDestination.
Expand Down Expand Up @@ -807,7 +807,9 @@ func (t *Translator) processUDPRouteParentRefs(udpRoute *UDPRouteContext, resour
continue
}
accepted = true
irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)

irKey := t.getIRKey(listener.gateway)

containerPort := servicePortToContainerPort(int32(listener.Port))
// Create the UDP Listener while parsing the UDPRoute since
// the listener directly links to a routeDestination.
Expand Down Expand Up @@ -942,7 +944,8 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour
continue
}
accepted = true
irKey := irStringKey(listener.gateway.Namespace, listener.gateway.Name)
irKey := t.getIRKey(listener.gateway)

containerPort := servicePortToContainerPort(int32(listener.Port))
// Create the TCP Listener while parsing the TCPRoute since
// the listener directly links to a routeDestination.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
envoyproxy:
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
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: gateway-2
namespace: envoy-gateway
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
port: 80
protocol: HTTP
- name: udp
port: 80
protocol: UDP
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
creationTimestamp: null
name: gateway-1
namespace: envoy-gateway
spec:
gatewayClassName: envoy-gateway-class
infrastructure: {}
listeners:
- 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:
creationTimestamp: null
name: gateway-2
namespace: envoy-gateway
spec:
gatewayClassName: envoy-gateway-class
infrastructure: {}
listeners:
- name: http
port: 80
protocol: HTTP
- name: udp
port: 80
protocol: UDP
status:
listeners:
- attachedRoutes: 0
conditions:
- lastTransitionTime: null
message: Port, protocol and hostname tuple must be unique for every listener
reason: HostnameConflict
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 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
- 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
supportedKinds:
- group: gateway.networking.k8s.io
kind: UDPRoute
infraIR:
envoy-gateway-class:
proxy:
config:
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
creationTimestamp: null
name: test
namespace: envoy-gateway-system
spec:
logging: {}
mergeGateways: true
telemetry: {}
status: {}
listeners:
- address: ""
ports:
- containerPort: 10080
name: envoy-gateway/gateway-1/http
protocol: HTTP
servicePort: 80
- containerPort: 10080
name: envoy-gateway/gateway-2/udp
protocol: UDP
servicePort: 80
metadata:
labels:
gateway.envoyproxy.io/owning-gatewayclass: envoy-gateway-class
name: envoy-gateway-class
xdsIR:
envoy-gateway-class:
accessLog:
text:
- path: /dev/stdout
http:
- address: 0.0.0.0
hostnames:
- '*'
isHTTP2: false
name: envoy-gateway/gateway-1/http
port: 10080
Loading