Skip to content

Commit

Permalink
feat: add coderd_group data source
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanndickson committed Jul 17, 2024
1 parent 0d1743d commit 393c5a9
Show file tree
Hide file tree
Showing 4 changed files with 405 additions and 0 deletions.
30 changes: 30 additions & 0 deletions docs/data-sources/group.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "coderd_group Data Source - coderd"
subcategory: ""
description: |-
An existing group on the coder deployment.
---

# coderd_group (Data Source)

An existing group on the coder deployment.



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

### Optional

- `id` (String) The ID of the group to retrieve. This field will be populated if a name and organisation ID is supplied.
- `name` (String) The name of the group to retrieve. This field will be populated if an ID is supplied.
- `organization_id` (String) The organization ID that the group belongs to. This field will be populated if an ID is supplied.

### Read-Only

- `avatar_url` (String) The URL of the group's avatar.
- `display_name` (String) The display name of the group.
- `members` (Set of String) Members of the group, by ID.
- `quota_allowance` (Number) The number of quota credits to allocate to each user in the group.
- `source` (String) The source of the group. Either 'oidc' or 'user'.
177 changes: 177 additions & 0 deletions internal/provider/group_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
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/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)

// Ensure provider defined types fully satisfy framework interfaces.
var _ datasource.DataSource = &GroupDataSource{}

func NewGroupDataSource() datasource.DataSource {
return &GroupDataSource{}
}

// GroupDataSource defines the data source implementation.
type GroupDataSource struct {
data *CoderdProviderData
}

// GroupDataSourceModel describes the data source data model.
type GroupDataSourceModel struct {
// ID or name and organization ID must be set
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
OrganizationID types.String `tfsdk:"organization_id"`

DisplayName types.String `tfsdk:"display_name"`
AvatarURL types.String `tfsdk:"avatar_url"`
QuotaAllowance types.Int32 `tfsdk:"quota_allowance"`
Members types.Set `tfsdk:"members"`
Source types.String `tfsdk:"source"`
}

func (d *GroupDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_group"
}

func (d *GroupDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "An existing group on the coder deployment.",

Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
MarkdownDescription: "The ID of the group to retrieve. This field will be populated if a name and organisation ID is supplied.",
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.AtLeastOneOf(path.Expressions{
path.MatchRoot("name"),
}...),
},
},
"name": schema.StringAttribute{
MarkdownDescription: "The name of the group to retrieve. This field will be populated if an ID is supplied.",
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.AlsoRequires(path.Expressions{
path.MatchRoot("organization_id"),
}...),
},
},
"organization_id": schema.StringAttribute{
MarkdownDescription: "The organization ID that the group belongs to. This field will be populated if an ID is supplied.",
Optional: true,
Computed: true,
},
"display_name": schema.StringAttribute{
MarkdownDescription: "The display name of the group.",
Computed: true,
},
"avatar_url": schema.StringAttribute{
MarkdownDescription: "The URL of the group's avatar.",
Computed: true,
},
"quota_allowance": schema.Int32Attribute{
MarkdownDescription: "The number of quota credits to allocate to each user in the group.",
Computed: true,
},
"members": schema.SetAttribute{
MarkdownDescription: "Members of the group, by ID.",
ElementType: types.StringType,
Computed: true,
},
"source": schema.StringAttribute{
MarkdownDescription: "The source of the group. Either 'oidc' or 'user'.",
Computed: true,
},
},
}
}

func (d *GroupDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.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(
"Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *CoderdProviderData, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

d.data = data
}

func (d *GroupDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data GroupDataSourceModel

// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

client := d.data.Client

var group codersdk.Group
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
}

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())
} 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())
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.DisplayName = types.StringValue(group.DisplayName)
data.AvatarURL = types.StringValue(group.AvatarURL)
data.QuotaAllowance = types.Int32Value(int32(group.QuotaAllowance))
members := make([]attr.Value, 0, len(group.Members))
for _, member := range group.Members {
members = append(members, types.StringValue(member.ID.String()))
}
data.Members = types.SetValueMust(types.StringType, members)
data.Source = types.StringValue(string(group.Source))

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

0 comments on commit 393c5a9

Please sign in to comment.