Skip to content

Commit 45843b9

Browse files
authored
Add list data source for floating ips (#448)
1 parent 6eaecaf commit 45843b9

File tree

9 files changed

+245
-60
lines changed

9 files changed

+245
-60
lines changed

hcloud/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ func Provider() *schema.Provider {
9696
firewall.DataSourceType: firewall.DataSource(),
9797
firewall.DataSourceListType: firewall.DataSourceList(),
9898
floatingip.DataSourceType: floatingip.DataSource(),
99+
floatingip.DataSourceListType: floatingip.DataSourceList(),
99100
image.DataSourceType: image.DataSource(),
100101
loadbalancer.DataSourceType: loadbalancer.DataSource(),
101102
location.DataSourceType: location.DataSource(),

hcloud/provider_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ func TestProvider_DataSources(t *testing.T) {
7171
firewall.DataSourceType,
7272
firewall.DataSourceListType,
7373
floatingip.DataSourceType,
74+
floatingip.DataSourceListType,
7475
image.DataSourceType,
7576
loadbalancer.DataSourceType,
7677
location.DataSourceType,

internal/e2etests/floatingip/data_source_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,60 @@ func TestAccHcloudDataSourceFloatingIPTest(t *testing.T) {
7474
},
7575
})
7676
}
77+
78+
func TestAccHcloudDataSourceFloatingIPListTest(t *testing.T) {
79+
res := &floatingip.RData{
80+
Name: "floatingip-ds-test",
81+
Type: "ipv4",
82+
Labels: map[string]string{
83+
"key": strconv.Itoa(acctest.RandInt()),
84+
},
85+
HomeLocationName: e2etests.TestLocationName,
86+
}
87+
res.SetRName("floatingip-ds-test")
88+
89+
floatingipBySel := &floatingip.DDataList{
90+
LabelSelector: fmt.Sprintf("key=${%s.labels[\"key\"]}", res.TFID()),
91+
}
92+
floatingipBySel.SetRName("floatingips_by_sel")
93+
94+
allFloatingIPsSel := &floatingip.DDataList{}
95+
allFloatingIPsSel.SetRName("all_floatingips_sel")
96+
97+
tmplMan := testtemplate.Manager{}
98+
resource.Test(t, resource.TestCase{
99+
PreCheck: e2etests.PreCheck(t),
100+
Providers: e2etests.Providers(),
101+
CheckDestroy: testsupport.CheckResourcesDestroyed(floatingip.ResourceType, floatingip.ByID(t, nil)),
102+
Steps: []resource.TestStep{
103+
{
104+
Config: tmplMan.Render(t,
105+
"testdata/r/hcloud_floating_ip", res,
106+
),
107+
},
108+
{
109+
Config: tmplMan.Render(t,
110+
"testdata/r/hcloud_floating_ip", res,
111+
"testdata/d/hcloud_floating_ips", floatingipBySel,
112+
"testdata/d/hcloud_floating_ips", allFloatingIPsSel,
113+
),
114+
115+
Check: resource.ComposeTestCheckFunc(
116+
resource.TestCheckTypeSetElemNestedAttrs(floatingipBySel.TFID(), "floating_ips.*",
117+
map[string]string{
118+
"name": fmt.Sprintf("%s--%d", res.Name, tmplMan.RandInt),
119+
"home_location": res.HomeLocationName,
120+
},
121+
),
122+
123+
resource.TestCheckTypeSetElemNestedAttrs(allFloatingIPsSel.TFID(), "floating_ips.*",
124+
map[string]string{
125+
"name": fmt.Sprintf("%s--%d", res.Name, tmplMan.RandInt),
126+
"home_location": res.HomeLocationName,
127+
},
128+
),
129+
),
130+
},
131+
},
132+
})
133+
}

internal/floatingip/data_source.go

Lines changed: 116 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,76 +2,114 @@ package floatingip
22

33
import (
44
"context"
5+
"crypto/sha1"
6+
"fmt"
7+
"strconv"
8+
"strings"
59

610
"github.com/hetznercloud/terraform-provider-hcloud/internal/hcclient"
11+
"github.com/hetznercloud/terraform-provider-hcloud/internal/util/datasourceutil"
712

813
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
914

1015
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1116
"github.com/hetznercloud/hcloud-go/hcloud"
1217
)
1318

14-
// DataSourceType is the type name of the Hetzner Cloud Floating IP resource.
15-
const DataSourceType = "hcloud_floating_ip"
19+
const (
20+
// DataSourceType is the type name of the Hetzner Cloud Floating IP resource.
21+
DataSourceType = "hcloud_floating_ip"
22+
23+
// DataSourceListType is the type name to receive a list of Hetzner Cloud Floating IPs resources.
24+
DataSourceListType = "hcloud_floating_ips"
25+
)
26+
27+
// getCommonDataSchema returns a new common schema used by all floating ip data sources.
28+
func getCommonDataSchema() map[string]*schema.Schema {
29+
return map[string]*schema.Schema{
30+
"id": {
31+
Type: schema.TypeInt,
32+
Optional: true,
33+
Computed: true,
34+
},
35+
"name": {
36+
Type: schema.TypeString,
37+
Optional: true,
38+
},
39+
"type": {
40+
Type: schema.TypeString,
41+
Computed: true,
42+
},
43+
"description": {
44+
Type: schema.TypeString,
45+
Computed: true,
46+
},
47+
"home_location": {
48+
Type: schema.TypeString,
49+
Computed: true,
50+
},
51+
"server_id": {
52+
Type: schema.TypeInt,
53+
Computed: true,
54+
},
55+
"ip_address": {
56+
Type: schema.TypeString,
57+
Optional: true,
58+
Computed: true,
59+
},
60+
"ip_network": {
61+
Type: schema.TypeString,
62+
Computed: true,
63+
},
64+
"labels": {
65+
Type: schema.TypeMap,
66+
Computed: true,
67+
},
68+
"delete_protection": {
69+
Type: schema.TypeBool,
70+
Computed: true,
71+
},
72+
}
73+
}
1674

1775
// DataSource creates a new Terraform schema for the hcloud_floating_ip data
1876
// source.
1977
func DataSource() *schema.Resource {
2078
return &schema.Resource{
2179
ReadContext: dataSourceHcloudFloatingIPRead,
22-
Schema: map[string]*schema.Schema{
23-
"id": {
24-
Type: schema.TypeInt,
25-
Optional: true,
26-
Computed: true,
27-
},
28-
"name": {
29-
Type: schema.TypeString,
30-
Optional: true,
31-
},
32-
"type": {
33-
Type: schema.TypeString,
34-
Computed: true,
35-
},
36-
"description": {
37-
Type: schema.TypeString,
38-
Computed: true,
39-
},
40-
"home_location": {
41-
Type: schema.TypeString,
42-
Computed: true,
80+
Schema: datasourceutil.MergeSchema(
81+
getCommonDataSchema(),
82+
map[string]*schema.Schema{
83+
"selector": {
84+
Type: schema.TypeString,
85+
Optional: true,
86+
Deprecated: "Please use the with_selector property instead.",
87+
ConflictsWith: []string{"with_selector"},
88+
},
89+
"with_selector": {
90+
Type: schema.TypeString,
91+
Optional: true,
92+
ConflictsWith: []string{"selector"},
93+
},
4394
},
44-
"server_id": {
45-
Type: schema.TypeInt,
95+
),
96+
}
97+
}
98+
99+
func DataSourceList() *schema.Resource {
100+
return &schema.Resource{
101+
ReadContext: dataSourceHcloudFloatingIPListRead,
102+
Schema: map[string]*schema.Schema{
103+
"floating_ips": {
104+
Type: schema.TypeList,
46105
Computed: true,
106+
Elem: &schema.Resource{
107+
Schema: getCommonDataSchema(),
108+
},
47109
},
48-
"ip_address": {
110+
"with_selector": {
49111
Type: schema.TypeString,
50112
Optional: true,
51-
Computed: true,
52-
},
53-
"ip_network": {
54-
Type: schema.TypeString,
55-
Computed: true,
56-
},
57-
"labels": {
58-
Type: schema.TypeMap,
59-
Computed: true,
60-
},
61-
"selector": {
62-
Type: schema.TypeString,
63-
Optional: true,
64-
Deprecated: "Please use the with_selector property instead.",
65-
ConflictsWith: []string{"with_selector"},
66-
},
67-
"with_selector": {
68-
Type: schema.TypeString,
69-
Optional: true,
70-
ConflictsWith: []string{"selector"},
71-
},
72-
"delete_protection": {
73-
Type: schema.TypeBool,
74-
Computed: true,
75113
},
76114
},
77115
}
@@ -148,3 +186,31 @@ func dataSourceHcloudFloatingIPRead(ctx context.Context, d *schema.ResourceData,
148186

149187
return diag.Errorf("please specify a id, ip_address or a selector to lookup the FloatingIP")
150188
}
189+
190+
func dataSourceHcloudFloatingIPListRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
191+
client := m.(*hcloud.Client)
192+
193+
selector := d.Get("with_selector").(string)
194+
195+
var allIPs []*hcloud.FloatingIP
196+
opts := hcloud.FloatingIPListOpts{
197+
ListOpts: hcloud.ListOpts{
198+
LabelSelector: selector,
199+
},
200+
}
201+
allIPs, err := client.FloatingIP.AllWithOpts(ctx, opts)
202+
if err != nil {
203+
return hcclient.ErrorToDiag(err)
204+
}
205+
206+
ids := make([]string, len(allIPs))
207+
tfIPs := make([]map[string]interface{}, len(allIPs))
208+
for i, ip := range allIPs {
209+
ids[i] = strconv.Itoa(ip.ID)
210+
tfIPs[i] = getFloatingIPAttributes(ip)
211+
}
212+
d.Set("floating_ips", tfIPs)
213+
d.SetId(fmt.Sprintf("%x", sha1.Sum([]byte(strings.Join(ids, "")))))
214+
215+
return nil
216+
}

internal/floatingip/resource.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -267,20 +267,35 @@ func resourceFloatingIPIsNotFound(err error, d *schema.ResourceData) bool {
267267
}
268268

269269
func setFloatingIPSchema(d *schema.ResourceData, f *hcloud.FloatingIP) {
270-
d.SetId(strconv.Itoa(f.ID))
271-
d.Set("ip_address", f.IP.String())
272-
d.Set("name", f.Name)
270+
for key, val := range getFloatingIPAttributes(f) {
271+
if key == "id" {
272+
d.SetId(strconv.Itoa(val.(int)))
273+
} else {
274+
d.Set(key, val)
275+
}
276+
}
277+
}
278+
279+
func getFloatingIPAttributes(f *hcloud.FloatingIP) map[string]interface{} {
280+
res := map[string]interface{}{
281+
"id": f.ID,
282+
"ip_address": f.IP.String(),
283+
"name": f.Name,
284+
"type": f.Type,
285+
"home_location": f.HomeLocation.Name,
286+
"description": f.Description,
287+
"labels": f.Labels,
288+
"delete_protection": f.Protection.Delete,
289+
}
290+
273291
if f.Type == hcloud.FloatingIPTypeIPv6 {
274-
d.Set("ip_network", f.Network.String())
292+
res["ip_network"] = f.Network.String()
275293
}
276294
if f.Server != nil {
277-
d.Set("server_id", f.Server.ID)
295+
res["server_id"] = f.Server.ID
278296
}
279-
d.Set("type", f.Type)
280-
d.Set("home_location", f.HomeLocation.Name)
281-
d.Set("description", f.Description)
282-
d.Set("labels", f.Labels)
283-
d.Set("delete_protection", f.Protection.Delete)
297+
298+
return res
284299
}
285300

286301
func setProtection(ctx context.Context, c *hcloud.Client, f *hcloud.FloatingIP, delete bool) error {

internal/floatingip/testing.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ func (d *DData) TFID() string {
7373
return fmt.Sprintf("data.%s.%s", DataSourceType, d.RName())
7474
}
7575

76+
// DDataList defines the fields for the "testdata/d/hcloud_floating_ips" template.
77+
type DDataList struct {
78+
testtemplate.DataCommon
79+
80+
LabelSelector string
81+
}
82+
83+
// TFID DDataList the data source identifier.
84+
func (d *DDataList) TFID() string {
85+
return fmt.Sprintf("data.%s.%s", DataSourceListType, d.RName())
86+
}
87+
7688
// RData defines the fields for the "testdata/r/hcloud_floating_ip" template.
7789
type RData struct {
7890
testtemplate.DataCommon
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{{- /* vim: set ft=terraform: */ -}}
2+
3+
data "hcloud_floating_ips" "{{ .RName }}" {
4+
{{ if .LabelSelector -}} with_selector = "{{ .LabelSelector }}"{{ end }}
5+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
layout: "hcloud"
3+
page_title: "Hetzner Cloud: hcloud_floating_ips"
4+
sidebar_current: "docs-hcloud-datasource-floating-ips-x"
5+
description: |-
6+
Provides details about multiple Hetzner Cloud Floating IPs.
7+
---
8+
9+
# Data Source: hcloud_floating_ips
10+
Provides details about multiple Hetzner Cloud Floating IPs.
11+
12+
13+
## Example Usage
14+
```hcl
15+
data "hcloud_floating_ips" "ip_2" {
16+
with_selector = "key=value"
17+
}
18+
```
19+
20+
## Argument Reference
21+
22+
- `with_selector` - (Optional, string) [Label selector](https://docs.hetzner.cloud/#overview-label-selector)
23+
24+
## Attributes Reference
25+
- `floating_ips` - (list) List of all matching floating ips. See `data.hcloud_floating_ip` for schema.

website/hcloud.erb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
<li<%= sidebar_current("docs-hcloud-datasource-floating-ip") %>>
3434
<a href="/docs/providers/hcloud/d/floating_ip.html">hcloud_floating_ip</a>
3535
</li>
36+
<li<%= sidebar_current("docs-hcloud-datasource-floating-ips-x") %>>
37+
<a href="/docs/providers/hcloud/d/floating_ips.html">hcloud_floating_ips</a>
38+
</li>
3639
<li<%= sidebar_current("docs-hcloud-datasource-image") %>>
3740
<a href="/docs/providers/hcloud/d/image.html">hcloud_image</a>
3841
</li>

0 commit comments

Comments
 (0)