Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: addcoderd_organization_sync_settings resource#173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
aslilac merged 14 commits intomainfromlilac/org-sync
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletionsdocs/resources/organization_sync_settings.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "coderd_organization_sync_settings Resource - terraform-provider-coderd"
subcategory: ""
description: |-
IdP sync settings for organizations.
This resource can only be created once. Attempts to create multiple will fail.
~> Warning
This resource is only compatible with Coder version 2.19.0 https://github.com/coder/coder/releases/tag/v2.19.0 and later.
---

# coderd_organization_sync_settings (Resource)

IdP sync settings for organizations.

This resource can only be created once. Attempts to create multiple will fail.

~> **Warning**
This resource is only compatible with Coder version [2.19.0](https://github.com/coder/coder/releases/tag/v2.19.0) and later.

## Example Usage

```terraform
// Important note: You can only have one resource of this type!
resource "coderd_organization_sync_settings" "org_sync" {
field = "wibble"
assign_default = false

mapping = {
wobble = [
coderd_organization.my_organization.id,
]
}
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `assign_default` (Boolean) When true, every user will be added to the default organization, regardless of claims.
- `field` (String) The claim field that specifies what organizations a user should be in.

### Optional

- `mapping` (Map of List of String) A map from OIDC group name to Coder organization ID.
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
// Important note: You can only have one resource of this type!
resource "coderd_organization_sync_settings" "org_sync" {
field = "wibble"
assign_default = false

mapping = {
wobble = [
coderd_organization.my_organization.id,
]
}
}
258 changes: 258 additions & 0 deletionsinternal/provider/organization_sync_settings_resource.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
package provider

import (
"context"
"fmt"

"github.com/coder/coder/v2/codersdk"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

// Ensure provider defined types fully satisfy framework interfaces.
var _ resource.Resource = &OrganizationSyncSettingsResource{}

type OrganizationSyncSettingsResource struct {
*CoderdProviderData
}

// OrganizationSyncSettingsResourceModel describes the resource data model.
type OrganizationSyncSettingsResourceModel struct {
Field types.String `tfsdk:"field"`
AssignDefault types.Bool `tfsdk:"assign_default"`
Mapping types.Map `tfsdk:"mapping"`
}

func NewOrganizationSyncSettingsResource() resource.Resource {
return &OrganizationSyncSettingsResource{}
}

func (r *OrganizationSyncSettingsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_organization_sync_settings"
}

func (r *OrganizationSyncSettingsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: `IdP sync settings for organizations.

This resource can only be created once. Attempts to create multiple will fail.

~> **Warning**
This resource is only compatible with Coder version [2.19.0](https://github.com/coder/coder/releases/tag/v2.19.0) and later.
`,
Attributes: map[string]schema.Attribute{
"field": schema.StringAttribute{
Required: true,
MarkdownDescription: "The claim field that specifies what organizations " +
"a user should be in.",
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
"assign_default": schema.BoolAttribute{
Required: true,
MarkdownDescription: "When true, every user will be added to the default " +
"organization, regardless of claims.",
},
"mapping": schema.MapAttribute{
ElementType: types.ListType{ElemType: UUIDType},
Optional: true,
MarkdownDescription: "A map from OIDC group name to Coder organization ID.",
},
},
}
}

func (r *OrganizationSyncSettingsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
}

data, ok := req.ProviderData.(*CoderdProviderData)

if !ok {
resp.Diagnostics.AddError(
"Unable to configure provider data",
fmt.Sprintf("Expected *CoderdProviderData, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

r.CoderdProviderData = data
}

func (r *OrganizationSyncSettingsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// Read Terraform prior state data into the model
var data OrganizationSyncSettingsResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

settings, err := r.Client.OrganizationIDPSyncSettings(ctx)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("unable to get organization sync settings, got error: %s", err))
return
}

// Store the latest values that we just fetched.
data.Field = types.StringValue(settings.Field)
data.AssignDefault = types.BoolValue(settings.AssignDefault)

if !data.Mapping.IsNull() {
// Convert IDs to strings
elements := make(map[string][]string)
for key, ids := range settings.Mapping {
for _, id := range ids {
elements[key] = append(elements[key], id.String())
}
}

mapping, diags := types.MapValueFrom(ctx, types.ListType{ElemType: UUIDType}, elements)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
data.Mapping = mapping
}

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *OrganizationSyncSettingsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
// Read Terraform plan data into the model
var data OrganizationSyncSettingsResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Trace(ctx, "creating organization sync", map[string]any{
"field": data.Field.ValueString(),
"assign_default": data.AssignDefault.ValueBool(),
})

// Create and Update use a shared implementation
resp.Diagnostics.Append(r.patch(ctx, data)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Trace(ctx, "successfully created organization sync", map[string]any{
"field": data.Field.ValueString(),
"assign_default": data.AssignDefault.ValueBool(),
})

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *OrganizationSyncSettingsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// Read Terraform plan data into the model
var data OrganizationSyncSettingsResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

// Update the organization metadata
tflog.Trace(ctx, "updating organization", map[string]any{
"field": data.Field.ValueString(),
"assign_default": data.AssignDefault.ValueBool(),
})

// Create and Update use a shared implementation
resp.Diagnostics.Append(r.patch(ctx, data)...)
if resp.Diagnostics.HasError() {
return
}

tflog.Trace(ctx, "successfully updated organization", map[string]any{
"field": data.Field.ValueString(),
"assign_default": data.AssignDefault.ValueBool(),
})

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *OrganizationSyncSettingsResource) patch(
ctx context.Context,
data OrganizationSyncSettingsResourceModel,
) diag.Diagnostics {
var diags diag.Diagnostics
field := data.Field.ValueString()
assignDefault := data.AssignDefault.ValueBool()

if data.Mapping.IsNull() {
_, err := r.Client.PatchOrganizationIDPSyncConfig(ctx, codersdk.PatchOrganizationIDPSyncConfigRequest{
Field: field,
AssignDefault: assignDefault,
})

if err != nil {
diags.AddError("failed to create organization sync", err.Error())
return diags
}
} else {
settings := codersdk.OrganizationSyncSettings{
Field: field,
AssignDefault: assignDefault,
Mapping: map[string][]uuid.UUID{},
}

// Terraform doesn't know how to turn one our `UUID` Terraform values into a
// `uuid.UUID`, so we have to do the unwrapping manually here.
var mapping map[string][]UUID
diags.Append(data.Mapping.ElementsAs(ctx, &mapping, false)...)
if diags.HasError() {
return diags
}
for key, ids := range mapping {
for _, id := range ids {
settings.Mapping[key] = append(settings.Mapping[key], id.ValueUUID())
}
}

_, err := r.Client.PatchOrganizationIDPSyncSettings(ctx, settings)
if err != nil {
diags.AddError("failed to create organization sync", err.Error())
return diags
}
}

return diags
}

func (r *OrganizationSyncSettingsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
// Read Terraform prior state data into the model
var data OrganizationSyncSettingsResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

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`.
Field: "",
})
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("unable to delete organization sync, got error: %s", err))
return
}
tflog.Trace(ctx, "successfully deleted organization sync", map[string]any{})

// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
}
Loading

[8]ページ先頭

©2009-2025 Movatter.jp