Compare commits

..

4 Commits

Author SHA1 Message Date
t.behrendt e181c97bcc docs: update docs
CI / install-dependencies (pull_request) Successful in 22s
CI / check lint (pull_request) Successful in 28s
CI / test (pull_request) Successful in 23s
CI / build check (pull_request) Successful in 1m47s
CI / check format (pull_request) Successful in 7m18s
CI / image check (pull_request) Failing after 6s
2026-05-19 21:44:42 +02:00
t.behrendt 2d9d6f56aa refactor: consolidate common controller code 2026-05-19 21:44:42 +02:00
t.behrendt fb926c81ee feat: add bare policy binding controller 2026-05-19 21:41:43 +02:00
t.behrendt bd6a71f541 feat: add bare application controller 2026-05-19 21:41:35 +02:00
6 changed files with 32 additions and 36 deletions
@@ -1,4 +1,4 @@
package controllers package baseController
import ( import (
"context" "context"
@@ -1,5 +1,5 @@
// AI generated tests and not yet reviewed. // AI generated tests and not yet reviewed.
package controllers package baseController
import ( import (
"context" "context"
+4 -4
View File
@@ -37,8 +37,8 @@ import (
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/internal/baseController"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1" v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/application/v1alpha1"
controllers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/controllers"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned" clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme" operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/application/v1alpha1" informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/application/v1alpha1"
@@ -68,7 +68,7 @@ type ApplicationController struct {
applicationListener listers.ApplicationLister applicationListener listers.ApplicationLister
controller *controllers.Controller controller *baseController.Controller
} }
func NewController( func NewController(
@@ -98,7 +98,7 @@ func NewController(
authentik: authentik, authentik: authentik,
applicationListener: applicationInformer.Lister(), applicationListener: applicationInformer.Lister(),
} }
c.controller = controllers.NewController( c.controller = baseController.NewController(
ctx, ctx,
workqueue.NewTypedRateLimitingQueue(ratelimiter), workqueue.NewTypedRateLimitingQueue(ratelimiter),
recorder, recorder,
@@ -160,7 +160,7 @@ func (c *ApplicationController) ensureFinalizers(ctx context.Context, app *v1alp
} }
func (c *ApplicationController) reconcileDelete(ctx context.Context, app *v1alpha1.Application) error { func (c *ApplicationController) reconcileDelete(ctx context.Context, app *v1alpha1.Application) error {
r, err := c.authentik.CoreApi.CoreApplicationsDestroy(ctx, app.Status.PK).Execute() r, err := c.authentik.CoreApi.CoreApplicationsDestroy(ctx, app.Spec.Slug).Execute()
if err != nil { if err != nil {
// This handles an edge-case, where when the Application on Authentik has already been deleted, but the finalizer is still present. We just remove the finalizer and return. // This handles an edge-case, where when the Application on Authentik has already been deleted, but the finalizer is still present. We just remove the finalizer and return.
if r != nil && r.StatusCode != http.StatusNotFound { if r != nil && r.StatusCode != http.StatusNotFound {
+21 -25
View File
@@ -130,7 +130,7 @@ func TestController_syncHandler_delete(t *testing.T) {
var destroyCalled bool var destroyCalled bool
server := newAuthentikTestServer(t, authentikTestHandlers{ server := newAuthentikTestServer(t, authentikTestHandlers{
proxyDestroy: func(w http.ResponseWriter, r *http.Request) { applicationDestroy: func(w http.ResponseWriter, r *http.Request) {
destroyCalled = true destroyCalled = true
if r.Method != http.MethodDelete { if r.Method != http.MethodDelete {
t.Errorf("destroy method = %s, want DELETE", r.Method) t.Errorf("destroy method = %s, want DELETE", r.Method)
@@ -165,7 +165,7 @@ func TestController_syncHandler_delete_providerAlreadyGone(t *testing.T) {
app.Finalizers = []string{DeleteAuthentikApplicationFinalizer} app.Finalizers = []string{DeleteAuthentikApplicationFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{ server := newAuthentikTestServer(t, authentikTestHandlers{
proxyDestroy: func(w http.ResponseWriter, _ *http.Request) { applicationDestroy: func(w http.ResponseWriter, _ *http.Request) {
http.NotFound(w, nil) http.NotFound(w, nil)
}, },
}) })
@@ -198,25 +198,31 @@ func TestController_syncHandler_notFound(t *testing.T) {
} }
} }
func TestController_syncHandler_invalidPK(t *testing.T) { func TestController_syncHandler_delete_usesSlugNotPK(t *testing.T) {
now := metav1.Now() now := metav1.Now()
app := testApplication() app := testApplication()
app.Status.PK = "not-a-number" app.Status.PK = "not-a-number"
app.DeletionTimestamp = &now app.DeletionTimestamp = &now
app.Finalizers = []string{DeleteAuthentikApplicationFinalizer} app.Finalizers = []string{DeleteAuthentikApplicationFinalizer}
server := newAuthentikTestServer(t, authentikTestHandlers{}) var destroySlug string
server := newAuthentikTestServer(t, authentikTestHandlers{
applicationDestroy: func(w http.ResponseWriter, r *http.Request) {
destroySlug = strings.TrimSuffix(strings.TrimPrefix(r.URL.Path, "/api/v3/core/applications/"), "/")
w.WriteHeader(http.StatusNoContent)
},
})
t.Cleanup(server.Close) t.Cleanup(server.Close)
ctrl, ctx, cancel := newTestController(t, app, server.URL) ctrl, ctx, cancel := newTestController(t, app, server.URL)
t.Cleanup(cancel) t.Cleanup(cancel)
err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name}) err := ctrl.syncHandler(ctx, cache.ObjectName{Namespace: app.Namespace, Name: app.Name})
if err == nil { if err != nil {
t.Fatal("syncHandler() error = nil, want parse error") t.Fatalf("syncHandler() error = %v", err)
} }
if !strings.Contains(err.Error(), "error parsing PK") { if destroySlug != app.Spec.Slug {
t.Fatalf("syncHandler() error = %v, want PK parse error", err) t.Fatalf("destroy slug = %q, want %q (delete must use spec.slug, not status.pk)", destroySlug, app.Spec.Slug)
} }
} }
@@ -295,7 +301,7 @@ type authentikTestHandlers struct {
applicationCreate http.HandlerFunc applicationCreate http.HandlerFunc
applicationRetrieve http.HandlerFunc applicationRetrieve http.HandlerFunc
applicationPartialUpdate http.HandlerFunc applicationPartialUpdate http.HandlerFunc
proxyDestroy http.HandlerFunc applicationDestroy http.HandlerFunc
} }
func newAuthentikTestServer(t *testing.T, handlers authentikTestHandlers) *httptest.Server { func newAuthentikTestServer(t *testing.T, handlers authentikTestHandlers) *httptest.Server {
@@ -331,26 +337,16 @@ func newAuthentikTestServer(t *testing.T, handlers authentikTestHandlers) *httpt
return return
} }
http.NotFound(w, r) http.NotFound(w, r)
case http.MethodDelete:
if handlers.applicationDestroy != nil {
handlers.applicationDestroy(w, r)
return
}
http.NotFound(w, r)
default: default:
http.Error(w, "unexpected method on application instance", http.StatusMethodNotAllowed) http.Error(w, "unexpected method on application instance", http.StatusMethodNotAllowed)
} }
case strings.HasPrefix(path, "/api/v3/providers/proxy/") && strings.HasSuffix(path, "/"):
idPath := strings.TrimPrefix(path, "/api/v3/providers/proxy/")
if idPath == "" {
http.NotFound(w, r)
return
}
if r.Method == http.MethodDelete {
if handlers.proxyDestroy != nil {
handlers.proxyDestroy(w, r)
return
}
http.NotFound(w, r)
return
}
http.Error(w, "unexpected method on proxy instance", http.StatusMethodNotAllowed)
default: default:
http.NotFound(w, r) http.NotFound(w, r)
} }
+3 -3
View File
@@ -37,8 +37,8 @@ import (
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/internal/baseController"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1" v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/policybinding/v1alpha1"
controllers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/controllers"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned" clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme" operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/policybinding/v1alpha1" informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/policybinding/v1alpha1"
@@ -68,7 +68,7 @@ type PolicyBindingController struct {
policyBindingListener listers.PolicyBindingLister policyBindingListener listers.PolicyBindingLister
controller *controllers.Controller controller *baseController.Controller
} }
func NewController( func NewController(
@@ -98,7 +98,7 @@ func NewController(
authentik: authentik, authentik: authentik,
policyBindingListener: policyBindingInformer.Lister(), policyBindingListener: policyBindingInformer.Lister(),
} }
c.controller = controllers.NewController( c.controller = baseController.NewController(
ctx, ctx,
workqueue.NewTypedRateLimitingQueue(ratelimiter), workqueue.NewTypedRateLimitingQueue(ratelimiter),
recorder, recorder,
+3 -3
View File
@@ -38,8 +38,8 @@ import (
"k8s.io/client-go/util/workqueue" "k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2" "k8s.io/klog/v2"
"gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/internal/baseController"
v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1" v1alpha1 "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/apis/proxyprovider/v1alpha1"
controllers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/controllers"
clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned" clientset "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned"
operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme" operatorscheme "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/clientset/versioned/scheme"
informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/proxyprovider/v1alpha1" informers "gitea.t000-n.de/t.behrendt/authentik-kubernetes-operator/pkg/generated/informers/externalversions/proxyprovider/v1alpha1"
@@ -69,7 +69,7 @@ type ProxyProviderController struct {
proxyLister listers.ProxyProviderLister proxyLister listers.ProxyProviderLister
controller *controllers.Controller controller *baseController.Controller
} }
func NewController( func NewController(
@@ -99,7 +99,7 @@ func NewController(
authentik: authentik, authentik: authentik,
proxyLister: proxyInformer.Lister(), proxyLister: proxyInformer.Lister(),
} }
c.controller = controllers.NewController( c.controller = baseController.NewController(
ctx, ctx,
workqueue.NewTypedRateLimitingQueue(ratelimiter), workqueue.NewTypedRateLimitingQueue(ratelimiter),
recorder, recorder,