From a2f1177ef0c2049b49418627547ddc30f21c2e3b Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 20 Feb 2025 19:46:09 +0000 Subject: [PATCH 1/8] feat: add `sync_mapping` attribute to `coderd_organization` resource --- internal/provider/organization_resource.go | 127 ++++++++++++++++++--- internal/provider/util.go | 6 +- 2 files changed, 116 insertions(+), 17 deletions(-) diff --git a/internal/provider/organization_resource.go b/internal/provider/organization_resource.go index 2c39f0c..8d3ac19 100644 --- a/internal/provider/organization_resource.go +++ b/internal/provider/organization_resource.go @@ -5,6 +5,7 @@ import ( "fmt" "regexp" + "github.com/coder/coder/v2/coderd/util/slice" "github.com/coder/coder/v2/codersdk" "github.com/coder/terraform-provider-coderd/internal/codersdkvalidator" "github.com/google/uuid" @@ -40,8 +41,9 @@ type OrganizationResourceModel struct { Description types.String `tfsdk:"description"` Icon types.String `tfsdk:"icon"` - GroupSync types.Object `tfsdk:"group_sync"` - RoleSync types.Object `tfsdk:"role_sync"` + SyncMapping types.Set `tfsdk:"sync_mapping"` + GroupSync types.Object `tfsdk:"group_sync"` + RoleSync types.Object `tfsdk:"role_sync"` } type GroupSyncModel struct { @@ -134,6 +136,12 @@ This resource is only compatible with Coder version [2.16.0](https://github.com/ Computed: true, Default: stringdefault.StaticString(""), }, + + "sync_mapping": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + MarkdownDescription: "Claims from the IdP provider that will give users access to this organization.", + }, }, Blocks: map[string]schema.Block{ @@ -361,21 +369,38 @@ func (r *OrganizationResource) Create(ctx context.Context, req resource.CreateRe // default it. data.DisplayName = types.StringValue(org.DisplayName) - // Now apply group and role sync settings, if specified orgID := data.ID.ValueUUID() - tflog.Trace(ctx, "updating group sync", map[string]any{ - "orgID": orgID, - }) + + // Apply org sync patches, if specified + if !data.SyncMapping.IsNull() { + tflog.Trace(ctx, "updating org sync", map[string]any{ + "orgID": orgID, + }) + + var claims []string + resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, &claims, false)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(r.patchOrgSyncMapping(ctx, orgID, []string{}, claims)...) + } + + // Apply group and role sync settings, if specified if !data.GroupSync.IsNull() { + tflog.Trace(ctx, "updating group sync", map[string]any{ + "orgID": orgID, + }) + resp.Diagnostics.Append(r.patchGroupSync(ctx, orgID, data.GroupSync)...) if resp.Diagnostics.HasError() { return } } - tflog.Trace(ctx, "updating role sync", map[string]any{ - "orgID": orgID, - }) if !data.RoleSync.IsNull() { + tflog.Trace(ctx, "updating role sync", map[string]any{ + "orgID": orgID, + }) resp.Diagnostics.Append(r.patchRoleSync(ctx, orgID, data.RoleSync)...) if resp.Diagnostics.HasError() { return @@ -423,19 +448,42 @@ func (r *OrganizationResource) Update(ctx context.Context, req resource.UpdateRe "icon": org.Icon, }) - tflog.Trace(ctx, "updating group sync", map[string]any{ - "orgID": orgID, - }) + // Apply org sync patches, if specified + if !data.SyncMapping.IsNull() { + tflog.Trace(ctx, "updating org sync mappings", map[string]any{ + "orgID": orgID, + }) + + var state OrganizationResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + var currentClaims []string + resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, ¤tClaims, false)...) + + var plannedClaims []string + resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, &plannedClaims, false)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(r.patchOrgSyncMapping(ctx, orgID, currentClaims, plannedClaims)...) + if resp.Diagnostics.HasError() { + return + } + } + if !data.GroupSync.IsNull() { + tflog.Trace(ctx, "updating group sync", map[string]any{ + "orgID": orgID, + }) resp.Diagnostics.Append(r.patchGroupSync(ctx, orgID, data.GroupSync)...) if resp.Diagnostics.HasError() { return } } - tflog.Trace(ctx, "updating role sync", map[string]any{ - "orgID": orgID, - }) if !data.RoleSync.IsNull() { + tflog.Trace(ctx, "updating role sync", map[string]any{ + "orgID": orgID, + }) resp.Diagnostics.Append(r.patchRoleSync(ctx, orgID, data.RoleSync)...) if resp.Diagnostics.HasError() { return @@ -456,6 +504,21 @@ func (r *OrganizationResource) Delete(ctx context.Context, req resource.DeleteRe orgID := data.ID.ValueUUID() + // Remove org sync mappings, if we were managing them + if !data.SyncMapping.IsNull() { + tflog.Trace(ctx, "deleting org sync mappings", map[string]any{ + "orgID": orgID, + }) + + var claims []string + resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, &claims, false)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(r.patchOrgSyncMapping(ctx, orgID, claims, []string{})...) + } + tflog.Trace(ctx, "deleting organization", map[string]any{ "id": orgID, "name": data.Name.ValueString(), @@ -554,3 +617,37 @@ func (r *OrganizationResource) patchRoleSync( return diags } + +func (r *OrganizationResource) patchOrgSyncMapping( + ctx context.Context, + orgID uuid.UUID, + currentClaims, plannedClaims []string, +) diag.Diagnostics { + var diags diag.Diagnostics + + add, remove := slice.SymmetricDifference(currentClaims, plannedClaims) + var addMappings []codersdk.IDPSyncMapping[uuid.UUID] + for _, claim := range add { + addMappings = append(addMappings, codersdk.IDPSyncMapping[uuid.UUID]{ + Given: claim, + Gets: orgID, + }) + } + var removeMappings []codersdk.IDPSyncMapping[uuid.UUID] + for _, claim := range remove { + addMappings = append(removeMappings, codersdk.IDPSyncMapping[uuid.UUID]{ + Given: claim, + Gets: orgID, + }) + } + + _, err := r.Client.PatchOrganizationIDPSyncMapping(ctx, codersdk.PatchOrganizationIDPSyncMappingRequest{ + Add: addMappings, + Remove: removeMappings, + }) + if err != nil { + diags.AddError("Org Sync Update error", err.Error()) + } + + return diags +} diff --git a/internal/provider/util.go b/internal/provider/util.go index 169286f..e409738 100644 --- a/internal/provider/util.go +++ b/internal/provider/util.go @@ -83,8 +83,10 @@ func computeDirectoryHash(directory string) (string, error) { return hex.EncodeToString(hash.Sum(nil)), nil } -// memberDiff returns the members to add and remove from the group, given the current members and the planned members. -// plannedMembers is deliberately our custom type, as Terraform cannot automatically produce `[]uuid.UUID` from a set. +// memberDiff returns the members to add and remove from the group, given the +// current members and the planned members. plannedMembers is deliberately our +// custom type, as Terraform cannot automatically produce `[]uuid.UUID` from a +// set. func memberDiff(currentMembers []uuid.UUID, plannedMembers []UUID) (add, remove []string) { curSet := make(map[uuid.UUID]struct{}, len(currentMembers)) planSet := make(map[uuid.UUID]struct{}, len(plannedMembers)) From 70566a7b4e8404f8bb095a57473584332d78ce77 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 20 Feb 2025 20:17:42 +0000 Subject: [PATCH 2/8] tests and docs and such --- docs/resources/organization.md | 29 +++++++++++++++ .../resources/coderd_organization/resource.tf | 25 +++++++++++++ internal/provider/organization_resource.go | 4 +-- .../provider/organization_resource_test.go | 35 +++++++++++++++++-- 4 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 examples/resources/coderd_organization/resource.tf diff --git a/docs/resources/organization.md b/docs/resources/organization.md index 6dbc5d1..9b73549 100644 --- a/docs/resources/organization.md +++ b/docs/resources/organization.md @@ -15,7 +15,35 @@ An organization on the Coder deployment. ~> **Warning** This resource is only compatible with Coder version [2.16.0](https://github.com/coder/coder/releases/tag/v2.16.0) and later. +## Example Usage +```terraform +resource "coderd_organization" "blueberry" { + name = "blueberry" + display_name = "Blueberry" + description = "The organization for blueberries" + icon = "/emojis/1fad0.png" + + sync_mapping = [ + "wibble", + "wobble", + ] + + group_sync { + field = "coder_groups" + mapping = { + toast = [coderd_group.bread.id] + } + } + + role_sync { + field = "coder_roles" + mapping = { + manager = ["organization-user-admin"] + } + } +} +``` ## Schema @@ -31,6 +59,7 @@ This resource is only compatible with Coder version [2.16.0](https://github.com/ - `group_sync` (Block, Optional) Group sync settings to sync groups from an IdP. (see [below for nested schema](#nestedblock--group_sync)) - `icon` (String) - `role_sync` (Block, Optional) Role sync settings to sync organization roles from an IdP. (see [below for nested schema](#nestedblock--role_sync)) +- `sync_mapping` (Set of String) Claims from the IdP provider that will give users access to this organization. ### Read-Only diff --git a/examples/resources/coderd_organization/resource.tf b/examples/resources/coderd_organization/resource.tf new file mode 100644 index 0000000..991c39e --- /dev/null +++ b/examples/resources/coderd_organization/resource.tf @@ -0,0 +1,25 @@ +resource "coderd_organization" "blueberry" { + name = "blueberry" + display_name = "Blueberry" + description = "The organization for blueberries" + icon = "/emojis/1fad0.png" + + sync_mapping = [ + "wibble", + "wobble", + ] + + group_sync { + field = "coder_groups" + mapping = { + toast = [coderd_group.bread.id] + } + } + + role_sync { + field = "coder_roles" + mapping = { + manager = ["organization-user-admin"] + } + } +} diff --git a/internal/provider/organization_resource.go b/internal/provider/organization_resource.go index 8d3ac19..082641f 100644 --- a/internal/provider/organization_resource.go +++ b/internal/provider/organization_resource.go @@ -457,7 +457,7 @@ func (r *OrganizationResource) Update(ctx context.Context, req resource.UpdateRe var state OrganizationResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) var currentClaims []string - resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, ¤tClaims, false)...) + resp.Diagnostics.Append(state.SyncMapping.ElementsAs(ctx, ¤tClaims, false)...) var plannedClaims []string resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, &plannedClaims, false)...) @@ -635,7 +635,7 @@ func (r *OrganizationResource) patchOrgSyncMapping( } var removeMappings []codersdk.IDPSyncMapping[uuid.UUID] for _, claim := range remove { - addMappings = append(removeMappings, codersdk.IDPSyncMapping[uuid.UUID]{ + removeMappings = append(removeMappings, codersdk.IDPSyncMapping[uuid.UUID]{ Given: claim, Gets: orgID, }) diff --git a/internal/provider/organization_resource_test.go b/internal/provider/organization_resource_test.go index 0a755c4..f753324 100644 --- a/internal/provider/organization_resource_test.go +++ b/internal/provider/organization_resource_test.go @@ -55,6 +55,12 @@ func TestAccOrganizationResource(t *testing.T) { }, }) + cfg4 := cfg2 + cfg4.SyncMapping = []string{"wibble", "wobble"} + + cfg5 := cfg4 + cfg5.SyncMapping = []string{"wibbley", "wobbley"} + t.Run("CreateImportUpdateReadOk", func(t *testing.T) { resource.Test(t, resource.TestCase{ IsUnitTest: true, @@ -96,6 +102,22 @@ func TestAccOrganizationResource(t *testing.T) { statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("role_sync").AtMapKey("mapping").AtMapKey("wobble").AtSliceIndex(0), knownvalue.StringExact("wobbly")), }, }, + // Add org sync + { + Config: cfg4.String(t), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibble")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobble")), + }, + }, + // Patch org sync + { + Config: cfg5.String(t), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibbley")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobbley")), + }, + }, }, }) }) @@ -110,8 +132,9 @@ type testAccOrganizationResourceConfig struct { Description *string Icon *string - GroupSync *codersdk.GroupSyncSettings - RoleSync *codersdk.RoleSyncSettings + SyncMapping []string + GroupSync *codersdk.GroupSyncSettings + RoleSync *codersdk.RoleSyncSettings } func (c testAccOrganizationResourceConfig) String(t *testing.T) string { @@ -128,6 +151,14 @@ resource "coderd_organization" "test" { description = {{orNull .Description}} icon = {{orNull .Icon}} + {{- if .SyncMapping}} + sync_mapping = [ + {{- range $name := .SyncMapping }} + "{{$name}}", + {{- end}} + ] + {{- end}} + {{- if .GroupSync}} group_sync { field = "{{.GroupSync.Field}}" From cd9bce48581f9f4ba0be1066bdd54ca37176b0e7 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 20 Feb 2025 20:29:49 +0000 Subject: [PATCH 3/8] hmm --- internal/provider/organization_resource_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/provider/organization_resource_test.go b/internal/provider/organization_resource_test.go index f753324..30d8dff 100644 --- a/internal/provider/organization_resource_test.go +++ b/internal/provider/organization_resource_test.go @@ -42,25 +42,25 @@ func TestAccOrganizationResource(t *testing.T) { cfg2.DisplayName = ptr.Ref("Example Organization New") cfg3 := cfg2 - cfg3.GroupSync = ptr.Ref(codersdk.GroupSyncSettings{ + cfg3.SyncMapping = []string{"wibble", "wobble"} + + cfg4 := cfg3 + cfg4.SyncMapping = []string{"wibbley", "wobbley"} + + cfg5 := cfg4 + cfg5.GroupSync = ptr.Ref(codersdk.GroupSyncSettings{ Field: "wibble", Mapping: map[string][]uuid.UUID{ "wibble": {uuid.MustParse("6e57187f-6543-46ab-a62c-a10065dd4314")}, }, }) - cfg3.RoleSync = ptr.Ref(codersdk.RoleSyncSettings{ + cfg5.RoleSync = ptr.Ref(codersdk.RoleSyncSettings{ Field: "wobble", Mapping: map[string][]string{ "wobble": {"wobbly"}, }, }) - cfg4 := cfg2 - cfg4.SyncMapping = []string{"wibble", "wobble"} - - cfg5 := cfg4 - cfg5.SyncMapping = []string{"wibbley", "wobbley"} - t.Run("CreateImportUpdateReadOk", func(t *testing.T) { resource.Test(t, resource.TestCase{ IsUnitTest: true, From 8733bb58495dc2b67d96aae0bf40c9935ab66c77 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Thu, 20 Feb 2025 20:35:57 +0000 Subject: [PATCH 4/8] you betcha --- .../provider/organization_resource_test.go | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/provider/organization_resource_test.go b/internal/provider/organization_resource_test.go index 30d8dff..72af707 100644 --- a/internal/provider/organization_resource_test.go +++ b/internal/provider/organization_resource_test.go @@ -92,30 +92,30 @@ func TestAccOrganizationResource(t *testing.T) { statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("display_name"), knownvalue.StringExact("Example Organization New")), }, }, - // Add group and role sync + // Add org sync { Config: cfg3.String(t), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("group_sync").AtMapKey("field"), knownvalue.StringExact("wibble")), - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("group_sync").AtMapKey("mapping").AtMapKey("wibble").AtSliceIndex(0), knownvalue.StringExact("6e57187f-6543-46ab-a62c-a10065dd4314")), - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("role_sync").AtMapKey("field"), knownvalue.StringExact("wobble")), - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("role_sync").AtMapKey("mapping").AtMapKey("wobble").AtSliceIndex(0), knownvalue.StringExact("wobbly")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibble")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobble")), }, }, - // Add org sync + // Patch org sync { Config: cfg4.String(t), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibble")), - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobble")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibbley")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobbley")), }, }, - // Patch org sync + // Add group and role sync { Config: cfg5.String(t), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibbley")), - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobbley")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("group_sync").AtMapKey("field"), knownvalue.StringExact("wibble")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("group_sync").AtMapKey("mapping").AtMapKey("wibble").AtSliceIndex(0), knownvalue.StringExact("6e57187f-6543-46ab-a62c-a10065dd4314")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("role_sync").AtMapKey("field"), knownvalue.StringExact("wobble")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("role_sync").AtMapKey("mapping").AtMapKey("wobble").AtSliceIndex(0), knownvalue.StringExact("wobbly")), }, }, }, From ca63b7c49039039c72561137021c0b8a6290eccb Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 21 Feb 2025 15:56:17 +0000 Subject: [PATCH 5/8] `org_sync_idp_groups` --- docs/resources/organization.md | 12 +++++++----- examples/resources/coderd_organization/resource.tf | 2 +- internal/provider/organization_resource.go | 4 ++-- internal/provider/organization_resource_test.go | 10 +++++----- .../provider/organization_sync_settings_resource.go | 2 +- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/resources/organization.md b/docs/resources/organization.md index 9b73549..0bbe141 100644 --- a/docs/resources/organization.md +++ b/docs/resources/organization.md @@ -12,8 +12,7 @@ description: |- An organization on the Coder deployment. -~> **Warning** -This resource is only compatible with Coder version [2.16.0](https://github.com/coder/coder/releases/tag/v2.16.0) and later. +~> **Warning** This resource is only compatible with Coder version [2.16.0](https://github.com/coder/coder/releases/tag/v2.16.0) and later. ## Example Usage @@ -24,7 +23,7 @@ resource "coderd_organization" "blueberry" { description = "The organization for blueberries" icon = "/emojis/1fad0.png" - sync_mapping = [ + org_sync_idp_groups = [ "wibble", "wobble", ] @@ -46,6 +45,7 @@ resource "coderd_organization" "blueberry" { ``` + ## Schema ### Required @@ -59,13 +59,14 @@ resource "coderd_organization" "blueberry" { - `group_sync` (Block, Optional) Group sync settings to sync groups from an IdP. (see [below for nested schema](#nestedblock--group_sync)) - `icon` (String) - `role_sync` (Block, Optional) Role sync settings to sync organization roles from an IdP. (see [below for nested schema](#nestedblock--role_sync)) -- `sync_mapping` (Set of String) Claims from the IdP provider that will give users access to this organization. +- `org_sync_idp_groups` (Set of String) Claims from the IdP provider that will give users access to this organization. ### Read-Only - `id` (String) Organization ID + ### Nested Schema for `group_sync` Optional: @@ -75,8 +76,8 @@ Optional: - `mapping` (Map of List of String) A map from OIDC group name to Coder group ID. - `regex_filter` (String) A regular expression that will be used to filter the groups returned by the OIDC provider. Any group not matched will be ignored. - + ### Nested Schema for `role_sync` Optional: @@ -93,6 +94,7 @@ Import is supported using the following syntax: # or the name of the organization. $ terraform import coderd_organization.our_org our-org ``` + Alternatively, in Terraform v1.5.0 and later, an [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used: ```terraform diff --git a/examples/resources/coderd_organization/resource.tf b/examples/resources/coderd_organization/resource.tf index 991c39e..cb26a86 100644 --- a/examples/resources/coderd_organization/resource.tf +++ b/examples/resources/coderd_organization/resource.tf @@ -4,7 +4,7 @@ resource "coderd_organization" "blueberry" { description = "The organization for blueberries" icon = "/emojis/1fad0.png" - sync_mapping = [ + org_sync_idp_groups = [ "wibble", "wobble", ] diff --git a/internal/provider/organization_resource.go b/internal/provider/organization_resource.go index 082641f..b986526 100644 --- a/internal/provider/organization_resource.go +++ b/internal/provider/organization_resource.go @@ -41,7 +41,7 @@ type OrganizationResourceModel struct { Description types.String `tfsdk:"description"` Icon types.String `tfsdk:"icon"` - SyncMapping types.Set `tfsdk:"sync_mapping"` + SyncMapping types.Set `tfsdk:"org_sync_idp_groups"` GroupSync types.Object `tfsdk:"group_sync"` RoleSync types.Object `tfsdk:"role_sync"` } @@ -137,7 +137,7 @@ This resource is only compatible with Coder version [2.16.0](https://github.com/ Default: stringdefault.StaticString(""), }, - "sync_mapping": schema.SetAttribute{ + "org_sync_idp_groups": schema.SetAttribute{ ElementType: types.StringType, Optional: true, MarkdownDescription: "Claims from the IdP provider that will give users access to this organization.", diff --git a/internal/provider/organization_resource_test.go b/internal/provider/organization_resource_test.go index 72af707..765aae0 100644 --- a/internal/provider/organization_resource_test.go +++ b/internal/provider/organization_resource_test.go @@ -96,16 +96,16 @@ func TestAccOrganizationResource(t *testing.T) { { Config: cfg3.String(t), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibble")), - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobble")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("org_sync_idp_groups").AtSliceIndex(0), knownvalue.StringExact("wibble")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("org_sync_idp_groups").AtSliceIndex(1), knownvalue.StringExact("wobble")), }, }, // Patch org sync { Config: cfg4.String(t), ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(0), knownvalue.StringExact("wibbley")), - statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("sync_mapping").AtSliceIndex(1), knownvalue.StringExact("wobbley")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("org_sync_idp_groups").AtSliceIndex(0), knownvalue.StringExact("wibbley")), + statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("org_sync_idp_groups").AtSliceIndex(1), knownvalue.StringExact("wobbley")), }, }, // Add group and role sync @@ -152,7 +152,7 @@ resource "coderd_organization" "test" { icon = {{orNull .Icon}} {{- if .SyncMapping}} - sync_mapping = [ + org_sync_idp_groups = [ {{- range $name := .SyncMapping }} "{{$name}}", {{- end}} diff --git a/internal/provider/organization_sync_settings_resource.go b/internal/provider/organization_sync_settings_resource.go index 0283c40..d492d3d 100644 --- a/internal/provider/organization_sync_settings_resource.go +++ b/internal/provider/organization_sync_settings_resource.go @@ -244,7 +244,7 @@ func (r *OrganizationSyncSettingsResource) Delete(ctx context.Context, req resou tflog.Trace(ctx, "deleting organization sync", map[string]any{}) _, err := r.Client.PatchOrganizationIDPSyncConfig(ctx, codersdk.PatchOrganizationIDPSyncConfigRequest{ // This disables organization sync without causing state conflicts for - // organization resources that might still specify `sync_mapping`. + // organization resources that might still specify `org_sync_idp_groups`. Field: "", }) if err != nil { From a8aceb703bba1b3206ab8a450d797aa7eb394fa1 Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 21 Feb 2025 19:23:36 +0000 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=A7=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/resources/organization.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/resources/organization.md b/docs/resources/organization.md index 0bbe141..88246dd 100644 --- a/docs/resources/organization.md +++ b/docs/resources/organization.md @@ -12,7 +12,8 @@ description: |- An organization on the Coder deployment. -~> **Warning** This resource is only compatible with Coder version [2.16.0](https://github.com/coder/coder/releases/tag/v2.16.0) and later. +~> **Warning** +This resource is only compatible with Coder version [2.16.0](https://github.com/coder/coder/releases/tag/v2.16.0) and later. ## Example Usage @@ -45,7 +46,6 @@ resource "coderd_organization" "blueberry" { ``` - ## Schema ### Required @@ -58,15 +58,14 @@ resource "coderd_organization" "blueberry" { - `display_name` (String) Display name of the organization. Defaults to name. - `group_sync` (Block, Optional) Group sync settings to sync groups from an IdP. (see [below for nested schema](#nestedblock--group_sync)) - `icon` (String) -- `role_sync` (Block, Optional) Role sync settings to sync organization roles from an IdP. (see [below for nested schema](#nestedblock--role_sync)) - `org_sync_idp_groups` (Set of String) Claims from the IdP provider that will give users access to this organization. +- `role_sync` (Block, Optional) Role sync settings to sync organization roles from an IdP. (see [below for nested schema](#nestedblock--role_sync)) ### Read-Only - `id` (String) Organization ID - ### Nested Schema for `group_sync` Optional: @@ -76,8 +75,8 @@ Optional: - `mapping` (Map of List of String) A map from OIDC group name to Coder group ID. - `regex_filter` (String) A regular expression that will be used to filter the groups returned by the OIDC provider. Any group not matched will be ignored. - + ### Nested Schema for `role_sync` Optional: @@ -94,7 +93,6 @@ Import is supported using the following syntax: # or the name of the organization. $ terraform import coderd_organization.our_org our-org ``` - Alternatively, in Terraform v1.5.0 and later, an [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used: ```terraform From 83b367c96052afc02c49c5ecd4ec74e8b432107d Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 21 Feb 2025 21:00:39 +0000 Subject: [PATCH 7/8] rename go values to match --- internal/provider/organization_resource.go | 20 +++++++++---------- .../provider/organization_resource_test.go | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/provider/organization_resource.go b/internal/provider/organization_resource.go index b986526..a83ff25 100644 --- a/internal/provider/organization_resource.go +++ b/internal/provider/organization_resource.go @@ -41,9 +41,9 @@ type OrganizationResourceModel struct { Description types.String `tfsdk:"description"` Icon types.String `tfsdk:"icon"` - SyncMapping types.Set `tfsdk:"org_sync_idp_groups"` - GroupSync types.Object `tfsdk:"group_sync"` - RoleSync types.Object `tfsdk:"role_sync"` + OrgSyncIdpGroups types.Set `tfsdk:"org_sync_idp_groups"` + GroupSync types.Object `tfsdk:"group_sync"` + RoleSync types.Object `tfsdk:"role_sync"` } type GroupSyncModel struct { @@ -372,13 +372,13 @@ func (r *OrganizationResource) Create(ctx context.Context, req resource.CreateRe orgID := data.ID.ValueUUID() // Apply org sync patches, if specified - if !data.SyncMapping.IsNull() { + if !data.OrgSyncIdpGroups.IsNull() { tflog.Trace(ctx, "updating org sync", map[string]any{ "orgID": orgID, }) var claims []string - resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, &claims, false)...) + resp.Diagnostics.Append(data.OrgSyncIdpGroups.ElementsAs(ctx, &claims, false)...) if resp.Diagnostics.HasError() { return } @@ -449,7 +449,7 @@ func (r *OrganizationResource) Update(ctx context.Context, req resource.UpdateRe }) // Apply org sync patches, if specified - if !data.SyncMapping.IsNull() { + if !data.OrgSyncIdpGroups.IsNull() { tflog.Trace(ctx, "updating org sync mappings", map[string]any{ "orgID": orgID, }) @@ -457,10 +457,10 @@ func (r *OrganizationResource) Update(ctx context.Context, req resource.UpdateRe var state OrganizationResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) var currentClaims []string - resp.Diagnostics.Append(state.SyncMapping.ElementsAs(ctx, ¤tClaims, false)...) + resp.Diagnostics.Append(state.OrgSyncIdpGroups.ElementsAs(ctx, ¤tClaims, false)...) var plannedClaims []string - resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, &plannedClaims, false)...) + resp.Diagnostics.Append(data.OrgSyncIdpGroups.ElementsAs(ctx, &plannedClaims, false)...) if resp.Diagnostics.HasError() { return } @@ -505,13 +505,13 @@ func (r *OrganizationResource) Delete(ctx context.Context, req resource.DeleteRe orgID := data.ID.ValueUUID() // Remove org sync mappings, if we were managing them - if !data.SyncMapping.IsNull() { + if !data.OrgSyncIdpGroups.IsNull() { tflog.Trace(ctx, "deleting org sync mappings", map[string]any{ "orgID": orgID, }) var claims []string - resp.Diagnostics.Append(data.SyncMapping.ElementsAs(ctx, &claims, false)...) + resp.Diagnostics.Append(data.OrgSyncIdpGroups.ElementsAs(ctx, &claims, false)...) if resp.Diagnostics.HasError() { return } diff --git a/internal/provider/organization_resource_test.go b/internal/provider/organization_resource_test.go index 765aae0..9733fdd 100644 --- a/internal/provider/organization_resource_test.go +++ b/internal/provider/organization_resource_test.go @@ -42,10 +42,10 @@ func TestAccOrganizationResource(t *testing.T) { cfg2.DisplayName = ptr.Ref("Example Organization New") cfg3 := cfg2 - cfg3.SyncMapping = []string{"wibble", "wobble"} + cfg3.OrgSyncIdpGroups = []string{"wibble", "wobble"} cfg4 := cfg3 - cfg4.SyncMapping = []string{"wibbley", "wobbley"} + cfg4.OrgSyncIdpGroups = []string{"wibbley", "wobbley"} cfg5 := cfg4 cfg5.GroupSync = ptr.Ref(codersdk.GroupSyncSettings{ @@ -132,9 +132,9 @@ type testAccOrganizationResourceConfig struct { Description *string Icon *string - SyncMapping []string - GroupSync *codersdk.GroupSyncSettings - RoleSync *codersdk.RoleSyncSettings + OrgSyncIdpGroups []string + GroupSync *codersdk.GroupSyncSettings + RoleSync *codersdk.RoleSyncSettings } func (c testAccOrganizationResourceConfig) String(t *testing.T) string { From 4e91fffd60d12d6a7ad5bea3b6e384d3da66d60d Mon Sep 17 00:00:00 2001 From: McKayla Washburn Date: Fri, 21 Feb 2025 21:06:03 +0000 Subject: [PATCH 8/8] duh --- internal/provider/organization_resource_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/provider/organization_resource_test.go b/internal/provider/organization_resource_test.go index 9733fdd..40a7465 100644 --- a/internal/provider/organization_resource_test.go +++ b/internal/provider/organization_resource_test.go @@ -151,9 +151,9 @@ resource "coderd_organization" "test" { description = {{orNull .Description}} icon = {{orNull .Icon}} - {{- if .SyncMapping}} + {{- if .OrgSyncIdpGroups}} org_sync_idp_groups = [ - {{- range $name := .SyncMapping }} + {{- range $name := .OrgSyncIdpGroups }} "{{$name}}", {{- end}} ] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy