Skip to content

Commit 399bfa7

Browse files
feat: add coderd_organization_group_sync resource (#248)
Fixes #230. To avoid users running into circular dependency issues with the `group_sync` block, we'll deprecate the block and add a resource solely for configuring organization group sync.
1 parent ac0a928 commit 399bfa7

File tree

11 files changed

+663
-3
lines changed

11 files changed

+663
-3
lines changed

docs/resources/organization.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ resource "coderd_organization" "blueberry" {
5656

5757
- `description` (String)
5858
- `display_name` (String) Display name of the organization. Defaults to name.
59-
- `group_sync` (Block, Optional) Group sync settings to sync groups from an IdP. (see [below for nested schema](#nestedblock--group_sync))
59+
- `group_sync` (Block, Optional, Deprecated) Group sync settings to sync groups from an IdP.
60+
61+
~> **Deprecated** This block is deprecated. Use the `coderd_organization_group_sync` resource instead. (see [below for nested schema](#nestedblock--group_sync))
6062
- `icon` (String)
6163
- `org_sync_idp_groups` (Set of String) Claims from the IdP provider that will give users access to this organization.
6264
- `role_sync` (Block, Optional) Role sync settings to sync organization roles from an IdP. (see [below for nested schema](#nestedblock--role_sync))
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "coderd_organization_group_sync Resource - terraform-provider-coderd"
4+
subcategory: ""
5+
description: |-
6+
Group sync settings for an organization on the Coder deployment.
7+
Multiple instances of this resource for a single organization will conflict.
8+
~> Warning
9+
This resource is only compatible with Coder version 2.16.0 https://github.com/coder/coder/releases/tag/v2.16.0 and later.
10+
---
11+
12+
# coderd_organization_group_sync (Resource)
13+
14+
Group sync settings for an organization on the Coder deployment.
15+
Multiple instances of this resource for a single organization will conflict.
16+
17+
~> **Warning**
18+
This resource is only compatible with Coder version [2.16.0](https://github.com/coder/coder/releases/tag/v2.16.0) and later.
19+
20+
## Example Usage
21+
22+
```terraform
23+
resource "coderd_organization_group_sync" "test" {
24+
organization_id = coderd_organization.test.id
25+
field = "groups"
26+
regex_filter = "test_.*|admin_.*"
27+
auto_create_missing = false
28+
29+
mapping = {
30+
"test_developers" = [coderd_group.test.id]
31+
"admin_users" = [coderd_group.admins.id]
32+
"mixed_group" = [coderd_group.test.id, coderd_group.admins.id]
33+
}
34+
}
35+
```
36+
37+
<!-- schema generated by tfplugindocs -->
38+
## Schema
39+
40+
### Required
41+
42+
- `field` (String) The claim field that specifies what groups a user should be in.
43+
- `mapping` (Map of List of String) A map from OIDC group name to Coder group ID.
44+
- `organization_id` (String) The ID of the organization to configure group sync for.
45+
46+
### Optional
47+
48+
- `auto_create_missing` (Boolean) Controls whether groups will be created if they are missing. Defaults to false.
49+
- `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.
50+
51+
## Import
52+
53+
Import is supported using the following syntax:
54+
55+
The [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import) can be used, for example:
56+
57+
```shell
58+
# The ID supplied must be an organization UUID
59+
$ terraform import coderd_organization_group_sync.main_group_sync <org-id>
60+
```
61+
Alternatively, in Terraform v1.5.0 and later, an [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used:
62+
63+
```terraform
64+
import {
65+
to = coderd_organization_group_sync.main_group_sync
66+
id = "<org-id>"
67+
}
68+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# The ID supplied must be an organization UUID
2+
$ terraform import coderd_organization_group_sync.main_group_sync <org-id>
3+
```
4+
Alternatively, in Terraform v1.5.0 and later, an [`import` block](https://developer.hashicorp.com/terraform/language/import) can be used:
5+
6+
```terraform
7+
import {
8+
to = coderd_organization_group_sync.main_group_sync
9+
id = "<org-id>"
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
resource "coderd_organization_group_sync" "test" {
2+
organization_id = coderd_organization.test.id
3+
field = "groups"
4+
regex_filter = "test_.*|admin_.*"
5+
auto_create_missing = false
6+
7+
mapping = {
8+
"test_developers" = [coderd_group.test.id]
9+
"admin_users" = [coderd_group.admins.id]
10+
"mixed_group" = [coderd_group.test.id, coderd_group.admins.id]
11+
}
12+
}

integration/integration_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,45 @@ func TestIntegration(t *testing.T) {
106106
assert.Equal(t, group.QuotaAllowance, 100)
107107
},
108108
},
109+
{
110+
name: "org-group-sync-test",
111+
preF: func(t testing.TB, c *codersdk.Client) {},
112+
assertF: func(t testing.TB, c *codersdk.Client) {
113+
org, err := c.OrganizationByName(ctx, "test-org-group-sync")
114+
assert.NoError(t, err)
115+
assert.Equal(t, "test-org-group-sync", org.Name)
116+
assert.Equal(t, "Test Organization for Group Sync", org.DisplayName)
117+
118+
testGroup, err := c.GroupByOrgAndName(ctx, org.ID, "test-group")
119+
assert.NoError(t, err)
120+
assert.Equal(t, "test-group", testGroup.Name)
121+
assert.Equal(t, "Test Group", testGroup.DisplayName)
122+
assert.Equal(t, 50, testGroup.QuotaAllowance)
123+
124+
adminGroup, err := c.GroupByOrgAndName(ctx, org.ID, "admin-group")
125+
assert.NoError(t, err)
126+
assert.Equal(t, "admin-group", adminGroup.Name)
127+
assert.Equal(t, "Admin Group", adminGroup.DisplayName)
128+
assert.Equal(t, 100, adminGroup.QuotaAllowance)
129+
130+
// Verify group sync settings
131+
groupSync, err := c.GroupIDPSyncSettings(ctx, org.ID.String())
132+
assert.NoError(t, err)
133+
assert.Equal(t, "groups", groupSync.Field)
134+
assert.NotNil(t, groupSync.RegexFilter)
135+
assert.Equal(t, "test_.*|admin_.*", groupSync.RegexFilter.String())
136+
assert.False(t, groupSync.AutoCreateMissing)
137+
138+
assert.Contains(t, groupSync.Mapping, "test_developers")
139+
assert.Contains(t, groupSync.Mapping, "admin_users")
140+
assert.Contains(t, groupSync.Mapping, "mixed_group")
141+
142+
assert.Contains(t, groupSync.Mapping["test_developers"], testGroup.ID)
143+
assert.Contains(t, groupSync.Mapping["admin_users"], adminGroup.ID)
144+
assert.Contains(t, groupSync.Mapping["mixed_group"], testGroup.ID)
145+
assert.Contains(t, groupSync.Mapping["mixed_group"], adminGroup.ID)
146+
},
147+
},
109148
{
110149
name: "template-test",
111150
preF: func(t testing.TB, c *codersdk.Client) {},
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
terraform {
2+
required_providers {
3+
coderd = {
4+
source = "coder/coderd"
5+
version = ">=0.0.0"
6+
}
7+
}
8+
}
9+
10+
resource "coderd_organization" "test" {
11+
name = "test-org-group-sync"
12+
display_name = "Test Organization for Group Sync"
13+
description = "Organization created for testing group sync functionality"
14+
}
15+
16+
resource "coderd_group" "test" {
17+
organization_id = coderd_organization.test.id
18+
name = "test-group"
19+
display_name = "Test Group"
20+
quota_allowance = 50
21+
}
22+
23+
resource "coderd_group" "admins" {
24+
organization_id = coderd_organization.test.id
25+
name = "admin-group"
26+
display_name = "Admin Group"
27+
quota_allowance = 100
28+
}
29+
30+
resource "coderd_organization_group_sync" "test" {
31+
organization_id = coderd_organization.test.id
32+
field = "groups"
33+
regex_filter = "test_.*|admin_.*"
34+
auto_create_missing = false
35+
36+
mapping = {
37+
"test_developers" = [coderd_group.test.id]
38+
"admin_users" = [coderd_group.admins.id]
39+
"mixed_group" = [coderd_group.test.id, coderd_group.admins.id]
40+
}
41+
}
42+
43+
data "coderd_organization" "test_data" {
44+
id = coderd_organization.test.id
45+
}

internal/codersdkvalidator/regex.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
)
88

99
func checkRegexp(it string) error {
10-
_, err := regexp.Compile("")
10+
_, err := regexp.Compile(it)
1111
return err
1212
}
1313

0 commit comments

Comments
 (0)
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