Thanks to visit codestin.com
Credit goes to github.com

Skip to content

chore: add uuid terraform type #43

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
35 changes: 14 additions & 21 deletions internal/provider/group_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"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/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
Expand All @@ -29,9 +28,9 @@ type GroupDataSource struct {
// GroupDataSourceModel describes the data source data model.
type GroupDataSourceModel struct {
// ID or name and organization ID must be set
ID types.String `tfsdk:"id"`
ID UUID `tfsdk:"id"`
Name types.String `tfsdk:"name"`
OrganizationID types.String `tfsdk:"organization_id"`
OrganizationID UUID `tfsdk:"organization_id"`

DisplayName types.String `tfsdk:"display_name"`
AvatarURL types.String `tfsdk:"avatar_url"`
Expand All @@ -41,7 +40,7 @@ type GroupDataSourceModel struct {
}

type Member struct {
ID types.String `tfsdk:"id"`
ID UUID `tfsdk:"id"`
Username types.String `tfsdk:"username"`
Email types.String `tfsdk:"email"`
CreatedAt types.Int64 `tfsdk:"created_at"`
Expand All @@ -64,6 +63,7 @@ func (d *GroupDataSource) Schema(ctx context.Context, req datasource.SchemaReque
MarkdownDescription: "The ID of the group to retrieve. This field will be populated if a name and organization ID is supplied.",
Optional: true,
Computed: true,
CustomType: UUIDType,
Validators: []validator.String{
stringvalidator.AtLeastOneOf(path.Expressions{
path.MatchRoot("name"),
Expand All @@ -78,6 +78,7 @@ func (d *GroupDataSource) Schema(ctx context.Context, req datasource.SchemaReque
},
"organization_id": schema.StringAttribute{
MarkdownDescription: "The organization ID that the group belongs to. This field will be populated if an ID is supplied. Defaults to the provider default organization ID.",
CustomType: UUIDType,
Optional: true,
Computed: true,
},
Expand All @@ -101,7 +102,8 @@ func (d *GroupDataSource) Schema(ctx context.Context, req datasource.SchemaReque
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
CustomType: UUIDType,
Computed: true,
},
"username": schema.StringAttribute{
Computed: true,
Expand Down Expand Up @@ -169,36 +171,27 @@ func (d *GroupDataSource) Read(ctx context.Context, req datasource.ReadRequest,
client := d.data.Client

if data.OrganizationID.IsNull() {
data.OrganizationID = types.StringValue(d.data.DefaultOrganizationID)
data.OrganizationID = UUIDValue(d.data.DefaultOrganizationID)
}

var group codersdk.Group
var err error
if !data.ID.IsNull() {
groupID, err := uuid.Parse(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied group ID as UUID, got error: %s", err))
return
}

groupID := data.ID.ValueUUID()
group, err = client.Group(ctx, groupID)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get group by ID, got error: %s", err))
return
}
data.Name = types.StringValue(group.Name)
data.OrganizationID = types.StringValue(group.OrganizationID.String())
data.OrganizationID = UUIDValue(group.OrganizationID)
} else {
orgID, err := uuid.Parse(data.OrganizationID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied organization ID as UUID, got error: %s", err))
return
}
group, err = client.GroupByOrgAndName(ctx, orgID, data.Name.ValueString())
group, err = client.GroupByOrgAndName(ctx, data.OrganizationID.ValueUUID(), data.Name.ValueString())
if err != nil {
resp.Diagnostics.AddError("Failed to get group by name and org ID", err.Error())
return
}
data.ID = types.StringValue(group.ID.String())
data.ID = UUIDValue(group.ID)
}

data.DisplayName = types.StringValue(group.DisplayName)
Expand All @@ -207,7 +200,7 @@ func (d *GroupDataSource) Read(ctx context.Context, req datasource.ReadRequest,
members := make([]Member, 0, len(group.Members))
for _, member := range group.Members {
members = append(members, Member{
ID: types.StringValue(member.ID.String()),
ID: UUIDValue(member.ID),
Username: types.StringValue(member.Username),
Email: types.StringValue(member.Email),
CreatedAt: types.Int64Value(member.CreatedAt.Unix()),
Expand Down
46 changes: 16 additions & 30 deletions internal/provider/group_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ type GroupResource struct {

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

Name types.String `tfsdk:"name"`
DisplayName types.String `tfsdk:"display_name"`
AvatarURL types.String `tfsdk:"avatar_url"`
QuotaAllowance types.Int32 `tfsdk:"quota_allowance"`
OrganizationID types.String `tfsdk:"organization_id"`
OrganizationID UUID `tfsdk:"organization_id"`
Members types.Set `tfsdk:"members"`
}

Expand All @@ -56,6 +56,7 @@ func (r *GroupResource) Schema(ctx context.Context, req resource.SchemaRequest,
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: "Group ID.",
CustomType: UUIDType,
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
Expand Down Expand Up @@ -84,6 +85,7 @@ func (r *GroupResource) Schema(ctx context.Context, req resource.SchemaRequest,
},
"organization_id": schema.StringAttribute{
MarkdownDescription: "The organization ID that the group belongs to. Defaults to the provider default organization ID.",
CustomType: UUIDType,
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.String{
Expand All @@ -92,7 +94,7 @@ func (r *GroupResource) Schema(ctx context.Context, req resource.SchemaRequest,
},
"members": schema.SetAttribute{
MarkdownDescription: "Members of the group, by ID. If null, members will not be added or removed.",
ElementType: types.StringType,
ElementType: UUIDType,
Optional: true,
},
},
Expand Down Expand Up @@ -132,14 +134,10 @@ func (r *GroupResource) Create(ctx context.Context, req resource.CreateRequest,
client := r.data.Client

if data.OrganizationID.IsUnknown() {
data.OrganizationID = types.StringValue(r.data.DefaultOrganizationID)
data.OrganizationID = UUIDValue(r.data.DefaultOrganizationID)
}

orgID, err := uuid.Parse(data.OrganizationID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied organization ID as UUID, got error: %s", err))
return
}
orgID := data.OrganizationID.ValueUUID()

displayName := data.Name.ValueString()
if data.DisplayName.ValueString() != "" {
Expand All @@ -160,7 +158,7 @@ func (r *GroupResource) Create(ctx context.Context, req resource.CreateRequest,
tflog.Trace(ctx, "successfully created group", map[string]any{
"id": group.ID.String(),
})
data.ID = types.StringValue(group.ID.String())
data.ID = UUIDValue(group.ID)
data.DisplayName = types.StringValue(group.DisplayName)

tflog.Trace(ctx, "setting group members")
Expand Down Expand Up @@ -196,11 +194,7 @@ func (r *GroupResource) Read(ctx context.Context, req resource.ReadRequest, resp

client := r.data.Client

groupID, err := uuid.Parse(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied group ID as UUID, got error: %s", err))
return
}
groupID := data.ID.ValueUUID()

group, err := client.Group(ctx, groupID)
if err != nil {
Expand All @@ -212,13 +206,13 @@ func (r *GroupResource) Read(ctx context.Context, req resource.ReadRequest, resp
data.DisplayName = types.StringValue(group.DisplayName)
data.AvatarURL = types.StringValue(group.AvatarURL)
data.QuotaAllowance = types.Int32Value(int32(group.QuotaAllowance))
data.OrganizationID = types.StringValue(group.OrganizationID.String())
data.OrganizationID = UUIDValue(group.OrganizationID)
if !data.Members.IsNull() {
members := make([]attr.Value, 0, len(group.Members))
for _, member := range group.Members {
members = append(members, types.StringValue(member.ID.String()))
members = append(members, UUIDValue(member.ID))
}
data.Members = types.SetValueMust(types.StringType, members)
data.Members = types.SetValueMust(UUIDType, members)
}

// Save updated data into Terraform state
Expand All @@ -237,13 +231,9 @@ func (r *GroupResource) Update(ctx context.Context, req resource.UpdateRequest,

client := r.data.Client
if data.OrganizationID.IsUnknown() {
data.OrganizationID = types.StringValue(r.data.DefaultOrganizationID)
}
groupID, err := uuid.Parse(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied group ID as UUID, got error: %s", err))
return
data.OrganizationID = UUIDValue(r.data.DefaultOrganizationID)
}
groupID := data.ID.ValueUUID()

group, err := client.Group(ctx, groupID)
if err != nil {
Expand Down Expand Up @@ -301,14 +291,10 @@ func (r *GroupResource) Delete(ctx context.Context, req resource.DeleteRequest,
}

client := r.data.Client
groupID, err := uuid.Parse(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied group ID as UUID, got error: %s", err))
return
}
groupID := data.ID.ValueUUID()

tflog.Trace(ctx, "deleting group")
err = client.DeleteGroup(ctx, groupID)
err := client.DeleteGroup(ctx, groupID)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete group, got error: %s", err))
return
Expand Down
23 changes: 9 additions & 14 deletions internal/provider/organization_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"

"github.com/coder/coder/v2/codersdk"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
Expand All @@ -30,7 +29,7 @@ type OrganizationDataSource struct {
// OrganizationDataSourceModel describes the data source data model.
type OrganizationDataSourceModel struct {
// Exactly one of ID, IsDefault, or Name must be set.
ID types.String `tfsdk:"id"`
ID UUID `tfsdk:"id"`
IsDefault types.Bool `tfsdk:"is_default"`
Name types.String `tfsdk:"name"`

Expand All @@ -52,6 +51,7 @@ func (d *OrganizationDataSource) Schema(ctx context.Context, req datasource.Sche
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: "The ID of the organization to retrieve. This field will be populated if the organization is found by name, or if the default organization is requested.",
CustomType: UUIDType,
Optional: true,
Computed: true,
},
Expand All @@ -77,7 +77,7 @@ func (d *OrganizationDataSource) Schema(ctx context.Context, req datasource.Sche
"members": schema.SetAttribute{
MarkdownDescription: "Members of the organization, by ID",
Computed: true,
ElementType: types.StringType,
ElementType: UUIDType,
},
},
}
Expand Down Expand Up @@ -116,23 +116,19 @@ func (d *OrganizationDataSource) Read(ctx context.Context, req datasource.ReadRe
client := d.data.Client

var org codersdk.Organization
var err error
if !data.ID.IsNull() { // By ID
orgID, err := uuid.Parse(data.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied ID as UUID, got error: %s", err))
return
}
orgID := data.ID.ValueUUID()
org, err = 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
}
if org.ID.String() != data.ID.ValueString() {
if org.ID != data.ID.ValueUUID() {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Organization ID %s does not match requested ID %s", org.ID, data.ID))
return
}
} else if data.IsDefault.ValueBool() { // Get Default
var err error
org, err = client.OrganizationByName(ctx, "default")
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get default organization, got error: %s", err))
Expand All @@ -143,7 +139,6 @@ func (d *OrganizationDataSource) Read(ctx context.Context, req datasource.ReadRe
return
}
} else { // By Name
var err error
org, err = client.OrganizationByName(ctx, data.Name.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get organization by name, got error: %s", err))
Expand All @@ -154,7 +149,7 @@ func (d *OrganizationDataSource) Read(ctx context.Context, req datasource.ReadRe
return
}
}
data.ID = types.StringValue(org.ID.String())
data.ID = UUIDValue(org.ID)
data.Name = types.StringValue(org.Name)
data.IsDefault = types.BoolValue(org.IsDefault)
data.CreatedAt = types.Int64Value(org.CreatedAt.Unix())
Expand All @@ -166,9 +161,9 @@ func (d *OrganizationDataSource) Read(ctx context.Context, req datasource.ReadRe
}
memberIDs := make([]attr.Value, 0, len(members))
for _, member := range members {
memberIDs = append(memberIDs, types.StringValue(member.UserID.String()))
memberIDs = append(memberIDs, UUIDValue(member.UserID))
}
data.Members = types.SetValueMust(types.StringType, memberIDs)
data.Members = types.SetValueMust(UUIDType, memberIDs)

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
Expand Down
14 changes: 7 additions & 7 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"

"cdr.dev/slog"
"github.com/google/uuid"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/function"
"github.com/hashicorp/terraform-plugin-framework/provider"
Expand All @@ -31,18 +32,16 @@ type CoderdProvider struct {
}

type CoderdProviderData struct {
Client *codersdk.Client
// TODO(ethanndickson): We should use a custom TFPF type for UUIDs everywhere
// possible, instead of `string` and `types.String`.
DefaultOrganizationID string
Client *codersdk.Client
DefaultOrganizationID uuid.UUID
}

// CoderdProviderModel describes the provider data model.
type CoderdProviderModel struct {
URL types.String `tfsdk:"url"`
Token types.String `tfsdk:"token"`

DefaultOrganizationID types.String `tfsdk:"default_organization_id"`
DefaultOrganizationID UUID `tfsdk:"default_organization_id"`
}

func (p *CoderdProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
Expand All @@ -63,6 +62,7 @@ func (p *CoderdProvider) Schema(ctx context.Context, req provider.SchemaRequest,
},
"default_organization_id": schema.StringAttribute{
MarkdownDescription: "Default organization ID to use when creating resources. Defaults to the first organization the token has access to.",
CustomType: UUIDType,
Optional: true,
},
},
Expand Down Expand Up @@ -109,11 +109,11 @@ func (p *CoderdProvider) Configure(ctx context.Context, req provider.ConfigureRe
resp.Diagnostics.AddError("default_organization_id", "failed to get default organization ID: "+err.Error())
return
}
data.DefaultOrganizationID = types.StringValue(user.OrganizationIDs[0].String())
data.DefaultOrganizationID = UUIDValue(user.OrganizationIDs[0])
}
providerData := &CoderdProviderData{
Client: client,
DefaultOrganizationID: data.DefaultOrganizationID.ValueString(),
DefaultOrganizationID: data.DefaultOrganizationID.ValueUUID(),
}
resp.DataSourceData = providerData
resp.ResourceData = providerData
Expand Down
Loading
Loading