Skip to content

Commit 0f59edf

Browse files
authored
Merge pull request scaleway#57 from terraform-providers/scaleway-user-data
add scaleway_user_data resource
2 parents f67919a + 695ee42 commit 0f59edf

9 files changed

+458
-0
lines changed

scaleway/import_user_data_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package scaleway
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform/helper/resource"
7+
)
8+
9+
func TestAccScalewayUserData_importBasic(t *testing.T) {
10+
resourceName := "scaleway_user_data.base"
11+
12+
resource.Test(t, resource.TestCase{
13+
PreCheck: func() { testAccPreCheck(t) },
14+
Providers: testAccProviders,
15+
CheckDestroy: testAccCheckScalewayUserDataDestroy,
16+
Steps: []resource.TestStep{
17+
resource.TestStep{
18+
Config: testAccCheckScalewayUserDataConfig,
19+
},
20+
21+
resource.TestStep{
22+
ResourceName: resourceName,
23+
ImportState: true,
24+
ImportStateVerify: true,
25+
},
26+
},
27+
})
28+
}

scaleway/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func Provider() terraform.ResourceProvider {
4444
},
4545

4646
ResourcesMap: map[string]*schema.Resource{
47+
"scaleway_user_data": resourceScalewayUserData(),
4748
"scaleway_server": resourceScalewayServer(),
4849
"scaleway_token": resourceScalewayToken(),
4950
"scaleway_ssh_key": resourceScalewaySSHKey(),

scaleway/resource_server.go

+91
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package scaleway
22

33
import (
44
"fmt"
5+
"hash/fnv"
56
"log"
67

78
"github.com/hashicorp/terraform/helper/schema"
@@ -10,6 +11,8 @@ import (
1011

1112
var commercialServerTypes []string
1213

14+
var sshHostFingerprints = "ssh-host-fingerprints"
15+
1316
func resourceScalewayServer() *schema.Resource {
1417
return &schema.Resource{
1518
Create: resourceScalewayServerCreate,
@@ -57,6 +60,29 @@ func resourceScalewayServer() *schema.Resource {
5760
Optional: true,
5861
Description: "The security group the server is attached to",
5962
},
63+
"user_data": {
64+
Type: schema.TypeSet,
65+
Optional: true,
66+
Elem: &schema.Resource{
67+
Schema: map[string]*schema.Schema{
68+
"key": {
69+
Type: schema.TypeString,
70+
Required: true,
71+
},
72+
"value": {
73+
Type: schema.TypeString,
74+
Required: true,
75+
},
76+
},
77+
},
78+
Set: func(val interface{}) int {
79+
h := fnv.New32a()
80+
userData := val.(map[string]interface{})
81+
h.Write([]byte(userData["key"].(string)))
82+
return int(h.Sum32())
83+
},
84+
Description: "User Data attached to the server on creation",
85+
},
6086
"volume": {
6187
Type: schema.TypeList,
6288
Optional: true,
@@ -201,6 +227,17 @@ func resourceScalewayServerCreate(d *schema.ResourceData, m interface{}) error {
201227
return err
202228
}
203229

230+
if val, ok := d.GetOk("user_data"); ok {
231+
s := val.(*schema.Set)
232+
for _, v := range s.List() {
233+
data := v.(map[string]interface{})
234+
err := scaleway.PatchUserdata(server.Identifier, data["key"].(string), []byte(data["value"].(string)), false)
235+
if err != nil {
236+
return err
237+
}
238+
}
239+
}
240+
204241
d.SetId(server.Identifier)
205242
if d.Get("state").(string) != "stopped" {
206243
task, err := scaleway.PostServerAction(server.Identifier, "poweron")
@@ -256,6 +293,26 @@ func resourceScalewayServerRead(d *schema.ResourceData, m interface{}) error {
256293
d.Set("state_detail", server.StateDetail)
257294
d.Set("tags", server.Tags)
258295

296+
userDatas := []map[string]interface{}{}
297+
keys, err := scaleway.GetUserdatas(d.Id(), false)
298+
if err != nil {
299+
return err
300+
}
301+
for _, key := range keys.UserData {
302+
if key == sshHostFingerprints {
303+
continue
304+
}
305+
data, err := scaleway.GetUserdata(d.Id(), key, false)
306+
if err != nil {
307+
return err
308+
}
309+
userDatas = append(userDatas, map[string]interface{}{
310+
"key": key,
311+
"value": data.String(),
312+
})
313+
}
314+
d.Set("user_data", userDatas)
315+
259316
d.SetConnInfo(map[string]string{
260317
"type": "ssh",
261318
"host": server.PublicAddress.IP,
@@ -304,6 +361,40 @@ func resourceScalewayServerUpdate(d *schema.ResourceData, m interface{}) error {
304361
return fmt.Errorf("Failed patching scaleway server: %q", err)
305362
}
306363

364+
if d.HasChange("user_data") {
365+
remote, err := scaleway.GetUserdatas(d.Id(), false)
366+
if err != nil {
367+
return err
368+
}
369+
370+
toDelete := []string{}
371+
local := d.Get("user_data").(*schema.Set)
372+
for _, key := range remote.UserData {
373+
exists := false
374+
for _, v := range local.List() {
375+
exists = exists || v.(map[string]interface{})["key"] == key
376+
}
377+
if !exists {
378+
toDelete = append(toDelete, key)
379+
}
380+
}
381+
for _, key := range toDelete {
382+
if err := scaleway.DeleteUserdata(d.Id(), key, false); err != nil {
383+
return err
384+
}
385+
}
386+
387+
for _, v := range local.List() {
388+
if err := scaleway.PatchUserdata(
389+
d.Id(),
390+
v.(map[string]interface{})["key"].(string),
391+
[]byte(v.(map[string]interface{})["value"].(string)),
392+
false); err != nil {
393+
return err
394+
}
395+
}
396+
}
397+
307398
if d.HasChange("public_ip") {
308399
ips, err := scaleway.GetIPS()
309400
if err != nil {

scaleway/resource_server_test.go

+76
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package scaleway
33
import (
44
"fmt"
55
"log"
6+
"strings"
67
"testing"
78

89
"github.com/hashicorp/terraform/helper/resource"
@@ -159,6 +160,47 @@ func TestAccScalewayServer_SecurityGroup(t *testing.T) {
159160
})
160161
}
161162

163+
func TestAccScalewayServer_UserData(t *testing.T) {
164+
resource.Test(t, resource.TestCase{
165+
PreCheck: func() { testAccPreCheck(t) },
166+
Providers: testAccProviders,
167+
CheckDestroy: testAccCheckScalewayServerDestroy,
168+
Steps: []resource.TestStep{
169+
resource.TestStep{
170+
Config: testAccCheckScalewayServerConfig_UserDatas,
171+
Check: resource.ComposeTestCheckFunc(
172+
testAccCheckScalewayServerExists("scaleway_server.base"),
173+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.#", "2"),
174+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.527074092.key", "app"),
175+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.527074092.value", "lb"),
176+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.2562481374.key", "roles"),
177+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.2562481374.value", "ingress,egress"),
178+
),
179+
},
180+
resource.TestStep{
181+
Config: testAccCheckScalewayServerConfig_UserData,
182+
Check: resource.ComposeTestCheckFunc(
183+
testAccCheckScalewayServerExists("scaleway_server.base"),
184+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.#", "1"),
185+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.2562481374.key", "roles"),
186+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.2562481374.value", "ingress,egress"),
187+
),
188+
},
189+
resource.TestStep{
190+
Config: strings.Replace(testAccCheckScalewayServerConfig_UserDatas, "ingress,egress", "ingress", -1),
191+
Check: resource.ComposeTestCheckFunc(
192+
testAccCheckScalewayServerExists("scaleway_server.base"),
193+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.#", "2"),
194+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.527074092.key", "app"),
195+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.527074092.value", "lb"),
196+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.2562481374.key", "roles"),
197+
resource.TestCheckResourceAttr("scaleway_server.base", "user_data.2562481374.value", "ingress"),
198+
),
199+
},
200+
},
201+
})
202+
}
203+
162204
func testAccCheckScalewayServerDestroy(s *terraform.State) error {
163205
client := testAccProvider.Meta().(*Client).scaleway
164206

@@ -311,6 +353,40 @@ resource "scaleway_server" "base" {
311353
tags = [ "terraform-test" ]
312354
}`, armImageIdentifier)
313355

356+
var testAccCheckScalewayServerConfig_UserData = fmt.Sprintf(`
357+
resource "scaleway_server" "base" {
358+
name = "test"
359+
# ubuntu 14.04
360+
image = "%s"
361+
type = "C1"
362+
tags = [ "terraform-test" ]
363+
state = "stopped"
364+
365+
user_data {
366+
key = "roles"
367+
value = "ingress,egress"
368+
}
369+
}`, armImageIdentifier)
370+
371+
var testAccCheckScalewayServerConfig_UserDatas = fmt.Sprintf(`
372+
resource "scaleway_server" "base" {
373+
name = "test"
374+
# ubuntu 14.04
375+
image = "%s"
376+
type = "C1"
377+
tags = [ "terraform-test" ]
378+
state = "stopped"
379+
380+
user_data {
381+
key = "roles"
382+
value = "ingress,egress"
383+
}
384+
user_data {
385+
key = "app"
386+
value = "lb"
387+
}
388+
}`, armImageIdentifier)
389+
314390
var testAccCheckScalewayServerConfig_IPAttachment = fmt.Sprintf(`
315391
resource "scaleway_ip" "base" {}
316392

scaleway/resource_user_data.go

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package scaleway
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/hashicorp/terraform/helper/schema"
8+
api "github.com/nicolai86/scaleway-sdk"
9+
)
10+
11+
func resourceScalewayUserData() *schema.Resource {
12+
return &schema.Resource{
13+
Create: resourceScalewayUserDataCreate,
14+
Read: resourceScalewayUserDataRead,
15+
Update: resourceScalewayUserDataUpdate,
16+
Delete: resourceScalewayUserDataDelete,
17+
Importer: &schema.ResourceImporter{
18+
State: schema.ImportStatePassthrough,
19+
},
20+
21+
Schema: map[string]*schema.Schema{
22+
"server": {
23+
Type: schema.TypeString,
24+
Required: true,
25+
ForceNew: true,
26+
Description: "The server the meta data is associated with",
27+
},
28+
"key": {
29+
Type: schema.TypeString,
30+
Required: true,
31+
ForceNew: true,
32+
Description: "The key of the user data to manage",
33+
},
34+
"value": {
35+
Type: schema.TypeString,
36+
Required: true,
37+
Description: "The value of the user",
38+
},
39+
},
40+
}
41+
}
42+
43+
func resourceScalewayUserDataCreate(d *schema.ResourceData, m interface{}) error {
44+
scaleway := m.(*Client).scaleway
45+
46+
mu.Lock()
47+
if err := scaleway.PatchUserdata(
48+
d.Get("server").(string),
49+
d.Get("key").(string),
50+
[]byte(d.Get("value").(string)),
51+
false); err != nil {
52+
return err
53+
}
54+
mu.Unlock()
55+
56+
d.SetId(fmt.Sprintf("userdata-%s-%s", d.Get("server").(string), d.Get("key").(string)))
57+
return resourceScalewayUserDataRead(d, m)
58+
}
59+
60+
func resourceScalewayUserDataRead(d *schema.ResourceData, m interface{}) error {
61+
scaleway := m.(*Client).scaleway
62+
63+
if d.Get("server").(string) == "" {
64+
// import case
65+
parts := strings.Split(d.Id(), "-")
66+
d.Set("key", parts[len(parts)-1])
67+
d.Set("server", strings.Join(parts[1:len(parts)-1], "-"))
68+
}
69+
userdata, err := scaleway.GetUserdata(
70+
d.Get("server").(string),
71+
d.Get("key").(string),
72+
false,
73+
)
74+
75+
if err != nil {
76+
if serr, ok := err.(api.APIError); ok {
77+
if serr.StatusCode == 404 {
78+
d.SetId("")
79+
return nil
80+
}
81+
}
82+
return err
83+
}
84+
85+
d.Set("value", userdata.String())
86+
return nil
87+
}
88+
89+
func resourceScalewayUserDataUpdate(d *schema.ResourceData, m interface{}) error {
90+
scaleway := m.(*Client).scaleway
91+
92+
mu.Lock()
93+
if err := scaleway.PatchUserdata(
94+
d.Get("server").(string),
95+
d.Get("key").(string),
96+
[]byte(d.Get("value").(string)),
97+
false); err != nil {
98+
return err
99+
}
100+
mu.Unlock()
101+
102+
return resourceScalewayUserDataRead(d, m)
103+
}
104+
105+
func resourceScalewayUserDataDelete(d *schema.ResourceData, m interface{}) error {
106+
scaleway := m.(*Client).scaleway
107+
108+
mu.Lock()
109+
defer mu.Unlock()
110+
111+
err := scaleway.DeleteUserdata(
112+
d.Get("server").(string),
113+
d.Get("key").(string),
114+
false)
115+
if err != nil {
116+
return err
117+
}
118+
d.SetId("")
119+
return nil
120+
}

0 commit comments

Comments
 (0)