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

Commit17513d7

Browse files
feat: add coderd_organization data source (#33)
1 parenta00ba07 commit17513d7

File tree

7 files changed

+366
-4
lines changed

7 files changed

+366
-4
lines changed

‎docs/data-sources/group.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ An existing group on the coder deployment.
1919

2020
-`id` (String) The ID of the group to retrieve. This field will be populated if a name and organization ID is supplied.
2121
-`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.
22+
-`organization_id` (String) 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.
2323

2424
###Read-Only
2525

‎docs/data-sources/organization.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title:"coderd_organization Data Source - coderd"
4+
subcategory:""
5+
description:|-
6+
An existing organization on the coder deployment.
7+
---
8+
9+
#coderd_organization (Data Source)
10+
11+
An existing organization 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 organization to retrieve. This field will be populated if the organization is found by name, or if the default organization is requested.
21+
-`is_default` (Boolean) Whether the organization is the default organization of the deployment. This field will be populated if the organization is found by ID or name.
22+
-`name` (String) The name of the organization to retrieve. This field will be populated if the organization is found by ID, or if the default organization is requested.
23+
24+
###Read-Only
25+
26+
-`created_at` (Number) Unix timestamp when the organization was created.
27+
-`members` (Set of String) Members of the organization, by ID
28+
-`updated_at` (Number) Unix timestamp when the organization was last updated.

‎go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ toolchain go1.22.5
66

77
require (
88
cdr.dev/slogv1.6.2-0.20240126064726-20367d4aede6
9-
github.com/coder/coder/v2v2.12.3
9+
github.com/coder/coder/v2v2.13.1
1010
github.com/docker/dockerv27.0.3+incompatible
1111
github.com/docker/go-connectionsv0.4.0
1212
github.com/google/uuidv1.6.0

‎go.sum

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,10 @@ github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo
8181
github.com/chenzhuoyu/iasmv0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
8282
github.com/cloudflare/circlv1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
8383
github.com/cloudflare/circlv1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
84-
github.com/coder/coder/v2v2.12.3 h1:tA+0lWIO7xXJ4guu+tqcram/6kKKX1pWd1WlipdhIpc=
85-
github.com/coder/coder/v2v2.12.3/go.mod h1:io26dngPVP3a7zD1lL/bzEOGDSincJGomBKlqmRRVNA=
84+
github.com/coder/coder/v2v2.13.0 h1:MlkRGqQcCAdwIkLc9iV8sQfT4jB3EThHopG0jF3BuFE=
85+
github.com/coder/coder/v2v2.13.0/go.mod h1:Gxc79InMB6b+sncuDUORtFLWi7aKshvis3QrMUhpq5Q=
86+
github.com/coder/coder/v2v2.13.1 h1:tCd8ljqIAufbVcBr8ODS1QbsrjJbmOIvgDkvdd/JMXc=
87+
github.com/coder/coder/v2v2.13.1/go.mod h1:Gxc79InMB6b+sncuDUORtFLWi7aKshvis3QrMUhpq5Q=
8688
github.com/coder/prettyv0.0.0-20230908205945-e89ba86370e0 h1:3A0ES21Ke+FxEM8CXx9n47SZOKOpgSE1bbJzlE4qPVs=
8789
github.com/coder/prettyv0.0.0-20230908205945-e89ba86370e0/go.mod h1:5UuS2Ts+nTToAMeOjNlnHFkPahrtDkmpydBen/3wgZc=
8890
github.com/coder/serpentv0.7.0 h1:zGpD2GlF3lKIVkMjNGKbkip88qzd5r/TRcc30X/SrT0=
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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/datasourcevalidator"
10+
"github.com/hashicorp/terraform-plugin-framework/attr"
11+
"github.com/hashicorp/terraform-plugin-framework/datasource"
12+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
13+
"github.com/hashicorp/terraform-plugin-framework/path"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
)
16+
17+
// Ensure provider defined types fully satisfy framework interfaces.
18+
var_ datasource.DataSource=&OrganizationDataSource{}
19+
var_ datasource.DataSourceWithConfigValidators=&OrganizationDataSource{}
20+
21+
funcNewOrganizationDataSource() datasource.DataSource {
22+
return&OrganizationDataSource{}
23+
}
24+
25+
// OrganizationDataSource defines the data source implementation.
26+
typeOrganizationDataSourcestruct {
27+
data*CoderdProviderData
28+
}
29+
30+
// OrganizationDataSourceModel describes the data source data model.
31+
typeOrganizationDataSourceModelstruct {
32+
// Exactly one of ID, IsDefault, or Name must be set.
33+
ID types.String`tfsdk:"id"`
34+
IsDefault types.Bool`tfsdk:"is_default"`
35+
Name types.String`tfsdk:"name"`
36+
37+
CreatedAt types.Int64`tfsdk:"created_at"`
38+
UpdatedAt types.Int64`tfsdk:"updated_at"`
39+
// TODO: This could reasonably store some User object - though we may need to make additional queries depending on what fields we
40+
// want, or to have one consistent user type for all data sources.
41+
Members types.Set`tfsdk:"members"`
42+
}
43+
44+
func (d*OrganizationDataSource)Metadata(ctx context.Context,req datasource.MetadataRequest,resp*datasource.MetadataResponse) {
45+
resp.TypeName=req.ProviderTypeName+"_organization"
46+
}
47+
48+
func (d*OrganizationDataSource)Schema(ctx context.Context,req datasource.SchemaRequest,resp*datasource.SchemaResponse) {
49+
resp.Schema= schema.Schema{
50+
MarkdownDescription:"An existing organization on the coder deployment.",
51+
52+
Attributes:map[string]schema.Attribute{
53+
"id": schema.StringAttribute{
54+
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.",
55+
Optional:true,
56+
Computed:true,
57+
},
58+
"is_default": schema.BoolAttribute{
59+
MarkdownDescription:"Whether the organization is the default organization of the deployment. This field will be populated if the organization is found by ID or name.",
60+
Optional:true,
61+
Computed:true,
62+
},
63+
"name": schema.StringAttribute{
64+
MarkdownDescription:"The name of the organization to retrieve. This field will be populated if the organization is found by ID, or if the default organization is requested.",
65+
Optional:true,
66+
Computed:true,
67+
},
68+
"created_at": schema.Int64Attribute{
69+
MarkdownDescription:"Unix timestamp when the organization was created.",
70+
Computed:true,
71+
},
72+
"updated_at": schema.Int64Attribute{
73+
MarkdownDescription:"Unix timestamp when the organization was last updated.",
74+
Computed:true,
75+
},
76+
77+
"members": schema.SetAttribute{
78+
MarkdownDescription:"Members of the organization, by ID",
79+
Computed:true,
80+
ElementType:types.StringType,
81+
},
82+
},
83+
}
84+
}
85+
86+
func (d*OrganizationDataSource)Configure(ctx context.Context,req datasource.ConfigureRequest,resp*datasource.ConfigureResponse) {
87+
// Prevent panic if the provider has not been configured.
88+
ifreq.ProviderData==nil {
89+
return
90+
}
91+
92+
data,ok:=req.ProviderData.(*CoderdProviderData)
93+
94+
if!ok {
95+
resp.Diagnostics.AddError(
96+
"Unexpected Data Source Configure Type",
97+
fmt.Sprintf("Expected *CoderdProviderData, got: %T. Please report this issue to the provider developers.",req.ProviderData),
98+
)
99+
100+
return
101+
}
102+
103+
d.data=data
104+
}
105+
106+
func (d*OrganizationDataSource)Read(ctx context.Context,req datasource.ReadRequest,resp*datasource.ReadResponse) {
107+
vardataOrganizationDataSourceModel
108+
109+
// Read Terraform configuration data into the model
110+
resp.Diagnostics.Append(req.Config.Get(ctx,&data)...)
111+
112+
ifresp.Diagnostics.HasError() {
113+
return
114+
}
115+
116+
client:=d.data.Client
117+
118+
varorg codersdk.Organization
119+
if!data.ID.IsNull() {// By ID
120+
orgID,err:=uuid.Parse(data.ID.ValueString())
121+
iferr!=nil {
122+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to parse supplied ID as UUID, got error: %s",err))
123+
return
124+
}
125+
org,err=client.Organization(ctx,orgID)
126+
iferr!=nil {
127+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to get organization by ID, got error: %s",err))
128+
return
129+
}
130+
iforg.ID.String()!=data.ID.ValueString() {
131+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Organization ID %s does not match requested ID %s",org.ID,data.ID))
132+
return
133+
}
134+
}elseifdata.IsDefault.ValueBool() {// Get Default
135+
varerrerror
136+
org,err=client.OrganizationByName(ctx,"default")
137+
iferr!=nil {
138+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to get default organization, got error: %s",err))
139+
return
140+
}
141+
if!org.IsDefault {
142+
resp.Diagnostics.AddError("Client Error","Found organization was not the default organization")
143+
return
144+
}
145+
}else {// By Name
146+
varerrerror
147+
org,err=client.OrganizationByName(ctx,data.Name.ValueString())
148+
iferr!=nil {
149+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to get organization by name, got error: %s",err))
150+
return
151+
}
152+
iforg.Name!=data.Name.ValueString() {
153+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Organization name %s does not match requested name %s",org.Name,data.Name))
154+
return
155+
}
156+
}
157+
data.ID=types.StringValue(org.ID.String())
158+
data.Name=types.StringValue(org.Name)
159+
data.IsDefault=types.BoolValue(org.IsDefault)
160+
data.CreatedAt=types.Int64Value(org.CreatedAt.Unix())
161+
data.UpdatedAt=types.Int64Value(org.UpdatedAt.Unix())
162+
members,err:=client.OrganizationMembers(ctx,org.ID)
163+
iferr!=nil {
164+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to get organization members, got error: %s",err))
165+
return
166+
}
167+
memberIDs:=make([]attr.Value,0,len(members))
168+
for_,member:=rangemembers {
169+
memberIDs=append(memberIDs,types.StringValue(member.UserID.String()))
170+
}
171+
data.Members=types.SetValueMust(types.StringType,memberIDs)
172+
173+
// Save data into Terraform state
174+
resp.Diagnostics.Append(resp.State.Set(ctx,&data)...)
175+
}
176+
177+
func (d*OrganizationDataSource)ConfigValidators(_ context.Context) []datasource.ConfigValidator {
178+
return []datasource.ConfigValidator{
179+
datasourcevalidator.ExactlyOneOf(
180+
path.MatchRoot("id"),
181+
path.MatchRoot("is_default"),
182+
path.MatchRoot("name"),
183+
),
184+
}
185+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"os"
6+
"regexp"
7+
"strings"
8+
"testing"
9+
"text/template"
10+
11+
"github.com/coder/coder/v2/codersdk"
12+
"github.com/coder/terraform-provider-coderd/integration"
13+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
14+
"github.com/stretchr/testify/require"
15+
)
16+
17+
funcTestAccOrganizationDataSource(t*testing.T) {
18+
ifos.Getenv("TF_ACC")=="" {
19+
t.Skip("Acceptance tests are disabled.")
20+
}
21+
ctx:=context.Background()
22+
client:=integration.StartCoder(ctx,t,"group_acc",true)
23+
firstUser,err:=client.User(ctx,codersdk.Me)
24+
require.NoError(t,err)
25+
26+
defaultCheckFn:=resource.ComposeAggregateTestCheckFunc(
27+
resource.TestCheckResourceAttr("data.coderd_organization.test","id",firstUser.OrganizationIDs[0].String()),
28+
resource.TestCheckResourceAttr("data.coderd_organization.test","is_default","true"),
29+
resource.TestCheckResourceAttr("data.coderd_organization.test","name","first-organization"),
30+
resource.TestCheckResourceAttr("data.coderd_organization.test","members.#","1"),
31+
resource.TestCheckTypeSetElemAttr("data.coderd_organization.test","members.*",firstUser.ID.String()),
32+
resource.TestCheckResourceAttrSet("data.coderd_organization.test","created_at"),
33+
resource.TestCheckResourceAttrSet("data.coderd_organization.test","updated_at"),
34+
)
35+
36+
t.Run("DefaultOrgByIDOk",func(t*testing.T) {
37+
cfg:=testAccOrganizationDataSourceConfig{
38+
URL:client.URL.String(),
39+
Token:client.SessionToken(),
40+
ID:PtrTo(firstUser.OrganizationIDs[0].String()),
41+
}
42+
resource.Test(t, resource.TestCase{
43+
PreCheck:func() {testAccPreCheck(t) },
44+
ProtoV6ProviderFactories:testAccProtoV6ProviderFactories,
45+
Steps: []resource.TestStep{
46+
{
47+
Config:cfg.String(t),
48+
Check:defaultCheckFn,
49+
},
50+
},
51+
})
52+
})
53+
54+
t.Run("DefaultOrgByNameOk",func(t*testing.T) {
55+
cfg:=testAccOrganizationDataSourceConfig{
56+
URL:client.URL.String(),
57+
Token:client.SessionToken(),
58+
Name:PtrTo("first-organization"),
59+
}
60+
resource.Test(t, resource.TestCase{
61+
PreCheck:func() {testAccPreCheck(t) },
62+
ProtoV6ProviderFactories:testAccProtoV6ProviderFactories,
63+
Steps: []resource.TestStep{
64+
{
65+
Config:cfg.String(t),
66+
Check:defaultCheckFn,
67+
},
68+
},
69+
})
70+
})
71+
72+
t.Run("DefaultOrgByIsDefaultOk",func(t*testing.T) {
73+
cfg:=testAccOrganizationDataSourceConfig{
74+
URL:client.URL.String(),
75+
Token:client.SessionToken(),
76+
IsDefault:PtrTo(true),
77+
}
78+
resource.Test(t, resource.TestCase{
79+
PreCheck:func() {testAccPreCheck(t) },
80+
ProtoV6ProviderFactories:testAccProtoV6ProviderFactories,
81+
Steps: []resource.TestStep{
82+
{
83+
Config:cfg.String(t),
84+
Check:defaultCheckFn,
85+
},
86+
},
87+
})
88+
})
89+
90+
t.Run("InvalidAttributesError",func(t*testing.T) {
91+
cfg:=testAccOrganizationDataSourceConfig{
92+
URL:client.URL.String(),
93+
Token:client.SessionToken(),
94+
IsDefault:PtrTo(true),
95+
Name:PtrTo("first-organization"),
96+
}
97+
resource.Test(t, resource.TestCase{
98+
PreCheck:func() {testAccPreCheck(t) },
99+
ProtoV6ProviderFactories:testAccProtoV6ProviderFactories,
100+
Steps: []resource.TestStep{
101+
{
102+
Config:cfg.String(t),
103+
ExpectError:regexp.MustCompile(`Exactly one of these attributes must be configured: \[id,is\_default,name\]`),
104+
},
105+
},
106+
})
107+
})
108+
109+
// TODO: Non-default org tests
110+
}
111+
112+
typetestAccOrganizationDataSourceConfigstruct {
113+
URLstring
114+
Tokenstring
115+
116+
ID*string
117+
Name*string
118+
IsDefault*bool
119+
}
120+
121+
func (ctestAccOrganizationDataSourceConfig)String(t*testing.T)string {
122+
tpl:=`
123+
provider coderd {
124+
url = "{{.URL}}"
125+
token = "{{.Token}}"
126+
}
127+
128+
data "coderd_organization" "test" {
129+
id = {{orNull .ID}}
130+
name = {{orNull .Name}}
131+
is_default = {{orNull .IsDefault}}
132+
}
133+
`
134+
135+
funcMap:= template.FuncMap{
136+
"orNull":PrintOrNull,
137+
}
138+
139+
buf:= strings.Builder{}
140+
tmpl,err:=template.New("groupDataSource").Funcs(funcMap).Parse(tpl)
141+
require.NoError(t,err)
142+
143+
err=tmpl.Execute(&buf,c)
144+
require.NoError(t,err)
145+
returnbuf.String()
146+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp