Skip to content

Commit f8d9602

Browse files
authored
feat(lb): add lb beta resource (scaleway#278)
1 parent da23f3e commit f8d9602

File tree

10 files changed

+3706
-0
lines changed

10 files changed

+3706
-0
lines changed

scaleway/helpers_lb.go

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package scaleway
2+
3+
import (
4+
"github.com/hashicorp/terraform/helper/schema"
5+
lb "github.com/scaleway/scaleway-sdk-go/api/lb/v1"
6+
"github.com/scaleway/scaleway-sdk-go/scw"
7+
)
8+
9+
// getLbAPIWithRegion returns a new lb API and the region for a Create request
10+
func getLbAPIWithRegion(d *schema.ResourceData, m interface{}) (*lb.API, scw.Region, error) {
11+
meta := m.(*Meta)
12+
lbApi := lb.NewAPI(meta.scwClient)
13+
14+
region, err := getRegion(d, meta)
15+
return lbApi, region, err
16+
}
17+
18+
// getLbAPIWithRegionAndID returns an lb API with region and ID extracted from the state
19+
func getLbAPIWithRegionAndID(m interface{}, id string) (*lb.API, scw.Region, string, error) {
20+
meta := m.(*Meta)
21+
lbApi := lb.NewAPI(meta.scwClient)
22+
23+
region, ID, err := parseRegionalID(id)
24+
return lbApi, region, ID, err
25+
}

scaleway/helpers_test.go

+35
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package scaleway
22

33
import (
44
"fmt"
5+
"github.com/hashicorp/terraform/helper/resource"
6+
"github.com/hashicorp/terraform/terraform"
7+
"net"
58
"net/http"
69
"strings"
710
"testing"
@@ -192,3 +195,35 @@ func TestGetRandomName(t *testing.T) {
192195
name := getRandomName("test")
193196
assert.True(t, strings.HasPrefix(name, "tf-test-"))
194197
}
198+
199+
func testCheckResourceAttrFunc(name string, key string, test func(string) error) resource.TestCheckFunc {
200+
return func(s *terraform.State) error {
201+
rs, ok := s.RootModule().Resources[name]
202+
if !ok {
203+
return fmt.Errorf("resource not found: %s", name)
204+
}
205+
value, ok := rs.Primary.Attributes[key]
206+
if !ok {
207+
return fmt.Errorf("key not found: %s", key)
208+
}
209+
err := test(value)
210+
if err != nil {
211+
return fmt.Errorf("test for %s %s did not pass test: %s", name, key, err)
212+
}
213+
return nil
214+
}
215+
}
216+
217+
func testCheckResourceAttrUUID(name string, key string) resource.TestCheckFunc {
218+
return resource.TestMatchResourceAttr(name, key, UUIDRegex)
219+
}
220+
221+
func testCheckResourceAttrIPv4(name string, key string) resource.TestCheckFunc {
222+
return testCheckResourceAttrFunc(name, key, func(value string) error {
223+
ip := net.ParseIP(value)
224+
if ip.To4() == nil {
225+
return fmt.Errorf("%s is not a valid IPv4", value)
226+
}
227+
return nil
228+
})
229+
}

scaleway/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ func Provider() terraform.ResourceProvider {
197197
"scaleway_instance_placement_group": resourceScalewayInstancePlacementGroup(),
198198
"scaleway_k8s_cluster_beta": resourceScalewayK8SClusterBeta(),
199199
"scaleway_k8s_pool_beta": resourceScalewayK8SPoolBeta(),
200+
"scaleway_lb_beta": resourceScalewayLbBeta(),
200201
"scaleway_object_bucket": resourceScalewayObjectBucket(),
201202
"scaleway_user_data": resourceScalewayUserData(),
202203
"scaleway_server": resourceScalewayServer(),

scaleway/resource_lb_beta.go

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package scaleway
2+
3+
import (
4+
"github.com/hashicorp/terraform/helper/schema"
5+
lb "github.com/scaleway/scaleway-sdk-go/api/lb/v1"
6+
)
7+
8+
func resourceScalewayLbBeta() *schema.Resource {
9+
return &schema.Resource{
10+
Create: resourceScalewayLbBetaCreate,
11+
Read: resourceScalewayLbBetaRead,
12+
Update: resourceScalewayLbBetaUpdate,
13+
Delete: resourceScalewayLbBetaDelete,
14+
Importer: &schema.ResourceImporter{
15+
State: schema.ImportStatePassthrough,
16+
},
17+
SchemaVersion: 0,
18+
Schema: map[string]*schema.Schema{
19+
"name": {
20+
Type: schema.TypeString,
21+
Optional: true,
22+
Computed: true,
23+
Description: "Name of the lb",
24+
},
25+
"type": {
26+
Type: schema.TypeString,
27+
Required: true,
28+
ForceNew: true,
29+
Description: "The type of load-balancer you want to create",
30+
},
31+
"tags": {
32+
Type: schema.TypeList,
33+
Elem: &schema.Schema{
34+
Type: schema.TypeString,
35+
},
36+
Optional: true,
37+
Description: "Array of tags to associate with the load-balancer",
38+
},
39+
"ip_id": {
40+
Type: schema.TypeString,
41+
Computed: true,
42+
Description: "The load-balance public IP ID",
43+
},
44+
"ip_address": {
45+
Type: schema.TypeString,
46+
Computed: true,
47+
Description: "The load-balance public IP address",
48+
},
49+
"region": regionSchema(),
50+
"organization_id": organizationIDSchema(),
51+
},
52+
}
53+
}
54+
55+
func resourceScalewayLbBetaCreate(d *schema.ResourceData, m interface{}) error {
56+
lbAPI, region, err := getLbAPIWithRegion(d, m)
57+
if err != nil {
58+
return err
59+
}
60+
61+
name, ok := d.GetOk("name")
62+
if !ok {
63+
name = getRandomName("lb")
64+
}
65+
createReq := &lb.CreateLbRequest{
66+
Region: region,
67+
OrganizationID: d.Get("organization_id").(string),
68+
Name: name.(string),
69+
Type: d.Get("type").(string),
70+
}
71+
if raw, ok := d.GetOk("tags"); ok {
72+
for _, tag := range raw.([]interface{}) {
73+
createReq.Tags = append(createReq.Tags, tag.(string))
74+
}
75+
}
76+
res, err := lbAPI.CreateLb(createReq)
77+
if err != nil {
78+
return err
79+
}
80+
81+
d.SetId(newRegionalId(region, res.ID))
82+
83+
_, err = lbAPI.WaitForLb(&lb.WaitForLbRequest{
84+
Region: region,
85+
LbID: res.ID,
86+
Timeout: BaremetalServerWaitForTimeout,
87+
})
88+
if err != nil {
89+
return err
90+
}
91+
92+
return resourceScalewayLbBetaRead(d, m)
93+
}
94+
95+
func resourceScalewayLbBetaRead(d *schema.ResourceData, m interface{}) error {
96+
lbAPI, region, ID, err := getLbAPIWithRegionAndID(m, d.Id())
97+
if err != nil {
98+
return err
99+
}
100+
101+
res, err := lbAPI.GetLb(&lb.GetLbRequest{
102+
Region: region,
103+
LbID: ID,
104+
})
105+
106+
if err != nil {
107+
if is404Error(err) {
108+
d.SetId("")
109+
return nil
110+
}
111+
return err
112+
}
113+
114+
d.Set("name", res.Name)
115+
d.Set("region", string(region))
116+
d.Set("organization_id", res.OrganizationID)
117+
d.Set("tags", res.Tags)
118+
d.Set("type", res.Type)
119+
d.Set("ip_id", res.IP[0].ID)
120+
d.Set("ip_address", res.IP[0].IPAddress)
121+
122+
return nil
123+
}
124+
125+
func resourceScalewayLbBetaUpdate(d *schema.ResourceData, m interface{}) error {
126+
lbAPI, region, ID, err := getLbAPIWithRegionAndID(m, d.Id())
127+
if err != nil {
128+
return err
129+
}
130+
131+
if d.HasChange("name") || d.HasChange("tags") {
132+
133+
req := &lb.UpdateLbRequest{
134+
Region: region,
135+
LbID: ID,
136+
Name: d.Get("name").(string),
137+
Tags: StringSliceFromState(d.Get("tags").([]interface{})),
138+
}
139+
140+
_, err = lbAPI.UpdateLb(req)
141+
if err != nil {
142+
return err
143+
}
144+
}
145+
146+
return resourceScalewayLbBetaRead(d, m)
147+
}
148+
149+
func resourceScalewayLbBetaDelete(d *schema.ResourceData, m interface{}) error {
150+
lbAPI, region, ID, err := getLbAPIWithRegionAndID(m, d.Id())
151+
if err != nil {
152+
return err
153+
}
154+
155+
err = lbAPI.DeleteLb(&lb.DeleteLbRequest{
156+
Region: region,
157+
LbID: ID,
158+
// This parameter will probably be breaking change when ip pre reservation will exist.
159+
ReleaseIP: true,
160+
})
161+
162+
if err != nil && !is404Error(err) {
163+
return err
164+
}
165+
166+
if is404Error(err) {
167+
return nil
168+
}
169+
170+
return err
171+
}

scaleway/resource_lb_beta_test.go

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
"github.com/hashicorp/terraform/helper/resource"
6+
"github.com/hashicorp/terraform/terraform"
7+
"github.com/scaleway/scaleway-sdk-go/api/lb/v1"
8+
"testing"
9+
)
10+
11+
func TestAccScalewayLbBeta(t *testing.T) {
12+
resource.ParallelTest(t, resource.TestCase{
13+
PreCheck: func() { testAccPreCheck(t) },
14+
Providers: testAccProviders,
15+
CheckDestroy: testAccCheckScalewayLbBetaDestroy,
16+
Steps: []resource.TestStep{
17+
{
18+
Config: `
19+
resource scaleway_lb_beta lb01 {
20+
name = "test-lb"
21+
type = "LB-S"
22+
}
23+
`,
24+
Check: resource.ComposeTestCheckFunc(
25+
testAccCheckScalewayLbBetaExists("scaleway_lb_beta.lb01"),
26+
resource.TestCheckResourceAttr("scaleway_lb_beta.lb01", "name", "test-lb"),
27+
testCheckResourceAttrUUID("scaleway_lb_beta.lb01", "ip_id"),
28+
testCheckResourceAttrIPv4("scaleway_lb_beta.lb01", "ip_address"),
29+
),
30+
},
31+
{
32+
Config: `
33+
resource scaleway_lb_beta lb01 {
34+
name = "test-lb"
35+
type = "LB-S"
36+
tags = ["tag1", "tag2"]
37+
}
38+
`,
39+
Check: resource.ComposeTestCheckFunc(
40+
testAccCheckScalewayLbBetaExists("scaleway_lb_beta.lb01"),
41+
resource.TestCheckResourceAttr("scaleway_lb_beta.lb01", "name", "test-lb"),
42+
resource.TestCheckResourceAttr("scaleway_lb_beta.lb01", "tags.0", "tag1"),
43+
resource.TestCheckResourceAttr("scaleway_lb_beta.lb01", "tags.1", "tag2"),
44+
testCheckResourceAttrUUID("scaleway_lb_beta.lb01", "ip_id"),
45+
testCheckResourceAttrIPv4("scaleway_lb_beta.lb01", "ip_address"),
46+
),
47+
},
48+
},
49+
})
50+
}
51+
52+
func testAccCheckScalewayLbBetaExists(n string) resource.TestCheckFunc {
53+
return func(s *terraform.State) error {
54+
rs, ok := s.RootModule().Resources[n]
55+
if !ok {
56+
return fmt.Errorf("resource not found: %s", n)
57+
}
58+
59+
lbAPI, region, ID, err := getLbAPIWithRegionAndID(testAccProvider.Meta(), rs.Primary.ID)
60+
if err != nil {
61+
return err
62+
}
63+
64+
_, err = lbAPI.GetLb(&lb.GetLbRequest{
65+
LbID: ID,
66+
Region: region,
67+
})
68+
69+
if err != nil {
70+
return err
71+
}
72+
73+
return nil
74+
}
75+
}
76+
77+
func testAccCheckScalewayLbBetaDestroy(s *terraform.State) error {
78+
for _, rs := range s.RootModule().Resources {
79+
if rs.Type != "scaleway_instance_ip" {
80+
continue
81+
}
82+
83+
lbAPI, region, ID, err := getLbAPIWithRegionAndID(testAccProvider.Meta(), rs.Primary.ID)
84+
if err != nil {
85+
return err
86+
}
87+
88+
_, err = lbAPI.GetLb(&lb.GetLbRequest{
89+
Region: region,
90+
LbID: ID,
91+
})
92+
93+
// If no error resource still exist
94+
if err == nil {
95+
return fmt.Errorf("IP (%s) still exists", rs.Primary.ID)
96+
}
97+
98+
// Unexpected api error we return it
99+
// We check for 403 because instance API return 403 for deleted IP
100+
if !is404Error(err) {
101+
return err
102+
}
103+
}
104+
105+
return nil
106+
}

0 commit comments

Comments
 (0)