Skip to content

Commit 45cddcd

Browse files
authored
feat(lb): add support for tags in LB IPs (#2564)
* bump sdk go * support tags in lb ips * add doc * update cassettes * decouple test * fix
1 parent ed3c182 commit 45cddcd

11 files changed

+4699
-720
lines changed

docs/data-sources/lb_ip.md

+2
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,6 @@ In addition to all above arguments, the following attributes are exported:
5050

5151
- `lb_id` - The ID of the associated Load Balancer, if any
5252

53+
- `tags` - The tags associated with this IP.
54+
5355
- `organization_id` - (Defaults to [provider](../index.md#organization_id) `organization_id`) The ID of the Organization the Load Balancer IP is associated with.

docs/data-sources/lb_ips.md

+10
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,22 @@ data "scaleway_lb_ips" "my_key" {
2121
ip_cidr_range = "0.0.0.0/0"
2222
zone = "fr-par-2"
2323
}
24+
25+
# Find IPs that share the same tags and type
26+
data "scaleway_lb_ips" "ips_by_tags_and_type" {
27+
tags = [ "a tag" ]
28+
ip_type = "ipv4"
29+
}
2430
```
2531

2632
## Argument Reference
2733

2834
- `ip_cidr_range` - (Optional) The IP CIDR range to filter for. IPs within a matching CIDR block are listed.
2935

36+
- `tags` - (Optional) List of tags used as filter. IPs with these exact tags are listed.
37+
38+
- `ip_type` - (Optional) The IP type used as a filter.
39+
3040
- `zone` - (Defaults to [provider](../index.md#zone) `zone`) The [zone](../guides/regions_and_zones.md#zones) in which the IPs exist.
3141

3242
## Attributes Reference

docs/resources/lb_ip.md

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ The following arguments are supported:
3434
- `zone` - (Defaults to [provider](../index.md#zone) `zone`) The [zone](../guides/regions_and_zones.md#zones) in which the IP should be reserved.
3535
- `project_id` - (Defaults to [provider](../index.md#project_id) `project_id`) The ID of the Project the IP is associated with.
3636
- `reverse` - (Optional) The reverse domain associated with this IP.
37+
- `tags` - (Optional) The tags associated with this IP.
3738
- `is_ipv6` - (Optional) If true, creates a flexible IP with an IPv6 address.
3839

3940
## Attributes Reference

internal/services/lb/ip.go

+27-6
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ func ResourceIP() *schema.Resource {
6363
Default: false,
6464
Description: "If true, creates a Flexible IP with an IPv6 address",
6565
},
66+
"tags": {
67+
Type: schema.TypeList,
68+
Elem: &schema.Schema{
69+
Type: schema.TypeString,
70+
},
71+
Optional: true,
72+
Description: "The tags associated with the flexible IP",
73+
},
6674
"region": regional.ComputedSchema(),
6775
},
6876
}
@@ -84,6 +92,7 @@ func resourceLbIPCreate(ctx context.Context, d *schema.ResourceData, m interface
8492
ProjectID: types.ExpandStringPtr(d.Get("project_id")),
8593
Reverse: types.ExpandStringPtr(d.Get("reverse")),
8694
IsIPv6: d.Get("is_ipv6").(bool),
95+
Tags: types.ExpandStrings(d.Get("tags")),
8796
}
8897

8998
res, err := lbAPI.CreateIP(createReq, scw.WithContext(ctx))
@@ -139,6 +148,7 @@ func resourceLbIPRead(ctx context.Context, d *schema.ResourceData, m interface{}
139148
_ = d.Set("ip_address", ip.IPAddress)
140149
_ = d.Set("reverse", ip.Reverse)
141150
_ = d.Set("lb_id", types.FlattenStringPtr(ip.LBID))
151+
_ = d.Set("tags", ip.Tags)
142152

143153
isIPv6 := false
144154
if ip.IPAddress != "" {
@@ -193,14 +203,25 @@ func resourceLbIPUpdate(ctx context.Context, d *schema.ResourceData, m interface
193203
}
194204
}
195205

206+
updateRequest := &lbSDK.ZonedAPIUpdateIPRequest{
207+
Zone: zone,
208+
IPID: ID,
209+
}
210+
211+
hasChanged := false
212+
196213
if d.HasChange("reverse") {
197-
req := &lbSDK.ZonedAPIUpdateIPRequest{
198-
Zone: zone,
199-
IPID: ID,
200-
Reverse: types.ExpandStringPtr(d.Get("reverse")),
201-
}
214+
updateRequest.Reverse = types.ExpandStringPtr(d.Get("reverse"))
215+
hasChanged = true
216+
}
217+
218+
if d.HasChange("tags") {
219+
updateRequest.Tags = types.ExpandUpdatedStringsPtr(d.Get("tags"))
220+
hasChanged = true
221+
}
202222

203-
_, err = lbAPI.UpdateIP(req, scw.WithContext(ctx))
223+
if hasChanged {
224+
_, err = lbAPI.UpdateIP(updateRequest, scw.WithContext(ctx))
204225
if err != nil {
205226
return diag.FromErr(err)
206227
}

internal/services/lb/ip_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,46 @@ func TestAccIP_IPv6(t *testing.T) {
103103
})
104104
}
105105

106+
func TestAccIP_WithTags(t *testing.T) {
107+
tt := acctest.NewTestTools(t)
108+
defer tt.Cleanup()
109+
resource.ParallelTest(t, resource.TestCase{
110+
PreCheck: func() { acctest.PreCheck(t) },
111+
ProviderFactories: tt.ProviderFactories,
112+
CheckDestroy: lbchecks.IsIPDestroyed(tt),
113+
Steps: []resource.TestStep{
114+
{
115+
Config: `
116+
resource scaleway_lb_ip tags {
117+
tags = [ "terraform-test", "lb", "ip" ]
118+
}
119+
`,
120+
Check: resource.ComposeTestCheckFunc(
121+
isIPPresent(tt, "scaleway_lb_ip.tags"),
122+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.#", "3"),
123+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.0", "terraform-test"),
124+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.1", "lb"),
125+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.2", "ip")),
126+
},
127+
{
128+
Config: `
129+
resource scaleway_lb_ip tags {
130+
tags = [ "terraform-test", "lb", "ip", "updated" ]
131+
}
132+
`,
133+
Check: resource.ComposeTestCheckFunc(
134+
isIPPresent(tt, "scaleway_lb_ip.tags"),
135+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.#", "4"),
136+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.0", "terraform-test"),
137+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.1", "lb"),
138+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.2", "ip"),
139+
resource.TestCheckResourceAttr("scaleway_lb_ip.tags", "tags.3", "updated"),
140+
),
141+
},
142+
},
143+
})
144+
}
145+
106146
func isIPPresent(tt *acctest.TestTools, n string) resource.TestCheckFunc {
107147
return func(state *terraform.State) error {
108148
rs, ok := state.RootModule().Resources[n]

internal/services/lb/ips_data_source.go

+38-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,25 @@ func DataSourceIPs() *schema.Resource {
2323
ValidateFunc: validation.IsCIDR,
2424
Description: "IPs within a CIDR block like it are listed.",
2525
},
26+
"ip_type": {
27+
Type: schema.TypeString,
28+
Optional: true,
29+
Default: lb.ListIPsRequestIPTypeAll.String(),
30+
ValidateFunc: validation.StringInSlice([]string{
31+
lb.ListIPsRequestIPTypeIPv4.String(),
32+
lb.ListIPsRequestIPTypeIPv6.String(),
33+
lb.ListIPsRequestIPTypeAll.String(),
34+
}, false),
35+
Description: "IP type to filter for",
36+
},
37+
"tags": {
38+
Type: schema.TypeList,
39+
Elem: &schema.Schema{
40+
Type: schema.TypeString,
41+
},
42+
Optional: true,
43+
Description: "IPs with these exact tags are listed",
44+
},
2645
"ips": {
2746
Type: schema.TypeList,
2847
Computed: true,
@@ -44,6 +63,13 @@ func DataSourceIPs() *schema.Resource {
4463
Computed: true,
4564
Type: schema.TypeString,
4665
},
66+
"tags": {
67+
Computed: true,
68+
Type: schema.TypeList,
69+
Elem: &schema.Schema{
70+
Type: schema.TypeString,
71+
},
72+
},
4773
"zone": zonal.Schema(),
4874
"organization_id": account.OrganizationIDSchema(),
4975
"project_id": account.ProjectIDSchema(),
@@ -65,16 +91,22 @@ func DataSourceLbIPsRead(ctx context.Context, d *schema.ResourceData, m interfac
6591
res, err := lbAPI.ListIPs(&lb.ZonedAPIListIPsRequest{
6692
Zone: zone,
6793
ProjectID: types.ExpandStringPtr(d.Get("project_id")),
94+
Tags: types.ExpandStrings(d.Get("tags")),
95+
IPType: lb.ListIPsRequestIPType(d.Get("ip_type").(string)),
6896
}, scw.WithContext(ctx))
6997
if err != nil {
7098
return diag.FromErr(err)
7199
}
72100

73101
var filteredList []*lb.IP
74-
for i := range res.IPs {
75-
if ipv4Match(d.Get("ip_cidr_range").(string), res.IPs[i].IPAddress) {
76-
filteredList = append(filteredList, res.IPs[i])
102+
if cidrRange, ok := d.GetOk("ip_cidr_range"); ok {
103+
for i := range res.IPs {
104+
if ipv4Match(cidrRange.(string), res.IPs[i].IPAddress) {
105+
filteredList = append(filteredList, res.IPs[i])
106+
}
77107
}
108+
} else {
109+
filteredList = res.IPs
78110
}
79111

80112
ips := []interface{}(nil)
@@ -87,6 +119,9 @@ func DataSourceLbIPsRead(ctx context.Context, d *schema.ResourceData, m interfac
87119
rawIP["zone"] = string(zone)
88120
rawIP["organization_id"] = ip.OrganizationID
89121
rawIP["project_id"] = ip.ProjectID
122+
if len(ip.Tags) > 0 {
123+
rawIP["tags"] = ip.Tags
124+
}
90125

91126
ips = append(ips, rawIP)
92127
}

internal/services/lb/ips_data_source_test.go

+111-7
Original file line numberDiff line numberDiff line change
@@ -29,23 +29,127 @@ func TestAccDataSourceIPs_Basic(t *testing.T) {
2929
resource scaleway_lb_ip ip2 {
3030
}
3131
32-
data "scaleway_lb_ips" "lbs_by_cidr_range" {
32+
data "scaleway_lb_ips" "ips_by_cidr_range" {
3333
ip_cidr_range = "0.0.0.0/0"
3434
depends_on = [scaleway_lb_ip.ip1, scaleway_lb_ip.ip2]
3535
}
36-
data "scaleway_lb_ips" "lbs_by_cidr_range_other_zone" {
36+
data "scaleway_lb_ips" "ips_by_cidr_range_other_zone" {
3737
ip_cidr_range = "0.0.0.0/0"
3838
zone = "fr-par-2"
3939
depends_on = [scaleway_lb_ip.ip1, scaleway_lb_ip.ip2]
4040
}
4141
`,
4242
Check: resource.ComposeTestCheckFunc(
43-
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.lbs_by_cidr_range", "ips.0.id"),
44-
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.lbs_by_cidr_range", "ips.0.ip_address"),
45-
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.lbs_by_cidr_range", "ips.1.id"),
46-
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.lbs_by_cidr_range", "ips.1.ip_address"),
43+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_cidr_range", "ips.0.id"),
44+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_cidr_range", "ips.0.ip_address"),
45+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_cidr_range", "ips.1.id"),
46+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_cidr_range", "ips.1.ip_address"),
4747

48-
resource.TestCheckNoResourceAttr("data.scaleway_lb_ips.lbs_by_cidr_range_other_zone", "ips.0.id"),
48+
resource.TestCheckNoResourceAttr("data.scaleway_lb_ips.ips_by_cidr_range_other_zone", "ips.0.id"),
49+
),
50+
},
51+
},
52+
})
53+
}
54+
55+
func TestAccDataSourceIPs_WithType(t *testing.T) {
56+
tt := acctest.NewTestTools(t)
57+
defer tt.Cleanup()
58+
resource.ParallelTest(t, resource.TestCase{
59+
PreCheck: func() { acctest.PreCheck(t) },
60+
ProviderFactories: tt.ProviderFactories,
61+
CheckDestroy: lbchecks.IsIPDestroyed(tt),
62+
Steps: []resource.TestStep{
63+
{
64+
Config: `
65+
resource scaleway_lb_ip ip1 {
66+
}
67+
`,
68+
},
69+
{
70+
Config: `
71+
resource scaleway_lb_ip ip1 {
72+
}
73+
resource scaleway_lb_ip ip2 {
74+
is_ipv6 = true
75+
}
76+
`,
77+
},
78+
{
79+
Config: `
80+
resource scaleway_lb_ip ip1 {
81+
}
82+
resource scaleway_lb_ip ip2 {
83+
is_ipv6 = true
84+
}
85+
resource scaleway_lb_ip ip3 {
86+
}
87+
88+
data "scaleway_lb_ips" "ips_by_type" {
89+
ip_type = "ipv4"
90+
depends_on = [scaleway_lb_ip.ip1, scaleway_lb_ip.ip2, scaleway_lb_ip.ip3]
91+
}
92+
`,
93+
Check: resource.ComposeTestCheckFunc(
94+
resource.TestCheckResourceAttr("data.scaleway_lb_ips.ips_by_type", "ips.#", "2"),
95+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_type", "ips.0.id"),
96+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_type", "ips.0.ip_address"),
97+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_type", "ips.1.id"),
98+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_type", "ips.1.ip_address"),
99+
),
100+
},
101+
},
102+
})
103+
}
104+
105+
func TestAccDataSourceIPs_WithTags(t *testing.T) {
106+
tt := acctest.NewTestTools(t)
107+
defer tt.Cleanup()
108+
resource.ParallelTest(t, resource.TestCase{
109+
PreCheck: func() { acctest.PreCheck(t) },
110+
ProviderFactories: tt.ProviderFactories,
111+
CheckDestroy: lbchecks.IsIPDestroyed(tt),
112+
Steps: []resource.TestStep{
113+
{
114+
Config: `
115+
resource scaleway_lb_ip ip1 {
116+
tags = [ "ipv4", "ip" ]
117+
}
118+
`,
119+
},
120+
{
121+
Config: `
122+
resource scaleway_lb_ip ip1 {
123+
tags = [ "ipv4", "ip" ]
124+
}
125+
resource scaleway_lb_ip ip2 {
126+
tags = [ "ipv4", "ip" ]
127+
}
128+
`,
129+
},
130+
{
131+
Config: `
132+
resource scaleway_lb_ip ip1 {
133+
tags = [ "ipv4", "ip" ]
134+
}
135+
resource scaleway_lb_ip ip2 {
136+
tags = [ "ipv4", "ip" ]
137+
}
138+
resource scaleway_lb_ip ip3 {
139+
tags = [ "other", "tags" ]
140+
}
141+
142+
data "scaleway_lb_ips" "ips_by_tags" {
143+
tags = [ "ipv4", "ip" ]
144+
depends_on = [scaleway_lb_ip.ip1, scaleway_lb_ip.ip2, scaleway_lb_ip.ip3]
145+
}
146+
`,
147+
Check: resource.ComposeTestCheckFunc(
148+
resource.TestCheckResourceAttr("data.scaleway_lb_ips.ips_by_tags", "ips.#", "2"),
149+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_tags", "ips.0.id"),
150+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_tags", "ips.0.ip_address"),
151+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_tags", "ips.1.id"),
152+
resource.TestCheckResourceAttrSet("data.scaleway_lb_ips.ips_by_tags", "ips.1.ip_address"),
49153
),
50154
},
51155
},

0 commit comments

Comments
 (0)