Skip to content

Commit 6a8cc19

Browse files
Feat/create user invite (#125)
* feat: added invite resource creation On-behalf-of: SAP [email protected] * chore: fixed formatting and added comments On-behalf-of: SAP [email protected] * chore: fixed typo On-behalf-of: SAP [email protected] * feat: added waiting for Ready state functionality On-behalf-of: SAP [email protected] * chore: refactored message styling On-behalf-of: SAP [email protected] * feat: added tests On-behalf-of: SAP [email protected] * feat: added exponential backoff and org type check On-behalf-of: SAP [email protected] * added protection from going out of array boundaries On-behalf-of: SAP [email protected] * fix: fixed tests On-behalf-of: SAP [email protected] * added more tests On-behalf-of: SAP [email protected] * fix: fixed potential bugs On-behalf-of: SAP [email protected] * chore: removed e-mail address from logging On-behalf-of: SAP [email protected] * chore: fixed typo On-behalf-of: SAP [email protected] * chore: some minor improvements * chore: refactored tests On-behalf-of: SAP [email protected] --------- Co-authored-by: aaronschweig <[email protected]>
1 parent 3c340ed commit 6a8cc19

File tree

4 files changed

+435
-2
lines changed

4 files changed

+435
-2
lines changed

internal/controller/initializer_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func NewLogicalClusterReconciler(log *logger.Logger, orgClient client.Client, cf
3333
subroutine.NewWorkspaceInitializer(orgClient, cfg, mgr),
3434
subroutine.NewWorkspaceAuthConfigurationSubroutine(orgClient, inClusterClient, cfg),
3535
subroutine.NewRealmSubroutine(inClusterClient, &cfg, cfg.BaseDomain),
36+
subroutine.NewInviteSubroutine(orgClient, mgr),
3637
subroutine.NewRemoveInitializer(mgr, cfg.InitializerName),
3738
}, log).
3839
WithReadOnly().

internal/subroutine/invite.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package subroutine
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
kcpv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
8+
accountv1alpha1 "github.com/platform-mesh/account-operator/api/v1alpha1"
9+
"github.com/platform-mesh/golang-commons/controller/lifecycle/runtimeobject"
10+
lifecyclesubroutine "github.com/platform-mesh/golang-commons/controller/lifecycle/subroutine"
11+
"github.com/rs/zerolog/log"
12+
13+
"k8s.io/apimachinery/pkg/api/meta"
14+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/types"
16+
"k8s.io/apimachinery/pkg/util/wait"
17+
18+
"github.com/platform-mesh/golang-commons/errors"
19+
ctrl "sigs.k8s.io/controller-runtime"
20+
"sigs.k8s.io/controller-runtime/pkg/client"
21+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
22+
mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager"
23+
24+
"k8s.io/client-go/util/retry"
25+
26+
"github.com/platform-mesh/security-operator/api/v1alpha1"
27+
)
28+
29+
func NewInviteSubroutine(orgsClient client.Client, mgr mcmanager.Manager) *inviteSubroutine {
30+
return &inviteSubroutine{
31+
orgsClient: orgsClient,
32+
mgr: mgr,
33+
}
34+
}
35+
36+
var _ lifecyclesubroutine.Subroutine = &inviteSubroutine{}
37+
38+
type inviteSubroutine struct {
39+
orgsClient client.Client
40+
mgr mcmanager.Manager
41+
}
42+
43+
func (w *inviteSubroutine) Finalize(ctx context.Context, instance runtimeobject.RuntimeObject) (ctrl.Result, errors.OperatorError) {
44+
return ctrl.Result{}, nil
45+
}
46+
47+
func (w *inviteSubroutine) Finalizers(_ runtimeobject.RuntimeObject) []string {
48+
return nil
49+
}
50+
51+
func (w *inviteSubroutine) GetName() string { return "InviteInitilizationSubroutine" }
52+
53+
func (w *inviteSubroutine) Process(ctx context.Context, instance runtimeobject.RuntimeObject) (ctrl.Result, errors.OperatorError) {
54+
lc := instance.(*kcpv1alpha1.LogicalCluster)
55+
56+
wsName := getWorkspaceName(lc)
57+
if wsName == "" {
58+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to get workspace name"), true, false)
59+
}
60+
61+
cl, err := w.mgr.ClusterFromContext(ctx)
62+
if err != nil {
63+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to get cluster from context %w", err), true, true)
64+
}
65+
66+
var account accountv1alpha1.Account
67+
err = w.orgsClient.Get(ctx, types.NamespacedName{Name: wsName}, &account)
68+
if err != nil {
69+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to get account resource %w", err), true, true)
70+
}
71+
72+
if account.Spec.Type != accountv1alpha1.AccountTypeOrg {
73+
log.Info().Str("workspace", wsName).Msg("account is not of type organization, skipping invite creation")
74+
return ctrl.Result{}, nil
75+
}
76+
77+
if account.Spec.Creator == nil {
78+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("account.Spec.Creator is nil for account %s", wsName), true, true)
79+
}
80+
81+
// the Invite resource is created in :root:orgs:<new org> workspace
82+
invite := &v1alpha1.Invite{ObjectMeta: metav1.ObjectMeta{Name: wsName}}
83+
_, err = controllerutil.CreateOrUpdate(ctx, cl.GetClient(), invite, func() error {
84+
invite.Spec.Email = *account.Spec.Creator
85+
86+
return nil
87+
})
88+
if err != nil {
89+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("failed to create invite resource %w", err), true, true)
90+
}
91+
92+
log.Info().Str("workspace", wsName).Msg("invite resource created")
93+
94+
err = wait.ExponentialBackoffWithContext(ctx, retry.DefaultBackoff,
95+
func(ctx context.Context) (bool, error) {
96+
if err := cl.GetClient().Get(ctx, types.NamespacedName{Name: wsName}, invite); err != nil {
97+
return false, err
98+
}
99+
100+
return meta.IsStatusConditionTrue(invite.GetConditions(), "Ready"), nil
101+
})
102+
if err != nil {
103+
log.Info().Str("workspace", wsName).Msg("invite resource not ready yet")
104+
return ctrl.Result{}, errors.NewOperatorError(fmt.Errorf("invite resource is not ready yet"), true, false)
105+
}
106+
107+
log.Info().Str("workspace", wsName).Msg("invite resource ready")
108+
return ctrl.Result{}, nil
109+
}

0 commit comments

Comments
 (0)