Skip to content

Commit d8ea4b6

Browse files
committed
Update HTTPRoutePolicy status on resource deletion
Add logic to update HTTPRoutePolicy status when associated Ingress or HTTPRoute resources are deleted. Introduce new methods to handle status updates and remove ancestor references, along with corresponding e2e tests for ingress and gateway API scenarios.
1 parent cf9f3ef commit d8ea4b6

File tree

6 files changed

+151
-19
lines changed

6 files changed

+151
-19
lines changed

internal/controller/httproute_controller.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ func (r *HTTPRouteReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
9797
hr := new(gatewayv1.HTTPRoute)
9898
if err := r.Get(ctx, req.NamespacedName, hr); err != nil {
9999
if client.IgnoreNotFound(err) == nil {
100+
if err := r.updateHTTPRouteStatusOnDeleting(req.NamespacedName); err != nil {
101+
return ctrl.Result{}, err
102+
}
100103
hr.Namespace = req.Namespace
101104
hr.Name = req.Name
102105

internal/controller/httproutepolicy.go

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ package controller
22

33
import (
44
"context"
5-
"encoding/json"
5+
"slices"
66

7+
"github.com/go-logr/logr"
78
networkingv1 "k8s.io/api/networking/v1"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
"k8s.io/apimachinery/pkg/types"
@@ -41,8 +42,6 @@ func (r *HTTPRouteReconciler) processHTTPRoutePolicies(tctx *provider.TranslateC
4142
}
4243
}
4344
}
44-
data, _ := json.MarshalIndent(conflicts, "", " ")
45-
r.Log.Info("conflicts policies", "data", string(data))
4645

4746
for i := range list.Items {
4847
var (
@@ -67,6 +66,39 @@ func (r *HTTPRouteReconciler) processHTTPRoutePolicies(tctx *provider.TranslateC
6766
return nil
6867
}
6968

69+
func (r *HTTPRouteReconciler) updateHTTPRouteStatusOnDeleting(nn types.NamespacedName) error {
70+
var (
71+
list v1alpha1.HTTPRoutePolicyList
72+
key = indexer.GenIndexKeyWithGK(gatewayv1.GroupName, "HTTPRoute", nn.Namespace, nn.Name)
73+
)
74+
if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
75+
return err
76+
}
77+
var (
78+
objs = make(map[types.NamespacedName]struct{})
79+
parentRefs []gatewayv1.ParentReference
80+
)
81+
// collect all parentRefs
82+
for _, policy := range list.Items {
83+
for _, ref := range policy.Spec.TargetRefs {
84+
var obj = types.NamespacedName{Namespace: policy.GetNamespace(), Name: string(ref.Name)}
85+
if _, ok := objs[obj]; !ok {
86+
objs[obj] = struct{}{}
87+
88+
var httpRoute gatewayv1.HTTPRoute
89+
if err := r.Get(context.Background(), obj, &httpRoute); err != nil {
90+
continue
91+
}
92+
parentRefs = append(parentRefs, httpRoute.Spec.ParentRefs...)
93+
}
94+
}
95+
}
96+
// delete AncestorRef which is not exist in the all parentRefs for each policy
97+
updateDeleteAncestors(r.Client, r.Log, list.Items, parentRefs)
98+
99+
return nil
100+
}
101+
70102
func (r *IngressReconciler) processHTTPRoutePolicies(tctx *provider.TranslateContext, ingress *networkingv1.Ingress) error {
71103
var (
72104
list v1alpha1.HTTPRoutePolicyList
@@ -102,6 +134,47 @@ func (r *IngressReconciler) processHTTPRoutePolicies(tctx *provider.TranslateCon
102134
return nil
103135
}
104136

137+
func (r *IngressReconciler) updateHTTPRoutePolicyStatusOnDeleting(nn types.NamespacedName) error {
138+
var (
139+
list v1alpha1.HTTPRoutePolicyList
140+
key = indexer.GenIndexKeyWithGK(networkingv1.GroupName, "Ingress", nn.Namespace, nn.Name)
141+
)
142+
if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil {
143+
return err
144+
}
145+
var (
146+
objs = make(map[types.NamespacedName]struct{})
147+
parentRefs []gatewayv1.ParentReference
148+
)
149+
// collect all parentRefs
150+
for _, policy := range list.Items {
151+
for _, ref := range policy.Spec.TargetRefs {
152+
var obj = types.NamespacedName{Namespace: policy.GetNamespace(), Name: string(ref.Name)}
153+
if _, ok := objs[obj]; !ok {
154+
objs[obj] = struct{}{}
155+
156+
var ingress networkingv1.Ingress
157+
if err := r.Get(context.Background(), obj, &ingress); err != nil {
158+
continue
159+
}
160+
ingressClass, err := r.getIngressClass(&ingress)
161+
if err != nil {
162+
continue
163+
}
164+
parentRefs = append(parentRefs, gatewayv1.ParentReference{
165+
Group: ptr.To(gatewayv1.Group(ingressClass.GroupVersionKind().Group)),
166+
Kind: ptr.To(gatewayv1.Kind("IngressClass")),
167+
Name: gatewayv1.ObjectName(ingressClass.Name),
168+
})
169+
}
170+
}
171+
}
172+
// delete AncestorRef which is not exist in the all parentRefs
173+
updateDeleteAncestors(r.Client, r.Log, list.Items, parentRefs)
174+
175+
return nil
176+
}
177+
105178
func modifyHTTPRoutePolicyStatus(parentRefs []gatewayv1.ParentReference, policy *v1alpha1.HTTPRoutePolicy, status bool, reason, message string) {
106179
condition := metav1.Condition{
107180
Type: string(v1alpha2.PolicyConditionAccepted),
@@ -141,3 +214,20 @@ func findPolicyWhichTargetRefTheRule(ruleName *gatewayv1.SectionName, kind strin
141214
}
142215
return
143216
}
217+
218+
func updateDeleteAncestors(client client.Client, logger logr.Logger, policies []v1alpha1.HTTPRoutePolicy, parentRefs []gatewayv1.ParentReference) {
219+
for i := range policies {
220+
policy := policies[i]
221+
length := len(policy.Status.Ancestors)
222+
policy.Status.Ancestors = slices.DeleteFunc(policy.Status.Ancestors, func(status v1alpha2.PolicyAncestorStatus) bool {
223+
return !slices.ContainsFunc(parentRefs, func(ref gatewayv1.ParentReference) bool {
224+
return parentRefValueEqual(status.AncestorRef, ref)
225+
})
226+
})
227+
if length != len(policy.Status.Ancestors) {
228+
if err := client.Status().Update(context.Background(), &policy); err != nil {
229+
logger.Error(err, "failed to update HTTPRoutePolicy status")
230+
}
231+
}
232+
}
233+
}

internal/controller/ingress_controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
9797
ingress := new(networkingv1.Ingress)
9898
if err := r.Get(ctx, req.NamespacedName, ingress); err != nil {
9999
if client.IgnoreNotFound(err) == nil {
100+
if err := r.updateHTTPRoutePolicyStatusOnDeleting(req.NamespacedName); err != nil {
101+
return ctrl.Result{}, err
102+
}
103+
100104
// Ingress was deleted, clean up corresponding resources
101105
ingress.Namespace = req.Namespace
102106
ingress.Name = req.Name

internal/controller/policies.go

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,18 @@ package controller
22

33
import (
44
"fmt"
5-
"slices"
6-
7-
"k8s.io/utils/ptr"
8-
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
9-
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
105

116
"github.com/go-logr/logr"
127
"k8s.io/apimachinery/pkg/api/meta"
138
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
149
"k8s.io/apimachinery/pkg/runtime/schema"
1510
"k8s.io/apimachinery/pkg/types"
11+
"k8s.io/utils/ptr"
1612
"sigs.k8s.io/controller-runtime/pkg/client"
1713
"sigs.k8s.io/controller-runtime/pkg/event"
1814
"sigs.k8s.io/controller-runtime/pkg/predicate"
15+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
16+
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
1917

2018
"github.com/api7/api7-ingress-controller/api/v1alpha1"
2119
"github.com/api7/api7-ingress-controller/internal/controller/config"
@@ -192,16 +190,6 @@ func SetAncestorStatus(status *v1alpha1.PolicyStatus, ancestorStatus gatewayv1al
192190
return true
193191
}
194192

195-
func DeleteAncestors(status *v1alpha1.PolicyStatus, parentRefs []gatewayv1.ParentReference) bool {
196-
var length = len(status.Ancestors)
197-
for _, parentRef := range parentRefs {
198-
status.Ancestors = slices.DeleteFunc(status.Ancestors, func(status gatewayv1alpha2.PolicyAncestorStatus) bool {
199-
return parentRefValueEqual(parentRef, status.AncestorRef)
200-
})
201-
}
202-
return length != len(status.Ancestors)
203-
}
204-
205193
func parentRefValueEqual(a, b gatewayv1.ParentReference) bool {
206194
return ptr.Equal(a.Group, b.Group) &&
207195
ptr.Equal(a.Kind, b.Kind) &&

test/e2e/gatewayapi/httproute.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,13 +843,19 @@ spec:
843843
}).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK))
844844
})
845845

846-
PIt("HTTPRoutePolicy status changes on HTTPRoute deleting", func() {
846+
It("HTTPRoutePolicy status changes on HTTPRoute deleting", func() {
847847
By("create HTTPRoute")
848848
ResourceApplied("HTTPRoute", "httpbin", varsRoute, 1)
849849

850850
By("create HTTPRoutePolicy")
851851
ResourceApplied("HTTPRoutePolicy", "http-route-policy-0", httpRoutePolicy, 1)
852852

853+
Eventually(func() string {
854+
spec, err := s.GetResourceYaml("HTTPRoutePolicy", "http-route-policy-0")
855+
Expect(err).NotTo(HaveOccurred(), "getting HTTPRoutePolicy")
856+
return spec
857+
}).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(ContainSubstring("type: Accepted"))
858+
853859
By("access dataplane to check the HTTPRoutePolicy")
854860
s.NewAPISIXClient().
855861
GET("/get").

test/e2e/ingress/ingress.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,5 +637,46 @@ spec:
637637
}).
638638
WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK))
639639
})
640+
641+
It("HTTPRoutePolicy status changes on Ingress deleting", func() {
642+
By("create Ingress")
643+
err := s.CreateResourceFromString(ingressSpec)
644+
Expect(err).NotTo(HaveOccurred(), "creating Ingress")
645+
646+
By("create HTTPRoutePolicy")
647+
err = s.CreateResourceFromString(httpRoutePolicySpec0)
648+
Expect(err).NotTo(HaveOccurred(), "creating HTTPRoutePolicy")
649+
Eventually(func() string {
650+
spec, err := s.GetResourceYaml("HTTPRoutePolicy", "http-route-policy-0")
651+
Expect(err).NotTo(HaveOccurred(), "HTTPRoutePolicy status should be True")
652+
return spec
653+
}).
654+
WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(ContainSubstring(`status: "True"`))
655+
656+
By("request the route without vars should be Not Found")
657+
Eventually(func() int {
658+
return s.NewAPISIXClient().GET("/get").WithHost("example.com").Expect().Raw().StatusCode
659+
}).
660+
WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound))
661+
662+
By("request the route with the correct vars should be OK")
663+
s.NewAPISIXClient().GET("/get").WithHost("example.com").
664+
WithHeader("X-HRP-Name", "http-route-policy-0").Expect().Status(http.StatusOK)
665+
666+
By("delete ingress")
667+
err = s.DeleteResource("Ingress", "default")
668+
Expect(err).NotTo(HaveOccurred(), "delete Ingress")
669+
Eventually(func() int {
670+
return s.NewAPISIXClient().GET("/get").WithHost("example.com").
671+
WithHeader("X-HRP-Name", "http-route-policy-0").Expect().Raw().StatusCode
672+
}).
673+
WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound))
674+
675+
Eventually(func() string {
676+
spec, err := s.GetResourceYaml("HTTPRoutePolicy", "http-route-policy-0")
677+
Expect(err).NotTo(HaveOccurred(), "getting HTTPRoutePolicy")
678+
return spec
679+
}).WithTimeout(8 * time.Second).ProbeEvery(time.Second).ShouldNot(ContainSubstring("ancestorRef:"))
680+
})
640681
})
641682
})

0 commit comments

Comments
 (0)