Skip to content

Commit b18fb09

Browse files
authored
Merge branch 'master' into enable_smtp
2 parents 32409cd + 0e2330e commit b18fb09

23 files changed

+100766
-6696
lines changed

docs/resources/instance_server.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ to find either the right `label` or the right local image `ID` for a given `type
143143
- `placement_group_id` - (Optional) The [placement group](https://developers.scaleway.com/en/products/instance/api/#placement-groups-d8f653) the server is attached to.
144144

145145

146-
~> **Important:** Updates to `placement_group_id` may trigger a stop/start of the server.
146+
~> **Important:** When updating `placement_group_id` the `state` must be set to `stopped`, otherwise it will fail.
147147

148148
- `root_volume` - (Optional) Root [volume](https://developers.scaleway.com/en/products/instance/api/#volumes-7e8a39) attached to the server on creation.
149149
- `size_in_gb` - (Required) Size of the root volume in gigabytes.
@@ -152,12 +152,14 @@ to find either the right `label` or the right local image `ID` for a given `type
152152
Updates to this field will recreate a new resource.
153153
- `delete_on_termination` - (Defaults to `true`) Forces deletion of the root volume on instance termination.
154154

155-
~> **Important:** Updates to `root_volume.size_in_gb` will trigger a stop/start of the server.
155+
~> **Important:** Updates to `root_volume.size_in_gb` will be ignored after the creation of the server.
156156

157157
- `additional_volume_ids` - (Optional) The [additional volumes](https://developers.scaleway.com/en/products/instance/api/#volumes-7e8a39)
158158
attached to the server. Updates to this field will trigger a stop/start of the server.
159159

160-
~> **Important:** If this field contains local volumes, updates will trigger a stop/start of the server.
160+
~> **Important:** If this field contains local volumes, the `state` must be set to `stopped`, otherwise it will fail.
161+
162+
~> **Important:** If this field contains local volumes, you have to first detach them, in one apply, and then delete the volume in another apply.
161163

162164
- `enable_ipv6` - (Defaults to `false`) Determines if IPv6 is enabled for the server.
163165

docs/resources/instance_volume.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ The following arguments are supported:
2424

2525
- `type` - (Required) The type of the volume. The possible values are: `b_ssd` (Block SSD), `l_ssd` (Local SSD).
2626
- `size_in_gb` - (Optional) The size of the volume. Only one of `size_in_gb`, `from_volume_id` and `from_volume_id` should be specified.
27-
- `from_volume_id` - (Optional) If set, the new volume will be copied from this volume. Only one of `size_in_gb`, `from_volume_id` and `from_volume_id` should be specified.
28-
- ``from_snapshot_id`` - (Optional) If set, the new volume will be created from this snapshot. Only one of `size_in_gb`, `from_volume_id` and `from_volume_id` should be specified.
27+
- `from_volume_id` - (Optional) If set, the new volume will be copied from this volume. Only one of `size_in_gb`, `from_volume_id` and `from_snapshot_id` should be specified.
28+
- ``from_snapshot_id`` - (Optional) If set, the new volume will be created from this snapshot. Only one of `size_in_gb`, `from_volume_id` and `from_snapshot_id` should be specified.
2929
- `name` - (Optional) The name of the volume. If not provided it will be randomly generated.
3030
- `zone` - (Defaults to [provider](../index.md#zone) `zone`) The [zone](../guides/regions_and_zones.md#zones) in which the volume should be created.
3131
- `organization_id` - (Defaults to [provider](../index.md#organization_id) `organization_id`) The ID of the organization the volume is associated with.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/terraform-providers/terraform-provider-scaleway
33
require (
44
github.com/aws/aws-sdk-go v1.34.32
55
github.com/dnaeon/go-vcr v1.0.1
6+
github.com/dustin/go-humanize v1.0.0
67
github.com/google/go-cmp v0.5.2
78
github.com/hashicorp/go-retryablehttp v0.6.7
89
github.com/hashicorp/terraform-plugin-sdk/v2 v2.2.0

go.sum

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
7979
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8080
github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY=
8181
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
82+
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
83+
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
8284
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
8385
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
8486
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -297,12 +299,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
297299
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
298300
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
299301
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
300-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201012095732-98ec365545de h1:yhT7zTv3WAMD3S3GqkpAFIL8O76emUsBKsiBcVBb4Bg=
301-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201012095732-98ec365545de/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
302-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201106174615-fd524d38cee8 h1:OUM8gK4Frdx3yhDJWQSToADtrvCTGaZXYrm6O3j3JaQ=
303-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201106174615-fd524d38cee8/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
304-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201109203223-9446a84bfb2a h1:bcVe/pXc4HWi8RwkiiYOdIjYWjQvR5eeMRaepXGW298=
305-
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201109203223-9446a84bfb2a/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
306302
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201113152841-1153aa56e20e h1:KW5n7q2CMM/MsFNAwdZWB0UioVa3E3XQSrKRZcjmaGo=
307303
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.7.0.20201113152841-1153aa56e20e/go.mod h1:CJJ5VAbozOl0yEw7nHB9+7BXTJbIn6h7W+f6Gau5IP8=
308304
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=

scaleway/helpers.go

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
package scaleway
22

33
import (
4-
"bytes"
54
"encoding/json"
65
"fmt"
76
"net"
87
"net/http"
98
"regexp"
109
"strings"
11-
"text/template"
1210
"time"
1311

14-
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1512
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
16-
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
1713
"github.com/scaleway/scaleway-sdk-go/namegenerator"
1814
"github.com/scaleway/scaleway-sdk-go/scw"
1915
"golang.org/x/xerrors"
@@ -302,37 +298,6 @@ func isUUID(s string) bool {
302298
return UUIDRegex.MatchString(s)
303299
}
304300

305-
// newTemplateFunc takes a go template string and returns a function that can be called to execute template.
306-
func newTemplateFunc(tplStr string) func(data interface{}) string {
307-
t := template.Must(template.New("tpl").Parse(tplStr))
308-
return func(tplParams interface{}) string {
309-
buffer := bytes.Buffer{}
310-
err := t.Execute(&buffer, tplParams)
311-
if err != nil {
312-
panic(err) // lintignore:R009
313-
}
314-
return buffer.String()
315-
}
316-
}
317-
318-
// testAccGetResourceAttr can be used in acceptance tests to extract value from state and store it in dest
319-
func testAccGetResourceAttr(resourceName string, attrName string, dest *string) resource.TestCheckFunc {
320-
return func(state *terraform.State) error {
321-
r, exist := state.RootModule().Resources[resourceName]
322-
if !exist {
323-
return fmt.Errorf("unknown ressource %s", resourceName)
324-
}
325-
326-
a, exist := r.Primary.Attributes[attrName]
327-
if !exist {
328-
return fmt.Errorf("unknown ressource %s", resourceName)
329-
}
330-
331-
*dest = a
332-
return nil
333-
}
334-
}
335-
336301
func flattenTime(date *time.Time) interface{} {
337302
if date != nil {
338303
return date.Format(time.RFC3339)
@@ -374,10 +339,7 @@ func expandStringWithDefault(data interface{}, defaultValue string) string {
374339
}
375340

376341
func expandStrings(data interface{}) []string {
377-
if data == nil {
378-
return []string{}
379-
}
380-
stringSlice := []string(nil)
342+
stringSlice := []string{}
381343
for _, s := range data.([]interface{}) {
382344
stringSlice = append(stringSlice, s.(string))
383345
}

scaleway/helpers_instance.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"sort"
88
"time"
99

10+
"github.com/dustin/go-humanize"
1011
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1112
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
1213
"github.com/scaleway/scaleway-sdk-go/scw"
@@ -159,3 +160,82 @@ func reachState(ctx context.Context, instanceAPI *instance.API, zone scw.Zone, s
159160
}
160161
return nil
161162
}
163+
164+
// getServerType is a util to get a instance.ServerType by its commercialType
165+
func getServerType(apiInstance *instance.API, zone scw.Zone, commercialType string) *instance.ServerType {
166+
serverType := (*instance.ServerType)(nil)
167+
168+
serverTypesRes, err := apiInstance.ListServersTypes(&instance.ListServersTypesRequest{
169+
Zone: zone,
170+
})
171+
if err != nil {
172+
l.Warningf("cannot get server types: %s", err)
173+
} else {
174+
serverType = serverTypesRes.Servers[commercialType]
175+
if serverType == nil {
176+
l.Warningf("unrecognized server type: %s", commercialType)
177+
}
178+
}
179+
180+
return serverType
181+
}
182+
183+
// validateLocalVolumeSizes validates the total size of local volumes.
184+
func validateLocalVolumeSizes(volumes map[string]*instance.VolumeTemplate, serverType *instance.ServerType, commercialType string) error {
185+
// Calculate local volume total size.
186+
var localVolumeTotalSize scw.Size
187+
for _, volume := range volumes {
188+
if volume.VolumeType == instance.VolumeVolumeTypeLSSD {
189+
localVolumeTotalSize += volume.Size
190+
}
191+
}
192+
193+
volumeConstraint := serverType.VolumesConstraint
194+
195+
// If no root volume provided, count the default root volume size added by the API.
196+
if rootVolume := volumes["0"]; rootVolume == nil {
197+
localVolumeTotalSize += volumeConstraint.MinSize
198+
}
199+
200+
if localVolumeTotalSize < volumeConstraint.MinSize || localVolumeTotalSize > volumeConstraint.MaxSize {
201+
min := humanize.Bytes(uint64(volumeConstraint.MinSize))
202+
if volumeConstraint.MinSize == volumeConstraint.MaxSize {
203+
return fmt.Errorf("%s total local volume size must be equal to %s", commercialType, min)
204+
}
205+
206+
max := humanize.Bytes(uint64(volumeConstraint.MaxSize))
207+
return fmt.Errorf("%s total local volume size must be between %s and %s", commercialType, min, max)
208+
}
209+
210+
return nil
211+
}
212+
213+
// sanitizeVolumeMap removes extra data for API validation.
214+
//
215+
// On the api side, there are two possibles validation schemas for volumes and the validator will be chosen dynamically depending on the passed JSON request
216+
// - With an image (in that case the root volume can be skipped because it is taken from the image)
217+
// - Without an image (in that case, the root volume must be defined)
218+
func sanitizeVolumeMap(serverName string, volumes map[string]*instance.VolumeTemplate) map[string]*instance.VolumeTemplate {
219+
m := make(map[string]*instance.VolumeTemplate)
220+
221+
for index, v := range volumes {
222+
v.Name = serverName + "-" + index
223+
224+
// Remove extra data for API validation.
225+
switch {
226+
// If a volume already got an ID it is passed as it to the API without specifying the volume type.
227+
// TODO: Fix once instance accept volume type in the schema validation
228+
case v.ID != "":
229+
v = &instance.VolumeTemplate{ID: v.ID, Name: v.Name}
230+
// For the root volume (index 0) if the specified size is not 0 it is considered as a new volume
231+
// It does not have yet a volume ID, it is passed to the API with only the size to be dynamically created by the API
232+
case index == "0" && v.Size != 0:
233+
v = &instance.VolumeTemplate{Size: v.Size}
234+
// If none of the above conditions are met, the volume is passed as it to the API
235+
default:
236+
}
237+
m[index] = v
238+
}
239+
240+
return m
241+
}

scaleway/provider_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ func getHTTPRecoder(t *testing.T, update bool) (client *http.Client, cleanup fun
7777

7878
// Add a filter which removes Authorization headers from all requests:
7979
r.AddFilter(func(i *cassette.Interaction) error {
80+
i.Request.Headers = i.Request.Headers.Clone()
8081
delete(i.Request.Headers, "x-auth-token")
8182
delete(i.Request.Headers, "X-Auth-Token")
8283
return nil

0 commit comments

Comments
 (0)