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

Commitc59e994

Browse files
committed
feat: add license resource
1 parentbf558f5 commitc59e994

File tree

3 files changed

+265
-0
lines changed

3 files changed

+265
-0
lines changed

‎internal/provider/license_resource.go

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/coder/coder/v2/codersdk"
9+
"github.com/hashicorp/terraform-plugin-framework/resource"
10+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
11+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier"
12+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
13+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
14+
"github.com/hashicorp/terraform-plugin-framework/types"
15+
)
16+
17+
// Ensure provider defined types fully satisfy framework interfaces.
18+
var_ resource.Resource=&LicenseResource{}
19+
20+
funcNewLicenseResource() resource.Resource {
21+
return&LicenseResource{}
22+
}
23+
24+
// LicenseResource defines the resource implementation.
25+
typeLicenseResourcestruct {
26+
data*CoderdProviderData
27+
}
28+
29+
// LicenseResourceModel describes the resource data model.
30+
typeLicenseResourceModelstruct {
31+
ID types.Int32`tfsdk:"id"`
32+
ExpiresAt types.Int64`tfsdk:"expires_at"`
33+
License types.String`tfsdk:"license"`
34+
}
35+
36+
func (r*LicenseResource)Metadata(ctx context.Context,req resource.MetadataRequest,resp*resource.MetadataResponse) {
37+
resp.TypeName=req.ProviderTypeName+"_license"
38+
}
39+
40+
func (r*LicenseResource)Schema(ctx context.Context,req resource.SchemaRequest,resp*resource.SchemaResponse) {
41+
resp.Schema= schema.Schema{
42+
MarkdownDescription:"A license for a Coder deployment.\n\nTerraform does not guarantee this resource"+
43+
"will be created before other resources or attributes that require a licensed deployment. "+
44+
"It is instead recommended to use the `depends_on` meta-argument.",
45+
46+
Attributes:map[string]schema.Attribute{
47+
"id": schema.Int32Attribute{
48+
MarkdownDescription:"Integer ID of the license.",
49+
Computed:true,
50+
PlanModifiers: []planmodifier.Int32{
51+
int32planmodifier.UseStateForUnknown(),
52+
},
53+
},
54+
"expires_at": schema.Int64Attribute{
55+
MarkdownDescription:"Unix timestamp of when the license expires.",
56+
Computed:true,
57+
},
58+
"license": schema.StringAttribute{
59+
MarkdownDescription:"A license key for Coder.",
60+
Required:true,
61+
Sensitive:true,
62+
PlanModifiers: []planmodifier.String{
63+
stringplanmodifier.RequiresReplace(),
64+
},
65+
},
66+
},
67+
}
68+
}
69+
70+
func (r*LicenseResource)Configure(ctx context.Context,req resource.ConfigureRequest,resp*resource.ConfigureResponse) {
71+
// Prevent panic if the provider has not been configured.
72+
ifreq.ProviderData==nil {
73+
return
74+
}
75+
76+
data,ok:=req.ProviderData.(*CoderdProviderData)
77+
78+
if!ok {
79+
resp.Diagnostics.AddError(
80+
"Unexpected Resource Configure Type",
81+
fmt.Sprintf("Expected *CoderdProviderData, got: %T. Please report this issue to the provider developers.",req.ProviderData),
82+
)
83+
84+
return
85+
}
86+
87+
r.data=data
88+
}
89+
90+
func (r*LicenseResource)Create(ctx context.Context,req resource.CreateRequest,resp*resource.CreateResponse) {
91+
vardataLicenseResourceModel
92+
93+
// Read Terraform plan data into the model
94+
resp.Diagnostics.Append(req.Plan.Get(ctx,&data)...)
95+
96+
ifresp.Diagnostics.HasError() {
97+
return
98+
}
99+
100+
client:=r.data.Client
101+
102+
license,err:=client.AddLicense(ctx, codersdk.AddLicenseRequest{
103+
License:data.License.ValueString(),
104+
})
105+
iferr!=nil {
106+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to add license, got error: %s",err))
107+
return
108+
}
109+
data.ID=types.Int32Value(license.ID)
110+
expiresAt,err:=license.ExpiresAt()
111+
iferr!=nil {
112+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to parse license expiration, got error: %s",err))
113+
return
114+
}
115+
data.ExpiresAt=types.Int64Value(expiresAt.Unix())
116+
117+
// Save data into Terraform state
118+
resp.Diagnostics.Append(resp.State.Set(ctx,&data)...)
119+
}
120+
121+
func (r*LicenseResource)Read(ctx context.Context,req resource.ReadRequest,resp*resource.ReadResponse) {
122+
vardataLicenseResourceModel
123+
124+
// Read Terraform prior state data into the model
125+
resp.Diagnostics.Append(req.State.Get(ctx,&data)...)
126+
127+
ifresp.Diagnostics.HasError() {
128+
return
129+
}
130+
131+
licenses,err:=r.data.Client.Licenses(ctx)
132+
iferr!=nil {
133+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to list licenses, got error: %s",err))
134+
return
135+
}
136+
137+
found:=false
138+
for_,license:=rangelicenses {
139+
iflicense.ID==data.ID.ValueInt32() {
140+
found=true
141+
expiresAt,err:=license.ExpiresAt()
142+
iferr!=nil {
143+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to parse license expiration, got error: %s",err))
144+
return
145+
}
146+
ifexpiresAt.Before(time.Now()) {
147+
resp.Diagnostics.AddError("Client Error","License has expired.")
148+
return
149+
}
150+
data.ExpiresAt=types.Int64Value(expiresAt.Unix())
151+
}
152+
}
153+
if!found {
154+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("License with ID %d not found",data.ID.ValueInt32()))
155+
}
156+
157+
// Save updated data into Terraform state
158+
resp.Diagnostics.Append(resp.State.Set(ctx,&data)...)
159+
}
160+
161+
func (r*LicenseResource)Update(ctx context.Context,req resource.UpdateRequest,resp*resource.UpdateResponse) {
162+
vardataLicenseResourceModel
163+
164+
// Read Terraform plan data into the model
165+
resp.Diagnostics.Append(req.Plan.Get(ctx,&data)...)
166+
167+
ifresp.Diagnostics.HasError() {
168+
return
169+
}
170+
171+
// Update is handled by replacement
172+
173+
// Save updated data into Terraform state
174+
resp.Diagnostics.Append(resp.State.Set(ctx,&data)...)
175+
}
176+
177+
func (r*LicenseResource)Delete(ctx context.Context,req resource.DeleteRequest,resp*resource.DeleteResponse) {
178+
vardataLicenseResourceModel
179+
180+
// Read Terraform prior state data into the model
181+
resp.Diagnostics.Append(req.State.Get(ctx,&data)...)
182+
183+
ifresp.Diagnostics.HasError() {
184+
return
185+
}
186+
187+
client:=r.data.Client
188+
189+
err:=client.DeleteLicense(ctx,data.ID.ValueInt32())
190+
iferr!=nil {
191+
resp.Diagnostics.AddError("Client Error",fmt.Sprintf("Unable to delete license, got error: %s",err))
192+
return
193+
}
194+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
"os"
6+
"strings"
7+
"testing"
8+
"text/template"
9+
10+
"github.com/coder/terraform-provider-coderd/integration"
11+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
funcTestAccLicenseResource(t*testing.T) {
16+
ifos.Getenv("TF_ACC")=="" {
17+
t.Skip("Acceptance tests are disabled.")
18+
}
19+
ctx:=context.Background()
20+
_=integration.StartCoder(ctx,t,"license_acc",false)
21+
22+
license:=os.Getenv("CODER_ENTERPRISE_LICENSE")
23+
iflicense=="" {
24+
t.Skip("No license found for license resource tests, skipping")
25+
}
26+
27+
cfg1:=testAccLicenseResourceconfig{
28+
License:license,
29+
}
30+
31+
resource.Test(t, resource.TestCase{
32+
IsUnitTest:true,
33+
PreCheck:func() {testAccPreCheck(t) },
34+
ProtoV6ProviderFactories:testAccProtoV6ProviderFactories,
35+
Steps: []resource.TestStep{
36+
{
37+
Config:cfg1.String(t),
38+
},
39+
},
40+
})
41+
}
42+
43+
typetestAccLicenseResourceconfigstruct {
44+
Licensestring
45+
}
46+
47+
func (ctestAccLicenseResourceconfig)String(t*testing.T)string {
48+
t.Helper()
49+
tpl:=`
50+
provider coderd {
51+
url = "{{.URL}}"
52+
token = "{{.Token}}"
53+
}
54+
55+
resource "coderd_group" "test" {
56+
license = {{orNull .License}}
57+
}
58+
`
59+
funcMap:= template.FuncMap{
60+
"orNull":PrintOrNull,
61+
}
62+
63+
buf:= strings.Builder{}
64+
tmpl,err:=template.New("licenseResource").Funcs(funcMap).Parse(tpl)
65+
require.NoError(t,err)
66+
67+
err=tmpl.Execute(&buf,c)
68+
require.NoError(t,err)
69+
returnbuf.String()
70+
}

‎internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ func (p *CoderdProvider) Resources(ctx context.Context) []func() resource.Resour
138138
NewGroupResource,
139139
NewTemplateResource,
140140
NewWorkspaceProxyResource,
141+
NewLicenseResource,
141142
}
142143
}
143144

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp