diff --git a/src/internal/controller/organization_controller.go b/src/internal/controller/organization_controller.go index 8767d4f..142087d 100644 --- a/src/internal/controller/organization_controller.go +++ b/src/internal/controller/organization_controller.go @@ -91,19 +91,31 @@ func newWrappedOrganizationReconciler(client client.Client, refResolver *zitadel } func (wr *wrappedOrganizationReconciler) Reconcile(ctx context.Context, ztdClient *management.Client) error { - // TODO: check if org exists first - resp, err := ztdClient.AddOrg(ctx, &pb.AddOrgRequest{ - Name: wr.organization.Name, + zitadelCluster, err := wr.refResolver.ZitadelCluster(ctx, &wr.organization.Spec.ZitadelClusterRef, wr.organization.Namespace) + if err != nil { + return err + } + orgRes, err := ztdClient.GetOrgByDomainGlobal(ctx, &pb.GetOrgByDomainGlobalRequest{ + Domain: strings.ToLower(fmt.Sprintf("%s.%s", wr.organization.Name, zitadelCluster.Spec.Host)), }) if err != nil { - if strings.Contains(err.Error(), "AlreadyExists") { - return nil + if !strings.Contains(err.Error(), "not found") { + return fmt.Errorf("Error getting org: %v", err) } - return fmt.Errorf("error creating organization in Zitadel: %v", err) } - patch := ctrlClient.MergeFrom(wr.organization.DeepCopy()) - wr.organization.Status.OrgId = resp.Id - return wr.Client.Status().Patch(ctx, wr.organization, patch) + // TODO: add initial user + if orgRes == nil { + resp, err := ztdClient.AddOrg(ctx, &pb.AddOrgRequest{ + Name: strings.ToLower(wr.organization.Name), + }) + if err != nil { + return fmt.Errorf("error creating organization in Zitadel: %v", err) + } + patch := ctrlClient.MergeFrom(wr.organization.DeepCopy()) + wr.organization.Status.OrgId = resp.Id + return wr.Client.Status().Patch(ctx, wr.organization, patch) + } + return nil } func (wr *wrappedOrganizationReconciler) PatchStatus(ctx context.Context, patcher condition.Patcher) error { diff --git a/src/internal/controller/zitadelcluster_controller.go b/src/internal/controller/zitadelcluster_controller.go index 10fafa2..1203285 100644 --- a/src/internal/controller/zitadelcluster_controller.go +++ b/src/internal/controller/zitadelcluster_controller.go @@ -153,6 +153,10 @@ func (r *ZitadelClusterReconciler) Reconcile(ctx context.Context, req ctrl.Reque Name: "DefaultInstance", Reconcile: r.reconcileDefaultInstance, }, + { + Name: "DefaultOrgManifest", + Reconcile: r.reconcileOrgManifest, + }, { Name: "SMTPConfig", Reconcile: r.reconcileSMTPConfig, @@ -457,6 +461,31 @@ func (r *ZitadelClusterReconciler) reconcileDefaultInstance(ctx context.Context, return ctrl.Result{}, nil } +func (r *ZitadelClusterReconciler) reconcileOrgManifest(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { + key := types.NamespacedName{ + Name: zitadel.Name, + Namespace: zitadel.Namespace, + } + desiredOrganization, err := r.Builder.BuildOrganization(builder.OrganizationOpts{ + Key: key, + Zitadel: zitadel, + }, zitadel) + if err != nil { + return ctrl.Result{}, fmt.Errorf("error building default organization: %v", err) + } + + var existingOrganization zitadelv1alpha1.Organization + if err := r.Get(ctx, key, &existingOrganization); err != nil { + if !errors.IsNotFound(err) { + return ctrl.Result{}, fmt.Errorf("error getting Organization: %v", err) + } + if err := r.Create(ctx, desiredOrganization); err != nil { + return ctrl.Result{}, fmt.Errorf("error creating Organization: %v", err) + } + } + return ctrl.Result{}, nil +} + func (r *ZitadelClusterReconciler) reconcileSMTPConfig(ctx context.Context, zitadel *zitadelv1alpha1.ZitadelCluster) (ctrl.Result, error) { adminClient, err := zitadelClient.NewAdminClient(ctx, zitadel, *r.RefResolver) if err != nil { @@ -707,6 +736,7 @@ func (r *ZitadelClusterReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&corev1.Service{}). Owns(&corev1.ConfigMap{}). Owns(&corev1.Secret{}). + Owns(&zitadelv1alpha1.Organization{}). WithOptions(controller.Options{RateLimiter: workqueue.NewItemExponentialFailureRateLimiter(time.Millisecond*500, time.Minute*3)}). Complete(r) } diff --git a/src/pkg/builder/organization_builder.go b/src/pkg/builder/organization_builder.go new file mode 100644 index 0000000..7126491 --- /dev/null +++ b/src/pkg/builder/organization_builder.go @@ -0,0 +1,42 @@ +package builder + +import ( + "fmt" + + zitadelv1alpha1 "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/api/v1alpha1" + metadata "bitbucket.org/topmanage-software-engineering/zitadel-k8s-operator/src/pkg/builder/metadata" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +type OrganizationOpts struct { + Key types.NamespacedName + Zitadel *zitadelv1alpha1.ZitadelCluster +} + +func (b *Builder) BuildOrganization(opts OrganizationOpts, owner metav1.Object) (*zitadelv1alpha1.Organization, error) { + objMeta := + metadata.NewMetadataBuilder(opts.Key). + Build() + + org := &zitadelv1alpha1.Organization{ + ObjectMeta: objMeta, + Spec: zitadelv1alpha1.OrganizationSpec{ + ZitadelClusterRef: zitadelv1alpha1.ZitadelClusterRef{ + ObjectReference: corev1.ObjectReference{ + Kind: "ZitadelCluster", + Namespace: opts.Zitadel.Namespace, + Name: opts.Zitadel.Name, + APIVersion: "v1alpha1", + }, + }, + }, + } + + if err := controllerutil.SetControllerReference(owner, org, b.scheme); err != nil { + return nil, fmt.Errorf("error setting controller reference in Secret manifest: %v", err) + } + return org, nil +}