Skip to content

Commit a185262

Browse files
committed
so close...
1 parent 3bf1734 commit a185262

File tree

2 files changed

+132
-48
lines changed

2 files changed

+132
-48
lines changed

internal/provider/organization_resource.go

Lines changed: 119 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import (
88
"github.com/coder/coder/v2/codersdk"
99
"github.com/coder/terraform-provider-coderd/internal/codersdkvalidator"
1010
"github.com/google/uuid"
11+
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
12+
"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
1113
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
14+
"github.com/hashicorp/terraform-plugin-framework/diag"
1215
"github.com/hashicorp/terraform-plugin-framework/path"
1316
"github.com/hashicorp/terraform-plugin-framework/resource"
1417
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -17,6 +20,7 @@ import (
1720
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
1821
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
1922
"github.com/hashicorp/terraform-plugin-framework/types"
23+
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
2024
"github.com/hashicorp/terraform-plugin-log/tflog"
2125
)
2226

@@ -41,6 +45,18 @@ type OrganizationResourceModel struct {
4145
RoleSync types.Object `tfsdk:"role_sync"`
4246
}
4347

48+
type GroupSyncModel struct {
49+
Field types.String `tfsdk:"field"`
50+
RegexFilter types.String `tfsdk:"regex_filter"`
51+
AutoCreateMissing types.Bool `tfsdk:"auto_create_missing"`
52+
Mapping types.Map `tfsdk:"mapping"`
53+
}
54+
55+
type RoleSyncModel struct {
56+
Field types.String `tfsdk:"field"`
57+
Mapping types.Map `tfsdk:"mapping"`
58+
}
59+
4460
func NewOrganizationResource() resource.Resource {
4561
return &OrganizationResource{}
4662
}
@@ -101,7 +117,7 @@ func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRe
101117
stringvalidator.LengthAtLeast(1),
102118
},
103119
},
104-
"regex": schema.StringAttribute{
120+
"regex_filter": schema.StringAttribute{
105121
Optional: true,
106122
MarkdownDescription: "A regular expression that will be used to " +
107123
"filter the groups returned by the OIDC provider. Any group " +
@@ -116,9 +132,12 @@ func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRe
116132
"they are missing.",
117133
},
118134
"mapping": schema.MapAttribute{
119-
ElementType: UUIDType,
135+
ElementType: types.ListType{ElemType: UUIDType},
120136
Optional: true,
121137
MarkdownDescription: "A map from OIDC group name to Coder group ID.",
138+
Validators: []validator.Map{
139+
mapvalidator.ValueListsAre(listvalidator.ValueStringsAre(stringvalidator.Any())),
140+
},
122141
},
123142
},
124143
},
@@ -133,10 +152,13 @@ func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRe
133152
},
134153
},
135154
"mapping": schema.MapAttribute{
136-
ElementType: UUIDType,
155+
ElementType: types.ListType{ElemType: UUIDType},
137156
Optional: true,
138157
MarkdownDescription: "A map from OIDC group name to Coder " +
139158
"organization role.",
159+
Validators: []validator.Map{
160+
mapvalidator.ValueListsAre(listvalidator.ValueStringsAre(stringvalidator.Any())),
161+
},
140162
},
141163
},
142164
},
@@ -191,6 +213,26 @@ func (r *OrganizationResource) Read(ctx context.Context, req resource.ReadReques
191213
}
192214
}
193215

216+
if !data.GroupSync.IsNull() {
217+
_, err := r.Client.GroupIDPSyncSettings(ctx, data.ID.ValueUUID().String())
218+
if err != nil {
219+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("unable to get organization group sync settings, got error: %s", err))
220+
return
221+
}
222+
223+
// data.GroupSync = ???
224+
}
225+
226+
if !data.RoleSync.IsNull() {
227+
_, err := r.Client.RoleIDPSyncSettings(ctx, data.ID.ValueUUID().String())
228+
if err != nil {
229+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("unable to get organization role sync settings, got error: %s", err))
230+
return
231+
}
232+
233+
// data.RoleSync = ???
234+
}
235+
194236
// We've fetched the organization ID from state, and the latest values for
195237
// everything else from the backend. Ensure that any mutable data is synced
196238
// with the backend.
@@ -241,6 +283,21 @@ func (r *OrganizationResource) Create(ctx context.Context, req resource.CreateRe
241283
// default it.
242284
data.DisplayName = types.StringValue(org.DisplayName)
243285

286+
// Now apply group and role sync settings, if specified
287+
orgID := data.ID.ValueUUID()
288+
tflog.Trace(ctx, "updating group sync", map[string]any{
289+
"orgID": orgID,
290+
})
291+
if !data.GroupSync.IsNull() {
292+
r.patchGroupSync(ctx, orgID, data.GroupSync)
293+
}
294+
tflog.Trace(ctx, "updating role sync", map[string]any{
295+
"orgID": orgID,
296+
})
297+
if !data.RoleSync.IsNull() {
298+
r.patchRoleSync(ctx, orgID, data.RoleSync)
299+
}
300+
244301
// Save data into Terraform state
245302
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
246303
}
@@ -282,12 +339,17 @@ func (r *OrganizationResource) Update(ctx context.Context, req resource.UpdateRe
282339
"icon": org.Icon,
283340
})
284341

285-
if data.GroupSync.IsNull() {
286-
err = r.patchGroupSync(ctx, orgID, data.GroupSync)
287-
if err != nil {
288-
resp.Diagnostics.AddError("Group Sync Update error", err.Error())
289-
return
290-
}
342+
tflog.Trace(ctx, "updating group sync", map[string]any{
343+
"orgID": orgID,
344+
})
345+
if !data.GroupSync.IsNull() {
346+
r.patchGroupSync(ctx, orgID, data.GroupSync)
347+
}
348+
tflog.Trace(ctx, "updating role sync", map[string]any{
349+
"orgID": orgID,
350+
})
351+
if !data.RoleSync.IsNull() {
352+
r.patchRoleSync(ctx, orgID, data.RoleSync)
291353
}
292354

293355
// Save updated data into Terraform state
@@ -331,48 +393,65 @@ func (r *OrganizationResource) ImportState(ctx context.Context, req resource.Imp
331393
func (r *OrganizationResource) patchGroupSync(
332394
ctx context.Context,
333395
orgID uuid.UUID,
334-
groupSyncAttr types.Object,
335-
) error {
336-
var settings codersdk.GroupSyncSettings
396+
groupSyncObject types.Object,
397+
) diag.Diagnostics {
398+
var diags diag.Diagnostics
337399

338-
field, ok := groupSyncAttr.Attributes()["field"].(types.String)
339-
if !ok {
340-
return fmt.Errorf("oh jeez")
400+
// Read values from Terraform
401+
var groupSyncData GroupSyncModel
402+
diags.Append(groupSyncObject.As(ctx, &groupSyncData, basetypes.ObjectAsOptions{})...)
403+
if diags.HasError() {
404+
return diags
341405
}
342-
settings.Field = field.ValueString()
343406

344-
mappingMap, ok := groupSyncAttr.Attributes()["mapping"].(types.Map)
345-
if !ok {
346-
return fmt.Errorf("oh jeez")
347-
}
348-
var mapping map[string][]uuid.UUID
349-
diags := mappingMap.ElementsAs(ctx, mapping, false)
407+
// Convert that into the type used to send the PATCH to the backend
408+
var groupSync codersdk.GroupSyncSettings
409+
groupSync.Field = groupSyncData.Field.ValueString()
410+
groupSync.RegexFilter = regexp.MustCompile(groupSyncData.RegexFilter.ValueString())
411+
groupSync.AutoCreateMissing = groupSyncData.AutoCreateMissing.ValueBool()
412+
diags.Append(groupSyncData.Mapping.ElementsAs(ctx, &groupSync.Mapping, false)...)
350413
if diags.HasError() {
351-
return fmt.Errorf("oh jeez")
414+
return diags
352415
}
353-
settings.Mapping = mapping
354416

355-
regexFilterStr, ok := groupSyncAttr.Attributes()["regex_filter"].(types.String)
356-
if !ok {
357-
return fmt.Errorf("oh jeez")
358-
}
359-
regexFilter, err := regexp.Compile(regexFilterStr.ValueString())
417+
// Perform the PATCH
418+
_, err := r.Client.PatchGroupIDPSyncSettings(ctx, orgID.String(), groupSync)
360419
if err != nil {
361-
return err
420+
diags.AddError("Group Sync Update error", err.Error())
421+
return diags
362422
}
363-
settings.RegexFilter = regexFilter
364423

365-
legacyMappingMap, ok := groupSyncAttr.Attributes()["legacy_group_name_mapping"].(types.Map)
366-
if !ok {
367-
return fmt.Errorf("oh jeez")
424+
return diags
425+
}
426+
427+
func (r *OrganizationResource) patchRoleSync(
428+
ctx context.Context,
429+
orgID uuid.UUID,
430+
roleSyncObject types.Object,
431+
) diag.Diagnostics {
432+
var diags diag.Diagnostics
433+
434+
// Read values from Terraform
435+
var roleSyncData RoleSyncModel
436+
diags.Append(roleSyncObject.As(ctx, &roleSyncData, basetypes.ObjectAsOptions{})...)
437+
if diags.HasError() {
438+
return diags
368439
}
369-
var legacyMapping map[string]string
370-
diags = legacyMappingMap.ElementsAs(ctx, legacyMapping, false)
440+
441+
// Convert that into the type used to send the PATCH to the backend
442+
var roleSync codersdk.RoleSyncSettings
443+
roleSync.Field = roleSyncData.Field.ValueString()
444+
diags.Append(roleSyncData.Mapping.ElementsAs(ctx, &roleSync.Mapping, false)...)
371445
if diags.HasError() {
372-
return fmt.Errorf("oh jeez")
446+
return diags
447+
}
448+
449+
// Perform the PATCH
450+
_, err := r.Client.PatchRoleIDPSyncSettings(ctx, orgID.String(), roleSync)
451+
if err != nil {
452+
diags.AddError("Role Sync Update error", err.Error())
453+
return diags
373454
}
374-
settings.LegacyNameMapping = legacyMapping
375455

376-
_, err = r.Client.PatchGroupIDPSyncSettings(ctx, orgID.String(), settings)
377-
return err
456+
return diags
378457
}

internal/provider/organization_resource_test.go

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package provider
22

33
import (
44
"context"
5-
"fmt"
65
"os"
76
"strings"
87
"testing"
@@ -42,22 +41,20 @@ func TestAccOrganizationResource(t *testing.T) {
4241
cfg2.Name = ptr.Ref("example-org-new")
4342
cfg2.DisplayName = ptr.Ref("Example Organization New")
4443

45-
cfg3 := cfg1
44+
cfg3 := cfg2
4645
cfg3.GroupSync = ptr.Ref(codersdk.GroupSyncSettings{
4746
Field: "wibble",
4847
Mapping: map[string][]uuid.UUID{
4948
"wibble": {uuid.MustParse("6e57187f-6543-46ab-a62c-a10065dd4314")},
5049
},
5150
})
5251
cfg3.RoleSync = ptr.Ref(codersdk.RoleSyncSettings{
53-
Field: "wibble",
52+
Field: "wobble",
5453
Mapping: map[string][]string{
55-
"wibble": {"wobble"},
54+
"wobble": {"wobbly"},
5655
},
5756
})
5857

59-
fmt.Println(cfg3)
60-
6158
t.Run("CreateImportUpdateReadOk", func(t *testing.T) {
6259
resource.Test(t, resource.TestCase{
6360
IsUnitTest: true,
@@ -89,6 +86,14 @@ func TestAccOrganizationResource(t *testing.T) {
8986
statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("display_name"), knownvalue.StringExact("Example Organization New")),
9087
},
9188
},
89+
// Add group and role sync
90+
{
91+
Config: cfg3.String(t),
92+
ConfigStateChecks: []statecheck.StateCheck{
93+
statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("group_sync.field"), knownvalue.StringExact("wibble")),
94+
statecheck.ExpectKnownValue("coderd_organization.test", tfjsonpath.New("role_sync.field"), knownvalue.StringExact("wobble")),
95+
},
96+
},
9297
},
9398
})
9499
})
@@ -126,7 +131,7 @@ resource "coderd_organization" "test" {
126131
field = "{{.GroupSync.Field}}"
127132
mapping = {
128133
{{- range $key, $value := .GroupSync.Mapping}}
129-
{{$key}} = "{{$value}}"
134+
{{$key}} = {{printf "%q" $value}}
130135
{{- end}}
131136
}
132137
}
@@ -137,7 +142,7 @@ resource "coderd_organization" "test" {
137142
field = "{{.RoleSync.Field}}"
138143
mapping = {
139144
{{- range $key, $value := .RoleSync.Mapping}}
140-
{{$key}} = "{{$value}}"
145+
{{$key}} = {{printf "%q" $value}}
141146
{{- end}}
142147
}
143148
}

0 commit comments

Comments
 (0)