Skip to content

Commit 1894bd6

Browse files
committed
feat: add coderd_group data source
1 parent 773aee7 commit 1894bd6

File tree

4 files changed

+457
-0
lines changed

4 files changed

+457
-0
lines changed

docs/data-sources/group.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "coderd_group Data Source - coderd"
4+
subcategory: ""
5+
description: |-
6+
An existing group on the coder deployment.
7+
---
8+
9+
# coderd_group (Data Source)
10+
11+
An existing group on the coder deployment.
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Optional
19+
20+
- `id` (String) The ID of the group to retrieve. This field will be populated if a name and organization ID is supplied.
21+
- `name` (String) The name of the group to retrieve. This field will be populated if an ID is supplied.
22+
- `organization_id` (String) The organization ID that the group belongs to. This field will be populated if an ID is supplied.
23+
24+
### Read-Only
25+
26+
- `avatar_url` (String) The URL of the group's avatar.
27+
- `display_name` (String) The display name of the group.
28+
- `members` (Set of String) Members of the group, by ID.
29+
- `quota_allowance` (Number) The number of quota credits to allocate to each user in the group.
30+
- `source` (String) The source of the group. Either 'oidc' or 'user'.
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/coder/coder/v2/codersdk"
8+
"github.com/google/uuid"
9+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
10+
"github.com/hashicorp/terraform-plugin-framework/datasource"
11+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
12+
"github.com/hashicorp/terraform-plugin-framework/path"
13+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
)
16+
17+
// Ensure provider defined types fully satisfy framework interfaces.
18+
var _ datasource.DataSource = &GroupDataSource{}
19+
20+
func NewGroupDataSource() datasource.DataSource {
21+
return &GroupDataSource{}
22+
}
23+
24+
// GroupDataSource defines the data source implementation.
25+
type GroupDataSource struct {
26+
data *CoderdProviderData
27+
}
28+
29+
// GroupDataSourceModel describes the data source data model.
30+
type GroupDataSourceModel struct {
31+
// ID or name and organization ID must be set
32+
ID types.String `tfsdk:"id"`
33+
Name types.String `tfsdk:"name"`
34+
OrganizationID types.String `tfsdk:"organization_id"`
35+
36+
DisplayName types.String `tfsdk:"display_name"`
37+
AvatarURL types.String `tfsdk:"avatar_url"`
38+
QuotaAllowance types.Int32 `tfsdk:"quota_allowance"`
39+
Source types.String `tfsdk:"source"`
40+
Members []Member `tfsdk:"members"`
41+
}
42+
43+
type Member struct {
44+
ID types.String `tfsdk:"id"`
45+
Username types.String `tfsdk:"username"`
46+
Email types.String `tfsdk:"email"`
47+
CreatedAt types.Int64 `tfsdk:"created_at"`
48+
LastSeenAt types.Int64 `tfsdk:"last_seen_at"`
49+
Status types.String `tfsdk:"status"`
50+
LoginType types.String `tfsdk:"login_type"`
51+
ThemePreference types.String `tfsdk:"theme_preference"`
52+
}
53+
54+
func (d *GroupDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
55+
resp.TypeName = req.ProviderTypeName + "_group"
56+
}
57+
58+
func (d *GroupDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
59+
resp.Schema = schema.Schema{
60+
MarkdownDescription: "An existing group on the coder deployment.",
61+
62+
Attributes: map[string]schema.Attribute{
63+
"id": schema.StringAttribute{
64+
MarkdownDescription: "The ID of the group to retrieve. This field will be populated if a name and organization ID is supplied.",
65+
Optional: true,
66+
Computed: true,
67+
Validators: []validator.String{
68+
stringvalidator.AtLeastOneOf(path.Expressions{
69+
path.MatchRoot("name"),
70+
}...),
71+
},
72+
},
73+
"name": schema.StringAttribute{
74+
MarkdownDescription: "The name of the group to retrieve. This field will be populated if an ID is supplied.",
75+
Optional: true,
76+
Computed: true,
77+
Validators: []validator.String{
78+
stringvalidator.AlsoRequires(path.Expressions{
79+
path.MatchRoot("organization_id"),
80+
}...),
81+
},
82+
},
83+
"organization_id": schema.StringAttribute{
84+
MarkdownDescription: "The organization ID that the group belongs to. This field will be populated if an ID is supplied.",
85+
Optional: true,
86+
Computed: true,
87+
},
88+
"display_name": schema.StringAttribute{
89+
Computed: true,
90+
},
91+
"avatar_url": schema.StringAttribute{
92+
Computed: true,
93+
},
94+
"quota_allowance": schema.Int32Attribute{
95+
MarkdownDescription: "The number of quota credits to allocate to each user in the group.",
96+
Computed: true,
97+
},
98+
"source": schema.StringAttribute{
99+
MarkdownDescription: "The source of the group. Either 'oidc' or 'user'.",
100+
Computed: true,
101+
},
102+
"members": schema.SetNestedAttribute{
103+
MarkdownDescription: "Members of the group.",
104+
Computed: true,
105+
NestedObject: schema.NestedAttributeObject{
106+
Attributes: map[string]schema.Attribute{
107+
"id": schema.StringAttribute{
108+
Computed: true,
109+
},
110+
"username": schema.StringAttribute{
111+
Computed: true,
112+
},
113+
"email": schema.StringAttribute{
114+
Computed: true,
115+
},
116+
"created_at": schema.Int64Attribute{
117+
MarkdownDescription: "Unix timestamp of when the member was created.",
118+
Computed: true,
119+
},
120+
"last_seen_at": schema.Int64Attribute{
121+
MarkdownDescription: "Unix timestamp of when the member was last seen.",
122+
Computed: true,
123+
},
124+
"status": schema.StringAttribute{
125+
MarkdownDescription: "The status of the member. Can be 'active', 'dormant' or 'suspended'.",
126+
Computed: true,
127+
},
128+
"login_type": schema.StringAttribute{
129+
MarkdownDescription: "The login type of the member. Can be 'oidc', 'token', 'password', 'github' or 'none'.",
130+
Computed: true,
131+
},
132+
"theme_preference": schema.StringAttribute{
133+
Computed: true,
134+
},
135+
// TODO: Upgrade requested user type if required
136+
},
137+
},
138+
},
139+
},
140+
}
141+
}
142+
143+
func (d *GroupDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
144+
// Prevent panic if the provider has not been configured.
145+
if req.ProviderData == nil {
146+
return
147+
}
148+
149+
data, ok := req.ProviderData.(*CoderdProviderData)
150+
151+
if !ok {
152+
resp.Diagnostics.AddError(
153+
"Unexpected Data Source Configure Type",
154+
fmt.Sprintf("Expected *CoderdProviderData, got: %T. Please report this issue to the provider developers.", req.ProviderData),
155+
)
156+
157+
return
158+
}
159+
160+
d.data = data
161+
}
162+
163+
func (d *GroupDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
164+
var data GroupDataSourceModel
165+
166+
// Read Terraform configuration data into the model
167+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
168+
169+
if resp.Diagnostics.HasError() {
170+
return
171+
}
172+
173+
client := d.data.Client
174+
175+
var group codersdk.Group
176+
if !data.ID.IsNull() {
177+
groupID, err := uuid.Parse(data.ID.ValueString())
178+
if err != nil {
179+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied group ID as UUID, got error: %s", err))
180+
return
181+
}
182+
183+
group, err = client.Group(ctx, groupID)
184+
if err != nil {
185+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to get group by ID, got error: %s", err))
186+
return
187+
}
188+
data.Name = types.StringValue(group.Name)
189+
data.OrganizationID = types.StringValue(group.OrganizationID.String())
190+
} else {
191+
orgID, err := uuid.Parse(data.OrganizationID.ValueString())
192+
if err != nil {
193+
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to parse supplied organization ID as UUID, got error: %s", err))
194+
return
195+
}
196+
group, err = client.GroupByOrgAndName(ctx, orgID, data.Name.ValueString())
197+
if err != nil {
198+
resp.Diagnostics.AddError("Failed to get group by name and org ID", err.Error())
199+
return
200+
}
201+
data.ID = types.StringValue(group.ID.String())
202+
}
203+
204+
data.DisplayName = types.StringValue(group.DisplayName)
205+
data.AvatarURL = types.StringValue(group.AvatarURL)
206+
data.QuotaAllowance = types.Int32Value(int32(group.QuotaAllowance))
207+
members := make([]Member, 0, len(group.Members))
208+
for _, member := range group.Members {
209+
members = append(members, Member{
210+
ID: types.StringValue(member.ID.String()),
211+
Username: types.StringValue(member.Username),
212+
Email: types.StringValue(member.Email),
213+
CreatedAt: types.Int64Value(member.CreatedAt.Unix()),
214+
LastSeenAt: types.Int64Value(member.LastSeenAt.Unix()),
215+
Status: types.StringValue(string(member.Status)),
216+
LoginType: types.StringValue(string(member.LoginType)),
217+
ThemePreference: types.StringValue(member.ThemePreference),
218+
})
219+
}
220+
data.Members = members
221+
data.Source = types.StringValue(string(group.Source))
222+
223+
// Save data into Terraform state
224+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
225+
}

0 commit comments

Comments
 (0)