Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion cmd/initializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,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)
Expand Down
13 changes: 13 additions & 0 deletions cmd/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,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")
Expand All @@ -173,6 +181,11 @@ var operatorCmd = &cobra.Command{
log.Error().Err(err).Str("controller", "invite").Msg("unable to create controller")
return err
}

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
}
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
Expand Down
10 changes: 5 additions & 5 deletions internal/controller/initializer_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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...)
}
78 changes: 78 additions & 0 deletions internal/controller/logical_cluster_controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package controller

import (
"context"
"slices"

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"
"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"

kcpcorev1alpha1 "github.com/kcp-dev/sdk/apis/core/v1alpha1"
)

type LogicalClusterReconciler struct {
log *logger.Logger
mgr mcmanager.Manager
mclifecycle *multicluster.LifecycleManager
}

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{
subroutine.NewWorkspaceInitializer(orgClient, cfg, mgr),
subroutine.NewIDPSubroutine(orgClient, mgr, cfg),
subroutine.NewInviteSubroutine(orgClient, mgr),
subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, inClusterClient, mgr, cfg),
}, log).WithReadOnly().BuildMultiCluster(mgr),
}
}

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 *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...)
}

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)
}
63 changes: 20 additions & 43 deletions internal/subroutine/idp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package subroutine
import (
"context"
"fmt"
"slices"
"strings"

accountv1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1"
Expand Down Expand Up @@ -92,32 +91,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,
idp := &v1alpha1.IdentityProviderConfiguration{ObjectMeta: metav1.ObjectMeta{Name: workspaceName}}
_, err = controllerutil.CreateOrUpdate(ctx, cl.GetClient(), idp, func() error {
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,
{
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)
}
return nil
})
Expand Down Expand Up @@ -195,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, ":")
Expand Down
Loading