Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
8 changes: 7 additions & 1 deletion internal/mode/static/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,18 @@ func (h *eventHandlerImpl) updateStatuses(ctx context.Context, logger logr.Logge

polReqs := status.PrepareBackendTLSPolicyRequests(graph.BackendTLSPolicies, transitionTime, h.cfg.gatewayCtlrName)
ngfPolReqs := status.PrepareNGFPolicyRequests(graph.NGFPolicies, transitionTime, h.cfg.gatewayCtlrName)
snippetFilterReqs := status.PrepareSnippetsFilterRequests(graph.SnippetsFilters, transitionTime)

reqs := make([]frameworkStatus.UpdateRequest, 0, len(gcReqs)+len(routeReqs)+len(polReqs)+len(ngfPolReqs))
reqs := make(
[]frameworkStatus.UpdateRequest,
0,
len(gcReqs)+len(routeReqs)+len(polReqs)+len(ngfPolReqs)+len(snippetFilterReqs),
)
reqs = append(reqs, gcReqs...)
reqs = append(reqs, routeReqs...)
reqs = append(reqs, polReqs...)
reqs = append(reqs, ngfPolReqs...)
reqs = append(reqs, snippetFilterReqs...)

h.cfg.statusUpdater.UpdateGroup(ctx, groupAllExceptGateways, reqs...)

Expand Down
11 changes: 11 additions & 0 deletions internal/mode/static/state/conditions/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -744,3 +744,14 @@ func NewSnippetsFilterInvalid(msg string) conditions.Condition {
Message: msg,
}
}

// NewSnippetFilterAccepted returns a Condition that indicates that the SnippetsFilter is accepted because it is
// valid.
func NewSnippetFilterAccepted() conditions.Condition {
return conditions.Condition{
Type: string(ngfAPI.SnippetsFilterConditionTypeAccepted),
Status: metav1.ConditionTrue,
Reason: string(ngfAPI.SnippetsFilterConditionReasonAccepted),
Message: "SnippetsFilter is accepted",
}
}
32 changes: 32 additions & 0 deletions internal/mode/static/status/prepare_requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,38 @@ func PrepareBackendTLSPolicyRequests(
return reqs
}

// PrepareSnippetsFilterRequests prepares status UpdateRequests for the given SnippetsFilters.
func PrepareSnippetsFilterRequests(
snippetsFilter map[types.NamespacedName]*graph.SnippetsFilter,
transitionTime metav1.Time,
) []frameworkStatus.UpdateRequest {
reqs := make([]frameworkStatus.UpdateRequest, 0, len(snippetsFilter))

for nsname, snippetFilter := range snippetsFilter {
allConds := make([]conditions.Condition, 0, len(snippetFilter.Conditions)+1)

// The order of conditions matters here.
// We add the default condition first, followed by the snippetsFilter conditions.
// DeduplicateConditions will ensure the last condition wins.
allConds = append(allConds, staticConds.NewSnippetFilterAccepted())
allConds = append(allConds, snippetFilter.Conditions...)

conds := conditions.DeduplicateConditions(allConds)
apiConds := conditions.ConvertConditions(conds, snippetFilter.Source.GetGeneration(), transitionTime)
status := ngfAPI.SnippetsFilterStatus{
Conditions: apiConds,
}

reqs = append(reqs, frameworkStatus.UpdateRequest{
NsName: nsname,
ResourceType: snippetFilter.Source,
Setter: newSnippetsFilterStatusSetter(status),
})
}

return reqs
}

// ControlPlaneUpdateResult describes the result of a control plane update.
type ControlPlaneUpdateResult struct {
// Error is the error that occurred during the update.
Expand Down
119 changes: 119 additions & 0 deletions internal/mode/static/status/prepare_requests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1768,3 +1768,122 @@ func TestBuildNGFPolicyStatuses(t *testing.T) {
})
}
}

func TestBuildSnippetFilterStatuses(t *testing.T) {
transitionTime := helpers.PrepareTimeForFakeClient(metav1.Now())

validSnippet := &graph.SnippetsFilter{
Source: &ngfAPI.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "valid-snippet",
Namespace: "test",
Generation: 1,
},
Spec: ngfAPI.SnippetsFilterSpec{
Snippets: []ngfAPI.Snippet{
{
Context: ngfAPI.NginxContextHTTP,
Value: "proxy_buffer on;",
},
},
},
},
Valid: true,
}

invalidSnippet := &graph.SnippetsFilter{
Source: &ngfAPI.SnippetsFilter{
ObjectMeta: metav1.ObjectMeta{
Name: "invalid-snippet",
Namespace: "test",
Generation: 1,
},
},
Conditions: []conditions.Condition{staticConds.NewSnippetsFilterInvalid("invalid snippetsFilter")},
Valid: false,
}

tests := []struct {
snippetsFilters map[types.NamespacedName]*graph.SnippetsFilter
expected map[types.NamespacedName]ngfAPI.SnippetsFilterStatus
name string
expectedReqs int
}{
{
name: "nil snippetsFilters",
expectedReqs: 0,
expected: map[types.NamespacedName]ngfAPI.SnippetsFilterStatus{},
},
{
name: "valid snippet",
snippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{
{Namespace: "test", Name: "valid-snippet"}: validSnippet,
},
expectedReqs: 1,
expected: map[types.NamespacedName]ngfAPI.SnippetsFilterStatus{
{Namespace: "test", Name: "valid-snippet"}: {
Conditions: []metav1.Condition{
{
Type: string(ngfAPI.SnippetsFilterConditionTypeAccepted),
Status: metav1.ConditionTrue,
ObservedGeneration: 1,
LastTransitionTime: transitionTime,
Reason: string(ngfAPI.SnippetsFilterConditionReasonAccepted),
Message: "SnippetsFilter is accepted",
},
},
},
},
},
{
name: "invalid snippet",
snippetsFilters: map[types.NamespacedName]*graph.SnippetsFilter{
{Namespace: "test", Name: "invalid-snippet"}: invalidSnippet,
},
expectedReqs: 1,
expected: map[types.NamespacedName]ngfAPI.SnippetsFilterStatus{
{Namespace: "test", Name: "invalid-snippet"}: {
Conditions: []metav1.Condition{
{
Type: string(ngfAPI.SnippetsFilterConditionTypeAccepted),
Status: metav1.ConditionFalse,
ObservedGeneration: 1,
LastTransitionTime: transitionTime,
Reason: string(ngfAPI.SnippetsFilterConditionReasonInvalid),
Message: "invalid snippetsFilter",
},
},
},
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
g := NewWithT(t)

k8sClient := createK8sClientFor(&ngfAPI.SnippetsFilter{})

for _, snippets := range test.snippetsFilters {
err := k8sClient.Create(context.Background(), snippets.Source)
g.Expect(err).ToNot(HaveOccurred())
}

updater := statusFramework.NewUpdater(k8sClient, zap.New())

reqs := PrepareSnippetsFilterRequests(test.snippetsFilters, transitionTime)

g.Expect(reqs).To(HaveLen(test.expectedReqs))

updater.Update(context.Background(), reqs...)

for nsname, expected := range test.expected {
var snippets ngfAPI.SnippetsFilter

err := k8sClient.Get(context.Background(), nsname, &snippets)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(helpers.Diff(expected, snippets.Status)).To(BeEmpty())
}
})
}
}
13 changes: 13 additions & 0 deletions internal/mode/static/status/status_setters.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,16 @@ func ancestorStatusEqual(p1, p2 v1alpha2.PolicyAncestorStatus) bool {

return frameworkStatus.ConditionsEqual(p1.Conditions, p2.Conditions)
}

func newSnippetsFilterStatusSetter(status ngfAPI.SnippetsFilterStatus) frameworkStatus.Setter {
return func(obj client.Object) (wasSet bool) {
sf := helpers.MustCastObject[*ngfAPI.SnippetsFilter](obj)

if frameworkStatus.ConditionsEqual(sf.Status.Conditions, status.Conditions) {
return false
}

sf.Status = status
return true
}
}
59 changes: 59 additions & 0 deletions internal/mode/static/status/status_setters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1563,3 +1563,62 @@ func TestPolicyStatusEqual(t *testing.T) {
})
}
}

func TestNewSnippetFilterStatusSetter(t *testing.T) {
tests := []struct {
name string
status, expStatus, newStatus ngfAPI.SnippetsFilterStatus
expStatusSet bool
}{
{
name: "SnippetFilter has no status",
newStatus: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "new condition"}},
},
expStatusSet: true,
expStatus: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "new condition"}},
},
},
{
name: "SnippetFilter has old status",
status: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "old condition"}},
},
newStatus: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "new condition"}},
},
expStatusSet: true,
expStatus: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "new condition"}},
},
},
{
name: "SnippetFilter has same status",
status: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "same condition"}},
},
newStatus: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "same condition"}},
},
expStatusSet: false,
expStatus: ngfAPI.SnippetsFilterStatus{
Conditions: []metav1.Condition{{Message: "same condition"}},
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
g := NewWithT(t)

setter := newSnippetsFilterStatusSetter(test.newStatus)
obj := &ngfAPI.SnippetsFilter{Status: test.status}

statusSet := setter(obj)

g.Expect(statusSet).To(Equal(test.expStatusSet))
g.Expect(obj.Status).To(Equal(test.expStatus))
})
}
}
Loading