From 9ca80b2779496fc607d9baf9fd2e147c9582ad35 Mon Sep 17 00:00:00 2001 From: Ivan Sabelnikov Date: Fri, 20 Oct 2023 19:11:56 +0100 Subject: [PATCH 1/2] feat: add is_default property to org --- docs/data-sources/org.md | 1 + docs/resources/org.md | 4 ++++ zitadel/org/const.go | 1 + zitadel/org/datasource.go | 5 +++++ zitadel/org/funcs.go | 42 ++++++++++++++++++++++++++++++++++++++- zitadel/org/resource.go | 5 +++++ 6 files changed, 57 insertions(+), 1 deletion(-) diff --git a/docs/data-sources/org.md b/docs/data-sources/org.md index 10527a93..6e1d65d0 100644 --- a/docs/data-sources/org.md +++ b/docs/data-sources/org.md @@ -30,6 +30,7 @@ output "org" { ### Read-Only +- `is_default` (Boolean) Indicates whether the org is the default org of the instance. - `name` (String) Name of the org. - `primary_domain` (String) Primary domain of the org - `state` (String) State of the org, supported values: ORG_STATE_UNSPECIFIED, ORG_STATE_ACTIVE, ORG_STATE_INACTIVE, ORG_STATE_REMOVED \ No newline at end of file diff --git a/docs/resources/org.md b/docs/resources/org.md index 0cebcd7e..269837de 100644 --- a/docs/resources/org.md +++ b/docs/resources/org.md @@ -24,6 +24,10 @@ resource "zitadel_org" "default" { - `name` (String) Name of the org +### Optional + +- `is_default` (Boolean) True sets the org as default org for the instance. Only one org can be default org. Nothing happens if you set it to false until you set another org as default org. + ### Read-Only - `id` (String) The ID of this resource. diff --git a/zitadel/org/const.go b/zitadel/org/const.go index 450075aa..42f7f0cc 100644 --- a/zitadel/org/const.go +++ b/zitadel/org/const.go @@ -4,6 +4,7 @@ const ( OrgIDVar = "id" orgIDsVar = "ids" NameVar = "name" + IsDefaultVar = "is_default" nameMethodVar = "name_method" DomainVar = "domain" domainMethodVar = "domain_method" diff --git a/zitadel/org/datasource.go b/zitadel/org/datasource.go index 80fcf297..b3cfc6c4 100644 --- a/zitadel/org/datasource.go +++ b/zitadel/org/datasource.go @@ -28,6 +28,11 @@ func GetDatasource() *schema.Resource { Computed: true, Description: "Name of the org.", }, + IsDefaultVar: { + Type: schema.TypeBool, + Computed: true, + Description: "Indicates whether the org is the default org of the instance.", + }, stateVar: { Type: schema.TypeString, Computed: true, diff --git a/zitadel/org/funcs.go b/zitadel/org/funcs.go index b089c6ff..dde5ed2b 100644 --- a/zitadel/org/funcs.go +++ b/zitadel/org/funcs.go @@ -50,7 +50,20 @@ func create(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Dia if err != nil { return diag.FromErr(err) } - d.SetId(resp.GetId()) + orgId := resp.GetId() + d.SetId(orgId) + if val, ok := d.GetOk(IsDefaultVar); ok && val.(bool) { + adminClient, err := helper.GetAdminClient(clientinfo) + if err != nil { + return diag.FromErr(err) + } + _, err = adminClient.SetDefaultOrg(ctx, &admin.SetDefaultOrgRequest{ + OrgId: orgId, + }) + if err != nil { + return diag.Errorf("error while setting default org id %s: %v", orgId, err) + } + } return nil } @@ -71,6 +84,19 @@ func update(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Dia if err != nil { return diag.Errorf("failed to update org: %v", err) } + // To unset the default org, we need to set another org as default org. + if isDefault, ok := d.GetOk(IsDefaultVar); ok && isDefault.(bool) && d.HasChange(IsDefaultVar) { + adminClient, err := helper.GetAdminClient(clientinfo) + if err != nil { + return diag.FromErr(err) + } + _, err = adminClient.SetDefaultOrg(ctx, &admin.SetDefaultOrgRequest{ + OrgId: d.Id(), + }) + if err != nil { + return diag.Errorf("error while setting default org id %s: %v", d.Id(), err) + } + } return nil } @@ -103,6 +129,19 @@ func get(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagno if err := d.Set(stateVar, state); err != nil { return diag.Errorf("error while setting org state %s: %v", state, err) } + adminClient, err := helper.GetAdminClient(clientinfo) + if err != nil { + return diag.FromErr(err) + } + defaultOrg, err := adminClient.GetDefaultOrg(ctx, &admin.GetDefaultOrgRequest{}) + if err != nil { + return diag.Errorf("error while getting default instance org: %v", err) + } + if defaultOrg.Org.Id == remoteOrg.Id { + if err := d.Set(IsDefaultVar, true); err != nil { + return diag.Errorf("error while setting org is_default: %v", err) + } + } return nil } @@ -159,6 +198,7 @@ func list(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagn for i, org := range resp.Result { orgIDs[i] = org.Id } + // If the ID is blank, the datasource is deleted and not usable. d.SetId("-") return diag.FromErr(d.Set(orgIDsVar, orgIDs)) diff --git a/zitadel/org/resource.go b/zitadel/org/resource.go index d43da0cf..d40188d3 100644 --- a/zitadel/org/resource.go +++ b/zitadel/org/resource.go @@ -15,6 +15,11 @@ func GetResource() *schema.Resource { Required: true, Description: "Name of the org", }, + IsDefaultVar: { + Type: schema.TypeBool, + Optional: true, + Description: "True sets the org as default org for the instance. Only one org can be default org. Nothing happens if you set it to false until you set another org as default org.", + }, primaryDomainVar: { Type: schema.TypeString, Computed: true, From 41799b4bbb198c85e28f2d84b0c2fa343a9a582e Mon Sep 17 00:00:00 2001 From: Ivan Sabelnikov Date: Fri, 20 Oct 2023 20:12:46 +0100 Subject: [PATCH 2/2] fix: 1) forever pending is_default = true => null 2) failing update when org name does not change --- zitadel/org/funcs.go | 22 ++++++++++++---------- zitadel/org/resource.go | 10 ++++++++-- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/zitadel/org/funcs.go b/zitadel/org/funcs.go index dde5ed2b..cd96505c 100644 --- a/zitadel/org/funcs.go +++ b/zitadel/org/funcs.go @@ -73,16 +73,19 @@ func update(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Dia if !ok { return diag.Errorf("failed to get client") } - client, err := helper.GetManagementClient(clientinfo) - if err != nil { - return diag.FromErr(err) - } + // If try updating the name to the same value API will return an error. + if d.HasChange(NameVar) { + client, err := helper.GetManagementClient(clientinfo) + if err != nil { + return diag.FromErr(err) + } - _, err = client.UpdateOrg(helper.CtxSetOrgID(ctx, d.Id()), &management.UpdateOrgRequest{ - Name: d.Get(NameVar).(string), - }) - if err != nil { - return diag.Errorf("failed to update org: %v", err) + _, err = client.UpdateOrg(helper.CtxSetOrgID(ctx, d.Id()), &management.UpdateOrgRequest{ + Name: d.Get(NameVar).(string), + }) + if err != nil { + return diag.Errorf("failed to update org: %v", err) + } } // To unset the default org, we need to set another org as default org. if isDefault, ok := d.GetOk(IsDefaultVar); ok && isDefault.(bool) && d.HasChange(IsDefaultVar) { @@ -198,7 +201,6 @@ func list(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagn for i, org := range resp.Result { orgIDs[i] = org.Id } - // If the ID is blank, the datasource is deleted and not usable. d.SetId("-") return diag.FromErr(d.Set(orgIDsVar, orgIDs)) diff --git a/zitadel/org/resource.go b/zitadel/org/resource.go index d40188d3..d2293a2c 100644 --- a/zitadel/org/resource.go +++ b/zitadel/org/resource.go @@ -16,8 +16,14 @@ func GetResource() *schema.Resource { Description: "Name of the org", }, IsDefaultVar: { - Type: schema.TypeBool, - Optional: true, + Type: schema.TypeBool, + Optional: true, + DiffSuppressOnRefresh: true, + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + // Need to avoid forever pending changes when trying to set this to false + // since setting to false will not actually unmark the org as default. + return new != "true" + }, Description: "True sets the org as default org for the instance. Only one org can be default org. Nothing happens if you set it to false until you set another org as default org.", }, primaryDomainVar: {