Skip to content

Commit 955feeb

Browse files
committed
Add status updater for backendtlspolicy, move logic
1 parent 871ffc1 commit 955feeb

File tree

18 files changed

+917
-510
lines changed

18 files changed

+917
-510
lines changed

deploy/helm-chart/templates/rbac.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ rules:
8787
- httproutes/status
8888
- gateways/status
8989
- gatewayclasses/status
90+
- backendtlspolicies/status
9091
verbs:
9192
- update
9293
- apiGroups:

deploy/manifests/nginx-gateway.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ rules:
8787
- httproutes/status
8888
- gateways/status
8989
- gatewayclasses/status
90+
- backendtlspolicies/status
9091
verbs:
9192
- update
9293
- apiGroups:
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package status
2+
3+
import (
4+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
5+
v1 "sigs.k8s.io/gateway-api/apis/v1"
6+
"sigs.k8s.io/gateway-api/apis/v1alpha2"
7+
)
8+
9+
// prepareBackendTLSPolicyStatus prepares the status for a BackendTLSPolicy resource.
10+
func prepareBackendTLSPolicyStatus(
11+
oldStatus v1alpha2.PolicyStatus,
12+
status BackendTLSPolicyStatus,
13+
gatewayCtlrName string,
14+
transitionTime metav1.Time,
15+
) v1alpha2.PolicyStatus {
16+
// maxAncestors is the max number of ancestor statuses which is the sum of all new ancestor statuses and all old
17+
// ancestor statuses.
18+
maxAncestors := len(status.AncestorStatuses) + len(oldStatus.Ancestors)
19+
ancestors := make([]v1alpha2.PolicyAncestorStatus, 0, maxAncestors)
20+
21+
// keep all the ancestor statuses that belong to other controllers
22+
for _, os := range oldStatus.Ancestors {
23+
if string(os.ControllerName) != gatewayCtlrName {
24+
ancestors = append(ancestors, os)
25+
}
26+
}
27+
28+
for _, as := range status.AncestorStatuses {
29+
// reassign the iteration variable inside the loop to fix implicit memory aliasing
30+
as := as
31+
a := v1alpha2.PolicyAncestorStatus{
32+
AncestorRef: v1.ParentReference{
33+
Namespace: (*v1.Namespace)(&as.GatewayNsName.Namespace),
34+
Name: v1alpha2.ObjectName(as.GatewayNsName.Name),
35+
},
36+
ControllerName: v1alpha2.GatewayController(gatewayCtlrName),
37+
Conditions: convertConditions(as.Conditions, status.ObservedGeneration, transitionTime),
38+
}
39+
ancestors = append(ancestors, a)
40+
}
41+
42+
return v1alpha2.PolicyStatus{
43+
Ancestors: ancestors,
44+
}
45+
}

internal/framework/status/setters.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
77
"sigs.k8s.io/controller-runtime/pkg/client"
88
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
9+
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
910

1011
ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
1112
)
@@ -85,6 +86,25 @@ func newHTTPRouteStatusSetter(gatewayCtlrName string, clock Clock, rs HTTPRouteS
8586
}
8687
}
8788

89+
func newBackendTLSPolicyStatusSetter(
90+
gatewayCtlrName string,
91+
clock Clock,
92+
bs BackendTLSPolicyStatus,
93+
) func(client.Object) bool {
94+
return func(object client.Object) bool {
95+
btp := object.(*gatewayv1alpha2.BackendTLSPolicy)
96+
status := prepareBackendTLSPolicyStatus(btp.Status, bs, gatewayCtlrName, clock.Now())
97+
98+
if btpStatusEqual(gatewayCtlrName, btp.Status, status) {
99+
return false
100+
}
101+
102+
btp.Status = status
103+
104+
return true
105+
}
106+
}
107+
88108
func gwStatusEqual(prev, cur gatewayv1.GatewayStatus) bool {
89109
addressesEqual := slices.EqualFunc(prev.Addresses, cur.Addresses, func(a1, a2 gatewayv1.GatewayStatusAddress) bool {
90110
if !equalPointers[gatewayv1.AddressType](a1.Type, a2.Type) {
@@ -181,6 +201,58 @@ func routeParentStatusEqual(p1, p2 gatewayv1.RouteParentStatus) bool {
181201
return conditionsEqual(p1.Conditions, p2.Conditions)
182202
}
183203

204+
func btpStatusEqual(gatewayCtlrName string, prev, cur gatewayv1alpha2.PolicyStatus) bool {
205+
// Since other controllers may update BackendTLSPolicy status we can't assume anything about the order of the
206+
// statuses, and we have to ignore statuses written by other controllers when checking for equality.
207+
// Therefore, we can't use slices.EqualFunc here because it cares about the order.
208+
209+
// First, we check if the prev status has any PolicyAncestorStatuses that are no longer present in the cur status.
210+
for _, prevAncestor := range prev.Ancestors {
211+
if prevAncestor.ControllerName != gatewayv1.GatewayController(gatewayCtlrName) {
212+
continue
213+
}
214+
215+
exists := slices.ContainsFunc(cur.Ancestors, func(curAncestor gatewayv1alpha2.PolicyAncestorStatus) bool {
216+
return btpAncestorStatusEqual(prevAncestor, curAncestor)
217+
})
218+
219+
if !exists {
220+
return false
221+
}
222+
}
223+
224+
// Then, we check if the cur status has any PolicyAncestorStatuses that are no longer present in the prev status.
225+
for _, curParent := range cur.Ancestors {
226+
exists := slices.ContainsFunc(prev.Ancestors, func(prevAncestor gatewayv1alpha2.PolicyAncestorStatus) bool {
227+
return btpAncestorStatusEqual(curParent, prevAncestor)
228+
})
229+
230+
if !exists {
231+
return false
232+
}
233+
}
234+
235+
return true
236+
}
237+
238+
func btpAncestorStatusEqual(p1, p2 gatewayv1alpha2.PolicyAncestorStatus) bool {
239+
if p1.ControllerName != p2.ControllerName {
240+
return false
241+
}
242+
243+
if p1.AncestorRef.Name != p2.AncestorRef.Name {
244+
return false
245+
}
246+
247+
if !equalPointers(p1.AncestorRef.Namespace, p2.AncestorRef.Namespace) {
248+
return false
249+
}
250+
251+
// we ignore the rest of the AncestorRef fields because we do not set them
252+
253+
return conditionsEqual(p1.Conditions, p2.Conditions)
254+
}
255+
184256
func conditionsEqual(prev, cur []v1.Condition) bool {
185257
return slices.EqualFunc(prev, cur, func(c1, c2 v1.Condition) bool {
186258
if c1.ObservedGeneration != c2.ObservedGeneration {

internal/framework/status/statuses.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ type Status interface {
1616

1717
// GatewayAPIStatuses holds the status-related information about Gateway API resources.
1818
type GatewayAPIStatuses struct {
19-
GatewayClassStatuses GatewayClassStatuses
20-
GatewayStatuses GatewayStatuses
21-
HTTPRouteStatuses HTTPRouteStatuses
19+
GatewayClassStatuses GatewayClassStatuses
20+
GatewayStatuses GatewayStatuses
21+
HTTPRouteStatuses HTTPRouteStatuses
22+
BackendTLSPolicyStatuses BackendTLSPolicyStatuses
2223
}
2324

2425
func (g GatewayAPIStatuses) APIGroup() string {
@@ -51,6 +52,10 @@ type GatewayStatuses map[types.NamespacedName]GatewayStatus
5152
// GatewayClassStatuses holds the statuses of GatewayClasses where the key is the namespaced name of a GatewayClass.
5253
type GatewayClassStatuses map[types.NamespacedName]GatewayClassStatus
5354

55+
// BackendTLSPolicyStatuses holds the statuses of BackendTLSPolicies where the key is the namespaced name of a
56+
// BackendTLSPolicy.
57+
type BackendTLSPolicyStatuses map[types.NamespacedName]BackendTLSPolicyStatus
58+
5459
// GatewayStatus holds the status of the winning Gateway resource.
5560
type GatewayStatus struct {
5661
// ListenerStatuses holds the statuses of listeners defined on the Gateway.
@@ -85,6 +90,14 @@ type HTTPRouteStatus struct {
8590
ObservedGeneration int64
8691
}
8792

93+
// BackendTLSPolicyStatus holds the status-related information about a BackendTLSPolicy resource.
94+
type BackendTLSPolicyStatus struct {
95+
// AncestorStatuses holds the statuses for parentRefs of the BackendTLSPolicy.
96+
AncestorStatuses []AncestorStatus
97+
// ObservedGeneration is the generation of the resource that was processed.
98+
ObservedGeneration int64
99+
}
100+
88101
// ParentStatus holds status-related information related to how the HTTPRoute binds to a specific parentRef.
89102
type ParentStatus struct {
90103
// GatewayNsName is the Namespaced name of the Gateway, which the parentRef references.
@@ -102,3 +115,10 @@ type GatewayClassStatus struct {
102115
// ObservedGeneration is the generation of the resource that was processed.
103116
ObservedGeneration int64
104117
}
118+
119+
type AncestorStatus struct {
120+
// GatewayNsName is the Namespaced name of the Gateway, which the ancestorRef references.
121+
GatewayNsName types.NamespacedName
122+
// Conditions is the list of conditions that are relevant to the ancestor.
123+
Conditions []conditions.Condition
124+
}

internal/framework/status/updater.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"k8s.io/apimachinery/pkg/util/wait"
1414
"sigs.k8s.io/controller-runtime/pkg/client"
1515
v1 "sigs.k8s.io/gateway-api/apis/v1"
16+
"sigs.k8s.io/gateway-api/apis/v1alpha2"
1617

1718
ngfAPI "github.com/nginxinc/nginx-gateway-fabric/apis/v1alpha1"
1819
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/controller"
@@ -204,6 +205,21 @@ func (upd *UpdaterImpl) updateGatewayAPI(ctx context.Context, statuses GatewayAP
204205
newHTTPRouteStatusSetter(upd.cfg.GatewayCtlrName, upd.cfg.Clock, rs),
205206
)
206207
}
208+
209+
for nsname, bs := range statuses.BackendTLSPolicyStatuses {
210+
select {
211+
case <-ctx.Done():
212+
return
213+
default:
214+
}
215+
216+
upd.writeStatuses(
217+
ctx,
218+
nsname,
219+
&v1alpha2.BackendTLSPolicy{},
220+
newBackendTLSPolicyStatusSetter(upd.cfg.GatewayCtlrName, upd.cfg.Clock, bs),
221+
)
222+
}
207223
}
208224

209225
func (upd *UpdaterImpl) writeStatuses(

internal/mode/static/build_statuses.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ func buildGatewayAPIStatuses(
2929

3030
statuses.GatewayStatuses = buildGatewayStatuses(graph.Gateway, graph.IgnoredGateways, gwAddresses, nginxReloadRes)
3131

32+
statuses.BackendTLSPolicyStatuses = buildBackendTLSPolicyStatuses(graph.BackendTLSPolicies)
33+
3234
for nsname, r := range graph.Routes {
3335
parentStatuses := make([]status.ParentStatus, 0, len(r.ParentRefs))
3436

@@ -190,3 +192,33 @@ func buildGatewayStatus(
190192
ObservedGeneration: gateway.Source.Generation,
191193
}
192194
}
195+
196+
func buildBackendTLSPolicyStatuses(backendTLSPolicies map[types.NamespacedName]*graph.BackendTLSPolicy,
197+
) status.BackendTLSPolicyStatuses {
198+
statuses := make(status.BackendTLSPolicyStatuses, len(backendTLSPolicies))
199+
ignoreStatus := false
200+
201+
for nsname, backendTLSPolicy := range backendTLSPolicies {
202+
if backendTLSPolicy.IsReferenced {
203+
if !backendTLSPolicy.Valid {
204+
for i := range backendTLSPolicy.Conditions {
205+
if backendTLSPolicy.Conditions[i].Reason == string(staticConds.BackendTLSPolicyReasonIgnored) {
206+
// We should not report the status of an ignored BackendTLSPolicy.
207+
ignoreStatus = true
208+
}
209+
}
210+
}
211+
if !ignoreStatus {
212+
statuses[nsname] = status.BackendTLSPolicyStatus{
213+
AncestorStatuses: []status.AncestorStatus{
214+
{
215+
GatewayNsName: backendTLSPolicy.Gateway,
216+
Conditions: conditions.DeduplicateConditions(backendTLSPolicy.Conditions),
217+
},
218+
},
219+
}
220+
}
221+
}
222+
}
223+
return statuses
224+
}

internal/mode/static/build_statuses_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ func TestBuildStatuses(t *testing.T) {
202202
},
203203
},
204204
},
205+
BackendTLSPolicyStatuses: status.BackendTLSPolicyStatuses{},
205206
}
206207

207208
g := NewWithT(t)
@@ -304,6 +305,7 @@ func TestBuildStatusesNginxErr(t *testing.T) {
304305
},
305306
},
306307
},
308+
BackendTLSPolicyStatuses: status.BackendTLSPolicyStatuses{},
307309
}
308310

309311
g := NewWithT(t)

internal/mode/static/state/conditions/conditions.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ import (
1010
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/conditions"
1111
)
1212

13+
// BackendTLSPolicyConditionType is a type of condition associated with a BackendTLSPolicy.
14+
// This type should be used with the BackendTLSPolicyStatus.Conditions field.
15+
type BackendTLSPolicyConditionType string
16+
17+
// BackendTLSPolicyConditionReason defines the set of reasons that explain why a particular BackendTLSPolicy condition
18+
// type has been raised.
19+
type BackendTLSPolicyConditionReason string
20+
1321
const (
1422
// ListenerReasonUnsupportedValue is used with the "Accepted" condition when a value of a field in a Listener
1523
// is invalid or not supported.
@@ -57,6 +65,22 @@ const (
5765
RouteMessageFailedNginxReload = GatewayMessageFailedNginxReload + ". NGINX may still be configured " +
5866
"for this HTTPRoute. However, future updates to this resource will not be configured until the Gateway " +
5967
"is programmed again"
68+
69+
// BackendTLSPolicyConditionAttached is the condition type indicating the BackendTLS policy is valid and attached to
70+
// the Gateway.
71+
BackendTLSPolicyConditionAttached BackendTLSPolicyConditionType = "Attached"
72+
73+
// BackendTLSPolicyReasonAttached is the condition reason for the BackendTLSPolicy Attached condition.
74+
BackendTLSPolicyReasonAttached BackendTLSPolicyConditionReason = "BackendTLSPolicyAttached"
75+
76+
// BackendTLSPolicyReasonIgnored is the condition reason for the BackendTLSPolicy being ignored by this Gateway.
77+
BackendTLSPolicyReasonIgnored BackendTLSPolicyConditionReason = "BackendTLSPolicyIgnored"
78+
79+
// BackendTLSPolicyConditionValid is the condition type indicating whether the BackendTLS policy is valid.
80+
BackendTLSPolicyConditionValid BackendTLSPolicyConditionType = "Valid"
81+
82+
// BackendTLSPolicyReasonInvalid is the condition reason for the BackendTLSPolicy Valid condition being False.
83+
BackendTLSPolicyReasonInvalid BackendTLSPolicyConditionReason = "BackendTLSPolicyInvalid"
6084
)
6185

6286
// NewTODO returns a Condition that can be used as a placeholder for a condition that is not yet implemented.
@@ -545,3 +569,35 @@ func NewNginxGatewayInvalid(msg string) conditions.Condition {
545569
Message: msg,
546570
}
547571
}
572+
573+
// NewBackendTLSPolicyAttached returns a Condition that indicates that the BackendTLSPolicy config is valid and attached
574+
// to the Gateway.
575+
func NewBackendTLSPolicyAttached() conditions.Condition {
576+
return conditions.Condition{
577+
Type: string(BackendTLSPolicyConditionAttached),
578+
Status: metav1.ConditionTrue,
579+
Reason: string(BackendTLSPolicyReasonAttached),
580+
Message: "BackendTLSPolicy is attached to the Gateway",
581+
}
582+
}
583+
584+
// NewBackendTLSPolicyIgnored returns a Condition that indicates that the BackendTLSPolicy config cannot be attached to
585+
// the Gateway and will be ignored.
586+
func NewBackendTLSPolicyIgnored(msg string) conditions.Condition {
587+
return conditions.Condition{
588+
Type: string(BackendTLSPolicyConditionAttached),
589+
Status: metav1.ConditionFalse,
590+
Reason: string(BackendTLSPolicyReasonIgnored),
591+
Message: msg,
592+
}
593+
}
594+
595+
// NewBackendTLSPolicyInvalid returns a Condition that indicates that the BackendTLSPolicy config is invalid.
596+
func NewBackendTLSPolicyInvalid(msg string) conditions.Condition {
597+
return conditions.Condition{
598+
Type: string(BackendTLSPolicyConditionValid),
599+
Status: metav1.ConditionFalse,
600+
Reason: string(BackendTLSPolicyReasonInvalid),
601+
Message: msg,
602+
}
603+
}

0 commit comments

Comments
 (0)