Skip to content

Commit

Permalink
feat(konnect): manage finalizers for KongRoute in KonnectEntityPlugin…
Browse files Browse the repository at this point in the history
…BindingFinalizerReconciler (#683)
  • Loading branch information
pmalek authored Oct 2, 2024
1 parent 0e3107a commit 9f1463a
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 59 deletions.
41 changes: 41 additions & 0 deletions controller/konnect/reconciler_generic_pluginbindingfinalizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,31 @@ func enqueueKongServiceForKongPluginBinding() func(
}
}

func enqueueKongRouteForKongPluginBinding() func(
ctx context.Context, obj client.Object) []reconcile.Request {
return func(ctx context.Context, obj client.Object) []reconcile.Request {
kpb, ok := obj.(*configurationv1alpha1.KongPluginBinding)
if !ok {
return nil
}

if kpb.Spec.Targets.RouteReference == nil ||
kpb.Spec.Targets.RouteReference.Kind != "KongRoute" ||
kpb.Spec.Targets.RouteReference.Group != configurationv1alpha1.GroupVersion.Group {
return nil
}

return []ctrl.Request{
{
NamespacedName: types.NamespacedName{
Namespace: kpb.Namespace,
Name: kpb.Spec.Targets.RouteReference.Name,
},
},
}
}
}

// Reconcile reconciles the Konnect entity that can be set as KongPluginBinding target.
// Its purpose is to:
// - check if the entity is marked for deletion and mark KongPluginBindings
Expand Down Expand Up @@ -189,6 +214,8 @@ func (r *KonnectEntityPluginBindingFinalizerReconciler[T, TEnt]) getKongPluginBi
switch any(ent).(type) {
case *configurationv1alpha1.KongService:
return IndexFieldKongPluginBindingKongServiceReference
case *configurationv1alpha1.KongRoute:
return IndexFieldKongPluginBindingKongRouteReference
default:
panic(fmt.Sprintf("unsupported entity type %s", constraints.EntityTypeName[T]()))
}
Expand Down Expand Up @@ -217,6 +244,20 @@ func (r *KonnectEntityPluginBindingFinalizerReconciler[T, TEnt]) setControllerBu
enqueueKongServiceForKongPluginBinding(),
),
)
case *configurationv1alpha1.KongRoute:
b.
For(&configurationv1alpha1.KongRoute{},
builder.WithPredicates(
predicate.NewPredicateFuncs(objRefersToKonnectGatewayControlPlane[configurationv1alpha1.KongRoute]),
kongPluginsAnnotationChangedPredicate,
),
).
Watches(
&configurationv1alpha1.KongPluginBinding{},
handler.EnqueueRequestsFromMapFunc(
enqueueKongRouteForKongPluginBinding(),
),
)
default:
panic(fmt.Sprintf("unsupported entity type %s", constraints.EntityTypeName[T]()))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ package konnect

//+kubebuilder:rbac:groups=configuration.konghq.com,resources=kongservices,verbs=get;update

//+kubebuilder:rbac:groups=configuration.konghq.com,resources=kongroutes,verbs=get;update

//+kubebuilder:rbac:groups=configuration.konghq.com,resources=kongpluginbindings,verbs=delete;list
125 changes: 66 additions & 59 deletions test/envtest/kongplugincleanupfinalizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"testing"

"github.com/stretchr/testify/require"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"sigs.k8s.io/controller-runtime/pkg/client"

Expand All @@ -18,7 +16,6 @@ import (
"github.com/kong/gateway-operator/pkg/consts"
"github.com/kong/gateway-operator/test/helpers/deploy"

configurationv1 "github.com/kong/kubernetes-configuration/api/configuration/v1"
configurationv1alpha1 "github.com/kong/kubernetes-configuration/api/configuration/v1alpha1"
)

Expand All @@ -42,64 +39,74 @@ func TestKongPluginFinalizer(t *testing.T) {
cp := deploy.KonnectGatewayControlPlaneWithID(t, ctx, clientNamespaced, apiAuth)

require.NoError(t, manager.SetupCacheIndicesForKonnectTypes(ctx, mgr, false))
reconcilers := []Reconciler{

StartReconcilers(ctx, t, mgr, logs,
konnect.NewKonnectEntityPluginReconciler[configurationv1alpha1.KongService](false, mgr.GetClient()),
}

StartReconcilers(ctx, t, mgr, logs, reconcilers...)

rateLimitingkongPlugin := &configurationv1.KongPlugin{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "rate-limiting-kp-",
},
PluginName: "rate-limiting",
Config: apiextensionsv1.JSON{
Raw: []byte(`{"minute": 5, "policy": "local"}`),
},
}
require.NoError(t, clientNamespaced.Create(ctx, rateLimitingkongPlugin))
t.Logf("deployed %s KongPlugin (%s) resource", client.ObjectKeyFromObject(rateLimitingkongPlugin), rateLimitingkongPlugin.PluginName)

wKongService := setupWatch[configurationv1alpha1.KongServiceList](t, ctx, clientWithWatch, client.InNamespace(ns.Name))
kongService := deploy.KongServiceAttachedToCP(t, ctx, clientNamespaced, cp)
kpb := deploy.KongPluginBinding(t, ctx, clientNamespaced,
&configurationv1alpha1.KongPluginBinding{
Spec: configurationv1alpha1.KongPluginBindingSpec{
ControlPlaneRef: &configurationv1alpha1.ControlPlaneRef{
Type: configurationv1alpha1.ControlPlaneRefKonnectNamespacedRef,
KonnectNamespacedRef: &configurationv1alpha1.KonnectNamespacedRef{
Name: cp.Name,
},
},
PluginReference: configurationv1alpha1.PluginRef{
Name: rateLimitingkongPlugin.Name,
},
Targets: configurationv1alpha1.KongPluginBindingTargets{
ServiceReference: &configurationv1alpha1.TargetRefWithGroupKind{
Group: configurationv1alpha1.GroupVersion.Group,
Kind: "KongService",
Name: kongService.Name,
},
},
},
},
konnect.NewKonnectEntityPluginReconciler[configurationv1alpha1.KongRoute](false, mgr.GetClient()),
)

_ = watchFor(t, ctx, wKongService, watch.Modified,
func(svc *configurationv1alpha1.KongService) bool {
return svc.Name == kongService.Name &&
slices.Contains(svc.GetFinalizers(), consts.CleanupPluginBindingFinalizer)
},
fmt.Sprintf("KongService doesn't have the %s finalizer set", consts.CleanupPluginBindingFinalizer),
)
t.Run("KongService", func(t *testing.T) {
rateLimitingkongPlugin := deploy.RateLimitingPlugin(t, ctx, clientNamespaced)

wKongService = setupWatch[configurationv1alpha1.KongServiceList](t, ctx, clientWithWatch, client.InNamespace(ns.Name))
require.NoError(t, clientNamespaced.Delete(ctx, kpb))
_ = watchFor(t, ctx, wKongService, watch.Modified,
func(svc *configurationv1alpha1.KongService) bool {
return svc.Name == kongService.Name &&
!slices.Contains(svc.GetFinalizers(), consts.CleanupPluginBindingFinalizer)
},
fmt.Sprintf("KongService has the %s finalizer set but it shouldn't", consts.CleanupPluginBindingFinalizer),
)
wKongService := setupWatch[configurationv1alpha1.KongServiceList](t, ctx, clientWithWatch, client.InNamespace(ns.Name))
kongService := deploy.KongServiceAttachedToCP(t, ctx, clientNamespaced, cp)
kpb := deploy.KongPluginBinding(t, ctx, clientNamespaced,
konnect.NewKongPluginBindingBuilder().
WithControlPlaneRefKonnectNamespaced(cp.Name).
WithPluginRef(rateLimitingkongPlugin.Name).
WithServiceTarget(kongService.Name).
Build(),
)

_ = watchFor(t, ctx, wKongService, watch.Modified,
func(svc *configurationv1alpha1.KongService) bool {
return svc.Name == kongService.Name &&
slices.Contains(svc.GetFinalizers(), consts.CleanupPluginBindingFinalizer)
},
fmt.Sprintf("KongService doesn't have the %s finalizer set", consts.CleanupPluginBindingFinalizer),
)

wKongService = setupWatch[configurationv1alpha1.KongServiceList](t, ctx, clientWithWatch, client.InNamespace(ns.Name))
require.NoError(t, clientNamespaced.Delete(ctx, kpb))
_ = watchFor(t, ctx, wKongService, watch.Modified,
func(svc *configurationv1alpha1.KongService) bool {
return svc.Name == kongService.Name &&
!slices.Contains(svc.GetFinalizers(), consts.CleanupPluginBindingFinalizer)
},
fmt.Sprintf("KongService has the %s finalizer set but it shouldn't", consts.CleanupPluginBindingFinalizer),
)
})

t.Run("KongRoute", func(t *testing.T) {
rateLimitingkongPlugin := deploy.RateLimitingPlugin(t, ctx, clientNamespaced)

kongService := deploy.KongServiceAttachedToCP(t, ctx, clientNamespaced, cp)
wKongRoute := setupWatch[configurationv1alpha1.KongRouteList](t, ctx, clientWithWatch, client.InNamespace(ns.Name))
kongRoute := deploy.KongRouteAttachedToService(t, ctx, clientNamespaced, kongService)
kpb := deploy.KongPluginBinding(t, ctx, clientNamespaced,
konnect.NewKongPluginBindingBuilder().
WithControlPlaneRefKonnectNamespaced(cp.Name).
WithPluginRef(rateLimitingkongPlugin.Name).
WithRouteTarget(kongRoute.Name).
Build(),
)

_ = watchFor(t, ctx, wKongRoute, watch.Modified,
func(svc *configurationv1alpha1.KongRoute) bool {
return svc.Name == kongRoute.Name &&
slices.Contains(svc.GetFinalizers(), consts.CleanupPluginBindingFinalizer)
},
fmt.Sprintf("KongRoute doesn't have the %s finalizer set", consts.CleanupPluginBindingFinalizer),
)

wKongRoute = setupWatch[configurationv1alpha1.KongRouteList](t, ctx, clientWithWatch, client.InNamespace(ns.Name))
require.NoError(t, clientNamespaced.Delete(ctx, kpb))
_ = watchFor(t, ctx, wKongRoute, watch.Modified,
func(svc *configurationv1alpha1.KongRoute) bool {
return svc.Name == kongRoute.Name &&
!slices.Contains(svc.GetFinalizers(), consts.CleanupPluginBindingFinalizer)
},
fmt.Sprintf("KongRoute has the %s finalizer set but it shouldn't", consts.CleanupPluginBindingFinalizer),
)
})
}
23 changes: 23 additions & 0 deletions test/helpers/deploy/deploy_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,29 @@ func ProxyCachePlugin(
return plugin
}

// RateLimitingPlugin deploys the rate-limiting KongPlugin resource and returns the resource.
// The provided client should be namespaced, i.e. created with `client.NewNamespacedClient(client, ns)`
func RateLimitingPlugin(
t *testing.T,
ctx context.Context,
cl client.Client,
) *configurationv1.KongPlugin {
t.Helper()

plugin := &configurationv1.KongPlugin{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "rate-limiting-kp-",
},
PluginName: "rate-limiting",
Config: apiextensionsv1.JSON{
Raw: []byte(`{"minute": 5, "policy": "local"}`),
},
}
require.NoError(t, cl.Create(ctx, plugin))
t.Logf("deployed new %s KongPlugin (%s)", client.ObjectKeyFromObject(plugin), plugin.PluginName)
return plugin
}

// KongKeySetAttachedToCP deploys a KongKeySet resource attached to a CP and returns the resource.
func KongKeySetAttachedToCP(
t *testing.T,
Expand Down

0 comments on commit 9f1463a

Please sign in to comment.