Skip to content

Commit 49db754

Browse files
authored
feat: environment api (#218)
1 parent bcb8d20 commit 49db754

File tree

7 files changed

+356
-3
lines changed

7 files changed

+356
-3
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.18
44

55
require (
66
github.com/Masterminds/semver v1.5.0
7-
github.com/Unleash/unleash-server-api-go v0.5.2
7+
github.com/Unleash/unleash-server-api-go v0.5.3
88
github.com/fatih/structs v1.1.0
99
github.com/hashicorp/terraform-plugin-docs v0.18.0
1010
github.com/hashicorp/terraform-plugin-framework v1.4.2

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa
1313
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
1414
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX7IL/m9Y5LO+KQYv+t1CQOiFe6+SV2J7bE=
1515
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
16-
github.com/Unleash/unleash-server-api-go v0.5.2 h1:jm/+AJzUmsotfyIODFFM1IjzCOT4515YMdzktRljcWk=
17-
github.com/Unleash/unleash-server-api-go v0.5.2/go.mod h1:/IvCtBfBrOVOa67elCLig45kt6NYkk79oxmRW80WOFY=
16+
github.com/Unleash/unleash-server-api-go v0.5.3 h1:CbWFE9eK5PVKXwpvKRYratuO/75ZtEqavMu6Sc0y4To=
17+
github.com/Unleash/unleash-server-api-go v0.5.3/go.mod h1:/IvCtBfBrOVOa67elCLig45kt6NYkk79oxmRW80WOFY=
1818
github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE=
1919
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
2020
github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
6+
unleash "github.com/Unleash/unleash-server-api-go/client"
7+
"github.com/hashicorp/terraform-plugin-framework/datasource"
8+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
9+
"github.com/hashicorp/terraform-plugin-framework/types"
10+
"github.com/hashicorp/terraform-plugin-log/tflog"
11+
)
12+
13+
var (
14+
_ datasource.DataSource = &environmentDataSource{}
15+
_ datasource.DataSourceWithConfigure = &environmentDataSource{}
16+
)
17+
18+
func NewEnvironmentDataSource() datasource.DataSource {
19+
return &environmentDataSource{}
20+
}
21+
22+
type environmentDataSource struct {
23+
client *unleash.APIClient
24+
}
25+
26+
type environmentDataSourceModel struct {
27+
Name types.String `tfsdk:"name"`
28+
Type types.String `tfsdk:"type"`
29+
}
30+
31+
func (d *environmentDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
32+
if req.ProviderData == nil {
33+
return
34+
}
35+
36+
client, ok := req.ProviderData.(*unleash.APIClient)
37+
if !ok {
38+
return
39+
}
40+
d.client = client
41+
}
42+
43+
func (d *environmentDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
44+
resp.TypeName = req.ProviderTypeName + "_environment"
45+
}
46+
47+
func (d *environmentDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
48+
resp.Schema = schema.Schema{
49+
Description: "Fetch a context field.",
50+
Attributes: map[string]schema.Attribute{
51+
"name": schema.StringAttribute{
52+
Description: "The name of the environment. Must be a URL-friendly string according to RFC 3968.",
53+
Required: true,
54+
},
55+
"type": schema.StringAttribute{
56+
Description: "The type of the environment. Unleash recognizes 'development', 'test', 'preproduction' and 'production'. " +
57+
"You can pass other values and Unleash will accept them but they will carry no special semantics.",
58+
Required: true,
59+
},
60+
},
61+
}
62+
}
63+
64+
func (d *environmentDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
65+
tflog.Debug(ctx, "Preparing to hydrate environment")
66+
var state environmentDataSourceModel
67+
68+
resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
69+
if resp.Diagnostics.HasError() {
70+
tflog.Error(ctx, "Unable to read environment data source")
71+
return
72+
}
73+
74+
environment, apiResponse, err := d.client.EnvironmentsAPI.GetEnvironment(ctx, state.Name.ValueString()).Execute()
75+
76+
if !ValidateApiResponse(apiResponse, 200, &resp.Diagnostics, err) {
77+
return
78+
}
79+
80+
state = environmentDataSourceModel{
81+
Name: types.StringValue(environment.Name),
82+
Type: types.StringValue(environment.Type),
83+
}
84+
85+
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
86+
tflog.Debug(ctx, "Finished reading environment field data source", map[string]any{"success": true})
87+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package provider
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
7+
)
8+
9+
func TestAccEnvironmentDataSource(t *testing.T) {
10+
resource.Test(t, resource.TestCase{
11+
PreCheck: func() { testAccPreCheck(t) },
12+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
13+
Steps: []resource.TestStep{
14+
{
15+
Config: `
16+
data "unleash_environment" "development" {
17+
name = "development"
18+
type = "development"
19+
}`,
20+
Check: resource.ComposeTestCheckFunc(
21+
resource.TestCheckResourceAttr("data.unleash_environment.development", "name", "development"),
22+
resource.TestCheckResourceAttr("data.unleash_environment.development", "type", "development"),
23+
),
24+
},
25+
},
26+
})
27+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package provider
2+
3+
import (
4+
"context"
5+
6+
unleash "github.com/Unleash/unleash-server-api-go/client"
7+
"github.com/hashicorp/terraform-plugin-framework/path"
8+
"github.com/hashicorp/terraform-plugin-framework/resource"
9+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
10+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
11+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
12+
"github.com/hashicorp/terraform-plugin-framework/types"
13+
"github.com/hashicorp/terraform-plugin-log/tflog"
14+
)
15+
16+
var (
17+
_ resource.Resource = &environmentResource{}
18+
_ resource.ResourceWithConfigure = &environmentResource{}
19+
_ resource.ResourceWithImportState = &environmentResource{}
20+
)
21+
22+
func NewEnvironmentResource() resource.Resource {
23+
return &environmentResource{}
24+
}
25+
26+
type environmentResource struct {
27+
client *unleash.APIClient
28+
}
29+
30+
type environmentResourceModel struct {
31+
Name types.String `tfsdk:"name"`
32+
Type types.String `tfsdk:"type"`
33+
}
34+
35+
func (r *environmentResource) Configure(ctx context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
36+
if req.ProviderData == nil {
37+
return
38+
}
39+
40+
client, ok := req.ProviderData.(*unleash.APIClient)
41+
if !ok {
42+
return
43+
}
44+
r.client = client
45+
}
46+
47+
func (r *environmentResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
48+
resp.TypeName = req.ProviderTypeName + "_environment"
49+
}
50+
51+
func (r *environmentResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
52+
resp.Schema = schema.Schema{
53+
Description: "Fetch a context field.",
54+
Attributes: map[string]schema.Attribute{
55+
"name": schema.StringAttribute{
56+
Description: "The name of the environment. Must be a URL-friendly string according to RFC 3968. " +
57+
"Changing this property will require the resource to be replaced, it's generally safer to remove this resource and create a new one.",
58+
Required: true,
59+
PlanModifiers: []planmodifier.String{
60+
stringplanmodifier.RequiresReplace(),
61+
},
62+
},
63+
"type": schema.StringAttribute{
64+
Description: "The type of the environment. Unleash recognizes 'development', 'test', 'preproduction' and 'production'. " +
65+
"You can pass other values and Unleash will accept them but they will carry no special semantics.",
66+
Required: true,
67+
},
68+
},
69+
}
70+
}
71+
72+
func (r *environmentResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
73+
tflog.Debug(ctx, "Preparing to import environment resource")
74+
75+
resource.ImportStatePassthroughID(ctx, path.Root("name"), req, resp)
76+
77+
tflog.Debug(ctx, "Finished importing environment data source", map[string]interface{}{"success": true})
78+
}
79+
80+
func (r *environmentResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
81+
tflog.Debug(ctx, "Preparing to create environment resource")
82+
var plan environmentResourceModel
83+
84+
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
85+
if resp.Diagnostics.HasError() {
86+
return
87+
}
88+
89+
createEnvironmentRequest := *unleash.NewCreateEnvironmentSchemaWithDefaults()
90+
createEnvironmentRequest.Name = plan.Name.ValueString()
91+
createEnvironmentRequest.Type = plan.Type.ValueString()
92+
93+
environment, apiResponse, err := r.client.EnvironmentsAPI.CreateEnvironment(ctx).CreateEnvironmentSchema(createEnvironmentRequest).Execute()
94+
95+
if !ValidateApiResponse(apiResponse, 201, &resp.Diagnostics, err) {
96+
return
97+
}
98+
99+
plan = environmentResourceModel{
100+
Name: types.StringValue(environment.Name),
101+
Type: types.StringValue(environment.Type),
102+
}
103+
104+
resp.State.Set(ctx, &plan)
105+
tflog.Debug(ctx, "Finished creating environment resource", map[string]interface{}{"success": true})
106+
107+
}
108+
109+
func (r *environmentResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
110+
tflog.Debug(ctx, "Preparing to read environment resource")
111+
var state environmentResourceModel
112+
113+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
114+
if resp.Diagnostics.HasError() {
115+
return
116+
}
117+
118+
environment, apiResponse, err := r.client.EnvironmentsAPI.GetEnvironment(ctx, state.Name.ValueString()).Execute()
119+
120+
if !ValidateApiResponse(apiResponse, 200, &resp.Diagnostics, err) {
121+
return
122+
}
123+
124+
state = environmentResourceModel{
125+
Name: types.StringValue(environment.Name),
126+
Type: types.StringValue(environment.Type),
127+
}
128+
129+
resp.State.Set(ctx, &state)
130+
131+
tflog.Debug(ctx, "Finished reading environment resource", map[string]interface{}{"success": true})
132+
}
133+
134+
func (r *environmentResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
135+
tflog.Debug(ctx, "Preparing to update environment resource")
136+
var plan environmentResourceModel
137+
138+
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
139+
if resp.Diagnostics.HasError() {
140+
return
141+
}
142+
143+
updateEnvironmentRequest := *unleash.NewUpdateEnvironmentSchemaWithDefaults()
144+
updateEnvironmentRequest.SetType(plan.Type.ValueString())
145+
146+
environment, apiResponse, err := r.client.EnvironmentsAPI.UpdateEnvironment(ctx, plan.Name.ValueString()).UpdateEnvironmentSchema(updateEnvironmentRequest).Execute()
147+
148+
if !ValidateApiResponse(apiResponse, 200, &resp.Diagnostics, err) {
149+
return
150+
}
151+
152+
plan = environmentResourceModel{
153+
Name: types.StringValue(environment.Name),
154+
Type: types.StringValue(environment.Type),
155+
}
156+
157+
resp.State.Set(ctx, &plan)
158+
tflog.Debug(ctx, "Finished updating environment resource", map[string]interface{}{"success": true})
159+
}
160+
161+
func (r *environmentResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
162+
tflog.Debug(ctx, "Preparing to delete environment resource")
163+
var state environmentResourceModel
164+
165+
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
166+
if resp.Diagnostics.HasError() {
167+
return
168+
}
169+
170+
apiResponse, err := r.client.EnvironmentsAPI.RemoveEnvironment(ctx, state.Name.ValueString()).Execute()
171+
172+
if !ValidateApiResponse(apiResponse, 200, &resp.Diagnostics, err) {
173+
return
174+
}
175+
176+
resp.State.RemoveResource(ctx)
177+
tflog.Debug(ctx, "Finished deleting environment resource", map[string]interface{}{"success": true})
178+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package provider
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
8+
)
9+
10+
func TestAccEnvironmentResource(t *testing.T) {
11+
if os.Getenv("UNLEASH_ENTERPRISE") != "true" {
12+
t.Skip("Skipping enterprise tests")
13+
}
14+
resource.Test(t, resource.TestCase{
15+
PreCheck: func() { testAccPreCheck(t) },
16+
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
17+
Steps: []resource.TestStep{
18+
{
19+
//basic creation
20+
Config: `
21+
resource "unleash_environment" "fynbos_environment" {
22+
name = "fynbos"
23+
type = "semi-arid"
24+
}
25+
`,
26+
Check: resource.ComposeAggregateTestCheckFunc(
27+
resource.TestCheckResourceAttr("unleash_environment.fynbos_environment", "name", "fynbos"),
28+
resource.TestCheckResourceAttr("unleash_environment.fynbos_environment", "type", "semi-arid"),
29+
),
30+
},
31+
{
32+
//modify type
33+
Config: `
34+
resource "unleash_environment" "fynbos_environment" {
35+
name = "fynbos"
36+
type = "shrubland"
37+
}
38+
`,
39+
Check: resource.ComposeAggregateTestCheckFunc(
40+
resource.TestCheckResourceAttr("unleash_environment.fynbos_environment", "name", "fynbos"),
41+
resource.TestCheckResourceAttr("unleash_environment.fynbos_environment", "type", "shrubland"),
42+
),
43+
},
44+
{
45+
//modify name - makes a new environment
46+
Config: `
47+
resource "unleash_environment" "fynbos_environment" {
48+
name = "nama_karoo"
49+
type = "semi-desert"
50+
}
51+
`,
52+
Check: resource.ComposeAggregateTestCheckFunc(
53+
resource.TestCheckResourceAttr("unleash_environment.fynbos_environment", "name", "nama_karoo"),
54+
resource.TestCheckResourceAttr("unleash_environment.fynbos_environment", "type", "semi-desert"),
55+
),
56+
},
57+
},
58+
})
59+
}

internal/provider/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ func (p *UnleashProvider) Resources(ctx context.Context) []func() resource.Resou
175175
NewOidcResource,
176176
NewSamlResource,
177177
NewContextFieldResource,
178+
NewEnvironmentResource,
178179
}
179180
}
180181

@@ -185,6 +186,7 @@ func (p *UnleashProvider) DataSources(ctx context.Context) []func() datasource.D
185186
NewPermissionDataSource,
186187
NewRoleDataSource,
187188
NewContextFieldDataSource,
189+
NewEnvironmentDataSource,
188190
}
189191
}
190192

0 commit comments

Comments
 (0)