diff --git a/internal/controller/httproute_controller.go b/internal/controller/httproute_controller.go index 99fd916ca..48aacf94a 100644 --- a/internal/controller/httproute_controller.go +++ b/internal/controller/httproute_controller.go @@ -80,20 +80,7 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { ). Watches(&v1alpha1.HTTPRoutePolicy{}, handler.EnqueueRequestsFromMapFunc(r.listHTTPRouteByHTTPRoutePolicy), - builder.WithPredicates( - predicate.Funcs{ - CreateFunc: func(e event.CreateEvent) bool { - return true - }, - DeleteFunc: func(e event.DeleteEvent) bool { - return true - }, - UpdateFunc: r.httpRoutePolicyPredicateOnUpdate, - GenericFunc: func(e event.GenericEvent) bool { - return false - }, - }, - ), + builder.WithPredicates(httpRoutePolicyPredicateFuncs(r.genericEvent)), ). WatchesRawSource( source.Channel( @@ -358,7 +345,7 @@ func (r *HTTPRouteReconciler) listHTTPRouteByHTTPRoutePolicy(ctx context.Context } var httpRoute gatewayv1.HTTPRoute - if err := r.Get(ctx, client.ObjectKey{Namespace: key.Namespace, Name: key.Name}, &httpRoute); err != nil { + if err := r.Get(ctx, key, &httpRoute); err != nil { r.Log.Error(err, "failed to get HTTPRoute by HTTPRoutePolicy targetRef", "namespace", key.Namespace, "name", key.Name) continue } @@ -376,39 +363,22 @@ func (r *HTTPRouteReconciler) listHTTPRouteByHTTPRoutePolicy(ctx context.Context } } keys[key] = struct{}{} - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Namespace: key.Namespace, - Name: key.Name, - }, - }) + requests = append(requests, reconcile.Request{NamespacedName: key}) } return requests } func (r *HTTPRouteReconciler) listHTTPRouteForGenericEvent(ctx context.Context, obj client.Object) (requests []reconcile.Request) { - var namespacedNameMap = make(map[types.NamespacedName]struct{}) - - switch v := obj.(type) { + switch obj.(type) { case *v1alpha1.BackendTrafficPolicy: - requests = r.listHTTPRoutesForBackendTrafficPolicy(ctx, v) + return r.listHTTPRoutesForBackendTrafficPolicy(ctx, obj) case *v1alpha1.HTTPRoutePolicy: - for _, ref := range v.Spec.TargetRefs { - namespacedName := types.NamespacedName{Namespace: v.GetNamespace(), Name: string(ref.Name)} - if _, ok := namespacedNameMap[namespacedName]; !ok { - namespacedNameMap[namespacedName] = struct{}{} - if err := r.Get(ctx, namespacedName, new(gatewayv1.HTTPRoute)); err != nil { - r.Log.Info("failed to Get HTTPRoute", "namespace", namespacedName.Namespace, "name", namespacedName.Name) - continue - } - requests = append(requests, reconcile.Request{NamespacedName: namespacedName}) - } - } + return r.listHTTPRouteByHTTPRoutePolicy(ctx, obj) default: - r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy") + r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy or HTTPRoutePolicy") + return nil } - return requests } func (r *HTTPRouteReconciler) processHTTPRouteBackendRefs(tctx *provider.TranslateContext) error { @@ -528,28 +498,41 @@ func (r *HTTPRouteReconciler) processHTTPRoute(tctx *provider.TranslateContext, return terror } -func (r *HTTPRouteReconciler) httpRoutePolicyPredicateOnUpdate(e event.UpdateEvent) bool { - oldPolicy, ok0 := e.ObjectOld.(*v1alpha1.HTTPRoutePolicy) - newPolicy, ok1 := e.ObjectNew.(*v1alpha1.HTTPRoutePolicy) - if !ok0 || !ok1 { - return false - } - var discardsRefs = make(map[string]v1alpha2.LocalPolicyTargetReferenceWithSectionName) - for _, ref := range oldPolicy.Spec.TargetRefs { - key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "") - discardsRefs[key] = ref - } - for _, ref := range newPolicy.Spec.TargetRefs { - key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "") - delete(discardsRefs, key) - } - if len(discardsRefs) > 0 { - dump := oldPolicy.DeepCopy() - dump.Spec.TargetRefs = make([]v1alpha2.LocalPolicyTargetReferenceWithSectionName, 0, len(discardsRefs)) - for _, ref := range discardsRefs { - dump.Spec.TargetRefs = append(dump.Spec.TargetRefs, ref) - } - r.genericEvent <- event.GenericEvent{Object: dump} +func httpRoutePolicyPredicateFuncs(channel chan event.GenericEvent) predicate.Predicate { + return predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return true + }, + DeleteFunc: func(e event.DeleteEvent) bool { + return true + }, + UpdateFunc: func(e event.UpdateEvent) bool { + oldPolicy, ok0 := e.ObjectOld.(*v1alpha1.HTTPRoutePolicy) + newPolicy, ok1 := e.ObjectNew.(*v1alpha1.HTTPRoutePolicy) + if !ok0 || !ok1 { + return false + } + var discardsRefs = make(map[string]v1alpha2.LocalPolicyTargetReferenceWithSectionName) + for _, ref := range oldPolicy.Spec.TargetRefs { + key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "") + discardsRefs[key] = ref + } + for _, ref := range newPolicy.Spec.TargetRefs { + key := indexer.GenHTTPRoutePolicyIndexKey(string(ref.Group), string(ref.Kind), e.ObjectOld.GetNamespace(), string(ref.Name), "") + delete(discardsRefs, key) + } + if len(discardsRefs) > 0 { + dump := oldPolicy.DeepCopy() + dump.Spec.TargetRefs = make([]v1alpha2.LocalPolicyTargetReferenceWithSectionName, 0, len(discardsRefs)) + for _, ref := range discardsRefs { + dump.Spec.TargetRefs = append(dump.Spec.TargetRefs, ref) + } + channel <- event.GenericEvent{Object: dump} + } + return true + }, + GenericFunc: func(e event.GenericEvent) bool { + return false + }, } - return true } diff --git a/internal/controller/httproutepolicy.go b/internal/controller/httproutepolicy.go index 9ca9bac14..8b2a9bd41 100644 --- a/internal/controller/httproutepolicy.go +++ b/internal/controller/httproutepolicy.go @@ -4,6 +4,7 @@ import ( "context" "time" + networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -19,8 +20,8 @@ func (r *HTTPRouteReconciler) processHTTPRoutePolicies(tctx *provider.TranslateC // list HTTPRoutePolices which sectionName is not specified var ( checker = conflictChecker{ - httpRoute: httpRoute, - policies: make(map[targetRefKey][]v1alpha1.HTTPRoutePolicy), + object: httpRoute, + policies: make(map[targetRefKey][]v1alpha1.HTTPRoutePolicy), } listForAllRules v1alpha1.HTTPRoutePolicyList key = indexer.GenHTTPRoutePolicyIndexKey(gatewayv1.GroupName, "HTTPRoute", httpRoute.GetNamespace(), httpRoute.GetName(), "") @@ -88,7 +89,7 @@ func (r *HTTPRouteReconciler) processHTTPRoutePolicies(tctx *provider.TranslateC for _, policies := range checker.policies { for i := range policies { policy := policies[i] - r.modifyHTTPRoutePolicyStatus(httpRoute, &policy, status, reason, message) + modifyHTTPRoutePolicyStatus(httpRoute.Spec.ParentRefs, &policy, status, reason, message) tctx.StatusUpdaters = append(tctx.StatusUpdaters, &policy) } } @@ -96,7 +97,49 @@ func (r *HTTPRouteReconciler) processHTTPRoutePolicies(tctx *provider.TranslateC return nil } -func (r *HTTPRouteReconciler) modifyHTTPRoutePolicyStatus(httpRoute *gatewayv1.HTTPRoute, policy *v1alpha1.HTTPRoutePolicy, status bool, reason, message string) { +func (r *IngressReconciler) processHTTPRoutePolicies(tctx *provider.TranslateContext, ingress *networkingv1.Ingress) error { + var ( + checker = conflictChecker{ + object: ingress, + policies: make(map[targetRefKey][]v1alpha1.HTTPRoutePolicy), + conflict: false, + } + list v1alpha1.HTTPRoutePolicyList + key = indexer.GenHTTPRoutePolicyIndexKey(networkingv1.GroupName, "Ingress", ingress.GetNamespace(), ingress.GetName(), "") + ) + if err := r.List(context.Background(), &list, client.MatchingFields{indexer.PolicyTargetRefs: key}); err != nil { + return err + } + + for _, item := range list.Items { + checker.append("", item) + tctx.HTTPRoutePolicies["*"] = append(tctx.HTTPRoutePolicies["*"], item) + } + + var ( + status = true + reason = string(v1alpha2.PolicyReasonAccepted) + message string + ) + if checker.conflict { + status = false + reason = string(v1alpha2.PolicyReasonConflicted) + message = "HTTPRoutePolicy conflict with others target to the Ingress" + + // clear HTTPRoutePolicies from TranslateContext + tctx.HTTPRoutePolicies = make(map[string][]v1alpha1.HTTPRoutePolicy) + } + + for i := range list.Items { + policy := list.Items[i] + modifyHTTPRoutePolicyStatus(tctx.RouteParentRefs, &policy, status, reason, message) + tctx.StatusUpdaters = append(tctx.StatusUpdaters, &policy) + } + + return nil +} + +func modifyHTTPRoutePolicyStatus(parentRefs []gatewayv1.ParentReference, policy *v1alpha1.HTTPRoutePolicy, status bool, reason, message string) { condition := metav1.Condition{ Type: string(v1alpha2.PolicyConditionAccepted), Status: metav1.ConditionTrue, @@ -108,13 +151,13 @@ func (r *HTTPRouteReconciler) modifyHTTPRoutePolicyStatus(httpRoute *gatewayv1.H if !status { condition.Status = metav1.ConditionFalse } - _ = SetAncestors(&policy.Status, httpRoute.Spec.ParentRefs, condition) + _ = SetAncestors(&policy.Status, parentRefs, condition) } type conflictChecker struct { - httpRoute *gatewayv1.HTTPRoute - policies map[targetRefKey][]v1alpha1.HTTPRoutePolicy - conflict bool + object client.Object + policies map[targetRefKey][]v1alpha1.HTTPRoutePolicy + conflict bool } type targetRefKey struct { @@ -127,8 +170,8 @@ type targetRefKey struct { func (c *conflictChecker) append(sectionName string, policy v1alpha1.HTTPRoutePolicy) { key := targetRefKey{ Group: gatewayv1.GroupName, - Namespace: gatewayv1.Namespace(c.httpRoute.GetNamespace()), - Name: gatewayv1.ObjectName(c.httpRoute.GetName()), + Namespace: gatewayv1.Namespace(c.object.GetNamespace()), + Name: gatewayv1.ObjectName(c.object.GetName()), SectionName: gatewayv1.SectionName(sectionName), } c.policies[key] = append(c.policies[key], policy) diff --git a/internal/controller/ingress_controller.go b/internal/controller/ingress_controller.go index 68e1e44ec..5c3bd9ded 100644 --- a/internal/controller/ingress_controller.go +++ b/internal/controller/ingress_controller.go @@ -6,11 +6,6 @@ import ( "fmt" "reflect" - "github.com/api7/api7-ingress-controller/api/v1alpha1" - "github.com/api7/api7-ingress-controller/internal/controller/config" - "github.com/api7/api7-ingress-controller/internal/controller/indexer" - "github.com/api7/api7-ingress-controller/internal/provider" - "github.com/api7/gopkg/pkg/log" "github.com/go-logr/logr" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -29,6 +24,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "sigs.k8s.io/controller-runtime/pkg/source" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + + "github.com/api7/api7-ingress-controller/api/v1alpha1" + "github.com/api7/api7-ingress-controller/internal/controller/config" + "github.com/api7/api7-ingress-controller/internal/controller/indexer" + "github.com/api7/api7-ingress-controller/internal/provider" + "github.com/api7/gopkg/pkg/log" ) // IngressReconciler reconciles a Ingress object. @@ -78,6 +79,10 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error { BackendTrafficPolicyPredicateFunc(r.genericEvent), ), ). + Watches(&v1alpha1.HTTPRoutePolicy{}, + handler.EnqueueRequestsFromMapFunc(r.listIngressesByHTTPRoutePolicy), + builder.WithPredicates(httpRoutePolicyPredicateFuncs(r.genericEvent)), + ). WatchesRawSource( source.Channel( r.genericEvent, @@ -146,6 +151,12 @@ func (r *IngressReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct return ctrl.Result{}, err } + // process HTTPRoutePolicy + if err := r.processHTTPRoutePolicies(tctx, ingress); err != nil { + r.Log.Error(err, "failed to process HTTPRoutePolicy", "ingress", ingress.Name) + return ctrl.Result{}, err + } + ProcessBackendTrafficPolicy(r.Client, r.Log, tctx) // update the ingress resources @@ -415,13 +426,46 @@ func (r *IngressReconciler) listIngressForBackendTrafficPolicy(ctx context.Conte } func (r *IngressReconciler) listIngressForGenericEvent(ctx context.Context, obj client.Object) (requests []reconcile.Request) { - switch v := obj.(type) { + switch obj.(type) { case *v1alpha1.BackendTrafficPolicy: - requests = r.listIngressForBackendTrafficPolicy(ctx, v) + return r.listIngressForBackendTrafficPolicy(ctx, obj) + case *v1alpha1.HTTPRoutePolicy: + return r.listIngressesByHTTPRoutePolicy(ctx, obj) default: r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to BackendTrafficPolicy") + return nil } - return requests +} + +func (r *IngressReconciler) listIngressesByHTTPRoutePolicy(ctx context.Context, obj client.Object) (requests []reconcile.Request) { + httpRoutePolicy, ok := obj.(*v1alpha1.HTTPRoutePolicy) + if !ok { + r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to HTTPRoutePolicy") + return nil + } + + var keys = make(map[types.NamespacedName]struct{}) + for _, ref := range httpRoutePolicy.Spec.TargetRefs { + if ref.Kind != "Ingress" { + continue + } + key := types.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: string(ref.Name), + } + if _, ok := keys[key]; ok { + continue + } + + var ingress networkingv1.Ingress + if err := r.Get(ctx, key, &ingress); err != nil { + r.Log.Error(err, "failed to get Ingress By HTTPRoutePolicy targetRef", "namespace", key.Namespace, "name", key.Name) + continue + } + keys[key] = struct{}{} + requests = append(requests, reconcile.Request{NamespacedName: key}) + } + return } // processTLS process the TLS configuration of the ingress diff --git a/internal/provider/adc/translator/httproute.go b/internal/provider/adc/translator/httproute.go index 688f52e18..7c9b8e2d7 100644 --- a/internal/provider/adc/translator/httproute.go +++ b/internal/provider/adc/translator/httproute.go @@ -12,6 +12,7 @@ import ( "k8s.io/utils/ptr" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + "github.com/api7/api7-ingress-controller/api/v1alpha1" "github.com/api7/gopkg/pkg/log" adctypes "github.com/api7/api7-ingress-controller/api/adc" @@ -231,10 +232,22 @@ func (t *Translator) fillPluginFromHTTPRequestRedirectFilter(plugins adctypes.Pl plugin.URI = uri } -func (t *Translator) fillHTTPRoutePolicies(tctx *provider.TranslateContext, rule gatewayv1.HTTPRouteRule, routes []*adctypes.Route) { - policies := tctx.HTTPRoutePolicies["*"] // policies which not specify a sectionName +func (t *Translator) fillHTTPRoutePoliciesForHTTPRoute(tctx *provider.TranslateContext, routes []*adctypes.Route, rule gatewayv1.HTTPRouteRule) { + var keys = []string{"*"} if rule.Name != nil { - policies = append(policies, tctx.HTTPRoutePolicies[string(*rule.Name)]...) // append policies which specify the sectionName as the same as rule.name + keys = append(keys, string(*rule.Name)) + } + t.fillHTTPRoutePolicies(tctx, routes, keys...) +} + +func (t *Translator) fillHTTPRoutePoliciesForIngress(tctx *provider.TranslateContext, routes []*adctypes.Route) { + t.fillHTTPRoutePolicies(tctx, routes, "*") +} + +func (t *Translator) fillHTTPRoutePolicies(tctx *provider.TranslateContext, routes []*adctypes.Route, ctxKeys ...string) { + var policies []v1alpha1.HTTPRoutePolicy + for _, key := range ctxKeys { + policies = append(policies, tctx.HTTPRoutePolicies[key]...) } for _, policy := range policies { @@ -352,7 +365,7 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou route.EnableWebsocket = ptr.To(true) routes = append(routes, route) } - t.fillHTTPRoutePolicies(tctx, rule, routes) + t.fillHTTPRoutePoliciesForHTTPRoute(tctx, routes, rule) service.Routes = routes result.Services = append(result.Services, service) diff --git a/internal/provider/adc/translator/ingress.go b/internal/provider/adc/translator/ingress.go index 72a263f51..c7e25c431 100644 --- a/internal/provider/adc/translator/ingress.go +++ b/internal/provider/adc/translator/ingress.go @@ -187,8 +187,8 @@ func (t *Translator) TranslateIngress(tctx *provider.TranslateContext, obj *netw } } route.Uris = uris - service.Routes = []*adctypes.Route{route} + t.fillHTTPRoutePoliciesForIngress(tctx, service.Routes) result.Services = append(result.Services, service) } } diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index 4b6fd0b17..098f3f7af 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -785,11 +785,11 @@ spec: Expect(err).NotTo(HaveOccurred(), "creating HTTPRoutePolicy") } for _, name := range []string{"http-route-policy-0", "http-route-policy-1", "http-route-policy-2"} { - Eventually(func() string { + Eventually(func(name string) string { spec, err := s.GetResourceYaml("HTTPRoutePolicy", name) Expect(err).NotTo(HaveOccurred(), "getting HTTPRoutePolicy yaml") return spec - }).WithTimeout(8 * time.Second).ProbeEvery(time.Second). + }).WithArguments(name).WithTimeout(10 * time.Second).ProbeEvery(time.Second). Should(ContainSubstring("reason: Conflicted")) } diff --git a/test/e2e/ingress/ingress.go b/test/e2e/ingress/ingress.go index 6bcc5e11a..e0372586f 100644 --- a/test/e2e/ingress/ingress.go +++ b/test/e2e/ingress/ingress.go @@ -3,6 +3,7 @@ package ingress import ( "context" "fmt" + "net/http" "strings" "time" @@ -364,4 +365,227 @@ stringData: Status(200) }) }) + + Context("HTTPRoutePolicy for Ingress", func() { + getGatewayProxySpec := func() string { + return fmt.Sprintf(` +apiVersion: gateway.apisix.io/v1alpha1 +kind: GatewayProxy +metadata: + name: api7-proxy-config + namespace: default +spec: + provider: + type: ControlPlane + controlPlane: + endpoints: + - %s + auth: + type: AdminKey + adminKey: + value: "%s" +`, framework.DashboardTLSEndpoint, s.AdminKey()) + } + + const ingressClassSpec = ` +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: api7 +spec: + controller: "gateway.api7.io/api7-ingress-controller" + parameters: + apiGroup: "gateway.apisix.io" + kind: "GatewayProxy" + name: "api7-proxy-config" + namespace: "default" + scope: "Namespace" +` + const ingressSpec = ` +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: default +spec: + ingressClassName: api7 + rules: + - host: example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: httpbin-service-e2e-test + port: + number: 80 +` + const httpRoutePolicySpec0 = ` +apiVersion: gateway.apisix.io/v1alpha1 +kind: HTTPRoutePolicy +metadata: + name: http-route-policy-0 +spec: + targetRefs: + - group: networking.k8s.io + kind: Ingress + name: default + priority: 10 + vars: + - - http_x_hrp_name + - == + - http-route-policy-0 +` + const httpRoutePolicySpec1 = ` +apiVersion: gateway.apisix.io/v1alpha1 +kind: HTTPRoutePolicy +metadata: + name: http-route-policy-0 +spec: + targetRefs: + - group: networking.k8s.io + kind: Ingress + name: default + priority: 10 + vars: + - - arg_hrp_name + - == + - http-route-policy-0 +` + const httpRoutePolicySpec2 = ` +apiVersion: gateway.apisix.io/v1alpha1 +kind: HTTPRoutePolicy +metadata: + name: http-route-policy-0 +spec: + targetRefs: + - group: networking.k8s.io + kind: Ingress + name: other + priority: 10 + vars: + - - arg_hrp_name + - == + - http-route-policy-0 +` + const httpRoutePolicySpec3 = ` +apiVersion: gateway.apisix.io/v1alpha1 +kind: HTTPRoutePolicy +metadata: + name: http-route-policy-1 +spec: + targetRefs: + - group: networking.k8s.io + kind: Ingress + name: default + priority: 20 + vars: + - - arg_hrp_name + - == + - http-route-policy-0 +` + BeforeEach(func() { + By("create GatewayProxy") + err := s.CreateResourceFromStringWithNamespace(getGatewayProxySpec(), "default") + Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") + time.Sleep(5 * time.Second) + + By("create IngressClass") + err = s.CreateResourceFromStringWithNamespace(ingressClassSpec, "") + Expect(err).NotTo(HaveOccurred(), "creating GatewayClass") + time.Sleep(5 * time.Second) + }) + + It("HTTPRoutePolicy targetRef an Ingress", func() { + By("create Ingress") + err := s.CreateResourceFromString(ingressSpec) + Expect(err).NotTo(HaveOccurred(), "creating Ingress") + + By("request the route should be OK") + Eventually(func() int { + return s.NewAPISIXClient().GET("/get").WithHost("example.com").Expect().Raw().StatusCode + }). + WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK)) + + By("create HTTPRoutePolicy") + err = s.CreateResourceFromString(httpRoutePolicySpec0) + Expect(err).NotTo(HaveOccurred(), "creating HTTPRoutePolicy") + Eventually(func() string { + spec, err := s.GetResourceYaml("HTTPRoutePolicy", "http-route-policy-0") + Expect(err).NotTo(HaveOccurred(), "HTTPRoutePolicy status should be True") + return spec + }). + WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(ContainSubstring(`status: "True"`)) + + By("request the route without vars should be Not Found") + Eventually(func() int { + return s.NewAPISIXClient().GET("/get").WithHost("example.com").Expect().Raw().StatusCode + }). + WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) + + By("request the route with the correct vars should be OK") + s.NewAPISIXClient().GET("/get").WithHost("example.com"). + WithHeader("X-HRP-Name", "http-route-policy-0").Expect().Status(http.StatusOK) + + By("update the HTTPRoutePolicy") + err = s.CreateResourceFromString(httpRoutePolicySpec1) + Expect(err).NotTo(HaveOccurred(), "updating HTTPRoutePolicy") + + By("request with the old vars should be Not Found") + Eventually(func() int { + return s.NewAPISIXClient().GET("/get").WithHost("example.com"). + WithHeader("X-HRP-Name", "http-route-policy-0").Expect().Raw().StatusCode + }). + WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) + + By("request with the new vars should be OK") + s.NewAPISIXClient().GET("/get").WithHost("example.com"). + WithQuery("hrp_name", "http-route-policy-0").Expect().Status(http.StatusOK) + + By("update the HTTPRoutePolicy's targetRef") + err = s.CreateResourceFromString(httpRoutePolicySpec2) + Expect(err).NotTo(HaveOccurred(), "updating HTTPRoutePolicy") + + By("request the route without vars should be OK") + Eventually(func() int { + return s.NewAPISIXClient().GET("/get").WithHost("example.com").Expect().Raw().StatusCode + }). + WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK)) + + By("revert the HTTPRoutePolicy") + err = s.CreateResourceFromString(httpRoutePolicySpec0) + Expect(err).NotTo(HaveOccurred(), "creating HTTPRoutePolicy") + + By("request the route without vars should be Not Found") + Eventually(func() int { + return s.NewAPISIXClient().GET("/get").WithHost("example.com").Expect().Raw().StatusCode + }). + WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) + + By("request the route with the correct vars should be OK") + s.NewAPISIXClient().GET("/get").WithHost("example.com"). + WithHeader("X-HRP-Name", "http-route-policy-0").Expect().Status(http.StatusOK) + + By("apply conflict HTTPRoutePolicy") + err = s.CreateResourceFromString(httpRoutePolicySpec3) + Expect(err).NotTo(HaveOccurred(), "creating HTTPRoutePolicy") + Eventually(func() string { + spec, err := s.GetResourceYaml("HTTPRoutePolicy", "http-route-policy-1") + Expect(err).NotTo(HaveOccurred(), "get HTTPRoutePolicy") + return spec + }).WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(ContainSubstring("reason: Conflicted")) + + By("delete the HTTPRoutePolicy") + for _, name := range []string{"http-route-policy-0", "http-route-policy-1"} { + err = s.DeleteResource("HTTPRoutePolicy", name) + Expect(err).NotTo(HaveOccurred(), "deleting HTTPRoutePolicy") + } + + By("request the route without vars should be OK") + Eventually(func() int { + return s.NewAPISIXClient().GET("/get").WithHost("example.com").Expect().Raw().StatusCode + }). + WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK)) + }) + }) })