@@ -8,7 +8,10 @@ import (
8
8
"github.com/coder/coder/v2/codersdk"
9
9
"github.com/coder/terraform-provider-coderd/internal/codersdkvalidator"
10
10
"github.com/google/uuid"
11
+ "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
12
+ "github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
11
13
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
14
+ "github.com/hashicorp/terraform-plugin-framework/diag"
12
15
"github.com/hashicorp/terraform-plugin-framework/path"
13
16
"github.com/hashicorp/terraform-plugin-framework/resource"
14
17
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -17,6 +20,7 @@ import (
17
20
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
18
21
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
19
22
"github.com/hashicorp/terraform-plugin-framework/types"
23
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
20
24
"github.com/hashicorp/terraform-plugin-log/tflog"
21
25
)
22
26
@@ -41,6 +45,18 @@ type OrganizationResourceModel struct {
41
45
RoleSync types.Object `tfsdk:"role_sync"`
42
46
}
43
47
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
+
44
60
func NewOrganizationResource () resource.Resource {
45
61
return & OrganizationResource {}
46
62
}
@@ -101,7 +117,7 @@ func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRe
101
117
stringvalidator .LengthAtLeast (1 ),
102
118
},
103
119
},
104
- "regex " : schema.StringAttribute {
120
+ "regex_filter " : schema.StringAttribute {
105
121
Optional : true ,
106
122
MarkdownDescription : "A regular expression that will be used to " +
107
123
"filter the groups returned by the OIDC provider. Any group " +
@@ -116,9 +132,12 @@ func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRe
116
132
"they are missing." ,
117
133
},
118
134
"mapping" : schema.MapAttribute {
119
- ElementType : UUIDType ,
135
+ ElementType : types. ListType { ElemType : UUIDType } ,
120
136
Optional : true ,
121
137
MarkdownDescription : "A map from OIDC group name to Coder group ID." ,
138
+ Validators : []validator.Map {
139
+ mapvalidator .ValueListsAre (listvalidator .ValueStringsAre (stringvalidator .Any ())),
140
+ },
122
141
},
123
142
},
124
143
},
@@ -133,10 +152,13 @@ func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRe
133
152
},
134
153
},
135
154
"mapping" : schema.MapAttribute {
136
- ElementType : UUIDType ,
155
+ ElementType : types. ListType { ElemType : UUIDType } ,
137
156
Optional : true ,
138
157
MarkdownDescription : "A map from OIDC group name to Coder " +
139
158
"organization role." ,
159
+ Validators : []validator.Map {
160
+ mapvalidator .ValueListsAre (listvalidator .ValueStringsAre (stringvalidator .Any ())),
161
+ },
140
162
},
141
163
},
142
164
},
@@ -191,6 +213,26 @@ func (r *OrganizationResource) Read(ctx context.Context, req resource.ReadReques
191
213
}
192
214
}
193
215
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
+
194
236
// We've fetched the organization ID from state, and the latest values for
195
237
// everything else from the backend. Ensure that any mutable data is synced
196
238
// with the backend.
@@ -241,6 +283,21 @@ func (r *OrganizationResource) Create(ctx context.Context, req resource.CreateRe
241
283
// default it.
242
284
data .DisplayName = types .StringValue (org .DisplayName )
243
285
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
+
244
301
// Save data into Terraform state
245
302
resp .Diagnostics .Append (resp .State .Set (ctx , & data )... )
246
303
}
@@ -282,12 +339,17 @@ func (r *OrganizationResource) Update(ctx context.Context, req resource.UpdateRe
282
339
"icon" : org .Icon ,
283
340
})
284
341
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 )
291
353
}
292
354
293
355
// Save updated data into Terraform state
@@ -331,48 +393,65 @@ func (r *OrganizationResource) ImportState(ctx context.Context, req resource.Imp
331
393
func (r * OrganizationResource ) patchGroupSync (
332
394
ctx context.Context ,
333
395
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
337
399
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
341
405
}
342
- settings .Field = field .ValueString ()
343
406
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 ) ... )
350
413
if diags .HasError () {
351
- return fmt . Errorf ( "oh jeez" )
414
+ return diags
352
415
}
353
- settings .Mapping = mapping
354
416
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 )
360
419
if err != nil {
361
- return err
420
+ diags .AddError ("Group Sync Update error" , err .Error ())
421
+ return diags
362
422
}
363
- settings .RegexFilter = regexFilter
364
423
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
368
439
}
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 )... )
371
445
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
373
454
}
374
- settings .LegacyNameMapping = legacyMapping
375
455
376
- _ , err = r .Client .PatchGroupIDPSyncSettings (ctx , orgID .String (), settings )
377
- return err
456
+ return diags
378
457
}
0 commit comments