Skip to content
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
65 changes: 13 additions & 52 deletions internal/gatewayapi/contexts.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,51 +27,21 @@ type GatewayContext struct {
listeners []*ListenerContext
}

// GetListenerContext returns the ListenerContext with listenerName.
// If the listener exists in the Gateway Spec but NOT yet in the GatewayContext,
// this creates a new ListenerContext for the listener and attaches it to the
// GatewayContext.
func (g *GatewayContext) GetListenerContext(listenerName v1beta1.SectionName) *ListenerContext {
if g.listeners == nil {
g.listeners = make([]*ListenerContext, 0)
}

for _, l := range g.listeners {
if l.Name == listenerName {
return l
// ResetListeners resets the listener statuses and re-generates the GatewayContext
// ListenerContexts from the Gateway spec.
func (g *GatewayContext) ResetListeners() {
numListeners := len(g.Spec.Listeners)
g.Status.Listeners = make([]v1beta1.ListenerStatus, numListeners)
g.listeners = make([]*ListenerContext, numListeners)
for i := range g.Spec.Listeners {
listener := &g.Spec.Listeners[i]
g.Status.Listeners[i] = v1beta1.ListenerStatus{Name: listener.Name}
g.listeners[i] = &ListenerContext{
Listener: listener,
gateway: g.Gateway,
listenerStatusIdx: i,
}
}

var listener *v1beta1.Listener
for i, l := range g.Spec.Listeners {
if l.Name == listenerName {
listener = &g.Spec.Listeners[i]
break
}
}
if listener == nil {
panic("listener not found")
}

listenerStatusIdx := -1
for i := range g.Status.Listeners {
if g.Status.Listeners[i].Name == listenerName {
listenerStatusIdx = i
break
}
}
if listenerStatusIdx == -1 {
g.Status.Listeners = append(g.Status.Listeners, v1beta1.ListenerStatus{Name: listenerName})
listenerStatusIdx = len(g.Status.Listeners) - 1
}

ctx := &ListenerContext{
Listener: listener,
gateway: g.Gateway,
listenerStatusIdx: listenerStatusIdx,
}
g.listeners = append(g.listeners, ctx)
return ctx
}

// ListenerContext wraps a Listener and provides helper methods for
Expand Down Expand Up @@ -118,19 +88,10 @@ func (l *ListenerContext) SetCondition(conditionType v1beta1.ListenerConditionTy
}
}

func (l *ListenerContext) ResetConditions() {
l.gateway.Status.Listeners[l.listenerStatusIdx].Conditions = make([]metav1.Condition, 0)
}

func (l *ListenerContext) SetSupportedKinds(kinds ...v1beta1.RouteGroupKind) {
l.gateway.Status.Listeners[l.listenerStatusIdx].SupportedKinds = kinds
}

func (l *ListenerContext) ResetAttachedRoutes() {
// Reset attached route count since it will be recomputed during translation.
l.gateway.Status.Listeners[l.listenerStatusIdx].AttachedRoutes = 0
}

func (l *ListenerContext) IncrementAttachedRoutes() {
l.gateway.Status.Listeners[l.listenerStatusIdx].AttachedRoutes++
}
Expand Down
99 changes: 97 additions & 2 deletions internal/gatewayapi/contexts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ func TestContexts(t *testing.T) {
gctx := &GatewayContext{
Gateway: gateway,
}
gctx.ResetListeners()
require.Len(t, gctx.listeners, 1)

lctx := gctx.GetListenerContext("http")
lctx := gctx.listeners[0]
require.NotNil(t, lctx)

lctx.SetCondition(v1beta1.ListenerConditionAccepted, metav1.ConditionFalse, v1beta1.ListenerReasonUnsupportedProtocol, "HTTPS protocol is not supported yet")
Expand All @@ -51,6 +53,99 @@ func TestContexts(t *testing.T) {
require.Len(t, gateway.Status.Listeners[0].SupportedKinds, 1)
require.EqualValues(t, gateway.Status.Listeners[0].SupportedKinds[0].Kind, "HTTPRoute")

lctx.ResetConditions()
gctx.ResetListeners()
require.Len(t, gateway.Status.Listeners[0].Conditions, 0)
}

func TestContextsStaleListener(t *testing.T) {
gateway := &v1beta1.Gateway{
ObjectMeta: metav1.ObjectMeta{
Namespace: "envoy-gateway",
Name: "gateway-1",
},
Spec: v1beta1.GatewaySpec{
Listeners: []v1beta1.Listener{
{
Name: "https",
},
{
Name: "http",
},
},
},
Status: v1beta1.GatewayStatus{
Listeners: []v1beta1.ListenerStatus{
{
Name: "https",
Conditions: []metav1.Condition{
{
Status: metav1.ConditionStatus(v1beta1.ListenerConditionProgrammed),
},
},
},
{
Name: "http",
Conditions: []metav1.Condition{
{
Status: metav1.ConditionStatus(v1beta1.ListenerConditionProgrammed),
},
},
},
},
},
}

gCtx := &GatewayContext{Gateway: gateway}

httpsListenerCtx := &ListenerContext{
Listener: &v1beta1.Listener{
Name: "https",
},
gateway: gateway,
listenerStatusIdx: 0,
}

httpListenerCtx := &ListenerContext{
Listener: &v1beta1.Listener{
Name: "http",
},
gateway: gateway,
listenerStatusIdx: 1,
}

gCtx.ResetListeners()

require.Len(t, gCtx.listeners, 2)

expectedListenerContexts := []*ListenerContext{
httpsListenerCtx,
httpListenerCtx,
}
require.EqualValues(t, expectedListenerContexts, gCtx.listeners)

require.Len(t, gCtx.Status.Listeners, 2)

expectedListenerStatuses := []v1beta1.ListenerStatus{
{
Name: "https",
},
{
Name: "http",
},
}
require.EqualValues(t, expectedListenerStatuses, gCtx.Status.Listeners)

// Remove one of the listeners
gateway.Spec.Listeners = gateway.Spec.Listeners[:1]

gCtx.ResetListeners()

// Ensure the listener status has been updated and the stale listener has been
// removed.
expectedListenerStatus := []v1beta1.ListenerStatus{{Name: "https"}}
require.EqualValues(t, expectedListenerStatus, gCtx.Gateway.Status.Listeners)

// Ensure that the listeners within GatewayContext have been properly updated.
expectedGCtxListeners := []*ListenerContext{httpsListenerCtx}
require.EqualValues(t, expectedGCtxListeners, gCtx.listeners)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: default
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
status:
listeners:
- name: http
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
attachedRoutes: 1
conditions:
- type: Programmed
status: "True"
reason: Programmed
message: Listener is ready
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
spec:
parentRefs:
- namespace: default
name: gateway-1
rules:
- matches:
- path:
value: "/"
backendRefs:
- name: service-1
port: 8080
status:
parents:
- parentRef:
namespace: default
name: gateway-1
controllerName: gateway.envoyproxy.io/gatewayclass-controller
conditions:
- type: Accepted
status: "True"
reason: Accepted
message: Route is accepted
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
namespace: default
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
status:
listeners:
- name: http
supportedKinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
attachedRoutes: 1
conditions:
- type: Programmed
status: "True"
reason: Programmed
message: Listener is ready
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
spec:
parentRefs:
- namespace: default
name: gateway-1
rules:
- matches:
- path:
value: "/"
backendRefs:
- name: service-1
port: 8080
status:
parents:
- parentRef:
namespace: default
name: gateway-1
controllerName: gateway.envoyproxy.io/gatewayclass-controller
conditions:
- type: Accepted
status: "True"
reason: Accepted
message: Route is accepted
xdsIR:
default-gateway-1:
http:
- name: default-gateway-1-http
address: 0.0.0.0
port: 10080
hostnames:
- "*"
routes:
- name: default-httproute-1-rule-0-match-0-*
pathMatch:
prefix: "/"
destinations:
- host: 7.7.7.7
port: 8080
weight: 1
infraIR:
default-gateway-1:
proxy:
metadata:
labels:
gateway.envoyproxy.io/owning-gateway-namespace: default
gateway.envoyproxy.io/owning-gateway-name: gateway-1
name: default-gateway-1
image: envoyproxy/envoy:translator-tests
listeners:
- address: ""
ports:
- name: http
protocol: "HTTP"
servicePort: 80
containerPort: 10080
Loading