Skip to content

Commit c9b6370

Browse files
authored
Feat: add support for variable set assignment resource (#870)
* Feat: add support for variable set assignment resource * Add tests * fix test * update test * remove token id to check failures in integration test * add back token id
1 parent de81881 commit c9b6370

File tree

9 files changed

+422
-2
lines changed

9 files changed

+422
-2
lines changed

client/api_client.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ type ApiClientInterface interface {
162162
ConfigurationVariablesBySetId(setId string) ([]ConfigurationVariable, error)
163163
AssignConfigurationSets(scope string, scopeId string, sets []string) error
164164
UnassignConfigurationSets(scope string, scopeId string, sets []string) error
165+
ConfigurationSetsAssignments(scope string, scopeId string) ([]ConfigurationSet, error)
165166
}
166167

167168
func NewApiClient(client http.HttpClientInterface, defaultOrganizationId string) ApiClientInterface {

client/api_client_mock.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/configuration_set_assignment.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,15 @@ func (client *ApiClient) UnassignConfigurationSets(scope string, scopeId string,
1818

1919
return client.http.Delete(url, map[string]string{"setIds": setIds})
2020
}
21+
22+
func (client *ApiClient) ConfigurationSetsAssignments(scope string, scopeId string) ([]ConfigurationSet, error) {
23+
var result []ConfigurationSet
24+
25+
url := fmt.Sprintf("/configuration-sets/assignments/%s/%s", scope, scopeId)
26+
27+
if err := client.http.Get(url, nil, &result); err != nil {
28+
return nil, err
29+
}
30+
31+
return result, nil
32+
}

client/configuration_set_assignment_test.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
11
package client_test
22

33
import (
4+
. "github.com/env0/terraform-provider-env0/client"
45
. "github.com/onsi/ginkgo"
6+
. "github.com/onsi/gomega"
7+
"go.uber.org/mock/gomock"
58
)
69

710
var _ = Describe("Configuration Set", func() {
811
scope := "environment"
912
scopeId := "12345"
1013
setIds := []string{"1", "2", "3"}
14+
mockConfigurationSets := []ConfigurationSet{
15+
{
16+
Id: "1",
17+
},
18+
{
19+
Id: "2",
20+
},
21+
{
22+
Id: "3",
23+
},
24+
}
1125

1226
Describe("assign configuration sets", func() {
1327
BeforeEach(func() {
14-
httpCall = mockHttpClient.EXPECT().Post("/configuration-sets/assignments/environment/12345?setIds=1,2,3", nil, nil).Times(1)
28+
httpCall = mockHttpClient.EXPECT().Post("/configuration-sets/assignments/environment/12345?setIds=1,2,3", nil, nil).
29+
Do(func(path string, request interface{}, response *interface{}) {}).
30+
Times(1)
1531
apiClient.AssignConfigurationSets(scope, scopeId, setIds)
1632
})
1733

@@ -22,10 +38,29 @@ var _ = Describe("Configuration Set", func() {
2238
BeforeEach(func() {
2339
httpCall = mockHttpClient.EXPECT().Delete("/configuration-sets/assignments/environment/12345", map[string]string{
2440
"setIds": "1,2,3",
25-
}).Times(1)
41+
}).
42+
Do(func(path string, request interface{}) {}).
43+
Times(1)
2644
apiClient.UnassignConfigurationSets(scope, scopeId, setIds)
2745
})
2846

2947
It("Should send delete request", func() {})
3048
})
49+
50+
Describe("get configuration sets by scope and scope id", func() {
51+
var configurationSets []ConfigurationSet
52+
53+
BeforeEach(func() {
54+
httpCall = mockHttpClient.EXPECT().
55+
Get("/configuration-sets/assignments/environment/12345", nil, gomock.Any()).
56+
Do(func(path string, request interface{}, response *[]ConfigurationSet) {
57+
*response = mockConfigurationSets
58+
}).Times(1)
59+
configurationSets, _ = apiClient.ConfigurationSetsAssignments(scope, scopeId)
60+
})
61+
62+
It("Should return configuration sets", func() {
63+
Expect(configurationSets).To(Equal(mockConfigurationSets))
64+
})
65+
})
3166
})

env0/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ func Provider(version string) plugin.ProviderFunc {
158158
"env0_gcp_gke_credentials": resourceGcpGkeCredentials(),
159159
"env0_environment_import": resourceEnvironmentImport(),
160160
"env0_variable_set": resourceVariableSet(),
161+
"env0_variable_set_assignment": resourceVariableSetAssignment(),
161162
},
162163
}
163164

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
package env0
2+
3+
import (
4+
"context"
5+
6+
"github.com/env0/terraform-provider-env0/client"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
)
10+
11+
type variableSetAssignmentSchema struct {
12+
Scope string
13+
ScopeId string
14+
SetIds []string
15+
}
16+
17+
func resourceVariableSetAssignment() *schema.Resource {
18+
return &schema.Resource{
19+
CreateContext: resourceVariableSetAssignmentCreate,
20+
UpdateContext: resourceVariableSetAssignmentUpdate,
21+
ReadContext: resourceVariableSetAssignmentRead,
22+
DeleteContext: resourceVariableSetAssignmentDelete,
23+
24+
Schema: map[string]*schema.Schema{
25+
"scope": {
26+
Type: schema.TypeString,
27+
Description: "the resource(scope) type to assign to. Valid values: 'template', 'environment', 'module', 'organization', 'project', 'deployment'",
28+
Required: true,
29+
ValidateDiagFunc: NewStringInValidator([]string{"template", "environment", "module", "organization", "project", "deployment"}),
30+
ForceNew: true,
31+
},
32+
"scope_id": {
33+
Type: schema.TypeString,
34+
Description: "the resource(scope)id (e.g. template id)",
35+
Required: true,
36+
ForceNew: true,
37+
},
38+
"set_ids": {
39+
Type: schema.TypeList,
40+
Description: "list of variable sets",
41+
Required: true,
42+
Elem: &schema.Schema{
43+
Type: schema.TypeString,
44+
Description: "the variable set id",
45+
},
46+
},
47+
},
48+
}
49+
}
50+
51+
func resourceVariableSetAssignmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
52+
apiClient := meta.(client.ApiClientInterface)
53+
54+
var assignmentSchema variableSetAssignmentSchema
55+
56+
if err := readResourceData(&assignmentSchema, d); err != nil {
57+
return diag.Errorf("schema resource data deserialization failed: %v", err)
58+
}
59+
60+
if len(assignmentSchema.SetIds) > 0 {
61+
if err := apiClient.AssignConfigurationSets(assignmentSchema.Scope, assignmentSchema.ScopeId, assignmentSchema.SetIds); err != nil {
62+
return diag.Errorf("failed to assign variable sets to the scope: %v", err)
63+
}
64+
}
65+
66+
d.SetId(assignmentSchema.ScopeId)
67+
68+
return nil
69+
}
70+
71+
func resourceVariableSetAssignmentUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
72+
apiClient := meta.(client.ApiClientInterface)
73+
74+
var assignmentSchema variableSetAssignmentSchema
75+
76+
if err := readResourceData(&assignmentSchema, d); err != nil {
77+
return diag.Errorf("schema resource data deserialization failed: %v", err)
78+
}
79+
80+
apiConfigurationSets, err := apiClient.ConfigurationSetsAssignments(assignmentSchema.Scope, assignmentSchema.ScopeId)
81+
if err != nil {
82+
return diag.Errorf("failed to get variable sets assignments: %v", err)
83+
}
84+
85+
// Compare between apiSetIds and schemaSetIds to find what to set ids to delete and what set ids to add.
86+
var toDelete, toAdd []string
87+
88+
// In API but not in Schema - delete.
89+
for _, apiConfigurationSet := range apiConfigurationSets {
90+
found := false
91+
92+
apiSetId := apiConfigurationSet.Id
93+
for _, schemaSetId := range assignmentSchema.SetIds {
94+
if apiSetId == schemaSetId {
95+
found = true
96+
break
97+
}
98+
}
99+
100+
if !found {
101+
toDelete = append(toDelete, apiSetId)
102+
}
103+
}
104+
105+
// In Schema but not in API - add.
106+
for _, schemaSetId := range assignmentSchema.SetIds {
107+
found := false
108+
109+
for _, apiConfigurationSet := range apiConfigurationSets {
110+
apiSetId := apiConfigurationSet.Id
111+
if schemaSetId == apiSetId {
112+
found = true
113+
break
114+
}
115+
}
116+
117+
if !found {
118+
toAdd = append(toAdd, schemaSetId)
119+
}
120+
}
121+
122+
if len(toDelete) > 0 {
123+
if err := apiClient.UnassignConfigurationSets(assignmentSchema.Scope, assignmentSchema.ScopeId, toDelete); err != nil {
124+
return diag.Errorf("failed to unassign variable sets: %v", err)
125+
}
126+
}
127+
128+
if len(toAdd) > 0 {
129+
if err := apiClient.AssignConfigurationSets(assignmentSchema.Scope, assignmentSchema.ScopeId, toAdd); err != nil {
130+
return diag.Errorf("failed to assign variable sets: %v", err)
131+
}
132+
}
133+
134+
return nil
135+
}
136+
137+
func resourceVariableSetAssignmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
138+
apiClient := meta.(client.ApiClientInterface)
139+
140+
var assignmentSchema variableSetAssignmentSchema
141+
142+
if err := readResourceData(&assignmentSchema, d); err != nil {
143+
return diag.Errorf("schema resource data deserialization failed: %v", err)
144+
}
145+
146+
if len(assignmentSchema.SetIds) > 0 {
147+
if err := apiClient.UnassignConfigurationSets(assignmentSchema.Scope, assignmentSchema.ScopeId, assignmentSchema.SetIds); err != nil {
148+
return diag.Errorf("failed to unassign variable sets: %v", err)
149+
}
150+
}
151+
152+
return nil
153+
}
154+
155+
func resourceVariableSetAssignmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
156+
apiClient := meta.(client.ApiClientInterface)
157+
158+
var assignmentSchema variableSetAssignmentSchema
159+
160+
if err := readResourceData(&assignmentSchema, d); err != nil {
161+
return diag.Errorf("schema resource data deserialization failed: %v", err)
162+
}
163+
164+
apiConfigurationSets, err := apiClient.ConfigurationSetsAssignments(assignmentSchema.Scope, assignmentSchema.ScopeId)
165+
if err != nil {
166+
return diag.Errorf("failed to get variable sets assignments: %v", err)
167+
}
168+
169+
newSchemaSetIds := []string{}
170+
171+
// To avoid drifts keep the schema order as much as possible.
172+
for _, schemaSetId := range assignmentSchema.SetIds {
173+
for _, apiConfigurationSet := range apiConfigurationSets {
174+
apiSetId := apiConfigurationSet.Id
175+
176+
if schemaSetId == apiSetId {
177+
newSchemaSetIds = append(newSchemaSetIds, schemaSetId)
178+
break
179+
}
180+
}
181+
}
182+
183+
for _, apiConfigurationSet := range apiConfigurationSets {
184+
apiSetId := apiConfigurationSet.Id
185+
found := false
186+
187+
for _, schemaSetId := range assignmentSchema.SetIds {
188+
if schemaSetId == apiSetId {
189+
found = true
190+
break
191+
}
192+
}
193+
194+
if !found {
195+
newSchemaSetIds = append(newSchemaSetIds, apiSetId)
196+
}
197+
}
198+
199+
if err := d.Set("set_ids", newSchemaSetIds); err != nil {
200+
return diag.Errorf("failed to set 'set_ids': %v", err)
201+
}
202+
203+
return nil
204+
}

0 commit comments

Comments
 (0)