From 88bf03f7b0a8b7f2b74e4ce5afc1212400682c4d Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Tue, 23 Dec 2025 15:27:50 +0100 Subject: [PATCH 1/9] feat: introduced initializer predicate On-behalf-of: SAP aleh.yarshou@sap.com --- cmd/operator.go | 13 ++++ internal/controller/workspace_controller.go | 83 +++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 internal/controller/workspace_controller.go diff --git a/cmd/operator.go b/cmd/operator.go index 1865f5b3..0841263d 100644 --- a/cmd/operator.go +++ b/cmd/operator.go @@ -151,6 +151,14 @@ var operatorCmd = &cobra.Command{ fga := openfgav1.NewOpenFGAServiceClient(conn) + k8sCfg := ctrl.GetConfigOrDie() + + runtimeClient, err := client.New(k8sCfg, client.Options{Scheme: scheme}) + if err != nil { + log.Error().Err(err).Msg("Failed to create in cluster client") + return err + } + if err = controller.NewStoreReconciler(log, fga, mgr). SetupWithManager(mgr, defaultCfg); err != nil { log.Error().Err(err).Str("controller", "store").Msg("unable to create controller") @@ -170,6 +178,11 @@ var operatorCmd = &cobra.Command{ log.Error().Err(err).Str("controller", "invite").Msg("unable to create controller") return err } + + if err = controller.NewWorkspaceReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, "root:security"); err != nil { + log.Error().Err(err).Str("controller", "workspace").Msg("unable to create controller") + return err + } // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/internal/controller/workspace_controller.go b/internal/controller/workspace_controller.go new file mode 100644 index 00000000..b0d9fd08 --- /dev/null +++ b/internal/controller/workspace_controller.go @@ -0,0 +1,83 @@ +package controller + +import ( + "context" + "slices" + "sync" + + kcpcorev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" + platformeshconfig "github.com/platform-mesh/golang-commons/config" + "github.com/platform-mesh/golang-commons/controller/lifecycle/builder" + "github.com/platform-mesh/golang-commons/controller/lifecycle/multicluster" + lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine" + "github.com/platform-mesh/golang-commons/logger" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/predicate" + mccontext "sigs.k8s.io/multicluster-runtime/pkg/context" + mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager" + mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile" + + "github.com/platform-mesh/security-operator/internal/config" + "github.com/platform-mesh/security-operator/internal/subroutine" +) + +var ( + shouldReconcileMutex sync.Mutex +) + +type WorkspaceReconciler struct { + log *logger.Logger + mgr mcmanager.Manager + initializer kcpcorev1alpha1.LogicalClusterInitializer + mclifecycle *multicluster.LifecycleManager +} + +func NewWorkspaceReconciler(log *logger.Logger, orgClient client.Client, cfg config.Config, inClusterClient client.Client, mgr mcmanager.Manager) *WorkspaceReconciler { + return &WorkspaceReconciler{ + log: log, + mgr: mgr, + mclifecycle: builder.NewBuilder("logicalcluster", "LogicalClusterReconciler", []lifecyclesubroutine.Subroutine{ + subroutine.NewWorkspaceInitializer(orgClient, cfg, mgr), + subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, inClusterClient, cfg), + }, log).WithReadOnly().WithStaticThenExponentialRateLimiter().BuildMultiCluster(mgr), + } +} + +func (r *WorkspaceReconciler) Reconcile(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error) { + ctxWithCluster := mccontext.WithCluster(ctx, req.ClusterName) + return r.mclifecycle.Reconcile(ctxWithCluster, req, &kcpcorev1alpha1.LogicalCluster{}) +} + +func (r *WorkspaceReconciler) SetupWithManager(mgr mcmanager.Manager, cfg *platformeshconfig.CommonServiceConfig, initializerName string, evp ...predicate.Predicate) error { + r.initializer = kcpcorev1alpha1.LogicalClusterInitializer(initializerName) + allPredicates := append([]predicate.Predicate{HasInitializerPredicate(initializerName)}, evp...) + return r.mclifecycle.SetupWithManager(mgr, cfg.MaxConcurrentReconciles, "LogicalCluster", &kcpcorev1alpha1.LogicalCluster{}, cfg.DebugLabelValue, r, r.log, allPredicates...) +} + +func HasInitializerPredicate(initializerName string) predicate.Predicate { + initializer := kcpcorev1alpha1.LogicalClusterInitializer(initializerName) + return predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + lc := e.Object.(*kcpcorev1alpha1.LogicalCluster) + return shouldReconcile(lc, initializer) + }, + UpdateFunc: func(e event.UpdateEvent) bool { + newLC := e.ObjectNew.(*kcpcorev1alpha1.LogicalCluster) + return shouldReconcile(newLC, initializer) + }, + DeleteFunc: func(e event.DeleteEvent) bool { + lc := e.Object.(*kcpcorev1alpha1.LogicalCluster) + return shouldReconcile(lc, initializer) + }, + GenericFunc: func(e event.GenericEvent) bool { + lc := e.Object.(*kcpcorev1alpha1.LogicalCluster) + return shouldReconcile(lc, initializer) + }, + } +} + +func shouldReconcile(lc *kcpcorev1alpha1.LogicalCluster, initializer kcpcorev1alpha1.LogicalClusterInitializer) bool { + return slices.Contains(lc.Spec.Initializers, initializer) && !slices.Contains(lc.Status.Initializers, initializer) +} From da5a7c2796c0f9cd1d264e8bff7e718e5a6a53a2 Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Thu, 22 Jan 2026 09:53:49 +0100 Subject: [PATCH 2/9] fixed tests and linter errors On-behalf-of: SAP aleh.yarshou@sap.com --- internal/controller/workspace_controller.go | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/internal/controller/workspace_controller.go b/internal/controller/workspace_controller.go index b0d9fd08..95505232 100644 --- a/internal/controller/workspace_controller.go +++ b/internal/controller/workspace_controller.go @@ -3,9 +3,8 @@ package controller import ( "context" "slices" - "sync" - kcpcorev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1" + kcpcorev1alpha1 "github.com/kcp-dev/sdk/apis/core/v1alpha1" platformeshconfig "github.com/platform-mesh/golang-commons/config" "github.com/platform-mesh/golang-commons/controller/lifecycle/builder" "github.com/platform-mesh/golang-commons/controller/lifecycle/multicluster" @@ -23,10 +22,6 @@ import ( "github.com/platform-mesh/security-operator/internal/subroutine" ) -var ( - shouldReconcileMutex sync.Mutex -) - type WorkspaceReconciler struct { log *logger.Logger mgr mcmanager.Manager @@ -40,7 +35,7 @@ func NewWorkspaceReconciler(log *logger.Logger, orgClient client.Client, cfg con mgr: mgr, mclifecycle: builder.NewBuilder("logicalcluster", "LogicalClusterReconciler", []lifecyclesubroutine.Subroutine{ subroutine.NewWorkspaceInitializer(orgClient, cfg, mgr), - subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, inClusterClient, cfg), + subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, inClusterClient, mgr, cfg), }, log).WithReadOnly().WithStaticThenExponentialRateLimiter().BuildMultiCluster(mgr), } } From de205751b01cb3fbfb52b957104127fc182c86e4 Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Thu, 22 Jan 2026 10:31:48 +0100 Subject: [PATCH 3/9] addressed linter complience On-behalf-of: SAP aleh.yarshou@sap.com --- cmd/operator.go | 1 - internal/controller/workspace_controller.go | 6 +++--- internal/subroutine/workspace_authorization_test.go | 8 ++++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cmd/operator.go b/cmd/operator.go index 3339c4ff..e8eaf83e 100644 --- a/cmd/operator.go +++ b/cmd/operator.go @@ -44,7 +44,6 @@ var ( type NewLogicalClusterClientFunc func(clusterKey logicalcluster.Name) (client.Client, error) - func logicalClusterClientFromKey(config *rest.Config, log *logger.Logger) NewLogicalClusterClientFunc { return func(clusterKey logicalcluster.Name) (client.Client, error) { cfg := rest.CopyConfig(config) diff --git a/internal/controller/workspace_controller.go b/internal/controller/workspace_controller.go index 95505232..cb8f34ba 100644 --- a/internal/controller/workspace_controller.go +++ b/internal/controller/workspace_controller.go @@ -4,12 +4,13 @@ import ( "context" "slices" - kcpcorev1alpha1 "github.com/kcp-dev/sdk/apis/core/v1alpha1" platformeshconfig "github.com/platform-mesh/golang-commons/config" "github.com/platform-mesh/golang-commons/controller/lifecycle/builder" "github.com/platform-mesh/golang-commons/controller/lifecycle/multicluster" lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine" "github.com/platform-mesh/golang-commons/logger" + "github.com/platform-mesh/security-operator/internal/config" + "github.com/platform-mesh/security-operator/internal/subroutine" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" @@ -18,8 +19,7 @@ import ( mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager" mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile" - "github.com/platform-mesh/security-operator/internal/config" - "github.com/platform-mesh/security-operator/internal/subroutine" + kcpcorev1alpha1 "github.com/kcp-dev/sdk/apis/core/v1alpha1" ) type WorkspaceReconciler struct { diff --git a/internal/subroutine/workspace_authorization_test.go b/internal/subroutine/workspace_authorization_test.go index 0c475f8b..63c36712 100644 --- a/internal/subroutine/workspace_authorization_test.go +++ b/internal/subroutine/workspace_authorization_test.go @@ -197,8 +197,8 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) { Annotations: map[string]string{}, }, }, - cfg: config.Config{BaseDomain: "test.domain", GroupClaim: "groups", UserClaim: "email"}, - setupMocks: func(m *mocks.MockClient, mgrClient *mocks.MockClient) {}, + cfg: config.Config{BaseDomain: "test.domain", GroupClaim: "groups", UserClaim: "email"}, + setupMocks: func(m *mocks.MockClient, mgrClient *mocks.MockClient) {}, expectError: true, expectedResult: ctrl.Result{}, }, @@ -211,8 +211,8 @@ func TestWorkspaceAuthSubroutine_Process(t *testing.T) { }, }, }, - cfg: config.Config{BaseDomain: "test.domain", GroupClaim: "groups", UserClaim: "email"}, - setupMocks: func(m *mocks.MockClient, mgrClient *mocks.MockClient) {}, + cfg: config.Config{BaseDomain: "test.domain", GroupClaim: "groups", UserClaim: "email"}, + setupMocks: func(m *mocks.MockClient, mgrClient *mocks.MockClient) {}, expectError: true, expectedResult: ctrl.Result{}, }, From 37e9eed9990d645a03c69d6339340cda31cb3867 Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Fri, 23 Jan 2026 16:34:28 +0100 Subject: [PATCH 4/9] added the rest of the subroutines On-behalf-of: SAP aleh.yarshou@sap.com --- internal/controller/workspace_controller.go | 4 +- internal/subroutine/idp.go | 62 +++++++-------------- 2 files changed, 23 insertions(+), 43 deletions(-) diff --git a/internal/controller/workspace_controller.go b/internal/controller/workspace_controller.go index cb8f34ba..ec3675df 100644 --- a/internal/controller/workspace_controller.go +++ b/internal/controller/workspace_controller.go @@ -35,8 +35,10 @@ func NewWorkspaceReconciler(log *logger.Logger, orgClient client.Client, cfg con mgr: mgr, mclifecycle: builder.NewBuilder("logicalcluster", "LogicalClusterReconciler", []lifecyclesubroutine.Subroutine{ subroutine.NewWorkspaceInitializer(orgClient, cfg, mgr), + subroutine.NewIDPSubroutine(orgClient, mgr, cfg), + subroutine.NewInviteSubroutine(orgClient, mgr), subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, inClusterClient, mgr, cfg), - }, log).WithReadOnly().WithStaticThenExponentialRateLimiter().BuildMultiCluster(mgr), + }, log).WithReadOnly().BuildMultiCluster(mgr), } } diff --git a/internal/subroutine/idp.go b/internal/subroutine/idp.go index ebbfed6f..7e42597e 100644 --- a/internal/subroutine/idp.go +++ b/internal/subroutine/idp.go @@ -3,7 +3,6 @@ package subroutine import ( "context" "fmt" - "slices" "strings" accountv1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1" @@ -90,32 +89,28 @@ func (i *IDPSubroutine) Process(ctx context.Context, instance runtimeobject.Runt return ctrl.Result{}, nil } - clients := []v1alpha1.IdentityProviderClientConfig{ - { - ClientName: workspaceName, - ClientType: v1alpha1.IdentityProviderClientTypeConfidential, - RedirectURIs: append(i.additionalRedirectURLs, fmt.Sprintf("https://%s.%s/*", workspaceName, i.baseDomain)), - PostLogoutRedirectURIs: []string{fmt.Sprintf("https://%s.%s/logout*", workspaceName, i.baseDomain)}, - SecretRef: corev1.SecretReference{ - Name: fmt.Sprintf("portal-client-secret-%s-%s", workspaceName, workspaceName), - Namespace: secretNamespace, - }, - }, - { - ClientName: kubectlClientName, - ClientType: v1alpha1.IdentityProviderClientTypePublic, - RedirectURIs: i.kubectlClientRedirectURLs, - SecretRef: corev1.SecretReference{ - Name: fmt.Sprintf("portal-client-secret-%s-%s", workspaceName, kubectlClientName), - Namespace: secretNamespace, - }, - }, - } - idp := &v1alpha1.IdentityProviderConfiguration{ObjectMeta: metav1.ObjectMeta{Name: workspaceName}} _, err = controllerutil.CreateOrPatch(ctx, cl.GetClient(), idp, func() error { - for _, desired := range clients { - idp.Spec.Clients = ensureClient(idp.Spec.Clients, desired) + idp.Spec.Clients = []v1alpha1.IdentityProviderClientConfig{ + { + ClientName: workspaceName, + ClientType: v1alpha1.IdentityProviderClientTypeConfidential, + RedirectURIs: append(i.additionalRedirectURLs, fmt.Sprintf("https://%s.%s/*", workspaceName, i.baseDomain)), + PostLogoutRedirectURIs: []string{fmt.Sprintf("https://%s.%s/logout*", workspaceName, i.baseDomain)}, + SecretRef: corev1.SecretReference{ + Name: fmt.Sprintf("portal-client-secret-%s-%s", workspaceName, workspaceName), + Namespace: secretNamespace, + }, + }, + { + ClientName: kubectlClientName, + ClientType: v1alpha1.IdentityProviderClientTypePublic, + RedirectURIs: i.kubectlClientRedirectURLs, + SecretRef: corev1.SecretReference{ + Name: fmt.Sprintf("portal-client-secret-%s-%s", workspaceName, kubectlClientName), + Namespace: secretNamespace, + }, + }, } return nil }) @@ -140,23 +135,6 @@ func (i *IDPSubroutine) Process(ctx context.Context, instance runtimeobject.Runt return ctrl.Result{}, nil } -// ensureClient updates only fields managed by this subroutine, preserving ClientID and RegistrationClientURI -// that are set by reconciling an idp resource -func ensureClient(existing []v1alpha1.IdentityProviderClientConfig, desired v1alpha1.IdentityProviderClientConfig) []v1alpha1.IdentityProviderClientConfig { - idx := slices.IndexFunc(existing, func(c v1alpha1.IdentityProviderClientConfig) bool { - return c.ClientName == desired.ClientName - }) - - if idx != -1 { - existing[idx].ClientType = desired.ClientType - existing[idx].RedirectURIs = desired.RedirectURIs - existing[idx].PostLogoutRedirectURIs = desired.PostLogoutRedirectURIs - existing[idx].SecretRef = desired.SecretRef - return existing - } - - return append(existing, desired) -} func getWorkspaceName(lc *kcpcorev1alpha1.LogicalCluster) string { if path, ok := lc.Annotations["kcp.io/path"]; ok { From a55d8494b9ab9a9114b0f430110061a3f2c18419 Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Sat, 24 Jan 2026 14:46:31 +0100 Subject: [PATCH 5/9] used update instead of patch for idp resource creation On-behalf-of: SAP aleh.yarshou@sap.com --- internal/subroutine/idp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/subroutine/idp.go b/internal/subroutine/idp.go index 7e42597e..5b7f1056 100644 --- a/internal/subroutine/idp.go +++ b/internal/subroutine/idp.go @@ -90,7 +90,7 @@ func (i *IDPSubroutine) Process(ctx context.Context, instance runtimeobject.Runt } idp := &v1alpha1.IdentityProviderConfiguration{ObjectMeta: metav1.ObjectMeta{Name: workspaceName}} - _, err = controllerutil.CreateOrPatch(ctx, cl.GetClient(), idp, func() error { + _, err = controllerutil.CreateOrUpdate(ctx, cl.GetClient(), idp, func() error { idp.Spec.Clients = []v1alpha1.IdentityProviderClientConfig{ { ClientName: workspaceName, From 34c546dfe710a4231efe7008e639a7a0330ebac7 Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Sat, 24 Jan 2026 14:59:01 +0100 Subject: [PATCH 6/9] used initializer name from the config On-behalf-of: SAP aleh.yarshou@sap.com --- cmd/operator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/operator.go b/cmd/operator.go index e8eaf83e..1d72dffd 100644 --- a/cmd/operator.go +++ b/cmd/operator.go @@ -183,7 +183,7 @@ var operatorCmd = &cobra.Command{ return err } - if err = controller.NewWorkspaceReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, "root:security"); err != nil { + if err = controller.NewWorkspaceReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, operatorCfg.InitializerName); err != nil { log.Error().Err(err).Str("controller", "workspace").Msg("unable to create controller") return err } From 15a2b7e65a387a93d6b097412df1a09bc57bdf71 Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Sat, 24 Jan 2026 15:06:56 +0100 Subject: [PATCH 7/9] chore: naming refactoring On-behalf-of: SAP aleh.yarshou@sap.com --- cmd/initializer.go | 2 +- cmd/operator.go | 2 +- internal/controller/initializer_controller.go | 10 +++++----- ...e_controller.go => logical_cluster_controller.go} | 12 +++++------- 4 files changed, 12 insertions(+), 14 deletions(-) rename internal/controller/{workspace_controller.go => logical_cluster_controller.go} (82%) diff --git a/cmd/initializer.go b/cmd/initializer.go index 38f224ba..8455e83d 100644 --- a/cmd/initializer.go +++ b/cmd/initializer.go @@ -93,7 +93,7 @@ var initializerCmd = &cobra.Command{ initializerCfg.IDP.AdditionalRedirectURLs = []string{} } - if err := controller.NewLogicalClusterReconciler(log, orgClient, initializerCfg, runtimeClient, mgr). + if err := controller.NewLogicalClusterInitializer(log, orgClient, initializerCfg, runtimeClient, mgr). SetupWithManager(mgr, defaultCfg); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LogicalCluster") os.Exit(1) diff --git a/cmd/operator.go b/cmd/operator.go index 1d72dffd..d89cae2e 100644 --- a/cmd/operator.go +++ b/cmd/operator.go @@ -183,7 +183,7 @@ var operatorCmd = &cobra.Command{ return err } - if err = controller.NewWorkspaceReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, operatorCfg.InitializerName); err != nil { + if err = controller.NewLogicalClusterReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, operatorCfg.InitializerName); err != nil { log.Error().Err(err).Str("controller", "workspace").Msg("unable to create controller") return err } diff --git a/internal/controller/initializer_controller.go b/internal/controller/initializer_controller.go index 8a77a2f9..a1ebb973 100644 --- a/internal/controller/initializer_controller.go +++ b/internal/controller/initializer_controller.go @@ -20,14 +20,14 @@ import ( kcpcorev1alpha1 "github.com/kcp-dev/sdk/apis/core/v1alpha1" ) -type LogicalClusterReconciler struct { +type LogicalClusterInitializer struct { log *logger.Logger mclifecycle *multicluster.LifecycleManager } -func NewLogicalClusterReconciler(log *logger.Logger, orgClient client.Client, cfg config.Config, inClusterClient client.Client, mgr mcmanager.Manager) *LogicalClusterReconciler { - return &LogicalClusterReconciler{ +func NewLogicalClusterInitializer(log *logger.Logger, orgClient client.Client, cfg config.Config, inClusterClient client.Client, mgr mcmanager.Manager) *LogicalClusterInitializer { + return &LogicalClusterInitializer{ log: log, mclifecycle: builder.NewBuilder("logicalcluster", "LogicalClusterReconciler", []lifecyclesubroutine.Subroutine{ subroutine.NewWorkspaceInitializer(orgClient, cfg, mgr), @@ -42,11 +42,11 @@ func NewLogicalClusterReconciler(log *logger.Logger, orgClient client.Client, cf } } -func (r *LogicalClusterReconciler) Reconcile(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error) { +func (r *LogicalClusterInitializer) Reconcile(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error) { ctxWithCluster := mccontext.WithCluster(ctx, req.ClusterName) return r.mclifecycle.Reconcile(ctxWithCluster, req, &kcpcorev1alpha1.LogicalCluster{}) } -func (r *LogicalClusterReconciler) SetupWithManager(mgr mcmanager.Manager, cfg *platformeshconfig.CommonServiceConfig, evp ...predicate.Predicate) error { +func (r *LogicalClusterInitializer) SetupWithManager(mgr mcmanager.Manager, cfg *platformeshconfig.CommonServiceConfig, evp ...predicate.Predicate) error { return r.mclifecycle.SetupWithManager(mgr, cfg.MaxConcurrentReconciles, "LogicalCluster", &kcpcorev1alpha1.LogicalCluster{}, cfg.DebugLabelValue, r, r.log, evp...) } diff --git a/internal/controller/workspace_controller.go b/internal/controller/logical_cluster_controller.go similarity index 82% rename from internal/controller/workspace_controller.go rename to internal/controller/logical_cluster_controller.go index ec3675df..735dfbd6 100644 --- a/internal/controller/workspace_controller.go +++ b/internal/controller/logical_cluster_controller.go @@ -22,15 +22,14 @@ import ( kcpcorev1alpha1 "github.com/kcp-dev/sdk/apis/core/v1alpha1" ) -type WorkspaceReconciler struct { +type LogicalClusterReconciler struct { log *logger.Logger mgr mcmanager.Manager - initializer kcpcorev1alpha1.LogicalClusterInitializer mclifecycle *multicluster.LifecycleManager } -func NewWorkspaceReconciler(log *logger.Logger, orgClient client.Client, cfg config.Config, inClusterClient client.Client, mgr mcmanager.Manager) *WorkspaceReconciler { - return &WorkspaceReconciler{ +func NewLogicalClusterReconciler(log *logger.Logger, orgClient client.Client, cfg config.Config, inClusterClient client.Client, mgr mcmanager.Manager) *LogicalClusterReconciler { + return &LogicalClusterReconciler{ log: log, mgr: mgr, mclifecycle: builder.NewBuilder("logicalcluster", "LogicalClusterReconciler", []lifecyclesubroutine.Subroutine{ @@ -42,13 +41,12 @@ func NewWorkspaceReconciler(log *logger.Logger, orgClient client.Client, cfg con } } -func (r *WorkspaceReconciler) Reconcile(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error) { +func (r *LogicalClusterReconciler) Reconcile(ctx context.Context, req mcreconcile.Request) (ctrl.Result, error) { ctxWithCluster := mccontext.WithCluster(ctx, req.ClusterName) return r.mclifecycle.Reconcile(ctxWithCluster, req, &kcpcorev1alpha1.LogicalCluster{}) } -func (r *WorkspaceReconciler) SetupWithManager(mgr mcmanager.Manager, cfg *platformeshconfig.CommonServiceConfig, initializerName string, evp ...predicate.Predicate) error { - r.initializer = kcpcorev1alpha1.LogicalClusterInitializer(initializerName) +func (r *LogicalClusterReconciler) SetupWithManager(mgr mcmanager.Manager, cfg *platformeshconfig.CommonServiceConfig, initializerName string, evp ...predicate.Predicate) error { allPredicates := append([]predicate.Predicate{HasInitializerPredicate(initializerName)}, evp...) return r.mclifecycle.SetupWithManager(mgr, cfg.MaxConcurrentReconciles, "LogicalCluster", &kcpcorev1alpha1.LogicalCluster{}, cfg.DebugLabelValue, r, r.log, allPredicates...) } From 905bc01189715a16ddb3c2c34e3f9ad2962a4ada Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Mon, 26 Jan 2026 09:35:25 +0100 Subject: [PATCH 8/9] updated initializer name passing On-behalf-of: SAP aleh.yarshou@sap.com --- cmd/operator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/operator.go b/cmd/operator.go index 2762ddb6..930a5d36 100644 --- a/cmd/operator.go +++ b/cmd/operator.go @@ -183,7 +183,7 @@ var operatorCmd = &cobra.Command{ return err } - if err = controller.NewLogicalClusterReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, operatorCfg.InitializerName); err != nil { + if err = controller.NewLogicalClusterReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, operatorCfg.InitializerName()); err != nil { log.Error().Err(err).Str("controller", "workspace").Msg("unable to create controller") return err } From 31cec8fe98685ad696bffada99f97a9d1c2be9ac Mon Sep 17 00:00:00 2001 From: OlegErshov Date: Fri, 6 Feb 2026 15:57:09 +0100 Subject: [PATCH 9/9] chore: refactoring after merge On-behalf-of: SAP aleh.yarshou@sap.com --- cmd/operator.go | 4 ++-- internal/subroutine/idp.go | 18 ------------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/cmd/operator.go b/cmd/operator.go index f3995646..b786552f 100644 --- a/cmd/operator.go +++ b/cmd/operator.go @@ -184,8 +184,8 @@ var operatorCmd = &cobra.Command{ if err = controller.NewLogicalClusterReconciler(log, orgClient, operatorCfg, runtimeClient, mgr).SetupWithManager(mgr, defaultCfg, operatorCfg.InitializerName()); err != nil { log.Error().Err(err).Str("controller", "logicalcluster").Msg("unable to create controller") - return err - } + return err + } if err = controller.NewAccountInfoReconciler(log, mgr).SetupWithManager(mgr, defaultCfg); err != nil { log.Error().Err(err).Str("controller", "accountinfo").Msg("unable to create controller") return err diff --git a/internal/subroutine/idp.go b/internal/subroutine/idp.go index cd3611dc..f0e00cb3 100644 --- a/internal/subroutine/idp.go +++ b/internal/subroutine/idp.go @@ -190,24 +190,6 @@ func (i *IDPSubroutine) patchAccountInfo(ctx context.Context, cl client.Client, return nil } -// ensureClient updates only fields managed by this subroutine, preserving ClientID and RegistrationClientURI -// that are set by reconciling an idp resource -func ensureClient(existing []v1alpha1.IdentityProviderClientConfig, desired v1alpha1.IdentityProviderClientConfig) []v1alpha1.IdentityProviderClientConfig { - idx := slices.IndexFunc(existing, func(c v1alpha1.IdentityProviderClientConfig) bool { - return c.ClientName == desired.ClientName - }) - - if idx != -1 { - existing[idx].ClientType = desired.ClientType - existing[idx].RedirectURIs = desired.RedirectURIs - existing[idx].PostLogoutRedirectURIs = desired.PostLogoutRedirectURIs - existing[idx].SecretRef = desired.SecretRef - return existing - } - - return append(existing, desired) -} - func getWorkspaceName(lc *kcpcorev1alpha1.LogicalCluster) string { if path, ok := lc.Annotations["kcp.io/path"]; ok { pathElements := strings.Split(path, ":")