From e7257a2712258007c5785f5adedee81284df5960 Mon Sep 17 00:00:00 2001 From: Laure-di Date: Fri, 6 Jun 2025 11:22:14 +0200 Subject: [PATCH] feat(instance): add support filesystem feat(file): add support v1beta1 Create, Read and Update function Delete Methode add tests fix date issue and register cassettes test: add validation for filesystem size granularity fix: convertion fix(instance): update schema filesystem test(instance): add test attach filesystem feat(instance): delete and update filesystem chore: master sdk-go go mod tidy update doc and tests fix fmt update go.mod fix(file): rename attribut size to size_in_gb fix: error return attachFS and typo doc fix: error return attachFS and typo doc update FileSystem Size to GB update FileSystem Size to GB refacto waiter --- docs/resources/file_filesystem.md | 4 +- docs/resources/instance_server.md | 32 +++ internal/services/file/filesystem.go | 25 +- internal/services/file/filesystem_test.go | 28 +- .../testdata/file-system-basic.cassette.yaml | 240 +++++++++--------- ...valid-size-granularity-fails.cassette.yaml | 18 +- ...-system-size-too-small-fails.cassette.yaml | 8 +- .../services/instance/helpers_instance.go | 53 +++- internal/services/instance/server.go | 101 ++++++++ internal/services/instance/server_test.go | 183 +++++++++++++ internal/services/instance/types.go | 15 ++ internal/services/instance/waiters.go | 16 ++ 12 files changed, 565 insertions(+), 158 deletions(-) diff --git a/docs/resources/file_filesystem.md b/docs/resources/file_filesystem.md index 2da3bca5f1..b4aecf305e 100644 --- a/docs/resources/file_filesystem.md +++ b/docs/resources/file_filesystem.md @@ -16,14 +16,14 @@ This resource allows you to define and manage the size, tags, and region of a fi ```terraform resource scaleway_file_filesystem file { name = "my-nfs-filesystem" - size = 100000000000 # 100 GB + size_in_gb = 100000000000 # 100 GB } ``` ## Argument Reference - `name` - (Optional) The name of the filesystem. If not provided, a random name will be generated. -- `size` - (Required) The size of the filesystem in bytes, with a granularity of 100 GB (10¹¹ bytes). +- `size_in_gb` - (Required) The size of the filesystem in bytes, with a granularity of 100 GB (10¹¹ bytes). - Minimum: 100 GB (100000000000 bytes) - Maximum: 10 TB (10000000000000 bytes) - `tags` - (Optional) A list of tags associated with the filesystem. diff --git a/docs/resources/instance_server.md b/docs/resources/instance_server.md index e50b0b16fe..dde0089895 100644 --- a/docs/resources/instance_server.md +++ b/docs/resources/instance_server.md @@ -45,6 +45,33 @@ resource "scaleway_instance_server" "web" { } ``` +### With filesystem + +```terraform +resource scaleway_block_volume volume { + iops = 15000 + size_in_gb = 15 +} + +resource scaleway_file_filesystem terraform_instance_filesystem { + name = "filesystem-instance-terraform" + size_in_gb = 100000000000 +} + +resource scaleway_instance_server base { + type = "POP2-HM-2C-16G" + state = "started" + tags = ["terraform-test", "scaleway_instance_server", "state"] + root_volume { + volume_type = "sbs_volume" + volume_id = scaleway_block_volume.volume.id + } + filesystems { + filesystem_id = scaleway_file_filesystem.terraform_instance_filesystem.id + } +} +``` + ### With a reserved IP ```terraform @@ -227,6 +254,9 @@ attached to the server. Updates to this field will trigger a stop/start of the s ~> **Important:** If this field contains local volumes, you have to first detach them, in one apply, and then delete the volume in another apply. +- `filesystems` - (Optional) List of filesystems attached to the server. + - `filesystem_id` - (Optional) The unique ID of the filesystem attached to the server. + - `enable_ipv6` - (Defaults to `false`) Determines if IPv6 is enabled for the server. Deprecated: Please use a scaleway_instance_ip with a `routed_ipv6` type. @@ -292,6 +322,8 @@ In addition to all arguments above, the following attributes are exported: - `placement_group_policy_respected` - (Deprecated) Always false, use [instance_placement_group ressource](instance_placement_group.md) to known when the placement group policy is respected. - `root_volume` - `volume_id` - The volume ID of the root volume of the server. +- `filesystem` + - `state` - The current status of the filesystem (e.g., attached, detached). - `private_ip` - The Scaleway internal IP address of the server (Deprecated use [ipam_ip datasource](../data-sources/ipam_ip.md#instance-private-network-ip) instead). - `public_ip` - The public IP address of the server (Deprecated use `public_ips` instead). - `public_ips` - The list of public IPs of the server. diff --git a/internal/services/file/filesystem.go b/internal/services/file/filesystem.go index 3e577e741e..13db89cc0f 100644 --- a/internal/services/file/filesystem.go +++ b/internal/services/file/filesystem.go @@ -2,6 +2,7 @@ package file import ( "context" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -37,10 +38,11 @@ func ResourceFileSystem() *schema.Resource { Optional: true, Description: "The name of the filesystem", }, - "size": { - Type: schema.TypeInt, - Required: true, - Description: "The Filesystem size in bytes, with a granularity of 100 GB (10^11 bytes). Must be compliant with the minimum (100 GB) and maximum (10 TB) allowed size.", + "size_in_gb": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 1000), + Description: "The Filesystem size_in_gb in bytes, with a granularity of 100 GB (10^11 bytes). Must be compliant with the minimum (100 GB) and maximum (10 TB) allowed size_in_gb.", }, "tags": { Type: schema.TypeList, @@ -87,10 +89,16 @@ func ResourceFileSystemCreate(ctx context.Context, d *schema.ResourceData, m any Region: region, Name: types.ExpandOrGenerateString(d.Get("name").(string), "file"), ProjectID: d.Get("project_id").(string), - Size: *types.ExpandUint64Ptr(d.Get("size")), + Size: *types.ExpandUint64Ptr(d.Get("size_in_gb")), Tags: types.ExpandStrings(d.Get("tags")), } + if size, ok := d.GetOk("size_in_gb"); ok { + sizeInGB := size.(int) + sizeInBytes := uint64(sizeInGB) * uint64(scw.GB) + req.Size = sizeInBytes + } + file, err := api.CreateFileSystem(req, scw.WithContext(ctx)) if err != nil { return diag.FromErr(err) @@ -128,7 +136,7 @@ func ResourceFileSystemRead(ctx context.Context, d *schema.ResourceData, m any) _ = d.Set("region", fileSystem.Region) _ = d.Set("organization_id", fileSystem.OrganizationID) _ = d.Set("status", fileSystem.Status) - _ = d.Set("size", int64(fileSystem.Size)) + _ = d.Set("size_in_gb", int(fileSystem.Size/scw.GB)) _ = d.Set("tags", fileSystem.Tags) _ = d.Set("created_at", fileSystem.CreatedAt.Format(time.RFC3339)) _ = d.Set("updated_at", fileSystem.UpdatedAt.Format(time.RFC3339)) @@ -163,8 +171,9 @@ func ResourceFileSystemUpdate(ctx context.Context, d *schema.ResourceData, m any req.Name = types.ExpandUpdatedStringPtr(d.Get("name")) } - if d.HasChange("size") { - req.Size = types.ExpandUint64Ptr(d.Get("size")) + if d.HasChange("size_in_gb") { + sizeInGB := uint64(d.Get("size_in_gb").(int)) * uint64(scw.GB) + req.Size = types.ExpandUint64Ptr(sizeInGB) } if d.HasChange("tags") { diff --git a/internal/services/file/filesystem_test.go b/internal/services/file/filesystem_test.go index 06b2347997..edeb3e9943 100644 --- a/internal/services/file/filesystem_test.go +++ b/internal/services/file/filesystem_test.go @@ -20,7 +20,7 @@ func TestAccFileSystem_Basic(t *testing.T) { fileSystemName := "TestAccFileSystem_Basic" fileSystemNameUpdated := "TestAccFileSystem_BasicUpdate" - size := int64(100_000_000_000) + sizeInGB := 100 resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -31,25 +31,25 @@ func TestAccFileSystem_Basic(t *testing.T) { Config: fmt.Sprintf(` resource "scaleway_file_filesystem" "fs" { name = "%s" - size = %d + size_in_gb = %d } - `, fileSystemName, size), + `, fileSystemName, sizeInGB), Check: resource.ComposeTestCheckFunc( testAccCheckFileSystemExists(tt, "scaleway_file_filesystem.fs"), resource.TestCheckResourceAttr("scaleway_file_filesystem.fs", "name", fileSystemName), - resource.TestCheckResourceAttr("scaleway_file_filesystem.fs", "size", strconv.FormatInt(size, 10)), + resource.TestCheckResourceAttr("scaleway_file_filesystem.fs", "size_in_gb", strconv.Itoa(sizeInGB)), ), }, { Config: fmt.Sprintf(` resource "scaleway_file_filesystem" "fs" { name = "%s" - size = %d + size_in_gb = %d } - `, fileSystemNameUpdated, size), + `, fileSystemNameUpdated, sizeInGB), Check: resource.ComposeTestCheckFunc( testAccCheckFileSystemExists(tt, "scaleway_file_filesystem.fs"), - resource.TestCheckResourceAttr("scaleway_file_filesystem.fs", "size", strconv.FormatInt(size, 10)), + resource.TestCheckResourceAttr("scaleway_file_filesystem.fs", "size_in_gb", strconv.Itoa(sizeInGB)), ), }, }, @@ -61,7 +61,7 @@ func TestAccFileSystem_SizeTooSmallFails(t *testing.T) { defer tt.Cleanup() fileSystemName := "TestAccFileSystem_SizeTooSmallFails" - size := int64(10_000_000_000) + sizeInGB := 10 resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -72,9 +72,9 @@ func TestAccFileSystem_SizeTooSmallFails(t *testing.T) { Config: fmt.Sprintf(` resource "scaleway_file_filesystem" "fs" { name = "%s" - size = %d + size_in_gb = %d } - `, fileSystemName, size), + `, fileSystemName, sizeInGB), ExpectError: regexp.MustCompile("size must be greater or equal to 100000000000"), }, }, @@ -86,7 +86,7 @@ func TestAccFileSystem_InvalidSizeGranularityFails(t *testing.T) { defer tt.Cleanup() fileSystemName := "TestAccFileSystem_InvalidSizeGranularityFails" - size := int64(25_000_000_000) + sizeInGB := 250 resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(t) }, @@ -97,10 +97,10 @@ func TestAccFileSystem_InvalidSizeGranularityFails(t *testing.T) { Config: fmt.Sprintf(` resource "scaleway_file_filesystem" "fs" { name = "%s" - size = %d + size_in_gb = %d } - `, fileSystemName, size), - ExpectError: regexp.MustCompile("size must be greater or equal to 100000000000"), + `, fileSystemName, sizeInGB), + ExpectError: regexp.MustCompile("size does not respect constraint, size must be a multiple of 100000000000"), }, }, }) diff --git a/internal/services/file/testdata/file-system-basic.cassette.yaml b/internal/services/file/testdata/file-system-basic.cassette.yaml index a5a78bd993..e0df6fc6dd 100644 --- a/internal/services/file/testdata/file-system-basic.cassette.yaml +++ b/internal/services/file/testdata/file-system-basic.cassette.yaml @@ -27,20 +27,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 377 + content_length: 367 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"creating","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"creating","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "377" + - "367" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:33 GMT + - Mon, 16 Jun 2025 12:40:20 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -48,10 +48,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 4df7f46a-4ead-45db-9d5f-b9e3ff8e472c + - 41978b6e-eff8-4b7d-8afc-f5e524fe6e13 status: 200 OK code: 200 - duration: 274.625083ms + duration: 176.580333ms - id: 1 request: proto: HTTP/1.1 @@ -68,7 +68,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -76,20 +76,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 377 + content_length: 367 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"creating","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"creating","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "377" + - "367" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:33 GMT + - Mon, 16 Jun 2025 12:40:20 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -97,10 +97,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 84d60524-ece9-4219-925a-fd3d5238e121 + - 63fb8928-9db5-48db-8645-59178ecabb10 status: 200 OK code: 200 - duration: 78.254833ms + duration: 43.219459ms - id: 2 request: proto: HTTP/1.1 @@ -117,7 +117,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -125,20 +125,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 378 + content_length: 368 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "378" + - "368" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:38 GMT + - Mon, 16 Jun 2025 12:40:25 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -146,10 +146,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 20f8bc16-b5f3-4aa8-93db-7e2110d7226f + - 6ee8ca43-dcbc-494d-be90-c8291b10acca status: 200 OK code: 200 - duration: 226.728042ms + duration: 482.33925ms - id: 3 request: proto: HTTP/1.1 @@ -166,7 +166,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -174,20 +174,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 378 + content_length: 368 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "378" + - "368" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:38 GMT + - Mon, 16 Jun 2025 12:40:25 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -195,10 +195,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 85533205-70f3-4507-8a2e-b5b5c872db7d + - ece86495-710f-4fcc-87c9-e7a903472caf status: 200 OK code: 200 - duration: 72.933083ms + duration: 61.259708ms - id: 4 request: proto: HTTP/1.1 @@ -215,7 +215,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -223,20 +223,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 378 + content_length: 368 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "378" + - "368" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:38 GMT + - Mon, 16 Jun 2025 12:40:25 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -244,10 +244,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - ffb6ba44-4198-402b-bade-9d1056f62c1e + - bb490fc0-5df0-4782-a65d-6e3df4108f0c status: 200 OK code: 200 - duration: 93.981208ms + duration: 63.040666ms - id: 5 request: proto: HTTP/1.1 @@ -264,7 +264,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -272,20 +272,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 378 + content_length: 368 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "378" + - "368" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:39 GMT + - Mon, 16 Jun 2025 12:40:26 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -293,10 +293,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 8d1980a9-616d-4cb7-8379-a965875aa615 + - 4f8b3f4a-35a2-4dd2-9e81-dd8da1539984 status: 200 OK code: 200 - duration: 147.937375ms + duration: 55.424458ms - id: 6 request: proto: HTTP/1.1 @@ -313,7 +313,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -321,20 +321,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 378 + content_length: 368 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "378" + - "368" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:40 GMT + - Mon, 16 Jun 2025 12:40:27 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -342,10 +342,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 279f4589-9a60-4355-af18-b065577575c3 + - 8f5924bc-9312-4c50-a92c-bf16a5d757a0 status: 200 OK code: 200 - duration: 96.605459ms + duration: 48.312833ms - id: 7 request: proto: HTTP/1.1 @@ -362,7 +362,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -370,20 +370,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 378 + content_length: 368 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_Basic","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "378" + - "368" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:41 GMT + - Mon, 16 Jun 2025 12:40:28 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -391,10 +391,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - f8975b8a-e0ed-45c2-9a8f-346bf790a5dc + - 8fae955b-906e-4fa5-9a70-25e64069e59f status: 200 OK code: 200 - duration: 73.752958ms + duration: 50.334708ms - id: 8 request: proto: HTTP/1.1 @@ -413,7 +413,7 @@ interactions: - application/json User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: PATCH response: proto: HTTP/2.0 @@ -421,20 +421,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 384 + content_length: 374 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "384" + - "374" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:41 GMT + - Mon, 16 Jun 2025 12:40:28 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -442,10 +442,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 51ef71a4-08af-419a-81e4-5909b1c7b3f8 + - f70a4f86-f671-4d02-9fe5-7a5af17d8bea status: 200 OK code: 200 - duration: 360.532708ms + duration: 100.775958ms - id: 9 request: proto: HTTP/1.1 @@ -462,7 +462,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -470,20 +470,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 384 + content_length: 374 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "384" + - "374" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:41 GMT + - Mon, 16 Jun 2025 12:40:28 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -491,10 +491,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - e9b678e6-2fa3-4f6c-9d33-dc266b7b6768 + - 47273c4c-c3db-4169-af5f-e892bf5e75a9 status: 200 OK code: 200 - duration: 119.121167ms + duration: 42.200667ms - id: 10 request: proto: HTTP/1.1 @@ -511,7 +511,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -519,20 +519,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 384 + content_length: 374 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "384" + - "374" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:42 GMT + - Mon, 16 Jun 2025 12:40:28 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -540,10 +540,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 50f62ab1-20a2-464c-89ed-a2e379cbf195 + - e317c6dd-2dd5-4c5d-86f8-530ea0467ce9 status: 200 OK code: 200 - duration: 216.022333ms + duration: 56.060375ms - id: 11 request: proto: HTTP/1.1 @@ -560,7 +560,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -568,20 +568,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 384 + content_length: 374 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "384" + - "374" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:42 GMT + - Mon, 16 Jun 2025 12:40:29 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -589,10 +589,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 65c3582f-73c5-4b28-8965-c819f2a6fae1 + - 25fa7dfe-b99c-49a6-b963-26da0e4bea41 status: 200 OK code: 200 - duration: 162.31775ms + duration: 65.977459ms - id: 12 request: proto: HTTP/1.1 @@ -609,7 +609,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -617,20 +617,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 384 + content_length: 374 uncompressed: false - body: '{"created_at":"2025-06-05T14:14:33.172071Z","id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-05T14:14:33.172071Z"}' + body: '{"created_at":"2025-06-16T12:40:19.942819Z","id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","name":"TestAccFileSystem_BasicUpdate","number_of_attachments":0,"organization_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","region":"fr-par","size":100000000000,"status":"available","tags":[],"updated_at":"2025-06-16T12:40:19.942819Z"}' headers: Content-Length: - - "384" + - "374" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:43 GMT + - Mon, 16 Jun 2025 12:40:30 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -638,10 +638,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - fe3263a9-6ccc-4d2f-9f86-2c4b3a5d4667 + - b7e9e1db-a32d-4673-b027-00a6b0a1dde6 status: 200 OK code: 200 - duration: 137.156792ms + duration: 41.812958ms - id: 13 request: proto: HTTP/1.1 @@ -658,7 +658,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: DELETE response: proto: HTTP/2.0 @@ -675,9 +675,9 @@ interactions: Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:44 GMT + - Mon, 16 Jun 2025 12:40:30 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -685,10 +685,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 190f61ce-0cbc-41e7-9bad-d44345208cba + - 6393c566-4efb-407d-9e7e-0f19ebbfd784 status: 204 No Content code: 204 - duration: 132.4795ms + duration: 82.050917ms - id: 14 request: proto: HTTP/1.1 @@ -705,7 +705,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -715,7 +715,7 @@ interactions: trailer: {} content_length: 131 uncompressed: false - body: '{"message":"resource is not found","resource":"filesystem","resource_id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","type":"not_found"}' + body: '{"message":"resource is not found","resource":"filesystem","resource_id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","type":"not_found"}' headers: Content-Length: - "131" @@ -724,9 +724,9 @@ interactions: Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:44 GMT + - Mon, 16 Jun 2025 12:40:30 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -734,10 +734,10 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - aea2d290-84b6-4302-ad90-f87143eb6f06 + - df373ae5-3b7a-475e-8976-47ece4e88f36 status: 404 Not Found code: 404 - duration: 87.874208ms + duration: 37.103625ms - id: 15 request: proto: HTTP/1.1 @@ -754,7 +754,7 @@ interactions: headers: User-Agent: - scaleway-sdk-go/v1.0.0-beta.7+dev (go1.24.1; darwin; arm64) terraform-provider/develop terraform/terraform-tests - url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/19c1099a-95a9-4ddb-85c4-1c609dfc4d34 + url: https://api.scaleway.com/file/v1alpha1/regions/fr-par/filesystems/f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b method: GET response: proto: HTTP/2.0 @@ -764,7 +764,7 @@ interactions: trailer: {} content_length: 131 uncompressed: false - body: '{"message":"resource is not found","resource":"filesystem","resource_id":"19c1099a-95a9-4ddb-85c4-1c609dfc4d34","type":"not_found"}' + body: '{"message":"resource is not found","resource":"filesystem","resource_id":"f92df0ae-6ba3-4f34-9576-9dbdb4bfde0b","type":"not_found"}' headers: Content-Length: - "131" @@ -773,9 +773,9 @@ interactions: Content-Type: - application/json Date: - - Thu, 05 Jun 2025 14:14:44 GMT + - Mon, 16 Jun 2025 12:40:30 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -783,7 +783,7 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - f458d891-e526-49da-99c3-8da82a0b0ef9 + - 308cf894-f126-4ba1-a643-d119c99717e7 status: 404 Not Found code: 404 - duration: 86.334708ms + duration: 37.545458ms diff --git a/internal/services/file/testdata/file-system-invalid-size-granularity-fails.cassette.yaml b/internal/services/file/testdata/file-system-invalid-size-granularity-fails.cassette.yaml index 3706bfef8a..a613a3a6bb 100644 --- a/internal/services/file/testdata/file-system-invalid-size-granularity-fails.cassette.yaml +++ b/internal/services/file/testdata/file-system-invalid-size-granularity-fails.cassette.yaml @@ -6,13 +6,13 @@ interactions: proto: HTTP/1.1 proto_major: 1 proto_minor: 1 - content_length: 137 + content_length: 138 transfer_encoding: [] trailer: {} host: api.scaleway.com remote_addr: "" request_uri: "" - body: '{"name":"TestAccFileSystem_InvalidSizeGranularityFails","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","size":25000000000,"tags":[]}' + body: '{"name":"TestAccFileSystem_InvalidSizeGranularityFails","project_id":"d3520a52-2c75-4ba0-bda8-82dd087f07f2","size":250000000000,"tags":[]}' form: {} headers: Content-Type: @@ -27,20 +27,20 @@ interactions: proto_minor: 0 transfer_encoding: [] trailer: {} - content_length: 182 + content_length: 176 uncompressed: false - body: '{"details":[{"argument_name":"size","help_message":"size must be greater or equal to 100000000000","reason":"constraint"}],"message":"invalid argument(s)","type":"invalid_arguments"}' + body: '{"details":[{"argument_name":"size","help_message":"size must be a multiple of 100000000000","reason":"constraint"}],"message":"invalid argument(s)","type":"invalid_arguments"}' headers: Content-Length: - - "182" + - "176" Content-Security-Policy: - default-src 'none'; frame-ancestors 'none' Content-Type: - application/json Date: - - Thu, 05 Jun 2025 15:04:00 GMT + - Mon, 16 Jun 2025 12:41:54 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -48,7 +48,7 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 1a3119e1-bf60-4f56-ae77-75a725054db8 + - c4b3c3a3-2afa-476e-aa57-0e45eac69c8d status: 400 Bad Request code: 400 - duration: 184.383ms + duration: 56.899875ms diff --git a/internal/services/file/testdata/file-system-size-too-small-fails.cassette.yaml b/internal/services/file/testdata/file-system-size-too-small-fails.cassette.yaml index 11bfd1ce3b..1b8487158b 100644 --- a/internal/services/file/testdata/file-system-size-too-small-fails.cassette.yaml +++ b/internal/services/file/testdata/file-system-size-too-small-fails.cassette.yaml @@ -38,9 +38,9 @@ interactions: Content-Type: - application/json Date: - - Thu, 05 Jun 2025 15:04:02 GMT + - Mon, 16 Jun 2025 12:40:19 GMT Server: - - Scaleway API Gateway (fr-par-1;edge01) + - Scaleway API Gateway (fr-par-1;edge02) Strict-Transport-Security: - max-age=63072000 X-Content-Type-Options: @@ -48,7 +48,7 @@ interactions: X-Frame-Options: - DENY X-Request-Id: - - 1fb11366-c9f7-412e-883d-fc8dd92c0d3d + - 0ec41b57-e5b9-4d56-94af-29939ef7c007 status: 400 Bad Request code: 400 - duration: 309.532458ms + duration: 66.228416ms diff --git a/internal/services/instance/helpers_instance.go b/internal/services/instance/helpers_instance.go index f7f0c79d0c..ad884f35e2 100644 --- a/internal/services/instance/helpers_instance.go +++ b/internal/services/instance/helpers_instance.go @@ -33,7 +33,7 @@ const ( // InstanceServerStateStandby transient state of the instance event waiting third action or rescue mode InstanceServerStateStandby = "standby" - DefaultInstanceServerWaitTimeout = 10 * time.Minute + DefaultInstanceServerWaitTimeout = 20 * time.Minute defaultInstancePrivateNICWaitTimeout = 10 * time.Minute defaultInstanceVolumeDeleteTimeout = 10 * time.Minute defaultInstanceSecurityGroupTimeout = 1 * time.Minute @@ -553,6 +553,57 @@ func getServerProjectID(ctx context.Context, api *instance.API, zone scw.Zone, s return server.Server.Project, nil } +func attachNewFileSystem(ctx context.Context, newIDs map[string]struct{}, oldIDs map[string]struct{}, api *instance.API, zone scw.Zone, server *instance.Server) error { + for id := range newIDs { + if _, alreadyAttached := oldIDs[id]; !alreadyAttached { + _, err := api.AttachServerFileSystem(&instance.AttachServerFileSystemRequest{ + Zone: zone, + ServerID: server.ID, + FilesystemID: locality.ExpandID(id), + }) + if err != nil { + return fmt.Errorf("error attaching filesystem %s: %w", id, err) + } + _, err = waitForFilesystems(ctx, api, zone, server.ID, *scw.TimeDurationPtr(DefaultInstanceServerWaitTimeout)) + if err != nil { + return err + } + } + } + + return nil +} + +func detachOldFileSystem(ctx context.Context, oldIDs map[string]struct{}, newIDs map[string]struct{}, api *instance.API, zone scw.Zone, server *instance.Server) error { + for id := range oldIDs { + if _, stillPresent := newIDs[id]; !stillPresent { + _, err := api.DetachServerFileSystem(&instance.DetachServerFileSystemRequest{ + Zone: zone, + ServerID: server.ID, + FilesystemID: locality.ExpandID(id), + }) + if err != nil { + return fmt.Errorf("error detaching filesystem %s: %w", id, err) + } + _, err = waitForFilesystems(ctx, api, zone, server.ID, *scw.TimeDurationPtr(DefaultInstanceServerWaitTimeout)) + if err != nil && !httperrors.Is404(err) { + return err + } + } + } + + return nil +} + +func collectFilesystemIDs(fsList []any, target map[string]struct{}) { + for _, fs := range fsList { + if fsMap, ok := fs.(map[string]any); ok { + id := fsMap["filesystem_id"].(string) + target[id] = struct{}{} + } + } +} + func DeleteASGServers( ctx context.Context, api *instance.API, diff --git a/internal/services/instance/server.go b/internal/services/instance/server.go index 9af336230e..5abd9a0aa8 100644 --- a/internal/services/instance/server.go +++ b/internal/services/instance/server.go @@ -192,6 +192,26 @@ func ResourceServer() *schema.Resource { Optional: true, Description: "The additional volumes attached to the server", }, + "filesystems": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Description: "Filesystems attach to the server", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "filesystem_id": { + Type: schema.TypeString, + Optional: true, + Description: "The filesystem ID attached to the server", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The state of the filesystem", + }, + }, + }, + }, "enable_ipv6": { Type: schema.TypeBool, Optional: true, @@ -528,6 +548,26 @@ func ResourceInstanceServerCreate(ctx context.Context, d *schema.ResourceData, m } } + /// + // Attach Filesystem + /// + + if filesystems, ok := d.GetOk("filesystems"); ok { + for _, filesystem := range filesystems.([]any) { + fs := filesystem.(map[string]any) + filesystemID := fs["filesystem_id"] + + _, err := api.AttachServerFileSystem(&instanceSDK.AttachServerFileSystemRequest{ + Zone: zone, + FilesystemID: regional.ExpandID(filesystemID.(string)).ID, + ServerID: res.Server.ID, + }) + if err != nil { + return diag.FromErr(err) + } + } + } + //// // Set user data //// @@ -653,6 +693,10 @@ func ResourceInstanceServerRead(ctx context.Context, d *schema.ResourceData, m a _ = d.Set("tags", server.Tags) } + if server.Filesystems != nil { + _ = d.Set("filesystems", flattenServerFileSystem(server.Zone, server.Filesystems)) + } + _ = d.Set("security_group_id", zonal.NewID(zone, server.SecurityGroup.ID).String()) // EnableIPv6 is deprecated _ = d.Set("enable_ipv6", server.EnableIPv6) //nolint:staticcheck @@ -1095,6 +1139,34 @@ func ResourceInstanceServerUpdate(ctx context.Context, d *schema.ResourceData, m } } + //// + // Update server filesystems + /// + + if d.HasChange("filesystems") { + oldRaw, newRaw := d.GetChange("filesystems") + + oldList := oldRaw.([]any) + newList := newRaw.([]any) + + oldIDs := make(map[string]struct{}) + newIDs := make(map[string]struct{}) + + collectFilesystemIDs(oldList, oldIDs) + collectFilesystemIDs(newList, newIDs) + + err := detachOldFileSystem(ctx, oldIDs, newIDs, api.API, zone, server) + if err != nil { + return diag.FromErr(err) + } + + err = attachNewFileSystem(ctx, newIDs, oldIDs, api.API, zone, server) + if err != nil { + return diag.FromErr(err) + } + + } + //// // Update server private network //// @@ -1226,6 +1298,35 @@ func ResourceInstanceServerDelete(ctx context.Context, d *schema.ResourceData, m return diag.FromErr(err) } + // Detach filesystem + if filesystems, ok := d.GetOk("filesystems"); ok { + fsList := filesystems.([]any) + for i, fsRaw := range fsList { + fsMap := fsRaw.(map[string]any) + + fsIDRaw, ok := fsMap["filesystem_id"] + if !ok || fsIDRaw == nil { + return diag.Errorf("filesystem_id is missing or nil for filesystem at index %d", i) + } + + fsID := fsIDRaw.(string) + + newFileSystemID := types.ExpandStringPtr(fsID) + if newFileSystemID == nil { + return diag.Errorf("failed to expand filesystem_id pointer at index %d", i) + } + + _, err = api.DetachServerFileSystem(&instanceSDK.DetachServerFileSystemRequest{ + Zone: zone, + ServerID: id, + FilesystemID: locality.ExpandID(*newFileSystemID), + }) + if err != nil { + return diag.FromErr(err) + } + } + } + // Delete private-nic if managed by instance_server resource if raw, ok := d.GetOk("private_network"); ok { ph, err := newPrivateNICHandler(api.API, id, zone) diff --git a/internal/services/instance/server_test.go b/internal/services/instance/server_test.go index 1fc4e70b6a..0157c1ba61 100644 --- a/internal/services/instance/server_test.go +++ b/internal/services/instance/server_test.go @@ -2098,6 +2098,189 @@ func TestAccServer_PrivateNetworkMissingPNIC(t *testing.T) { }) } +func TestAccServer_AttachDetachFileSystem(t *testing.T) { + tt := acctest.NewTestTools(t) + defer tt.Cleanup() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ProviderFactories: tt.ProviderFactories, + CheckDestroy: instancechecks.IsServerDestroyed(tt), + Steps: []resource.TestStep{ + { + Config: ` + resource "scaleway_block_volume" "volume" { + iops = 15000 + size_in_gb = 15 + } + + resource "scaleway_file_filesystem" "terraform_instance_filesystem"{ + name="filesystem-instance-terraform-test" + size_in_gb = 100 + } + + resource "scaleway_instance_server" "base" { + type = "POP2-HM-2C-16G" + state = "started" + tags = [ "terraform-test", "scaleway_instance_server", "state" ] + root_volume { + volume_type = "sbs_volume" + volume_id = scaleway_block_volume.volume.id + } + filesystems { + filesystem_id = scaleway_file_filesystem.terraform_instance_filesystem.id + } + }`, + Check: resource.ComposeTestCheckFunc( + isServerPresent(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "type", "POP2-HM-2C-16G"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.delete_on_termination", "true"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.size_in_gb", "15"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "root_volume.0.volume_id"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "filesystems.0.filesystem_id"), + serverHasNewVolume(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.0", "terraform-test"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.1", "scaleway_instance_server"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.2", "state"), + ), + }, + { + Config: ` + resource "scaleway_block_volume" "volume" { + iops = 15000 + size_in_gb = 15 + } + + resource "scaleway_file_filesystem" "terraform_instance_filesystem"{ + name="filesystem-instance-terraform-test" + size_in_gb = 100 + } + + resource "scaleway_file_filesystem" "terraform_instance_filesystem_2"{ + name="filesystem-instance-terraform-test-2" + size_in_gb = 100 + } + + resource "scaleway_instance_server" "base" { + type = "POP2-HM-2C-16G" + state = "started" + tags = [ "terraform-test", "scaleway_instance_server", "state" ] + root_volume { + volume_type = "sbs_volume" + volume_id = scaleway_block_volume.volume.id + } + + filesystems { + filesystem_id = scaleway_file_filesystem.terraform_instance_filesystem_2.id + } + }`, + Check: resource.ComposeTestCheckFunc( + isServerPresent(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "type", "POP2-HM-2C-16G"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.delete_on_termination", "true"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.size_in_gb", "15"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "root_volume.0.volume_id"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "filesystems.0.filesystem_id"), + resource.TestCheckNoResourceAttr("scaleway_instance_server.base", "filesystems.1.filesystem_id"), + serverHasNewVolume(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.0", "terraform-test"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.1", "scaleway_instance_server"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.2", "state"), + ), + }, + { + Config: ` + resource "scaleway_block_volume" "volume" { + iops = 15000 + size_in_gb = 15 + } + + resource "scaleway_file_filesystem" "terraform_instance_filesystem"{ + name="filesystem-instance-terraform-test" + size_in_gb = 100 + } + + resource "scaleway_file_filesystem" "terraform_instance_filesystem_2"{ + name="filesystem-instance-terraform-test-2" + size_in_gb = 100 + } + + resource "scaleway_instance_server" "base" { + type = "POP2-HM-2C-16G" + state = "started" + tags = [ "terraform-test", "scaleway_instance_server", "state" ] + root_volume { + volume_type = "sbs_volume" + volume_id = scaleway_block_volume.volume.id + } + filesystems { + filesystem_id = scaleway_file_filesystem.terraform_instance_filesystem_2.id + } + filesystems { + filesystem_id = scaleway_file_filesystem.terraform_instance_filesystem.id + } + }`, + Check: resource.ComposeTestCheckFunc( + isServerPresent(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "type", "POP2-HM-2C-16G"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.delete_on_termination", "true"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.size_in_gb", "15"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "root_volume.0.volume_id"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "filesystems.0.filesystem_id"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "filesystems.1.filesystem_id"), + serverHasNewVolume(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.0", "terraform-test"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.1", "scaleway_instance_server"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.2", "state"), + ), + }, + { + Config: ` + resource "scaleway_block_volume" "volume" { + iops = 15000 + size_in_gb = 15 + } + + resource "scaleway_file_filesystem" "terraform_instance_filesystem"{ + name="filesystem-instance-terraform-test" + size_in_gb = 100 + } + + resource "scaleway_file_filesystem" "terraform_instance_filesystem_2"{ + name="filesystem-instance-terraform-test-2" + size_in_gb = 100 + } + + resource "scaleway_instance_server" "base" { + type = "POP2-HM-2C-16G" + state = "started" + tags = [ "terraform-test", "scaleway_instance_server", "state" ] + root_volume { + volume_type = "sbs_volume" + volume_id = scaleway_block_volume.volume.id + } + + filesystems { + filesystem_id = scaleway_file_filesystem.terraform_instance_filesystem_2.id + } + }`, + Check: resource.ComposeTestCheckFunc( + isServerPresent(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "type", "POP2-HM-2C-16G"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.delete_on_termination", "true"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "root_volume.0.size_in_gb", "15"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "root_volume.0.volume_id"), + resource.TestCheckResourceAttrSet("scaleway_instance_server.base", "filesystems.0.filesystem_id"), + resource.TestCheckNoResourceAttr("scaleway_instance_server.base", "filesystems.1.filesystem_id"), + serverHasNewVolume(tt, "scaleway_instance_server.base"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.0", "terraform-test"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.1", "scaleway_instance_server"), + resource.TestCheckResourceAttr("scaleway_instance_server.base", "tags.2", "state"), + ), + }, + }, + }) +} + func TestAccServer_AdminPasswordEncryptionSSHKeyID(t *testing.T) { tt := acctest.NewTestTools(t) defer tt.Cleanup() diff --git a/internal/services/instance/types.go b/internal/services/instance/types.go index 7afb3f6d67..2935b464ca 100644 --- a/internal/services/instance/types.go +++ b/internal/services/instance/types.go @@ -5,6 +5,7 @@ import ( "github.com/scaleway/scaleway-sdk-go/api/instance/v1" "github.com/scaleway/scaleway-sdk-go/scw" + "github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional" "github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal" ) @@ -101,6 +102,20 @@ func flattenServerPublicIPs(zone scw.Zone, ips []*instance.ServerIP) []any { return flattenedIPs } +func flattenServerFileSystem(zone scw.Zone, fs []*instance.ServerFilesystem) []any { + filesystems := make([]any, len(fs)) + region, _ := zone.Region() + + for i, f := range fs { + filesystems[i] = map[string]any{ + "filesystem_id": regional.NewIDString(region, f.FilesystemID), + "status": f.State, + } + } + + return filesystems +} + func flattenServerIPIDs(ips []*instance.ServerIP) []any { ipIDs := make([]any, len(ips)) diff --git a/internal/services/instance/waiters.go b/internal/services/instance/waiters.go index bfafd398f5..6d3b43658c 100644 --- a/internal/services/instance/waiters.go +++ b/internal/services/instance/waiters.go @@ -91,3 +91,19 @@ func waitForImage(ctx context.Context, api *instance.API, zone scw.Zone, id stri return image, err } + +func waitForFilesystems(ctx context.Context, api *instance.API, zone scw.Zone, id string, timeout time.Duration) (*instance.Server, error) { + retryInterval := instancehelpers.DefaultInstanceRetryInterval + if transport.DefaultWaitRetryInterval != nil { + retryInterval = *transport.DefaultWaitRetryInterval + } + + server, err := api.WaitForServerFileSystem(&instance.WaitForServerFileSystemRequest{ + ServerID: id, + Zone: zone, + Timeout: scw.TimeDurationPtr(timeout), + RetryInterval: &retryInterval, + }, scw.WithContext(ctx)) + + return server, err +}