Skip to content

Commit e3bd76e

Browse files
committed
add policyAffected status for policy target refs
1 parent 36e64ae commit e3bd76e

File tree

6 files changed

+543
-1
lines changed

6 files changed

+543
-1
lines changed

internal/controller/state/conditions/conditions.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,18 @@ const (
107107
// has an overlapping hostname:port/path combination with another Route.
108108
PolicyReasonTargetConflict v1alpha2.PolicyConditionReason = "TargetConflict"
109109

110+
// ClientSettingsPolicyAffected is used with the "PolicyAffected" condition when a
111+
// ClientSettingsPolicy is applied to a Gateway, HTTPRoute, or GRPCRoute.
112+
ClientSettingsPolicyAffected v1alpha2.PolicyConditionType = "ClientSettingsPolicyAffected"
113+
114+
// ObservabilityPolicyAffected is used with the "PolicyAffected" condition when an
115+
// ObservabilityPolicy is applied to a HTTPRoute, or GRPCRoute.
116+
ObservabilityPolicyAffected v1alpha2.PolicyConditionType = "ObservabilityPolicyAffected"
117+
118+
// PolicyAffectedReason is used with the "PolicyAffected" condition when a
119+
// ObservabilityPolicy or ClientSettingsPolicy is applied to Gateways or Routes.
120+
PolicyAffectedReason v1alpha2.PolicyConditionReason = "PolicyAffected"
121+
110122
// GatewayResolvedRefs condition indicates whether the controller was able to resolve the
111123
// parametersRef on the Gateway.
112124
GatewayResolvedRefs v1.GatewayConditionType = "ResolvedRefs"
@@ -185,6 +197,33 @@ func ConvertConditions(
185197
return apiConds
186198
}
187199

200+
// HasMatchingCondition checks if the given condition matches any of the existing conditions.
201+
func HasMatchingCondition(existingConditions []Condition, cond Condition) bool {
202+
condMap := make(map[Condition]struct{}, len(existingConditions))
203+
for _, cond := range existingConditions {
204+
key := Condition{
205+
Type: cond.Type,
206+
Status: cond.Status,
207+
Reason: cond.Reason,
208+
Message: cond.Message,
209+
}
210+
condMap[key] = struct{}{}
211+
}
212+
213+
key := Condition{
214+
Type: cond.Type,
215+
Status: cond.Status,
216+
Reason: cond.Reason,
217+
Message: cond.Message,
218+
}
219+
220+
if _, exists := condMap[key]; exists {
221+
return true
222+
}
223+
224+
return false
225+
}
226+
188227
// NewDefaultGatewayClassConditions returns Conditions that indicate that the GatewayClass is accepted and that the
189228
// Gateway API CRD versions are supported.
190229
func NewDefaultGatewayClassConditions() []Condition {
@@ -940,3 +979,25 @@ func NewSnippetsFilterAccepted() Condition {
940979
Message: "SnippetsFilter is accepted",
941980
}
942981
}
982+
983+
// NewObservabilityPolicyAffected returns a Condition that indicates that an ObservabilityPolicy
984+
// is applied to the resource.
985+
func NewObservabilityPolicyAffected() Condition {
986+
return Condition{
987+
Type: string(ObservabilityPolicyAffected),
988+
Status: metav1.ConditionTrue,
989+
Reason: string(PolicyAffectedReason),
990+
Message: "ObservabilityPolicy is applied to the resource",
991+
}
992+
}
993+
994+
// NewClientSettingsPolicyAffected returns a Condition that indicates that a ClientSettingsPolicy
995+
// is applied to the resource.
996+
func NewClientSettingsPolicyAffected() Condition {
997+
return Condition{
998+
Type: string(ClientSettingsPolicyAffected),
999+
Status: metav1.ConditionTrue,
1000+
Reason: string(PolicyAffectedReason),
1001+
Message: "ClientSettingsPolicy is applied to the resource",
1002+
}
1003+
}

internal/controller/state/conditions/conditions_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,43 @@ func TestConvertConditions(t *testing.T) {
105105
result := ConvertConditions(conds, generation, time)
106106
g.Expect(result).Should(Equal(expected))
107107
}
108+
109+
func TestHasMatchingConding(t *testing.T) {
110+
t.Parallel()
111+
112+
tests := []struct {
113+
condition Condition
114+
name string
115+
conds []Condition
116+
expected bool
117+
}{
118+
{
119+
name: "no conditions in the list",
120+
conds: nil,
121+
condition: NewClientSettingsPolicyAffected(),
122+
expected: false,
123+
},
124+
{
125+
name: "condition matches existing condition",
126+
conds: []Condition{NewClientSettingsPolicyAffected()},
127+
condition: NewClientSettingsPolicyAffected(),
128+
expected: true,
129+
},
130+
{
131+
name: "condition does not match existing condition",
132+
conds: []Condition{NewClientSettingsPolicyAffected()},
133+
condition: NewObservabilityPolicyAffected(),
134+
expected: false,
135+
},
136+
}
137+
138+
for _, test := range tests {
139+
t.Run(test.name, func(t *testing.T) {
140+
t.Parallel()
141+
g := NewWithT(t)
142+
143+
result := HasMatchingCondition(test.conds, test.condition)
144+
g.Expect(result).To(Equal(test.expected))
145+
})
146+
}
147+
}

internal/controller/state/graph/graph.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,9 @@ func BuildGraph(
280280
gws,
281281
)
282282

283+
// add status conditions to each targetRef based on the policies that affect them.
284+
addPolicyAffectedStatusToTargetRefs(processedPolicies, routes, gws)
285+
283286
setPlusSecretContent(state.Secrets, plusSecrets)
284287

285288
g := &Graph{

internal/controller/state/graph/graph_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,9 @@ func TestBuildGraph(t *testing.T) {
765765
Rules: []RouteRule{createValidRuleWithBackendRefsAndFilters(routeMatches, RouteTypeHTTP)},
766766
},
767767
Policies: []*Policy{processedRoutePolicy},
768+
Conditions: []conditions.Condition{
769+
conditions.NewClientSettingsPolicyAffected(),
770+
},
768771
}
769772

770773
routeTR := &L4Route{
@@ -1080,7 +1083,10 @@ func TestBuildGraph(t *testing.T) {
10801083
ErrorLevel: helpers.GetPointer(ngfAPIv1alpha2.NginxLogLevelError),
10811084
},
10821085
},
1083-
Conditions: []conditions.Condition{conditions.NewGatewayResolvedRefs()},
1086+
Conditions: []conditions.Condition{
1087+
conditions.NewGatewayResolvedRefs(),
1088+
conditions.NewClientSettingsPolicyAffected(),
1089+
},
10841090
DeploymentName: types.NamespacedName{
10851091
Namespace: "test",
10861092
Name: "gateway-1-my-class",

internal/controller/state/graph/policies.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,60 @@ func refGroupKind(group v1.Group, kind v1.Kind) string {
448448

449449
return fmt.Sprintf("%s/%s", group, kind)
450450
}
451+
452+
// addPolicyAffectedStatusToTargetRefs adds the policyAffected status to the target references
453+
// of ClientSetttingsPolicies and ObservabilityPolicies.
454+
func addPolicyAffectedStatusToTargetRefs(
455+
processedPolicies map[PolicyKey]*Policy,
456+
routes map[RouteKey]*L7Route,
457+
gws map[types.NamespacedName]*Gateway,
458+
) {
459+
for policyKey, policy := range processedPolicies {
460+
for _, ref := range policy.TargetRefs {
461+
switch ref.Kind {
462+
case kinds.Gateway:
463+
if !gatewayExists(ref.Nsname, gws) {
464+
continue
465+
}
466+
gw := gws[ref.Nsname]
467+
if gw == nil {
468+
continue
469+
}
470+
471+
// set the policy status on the Gateway.
472+
policyKind := policyKey.GVK.Kind
473+
addStatusToTargetRefs(policyKind, &gw.Conditions)
474+
case kinds.HTTPRoute, kinds.GRPCRoute:
475+
routeKey := routeKeyForKind(ref.Kind, ref.Nsname)
476+
l7route, exists := routes[routeKey]
477+
if !exists {
478+
continue
479+
}
480+
481+
// set the policy status on L7 routes.
482+
policyKind := policyKey.GVK.Kind
483+
addStatusToTargetRefs(policyKind, &l7route.Conditions)
484+
default:
485+
continue
486+
}
487+
}
488+
}
489+
}
490+
491+
func addStatusToTargetRefs(policyKind string, conditionsList *[]conditions.Condition) {
492+
if conditionsList == nil {
493+
return
494+
}
495+
switch policyKind {
496+
case kinds.ObservabilityPolicy:
497+
if conditions.HasMatchingCondition(*conditionsList, conditions.NewObservabilityPolicyAffected()) {
498+
return
499+
}
500+
*conditionsList = append(*conditionsList, conditions.NewObservabilityPolicyAffected())
501+
case kinds.ClientSettingsPolicy:
502+
if conditions.HasMatchingCondition(*conditionsList, conditions.NewClientSettingsPolicyAffected()) {
503+
return
504+
}
505+
*conditionsList = append(*conditionsList, conditions.NewClientSettingsPolicyAffected())
506+
}
507+
}

0 commit comments

Comments
 (0)