Skip to content

Commit e9459e9

Browse files
committed
ok with no_ip_allowed_on_delete
1 parent 41ef848 commit e9459e9

File tree

6 files changed

+6730
-681
lines changed

6 files changed

+6730
-681
lines changed

docs/resources/k8s_acl.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
subcategory: "Kubernetes"
3+
page_title: "Scaleway: scaleway_k8s_acl"
4+
---
5+
6+
# Resource: scaleway_k8s_acl
7+
8+
Creates and manages Scaleway Kubernetes cluster authorized IPs.
9+
For more information, please refer to the [API documentation](https://www.scaleway.com/en/developers/api/kubernetes/#path-access-control-list-add-new-acls)
10+
11+
## Example Usage
12+
13+
### Basic
14+
15+
```terraform
16+
resource "scaleway_vpc_private_network" "acl_basic" {}
17+
18+
resource "scaleway_k8s_cluster" "acl_basic" {
19+
name = "acl-basic"
20+
version = "1.32.2"
21+
cni = "cilium"
22+
delete_additional_resources = true
23+
private_network_id = scaleway_vpc_private_network.acl_basic.id
24+
}
25+
26+
resource "scaleway_k8s_acl" "acl_basic" {
27+
cluster_id = scaleway_k8s_cluster.acl_basic.id
28+
acl_rules {
29+
ip = "1.2.3.4/32"
30+
description = "Allow 1.2.3.4"
31+
}
32+
acl_rules {
33+
scaleway_ranges = true
34+
description = "Allow all Scaleway ranges"
35+
}
36+
}
37+
```
38+
39+
## Argument Reference
40+
41+
The following arguments are supported:
42+
43+
- `cluster_id` - (Required) UUID of the Cluster.
44+
45+
~> **Important:** Updates to `cluster_id` will recreate the ACL.
46+
47+
- `acl_rules` - A list of ACLs (structure is described below)
48+
49+
- `region` - (Defaults to [provider](../index.md#region) `region`) The [region](../guides/regions_and_zones.md#regions) in which the ACL rule should be created.
50+
51+
The `acl_rules` block supports:
52+
53+
- `ip` - (Optional) The IP range to whitelist in [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation)
54+
55+
~> **Important:** If the `ip` field is set, `scaleway_ranges` cannot be set to true in the same rule.
56+
57+
- `scaleway_ranges` - (Optional) 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.
58+
Only one rule with this field set to true can be added.
59+
60+
~> **Important:** If the `scaleway_ranges` field is set to true, the `ip` field cannot be set on the same rule.
61+
62+
- `description` - (Optional) A text describing this rule.
63+
64+
## Attributes Reference
65+
66+
In addition to all arguments above, the following attributes are exported:
67+
68+
- `acl_rules.0.id` - The ID of each ACL rule.
69+
70+
~> **Important:** Kubernetes ACL rules' IDs are [regional](../guides/regions_and_zones.md#resource-ids), which means they are of the form `{region}/{id}`, e.g. `fr-par/11111111-1111-1111-1111-111111111111`
71+
72+
## Import
73+
74+
Kubernetes ACLs can be imported using the `{region}/{cluster-id}`, e.g.
75+
76+
```bash
77+
terraform import scaleway_k8s_acl.acl01 fr-par/11111111-1111-1111-1111-111111111111
78+
```

internal/services/k8s/acl.go

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ func ResourceACL() *schema.Resource {
4141
ForceNew: true,
4242
ValidateDiagFunc: verify.IsUUIDorUUIDWithLocality(),
4343
DiffSuppressFunc: dsf.Locality,
44-
Description: "Cluster on which the ACL is applied",
44+
Description: "Cluster on which the ACL should be applied",
45+
},
46+
"no_ip_allowed_on_delete": {
47+
Type: schema.TypeBool,
48+
Optional: true,
49+
Default: false,
50+
Description: "Determines whether deleting the resource should allow all IPs again or no IP at all",
4551
},
4652
"acl_rules": {
4753
Type: schema.TypeList,
@@ -58,7 +64,7 @@ func ResourceACL() *schema.Resource {
5864
"scaleway_ranges": {
5965
Type: schema.TypeBool,
6066
Optional: true,
61-
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",
67+
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.",
6268
},
6369
"description": {
6470
Type: schema.TypeString,
@@ -143,7 +149,8 @@ func ResourceACLRead(ctx context.Context, d *schema.ResourceData, m interface{})
143149
return diag.FromErr(err)
144150
}
145151

146-
_ = d.Set("cluster_id", clusterID)
152+
_ = d.Set("cluster_id", regional.NewIDString(region, clusterID))
153+
_ = d.Set("region", region)
147154
_ = d.Set("acl_rules", flattenACL(acls.Rules))
148155

149156
return nil
@@ -192,19 +199,23 @@ func ResourceACLDelete(ctx context.Context, d *schema.ResourceData, m interface{
192199
return diag.FromErr(err)
193200
}
194201

195-
allIPRange, err := types.ExpandIPNet("0.0.0.0/0")
196-
if err != nil {
197-
return diag.FromErr(err)
202+
rulesToSet := []*k8s.ACLRuleRequest(nil)
203+
204+
if d.Get("no_ip_allowed_on_delete").(bool) == false {
205+
allowedIPs, err := types.ExpandIPNet("0.0.0.0/0")
206+
if err != nil {
207+
return diag.FromErr(err)
208+
}
209+
rulesToSet = append(rulesToSet, &k8s.ACLRuleRequest{
210+
IP: &allowedIPs,
211+
Description: "Automatically generated after scaleway_k8s_acl resource deletion",
212+
})
198213
}
199214

200215
req := &k8s.SetClusterACLRulesRequest{
201216
Region: region,
202217
ClusterID: clusterID,
203-
ACLs: []*k8s.ACLRuleRequest{
204-
{
205-
IP: &allIPRange,
206-
},
207-
},
218+
ACLs: rulesToSet,
208219
}
209220

210221
_, err = api.SetClusterACLRules(req, scw.WithContext(ctx))

internal/services/k8s/acl_test.go

Lines changed: 109 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ func TestAccACL_Basic(t *testing.T) {
4343
}
4444
}`, clusterName, latestK8sVersion),
4545
Check: resource.ComposeTestCheckFunc(
46+
resource.TestCheckResourceAttrPair("scaleway_k8s_acl.acl_basic", "cluster_id", "scaleway_k8s_cluster.acl_basic", "id"),
47+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "no_ip_allowed_on_delete", "false"),
4648
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.#", "1"),
4749
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.ip", "1.2.3.4/32"),
4850
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.scaleway_ranges", "false"),
@@ -64,6 +66,7 @@ func TestAccACL_Basic(t *testing.T) {
6466
6567
resource "scaleway_k8s_acl" "acl_basic" {
6668
cluster_id = scaleway_k8s_cluster.acl_basic.id
69+
no_ip_allowed_on_delete = true
6770
acl_rules {
6871
ip = "1.2.3.4/32"
6972
}
@@ -73,6 +76,8 @@ func TestAccACL_Basic(t *testing.T) {
7376
}
7477
}`, clusterName, latestK8sVersion),
7578
Check: resource.ComposeTestCheckFunc(
79+
resource.TestCheckResourceAttrPair("scaleway_k8s_acl.acl_basic", "cluster_id", "scaleway_k8s_cluster.acl_basic", "id"),
80+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "no_ip_allowed_on_delete", "true"),
7681
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.#", "2"),
7782
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.ip", "1.2.3.4/32"),
7883
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.scaleway_ranges", "false"),
@@ -108,6 +113,8 @@ func TestAccACL_Basic(t *testing.T) {
108113
}
109114
}`, clusterName, latestK8sVersion),
110115
Check: resource.ComposeTestCheckFunc(
116+
resource.TestCheckResourceAttrPair("scaleway_k8s_acl.acl_basic", "cluster_id", "scaleway_k8s_cluster.acl_basic", "id"),
117+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "no_ip_allowed_on_delete", "false"),
111118
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.#", "2"),
112119
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.ip", "1.2.3.4/32"),
113120
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.scaleway_ranges", "false"),
@@ -131,14 +138,108 @@ func TestAccACL_Basic(t *testing.T) {
131138
private_network_id = scaleway_vpc_private_network.acl_basic.id
132139
}`, clusterName, latestK8sVersion),
133140
Check: resource.ComposeTestCheckFunc(
134-
testAccCheckK8SClusterAllIPsAllowed(tt, "scaleway_k8s_cluster.acl_basic"),
141+
testAccCheckK8SClusterAllowedIPs(tt, "scaleway_k8s_cluster.acl_basic", "0.0.0.0/0"),
135142
),
136143
},
137144
},
138145
})
139146
}
140147

141-
func testAccCheckK8SClusterAllIPsAllowed(tt *acctest.TestTools, n string) resource.TestCheckFunc {
148+
func TestAccACL_AllowedIPsOnDelete(t *testing.T) {
149+
tt := acctest.NewTestTools(t)
150+
defer tt.Cleanup()
151+
152+
clusterName := "k8s-acl-allowed-ips-on-delete"
153+
latestK8sVersion := testAccK8SClusterGetLatestK8SVersion(tt)
154+
155+
resource.ParallelTest(t, resource.TestCase{
156+
PreCheck: func() { acctest.PreCheck(t) },
157+
ProviderFactories: tt.ProviderFactories,
158+
CheckDestroy: testAccCheckK8SClusterDestroy(tt),
159+
Steps: []resource.TestStep{
160+
{
161+
Config: fmt.Sprintf(`
162+
resource "scaleway_vpc_private_network" "acl_basic" {}
163+
164+
resource "scaleway_k8s_cluster" "acl_basic" {
165+
name = "%s"
166+
version = "%s"
167+
cni = "cilium"
168+
delete_additional_resources = true
169+
private_network_id = scaleway_vpc_private_network.acl_basic.id
170+
}
171+
172+
resource "scaleway_k8s_acl" "acl_basic" {
173+
cluster_id = scaleway_k8s_cluster.acl_basic.id
174+
no_ip_allowed_on_delete = true
175+
acl_rules {
176+
ip = "1.2.3.4/32"
177+
}
178+
}`, clusterName, latestK8sVersion),
179+
Check: resource.ComposeTestCheckFunc(
180+
resource.TestCheckResourceAttrPair("scaleway_k8s_acl.acl_basic", "cluster_id", "scaleway_k8s_cluster.acl_basic", "id"),
181+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "no_ip_allowed_on_delete", "true"),
182+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.#", "1"),
183+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.ip", "1.2.3.4/32"),
184+
),
185+
},
186+
{
187+
Config: fmt.Sprintf(`
188+
resource "scaleway_vpc_private_network" "acl_basic" {}
189+
190+
resource "scaleway_k8s_cluster" "acl_basic" {
191+
name = "%s"
192+
version = "%s"
193+
cni = "cilium"
194+
delete_additional_resources = true
195+
private_network_id = scaleway_vpc_private_network.acl_basic.id
196+
}`, clusterName, latestK8sVersion),
197+
Check: testAccCheckK8SClusterAllowedIPs(tt, "scaleway_k8s_cluster.acl_basic", ""),
198+
},
199+
{
200+
Config: fmt.Sprintf(`
201+
resource "scaleway_vpc_private_network" "acl_basic" {}
202+
203+
resource "scaleway_k8s_cluster" "acl_basic" {
204+
name = "%s"
205+
version = "%s"
206+
cni = "cilium"
207+
delete_additional_resources = true
208+
private_network_id = scaleway_vpc_private_network.acl_basic.id
209+
}
210+
211+
resource "scaleway_k8s_acl" "acl_basic" {
212+
cluster_id = scaleway_k8s_cluster.acl_basic.id
213+
no_ip_allowed_on_delete = false
214+
acl_rules {
215+
ip = "1.2.3.4/32"
216+
}
217+
}`, clusterName, latestK8sVersion),
218+
Check: resource.ComposeTestCheckFunc(
219+
resource.TestCheckResourceAttrPair("scaleway_k8s_acl.acl_basic", "cluster_id", "scaleway_k8s_cluster.acl_basic", "id"),
220+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "no_ip_allowed_on_delete", "false"),
221+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.#", "1"),
222+
resource.TestCheckResourceAttr("scaleway_k8s_acl.acl_basic", "acl_rules.0.ip", "1.2.3.4/32"),
223+
),
224+
},
225+
{
226+
Config: fmt.Sprintf(`
227+
resource "scaleway_vpc_private_network" "acl_basic" {}
228+
229+
resource "scaleway_k8s_cluster" "acl_basic" {
230+
name = "%s"
231+
version = "%s"
232+
cni = "cilium"
233+
delete_additional_resources = true
234+
private_network_id = scaleway_vpc_private_network.acl_basic.id
235+
}`, clusterName, latestK8sVersion),
236+
Check: testAccCheckK8SClusterAllowedIPs(tt, "scaleway_k8s_cluster.acl_basic", "0.0.0.0/0"),
237+
},
238+
},
239+
})
240+
}
241+
242+
func testAccCheckK8SClusterAllowedIPs(tt *acctest.TestTools, n string, expected string) resource.TestCheckFunc {
142243
return func(s *terraform.State) error {
143244
rs, ok := s.RootModule().Resources[n]
144245
if !ok {
@@ -167,14 +268,12 @@ func testAccCheckK8SClusterAllIPsAllowed(tt *acctest.TestTools, n string) resour
167268
}
168269

169270
switch {
170-
case acls.TotalCount > 1:
171-
return fmt.Errorf("unexpected number of ACL rules: %d (expected: 1)", acls.TotalCount)
172-
case acls.Rules[0].IP == nil:
173-
return fmt.Errorf("unexpected ACL rule: %+v", acls.Rules[0])
174-
case acls.Rules[0].IP.String() != "0.0.0.0/0":
175-
return fmt.Errorf("unexpected IP in ACL rule: %q (expected \"0.0.0.0/0\")", acls.Rules[0].IP.String())
271+
case expected == "" && acls.TotalCount == 0:
272+
return nil
273+
case expected != "" && acls.TotalCount == 1 && acls.Rules[0].IP != nil && acls.Rules[0].IP.String() == expected:
274+
return nil
275+
default:
276+
return fmt.Errorf("expected 1 ACL rule for subnet %q, got: %+v", expected, acls.Rules)
176277
}
177-
178-
return nil
179278
}
180279
}

0 commit comments

Comments
 (0)