Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(instance): brk change, use TypeMap for user_data and remove user… #738

Merged
merged 8 commits into from
Jan 13, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 47 additions & 8 deletions docs/guides/migration_guide_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,49 @@ terraform import $NEW_RESOURCE_NAME $ID

### Instance

#### Breaking changes

##### User-data is a Map and cloud_init field is included in the user-data map

User data are now saved as TypeMap instead of TypeSet.
In particular, the `cloud_init` attribute is now managed as a common field in the user-data with the standard `cloud-init`.

v1.X:

```hcl
resource "scaleway_instance_server" "web" {
type = "DEV1-S"
image = "ubuntu_focal"

user_data {
key = "foo"
value = "bar"
}

cloud_init = file("cloud-init.yml")
}
```

v2.X:

```hcl
resource "scaleway_instance_server" "web" {
type = "DEV1-S"
image = "ubuntu_focal"

user_data {
foo = "bar"
cloud-init = file("cloud-init.yml")
}
}
```

#### Renaming

All the old instance resources have been regrouped under a new name: `Instance`.
This means that all old instance resources are now prefixed with `scaleway_instance_`.

#### Renamed: `scaleway_server` -> `scaleway_instance_server`
##### Renamed: `scaleway_server` -> `scaleway_instance_server`

`scaleway_server` was renamed to `scaleway_instance_server`.

Expand Down Expand Up @@ -206,7 +245,7 @@ resource "scaleway_instance_server" "web" {
}
```

#### Renamed: `scaleway_ip` -> `scaleway_instance_ip`
##### Renamed: `scaleway_ip` -> `scaleway_instance_ip`

`scaleway_ip` was renamed to `scaleway_instance_ip` and the `server` attribute, used to attach an IP has been moved to `scaleway_instance_server.id_id`

Expand All @@ -215,35 +254,35 @@ resource "scaleway_instance_ip" "test_ip" {
}
```

#### Renamed: `scaleway_volume` -> `scaleway_instance_volume`
##### Renamed: `scaleway_volume` -> `scaleway_instance_volume`

`scaleway_volume` was renamed to `scaleway_instance_volume`.
The former attributes can still be used on the new volume resource.

Additionally, from now on, you can also create new volumes based on other volumes or snapshots.
For more information check the [new volume `scaleway_instance_volume` resource](../resources/instance_volume.md).

#### Renamed: `scaleway_ssh_key` -> `scaleway_account_ssk_key`
##### Renamed: `scaleway_ssh_key` -> `scaleway_account_ssk_key`

`scaleway_ssh_key` was renamed to `scaleway_account_ssk_key`
The `key` attribute has been renamed to `public_key`.
A `name` required attribute and an `organization_id` optional attribute have been added.

#### Removed: `scaleway_user_data`
##### Removed: `scaleway_user_data`

`scaleway_user_data` is now part of the `scaleway_instance_server` resource.

#### Removed: `scaleway_token`
##### Removed: `scaleway_token`

The `scaleway_token` was removed in version 2.

Tokens should be created in the console.

#### Renamed: `scaleway_ip_reverse_dns` -> `scaleway_instance_ip_reverse_dns`
##### Renamed: `scaleway_ip_reverse_dns` -> `scaleway_instance_ip_reverse_dns`

`scaleway_ip_reverse_dns` was renamed to `scaleway_instance_ip_reverse_dns`.

#### Removed: `scaleway_volume_attachment`
##### Removed: `scaleway_volume_attachment`

The `scaleway_volume_attachment` was removed in version 2.

Expand Down
26 changes: 8 additions & 18 deletions docs/resources/instance_server.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,13 @@ resource "scaleway_instance_server" "web" {

```hcl
resource "scaleway_instance_server" "web" {
type = "DEV1-S"
type = "DEV1-S"
image = "ubuntu_focal"

tags = [ "web", "public" ]

user_data {
key = "plop"
value = "world"
}

user_data {
key = "xavier"
value = "niel"
foo = "bar"
cloud-init = file("${path.module}/cloud-init.yml")
}

cloud_init = file("${path.module}/cloud-init.yml")
}
```

Expand Down Expand Up @@ -169,13 +160,12 @@ attached to the server. Updates to this field will trigger a stop/start of the s

- `state` - (Defaults to `started`) The state of the server. Possible values are: `started`, `stopped` or `standby`.

- `cloud_init` - (Optional) The cloud init script associated with this server. Updates to this field will trigger a stop/start of the server.

- `user_data` - (Optional) The user data associated with the server.

- `key` - (Required) The user data key. The `cloud-init` key is reserved, please use `cloud_init` attribute instead.

- `value` - (Required) The user data content. It could be a string or a file content using [file](https://www.terraform.io/docs/configuration/functions/file.html) or [filebase64](https://www.terraform.io/docs/configuration/functions/filebase64.html) for example.
Use the `cloud-init` key to use [cloud-init](https://cloudinit.readthedocs.io/en/latest/) on your instance.
You can define values using:
- string
- UTF-8 encoded file content using [file](https://www.terraform.io/docs/configuration/functions/file.html)
- Binary files using [filebase64](https://www.terraform.io/docs/configuration/functions/filebase64.html).

- `boot_type` - The boot Type of the server. Possible values are: `local`, `bootscript` or `rescue`.

Expand Down
23 changes: 0 additions & 23 deletions scaleway/helpers_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package scaleway
import (
"context"
"fmt"
"hash/crc32"
"sort"
"time"

Expand Down Expand Up @@ -62,28 +61,6 @@ func instanceAPIWithZoneAndNestedID(m interface{}, zonedNestedID string) (*insta
return instanceAPI, zone, innerID, outerID, nil
}

// hash hashes a string to a unique hashcode.
//
// crc32 returns a uint32, but for our use we need
// and non negative integer. Here we cast to an integer
// and invert it if the result is negative.
func hash(s string) int {
v := int(crc32.ChecksumIEEE([]byte(s)))
if v >= 0 {
return v
}
if -v >= 0 {
return -v
}
// v == MinInt
return 0
}

func userDataHash(v interface{}) int {
userData := v.(map[string]interface{})
return hash(userData["key"].(string) + userData["value"].(string))
}

// orderVolumes return an ordered slice based on the volume map key "0", "1", "2",...
func orderVolumes(v map[string]*instance.Volume) []*instance.Volume {
indexes := []string{}
Expand Down
66 changes: 20 additions & 46 deletions scaleway/resource_instance_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,26 +195,11 @@ func resourceScalewayInstanceServer() *schema.Resource {
ValidateFunc: validation.StringLenBetween(0, 127998),
},
"user_data": {
Type: schema.TypeSet,
Type: schema.TypeMap,
Optional: true,
MaxItems: 98,
Description: "The user data associated with the server", // TODO: document reserved keys (`cloud-init`)
Set: userDataHash,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"key": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validationStringNotInSlice([]string{"cloud-init"}, true),
Description: "A user data key, the value \"cloud-init\" is not allowed",
},
"value": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 127998),
Description: "A user value",
},
},
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"zone": zoneSchema(),
Expand Down Expand Up @@ -340,11 +325,9 @@ func resourceScalewayInstanceServerCreate(ctx context.Context, d *schema.Resourc
UserData: make(map[string]io.Reader),
}

if allUserData, ok := d.GetOk("user_data"); ok {
userDataSet := allUserData.(*schema.Set)
for _, rawUserData := range userDataSet.List() {
userData := rawUserData.(map[string]interface{})
userDataRequests.UserData[userData["key"].(string)] = bytes.NewBufferString(userData["value"].(string))
if rawUserData, ok := d.GetOk("user_data"); ok {
for key, value := range rawUserData.(map[string]interface{}) {
userDataRequests.UserData[key] = bytes.NewBufferString(value.(string))
}
}

Expand Down Expand Up @@ -487,23 +470,20 @@ func resourceScalewayInstanceServerRead(ctx context.Context, d *schema.ResourceD
ServerID: ID,
}, scw.WithContext(ctx))

var userDataList []interface{}
userData := make(map[string]interface{})
for key, value := range allUserData.UserData {
userData, err := ioutil.ReadAll(value)
userDataValue, err := ioutil.ReadAll(value)
if err != nil {
return diag.FromErr(err)
}
if key != "cloud-init" {
userDataList = append(userDataList, map[string]interface{}{
"key": key,
"value": string(userData),
})
} else {
_ = d.Set("cloud_init", string(userData))
}
//if key != "cloud-init" {
userData[key] = string(userDataValue)
// } else {
//_ = d.Set("cloud_init", string(userDataValue))
//}
}
if len(userDataList) > 0 {
_ = d.Set("user_data", schema.NewSet(userDataHash, userDataList))
if len(userData) > 0 {
_ = d.Set("user_data", userData)
}

return nil
Expand Down Expand Up @@ -661,25 +641,19 @@ func resourceScalewayInstanceServerUpdate(ctx context.Context, d *schema.Resourc
////
// Update server user data
////
if d.HasChanges("cloud_init", "user_data") {
if d.HasChanges("user_data") {
userDataRequests := &instance.SetAllServerUserDataRequest{
Zone: zone,
ServerID: ID,
UserData: make(map[string]io.Reader),
}

if allUserData, ok := d.GetOk("user_data"); ok {
userDataSet := allUserData.(*schema.Set)
for _, rawUserData := range userDataSet.List() {
userData := rawUserData.(map[string]interface{})
userDataRequests.UserData[userData["key"].(string)] = bytes.NewBufferString(userData["value"].(string))
userDataMap := allUserData.(map[string]interface{})
for key, value := range userDataMap {
userDataRequests.UserData[key] = bytes.NewBufferString(value.(string))
}
}

// cloud init script is set in user data
if cloudInit, ok := d.GetOk("cloud_init"); ok {
userDataRequests.UserData["cloud-init"] = bytes.NewBufferString(cloudInit.(string))
if !isStopped {
if !isStopped && d.HasChange("user_data.cloud-init") {
warnings = append(warnings, diag.Diagnostic{
Severity: diag.Warning,
Summary: "instance may need to be rebooted to use the new cloud init config",
Expand Down
Loading