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: add organization resource#131

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 19 commits intomainfromlilac/add-organization-resource
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
19 commits
Select commitHold shift + click to select a range
8b73a3e
add organization resource
aslilacNov 5, 2024
69fab48
Merge branch 'main' into lilac/add-organization-resource
aslilacNov 7, 2024
4743b9e
flesh out the organization resource
aslilacNov 7, 2024
435032b
register new resource type + gen
aslilacNov 7, 2024
71dc51b
start with tests from ethan
aslilacNov 8, 2024
3397984
ooooh, I get it, that was correct :^)
aslilacNov 8, 2024
75c0858
hmm
aslilacNov 8, 2024
cc2bb2e
lets do members differently actually
aslilacNov 8, 2024
d23168a
gen
aslilacNov 8, 2024
28b395a
statecheck
aslilacNov 8, 2024
f2d3e3c
feedback
aslilacNov 12, 2024
236c11e
hiyo
aslilacNov 12, 2024
16d10e7
:^)
aslilacNov 12, 2024
f3ff5fb
how about
aslilacNov 12, 2024
739b20c
Merge branch 'main' into lilac/add-organization-resource
aslilacNov 14, 2024
a716a58
add log fields
aslilacNov 14, 2024
c2e661e
fix import
aslilacNov 14, 2024
0a2f330
?
aslilacNov 14, 2024
435cb20
sure
aslilacNov 14, 2024
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
4 changes: 4 additions & 0 deletionsMakefile
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
default: testacc

fmt:
go fmt ./...
terraform fmt -recursive

vet:
go vet ./...

gen:
go generate ./...

Expand Down
39 changes: 39 additions & 0 deletionsdocs/resources/organization.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "coderd_organization Resource - terraform-provider-coderd"
subcategory: ""
description: |-
An organization on the Coder deployment
---

# coderd_organization (Resource)

An organization on the Coder deployment



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

### Required

- `name` (String) Name of the organization.

### Optional

- `description` (String)
- `display_name` (String) Display name of the organization. Defaults to name.
- `icon` (String)

### Read-Only

- `id` (String) Organization ID

## Import

Import is supported using the following syntax:

```shell
# Organizations can be imported by their name
terraform import coderd_organization.our_org our_org
```
2 changes: 2 additions & 0 deletionsexamples/resources/coderd_organization/import.sh
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
# Organizations can be imported by their name
terraform import coderd_organization.our_org our_org
262 changes: 262 additions & 0 deletionsinternal/provider/organization_resource.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
package provider

import (
"context"
"fmt"

"github.com/coder/coder/v2/codersdk"
"github.com/coder/terraform-provider-coderd/internal/codersdkvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"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 = &OrganizationResource{}
var _ resource.ResourceWithImportState = &OrganizationResource{}

type OrganizationResource struct {
*CoderdProviderData
}

// OrganizationResourceModel describes the resource data model.
type OrganizationResourceModel struct {
ID UUID `tfsdk:"id"`

Name types.String `tfsdk:"name"`
DisplayName types.String `tfsdk:"display_name"`
Description types.String `tfsdk:"description"`
Icon types.String `tfsdk:"icon"`
}

func NewOrganizationResource() resource.Resource {
return &OrganizationResource{}
}

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

func (r *OrganizationResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "An organization on the Coder deployment",

Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
CustomType: UUIDType,
Computed: true,
MarkdownDescription: "Organization ID",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"name": schema.StringAttribute{
MarkdownDescription: "Name of the organization.",
Required: true,
Validators: []validator.String{
codersdkvalidator.Name(),
},
},
"display_name": schema.StringAttribute{
MarkdownDescription: "Display name of the organization. Defaults to name.",
Computed: true,
Optional: true,
Default: stringdefault.StaticString(""),
Validators: []validator.String{
codersdkvalidator.DisplayName(),
},
},
"description": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
},
"icon": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString(""),
},
},
}
}

func (r *OrganizationResource) 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 *OrganizationResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// Read Terraform prior state data into the model
var data OrganizationResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

var org codersdk.Organization
var err error
if data.ID.IsNull() {
Copy link
Member

@ethanndicksonethanndicksonNov 14, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Your import test supplies a UUID into the name field, butOrganization andOrganizationByName call the same endpoint, so I believe supporting imports by name will always allow you to import by ID? Hence why the import test is passing when it shouldn't. Setting the attributes at the bottom corrects the issue where the name is temporarily the UUID, so I don't think it's bug prone.

orgName := data.Name.ValueString()
org, err = r.Client.OrganizationByName(ctx, orgName)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get organization by name, got error: %s", err))
return
}
data.ID = UUIDValue(org.ID)
} else {
orgID := data.ID.ValueUUID()
org, err = r.Client.Organization(ctx, orgID)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get organization by ID, got error: %s", err))
return
}
}

// We've fetched the organization ID from state, and the latest values for
// everything else from the backend. Ensure that any mutable data is synced
// with the backend.
data.Name = types.StringValue(org.Name)
data.DisplayName = types.StringValue(org.DisplayName)
data.Description = types.StringValue(org.Description)
data.Icon = types.StringValue(org.Icon)

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

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

tflog.Trace(ctx, "creating organization", map[string]any{
"id": data.ID.ValueUUID(),
"name": data.Name.ValueString(),
"display_name": data.DisplayName.ValueString(),
"description": data.Description.ValueString(),
"icon": data.Icon.ValueString(),
})
org, err := r.Client.CreateOrganization(ctx, codersdk.CreateOrganizationRequest{
Name: data.Name.ValueString(),
DisplayName: data.DisplayName.ValueString(),
Description: data.Description.ValueString(),
Icon: data.Icon.ValueString(),
})
if err != nil {
resp.Diagnostics.AddError("Failed to create organization", err.Error())
return
}
tflog.Trace(ctx, "successfully created organization", map[string]any{
"id": org.ID,
"name": org.Name,
"display_name": org.DisplayName,
"description": org.Description,
"icon": org.Icon,
})
// Fill in `ID` since it must be "computed".
data.ID = UUIDValue(org.ID)
// We also fill in `DisplayName`, since it's optional but the backend will
// default it.
data.DisplayName = types.StringValue(org.DisplayName)

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

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

orgID := data.ID.ValueUUID()

// Update the organization metadata
tflog.Trace(ctx, "updating organization", map[string]any{
"id": orgID,
"new_name": data.Name.ValueString(),
"new_display_name": data.DisplayName.ValueString(),
"new_description": data.Description.ValueString(),
"new_icon": data.Icon.ValueString(),
})
org, err := r.Client.UpdateOrganization(ctx, orgID.String(), codersdk.UpdateOrganizationRequest{
Name: data.Name.ValueString(),
DisplayName: data.DisplayName.ValueString(),
Description: data.Description.ValueStringPointer(),
Icon: data.Icon.ValueStringPointer(),
})
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update organization %s, got error: %s", orgID, err))
return
}
tflog.Trace(ctx, "successfully updated organization", map[string]any{
"id": orgID,
"name": org.Name,
"display_name": org.DisplayName,
"description": org.Description,
"icon": org.Icon,
})

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

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

orgID := data.ID.ValueUUID()

tflog.Trace(ctx, "deleting organization", map[string]any{
"id": orgID,
"name": data.Name.ValueString(),
})
err := r.Client.DeleteOrganization(ctx, orgID.String())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete organization %s, got error: %s", orgID, err))
return
}
tflog.Trace(ctx, "successfully deleted organization", map[string]any{
"id": orgID,
"name": data.Name.ValueString(),
})

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

func (r *OrganizationResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
// Terraform will eventually `Read` in the rest of the fields after we have
// set the `name` attribute.
resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp)
}
Loading

[8]ページ先頭

©2009-2025 Movatter.jp