Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
105 changes: 44 additions & 61 deletions internal/controller/httproute_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
63 changes: 53 additions & 10 deletions internal/controller/httproutepolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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(), "")
Expand Down Expand Up @@ -88,15 +89,57 @@ 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)
}
}

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,
Expand All @@ -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 {
Expand All @@ -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)
Expand Down
60 changes: 52 additions & 8 deletions internal/controller/ingress_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
21 changes: 17 additions & 4 deletions internal/provider/adc/translator/httproute.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
Loading
Loading