Skip to content

Commit 4a978b1

Browse files
committed
feat(k8s): ACL CRUD + add scaleway_k8s_acl resource to provider
1 parent 6f2f988 commit 4a978b1

File tree

2 files changed

+245
-0
lines changed

2 files changed

+245
-0
lines changed

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ func Provider(config *Config) plugin.ProviderFunc {
185185
"scaleway_ipam_ip": ipam.ResourceIP(),
186186
"scaleway_ipam_ip_reverse_dns": ipam.ResourceIPReverseDNS(),
187187
"scaleway_job_definition": jobs.ResourceDefinition(),
188+
"scaleway_k8s_acl": k8s.ResourceACL(),
188189
"scaleway_k8s_cluster": k8s.ResourceCluster(),
189190
"scaleway_k8s_pool": k8s.ResourcePool(),
190191
"scaleway_lb": lb.ResourceLb(),

internal/services/k8s/acl.go

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
package k8s
2+
3+
import (
4+
"context"
5+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7+
"github.com/scaleway/scaleway-sdk-go/api/k8s/v1"
8+
"github.com/scaleway/scaleway-sdk-go/scw"
9+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/cdf"
10+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
11+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
12+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
13+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/types"
14+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
15+
)
16+
17+
func ResourceACL() *schema.Resource {
18+
return &schema.Resource{
19+
CreateContext: ResourceACLCreate,
20+
ReadContext: ResourceACLRead,
21+
UpdateContext: ResourceACLUpdate,
22+
DeleteContext: ResourceACLDelete,
23+
Importer: &schema.ResourceImporter{
24+
StateContext: schema.ImportStatePassthroughContext,
25+
},
26+
Timeouts: &schema.ResourceTimeout{
27+
Create: schema.DefaultTimeout(defaultK8SClusterTimeout),
28+
Read: schema.DefaultTimeout(defaultK8SClusterTimeout),
29+
Update: schema.DefaultTimeout(defaultK8SClusterTimeout),
30+
Delete: schema.DefaultTimeout(defaultK8SClusterTimeout),
31+
Default: schema.DefaultTimeout(defaultK8SClusterTimeout),
32+
},
33+
SchemaVersion: 0,
34+
Schema: map[string]*schema.Schema{
35+
"cluster_id": {
36+
Type: schema.TypeString,
37+
Required: true,
38+
ForceNew: true,
39+
ValidateDiagFunc: verify.IsUUIDorUUIDWithLocality(),
40+
Description: "Cluster on which the ACL is applied",
41+
},
42+
"acls": {
43+
Type: schema.TypeList,
44+
Optional: true,
45+
Description: "The list of network rules that manage inbound traffic",
46+
Elem: &schema.Resource{
47+
Schema: map[string]*schema.Schema{
48+
"ip": {
49+
Type: schema.TypeString,
50+
Required: true,
51+
Description: "The IP subnet to be allowed",
52+
},
53+
"scaleway_ranges": {
54+
Type: schema.TypeBool,
55+
Optional: true,
56+
Description: "Allow access to cluster from all Scaleway ranges as defined in https://www.scaleway.com/en/docs/console/account/reference-content/scaleway-network-information/#ip-ranges-used-by-scaleway. Only one rule with this field set to true can be added",
57+
},
58+
"description": {
59+
Type: schema.TypeString,
60+
Optional: true,
61+
Description: "The description of the ACL rule",
62+
},
63+
},
64+
},
65+
},
66+
// Common
67+
"region": regional.Schema(),
68+
},
69+
CustomizeDiff: cdf.LocalityCheck("cluster_id"),
70+
}
71+
}
72+
73+
func ResourceACLCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
74+
api, region, err := newAPIWithRegion(d, m)
75+
if err != nil {
76+
return diag.FromErr(err)
77+
}
78+
79+
clusterID := d.Get("cluster_id").(string)
80+
81+
_, err = waitCluster(ctx, api, region, locality.ExpandID(clusterID), d.Timeout(schema.TimeoutCreate))
82+
if err != nil {
83+
return diag.FromErr(err)
84+
}
85+
86+
acls, err := expandACL(d.Get("acls").([]interface{}))
87+
if err != nil {
88+
return diag.FromErr(err)
89+
}
90+
91+
createReq := &k8s.SetClusterACLRulesRequest{
92+
Region: region,
93+
ClusterID: clusterID,
94+
ACLs: acls,
95+
}
96+
97+
_, err = api.SetClusterACLRules(createReq, scw.WithContext(ctx))
98+
if err != nil {
99+
return diag.FromErr(err)
100+
}
101+
102+
d.SetId(clusterID)
103+
104+
return ResourceACLRead(ctx, d, m)
105+
}
106+
107+
func ResourceACLRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
108+
api, region, clusterID, err := NewAPIWithRegionAndID(m, d.Id())
109+
if err != nil {
110+
return diag.FromErr(err)
111+
}
112+
113+
_, err = waitCluster(ctx, api, region, clusterID, d.Timeout(schema.TimeoutRead))
114+
if err != nil && !httperrors.Is404(err) {
115+
return diag.FromErr(err)
116+
}
117+
118+
acls, err := api.ListClusterACLRules(&k8s.ListClusterACLRulesRequest{
119+
Region: region,
120+
ClusterID: clusterID,
121+
}, scw.WithContext(ctx))
122+
if err != nil {
123+
if httperrors.Is404(err) {
124+
d.SetId("")
125+
126+
return nil
127+
}
128+
129+
return diag.FromErr(err)
130+
}
131+
132+
id := regional.NewID(region, clusterID).String()
133+
d.SetId(id)
134+
135+
_ = d.Set("cluster_id", clusterID)
136+
_ = d.Set("acls", flattenACL(acls.Rules))
137+
138+
return nil
139+
}
140+
141+
func ResourceACLUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
142+
api, region, clusterID, err := NewAPIWithRegionAndID(m, d.Id())
143+
if err != nil {
144+
return diag.FromErr(err)
145+
}
146+
147+
_, err = waitCluster(ctx, api, region, clusterID, d.Timeout(schema.TimeoutUpdate))
148+
if err != nil && !httperrors.Is404(err) {
149+
return diag.FromErr(err)
150+
}
151+
152+
if d.HasChange("acls") {
153+
acls, err := expandACL(d.Get("acls").([]interface{}))
154+
if err != nil {
155+
return diag.FromErr(err)
156+
}
157+
158+
req := &k8s.SetClusterACLRulesRequest{
159+
Region: region,
160+
ClusterID: clusterID,
161+
ACLs: acls,
162+
}
163+
_, err = api.SetClusterACLRules(req, scw.WithContext(ctx))
164+
if err != nil {
165+
return diag.FromErr(err)
166+
}
167+
}
168+
169+
return ResourceACLRead(ctx, d, m)
170+
}
171+
172+
func ResourceACLDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
173+
api, region, clusterID, err := NewAPIWithRegionAndID(m, d.Id())
174+
if err != nil {
175+
return diag.FromErr(err)
176+
}
177+
178+
_, err = waitCluster(ctx, api, region, clusterID, d.Timeout(schema.TimeoutDelete))
179+
if err != nil && !httperrors.Is404(err) {
180+
return diag.FromErr(err)
181+
}
182+
183+
req := &k8s.SetClusterACLRulesRequest{
184+
Region: region,
185+
ClusterID: clusterID,
186+
ACLs: nil,
187+
}
188+
_, err = api.SetClusterACLRules(req, scw.WithContext(ctx))
189+
if err != nil {
190+
return diag.FromErr(err)
191+
}
192+
193+
_, err = waitCluster(ctx, api, region, clusterID, d.Timeout(schema.TimeoutDelete))
194+
if err != nil && !httperrors.Is404(err) {
195+
return diag.FromErr(err)
196+
}
197+
198+
return nil
199+
}
200+
201+
func expandACL(data []interface{}) ([]*k8s.ACLRuleRequest, error) {
202+
expandedACLs := []*k8s.ACLRuleRequest(nil)
203+
204+
for _, rule := range data {
205+
r := rule.(map[string]interface{})
206+
expandedRule := &k8s.ACLRuleRequest{}
207+
208+
if ipRaw, ok := r["ip"]; ok {
209+
ip, err := types.ExpandIPNet(ipRaw.(string))
210+
if err != nil {
211+
return nil, err
212+
}
213+
expandedRule.IP = &ip
214+
}
215+
if scwRangesRaw, ok := r["scaleway_ranges"]; ok {
216+
expandedRule.ScalewayRanges = scw.BoolPtr(scwRangesRaw.(bool))
217+
}
218+
if descriptionRaw, ok := r["description"]; ok {
219+
expandedRule.Description = descriptionRaw.(string)
220+
}
221+
222+
expandedACLs = append(expandedACLs, expandedRule)
223+
}
224+
225+
return expandedACLs, nil
226+
}
227+
228+
func flattenACL(rules []*k8s.ACLRule) interface{} {
229+
if rules == nil {
230+
return nil
231+
}
232+
233+
flattenedACLs := []map[string]interface{}(nil)
234+
for _, rule := range rules {
235+
flattenedACLs = append(flattenedACLs, map[string]interface{}{
236+
//"id": rule.ID,
237+
"ip": rule.IP,
238+
"scaleway_ranges": rule.ScalewayRanges,
239+
"description": rule.Description,
240+
})
241+
}
242+
243+
return flattenedACLs
244+
}

0 commit comments

Comments
 (0)