Skip to content

feat(file): add support v1beta1 #3141

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

Merged
merged 16 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 5 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,8 @@ webhosting:
- changed-files:
- any-glob-to-any-file:
- internal/services/webhosting/**
file:
- changed-files:
- any-glob-to-any-file:
- internal/services/file/**

1 change: 1 addition & 0 deletions .github/workflows/acceptance-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
- cockpit
- container
- domain
- file
- flexibleip
- function
- iam
Expand Down
52 changes: 52 additions & 0 deletions docs/resources/file_filesystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
subcategory: "File"
page_title: "Scaleway: scaleway_file_filesystem"
---

# Resource: scaleway_file_filesystem

Creates and manages a Scaleway File Storage (NFS) filesystem in a specific region. A filesystem is a scalable storage resource that can be mounted on Compute instances and is typically used for shared, persistent storage.

This resource allows you to define and manage the size, tags, and region of a filesystem, and track its creation and update timestamps, current status, and number of active attachments.

## Example Usage

### Basic

```terraform
resource scaleway_file_filesystem file {
name = "my-nfs-filesystem"
size = 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).
- Minimum: 100 GB (100000000000 bytes)
- Maximum: 10 TB (10000000000000 bytes)
- `tags` - (Optional) A list of tags associated with the filesystem.
- `region` - (Defaults to [provider](../index.md#region) `region`) The region where the filesystem will be created (e.g., fr-par, nl-ams).
- `project_id` - (Defaults to [provider](../index.md#project_id) `project_id`) The ID of the project the server is
associated with.
- `organization_id` - (Defaults to [provider](../index.md#organization_id) `organization_id`) The ID of the organization the user is associated with.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

- `id` - The ID of the filesystem.
- `status` - The current status of the filesystem. Possible values include creating, available, etc.
- `number_of_attachments` - The number of active attachments (mounts) on the filesystem.
- `created_at` - The date and time when the File Storage filesystem was created.
- `updated_at` - The date and time of the last update to the File Storage filesystem.

## Import


File Storage filesystems can be imported using the `{region}/{id}`, e.g.

```bash
terraform import scaleway_file_filesystem.main fr-par/11111111-1111-1111-1111-111111111111
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/nats-io/jwt/v2 v2.7.4
github.com/nats-io/nats.go v1.38.0
github.com/robfig/cron/v3 v3.0.1
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250604134054-a06406d42247
github.com/stretchr/testify v1.10.0
golang.org/x/crypto v0.38.0
gopkg.in/dnaeon/go-vcr.v3 v3.2.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,8 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b h1:wzu3hPSNK2PPo7OXBzofeS5hOWqnVRP8xqIXom9ufoc=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250512145715-0fc65cc3636b/go.mod h1:qiGzapFyNPFwBBLJ+hTFykKSnU95n1zL64+o1ubmwf0=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250604134054-a06406d42247 h1:wlIvcSpGl3mGDpQmwrZHnYMIlB7Mwx3bhg151LG22Ws=
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.33.0.20250604134054-a06406d42247/go.mod h1:qiGzapFyNPFwBBLJ+hTFykKSnU95n1zL64+o1ubmwf0=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
Expand Down
22 changes: 12 additions & 10 deletions internal/acctest/validate_cassettes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ import (

func exceptionsCassettesCases() map[string]struct{} {
return map[string]struct{}{
"../services/mnq/testdata/sns-topic-basic.cassette.yaml": {},
"../services/mnq/testdata/sns-topic-subscription-basic.cassette.yaml": {},
"../services/mnq/testdata/sqs-already-activated.cassette.yaml": {},
"../services/object/testdata/bucket-cors-empty-origin.cassette.yaml": {},
"../services/object/testdata/bucket-destroy-force.cassette.yaml": {},
"../services/rdb/testdata/data-source-privilege-basic.cassette.yaml": {},
"../services/rdb/testdata/privilege-basic.cassette.yaml": {},
"../services/object/testdata/object-bucket-destroy-force.cassette.yaml": {},
"../services/secret/testdata/secret-protected.cassette.yaml": {},
"../services/secret/testdata/secret-version-type.cassette.yaml": {},
"../services/mnq/testdata/sns-topic-basic.cassette.yaml": {},
"../services/mnq/testdata/sns-topic-subscription-basic.cassette.yaml": {},
"../services/mnq/testdata/sqs-already-activated.cassette.yaml": {},
"../services/object/testdata/bucket-cors-empty-origin.cassette.yaml": {},
"../services/object/testdata/bucket-destroy-force.cassette.yaml": {},
"../services/rdb/testdata/data-source-privilege-basic.cassette.yaml": {},
"../services/rdb/testdata/privilege-basic.cassette.yaml": {},
"../services/object/testdata/object-bucket-destroy-force.cassette.yaml": {},
"../services/secret/testdata/secret-protected.cassette.yaml": {},
"../services/secret/testdata/secret-version-type.cassette.yaml": {},
"../services/file/testdata/file-system-invalid-size-granularity-fails.cassette.yaml": {},
"../services/file/testdata/file-system-size-too-small-fails.cassette.yaml": {},
}
}

Expand Down
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/container"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/domain"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/edgeservices"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/file"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/flexibleip"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/function"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/iam"
Expand Down Expand Up @@ -151,6 +152,7 @@ func Provider(config *Config) plugin.ProviderFunc {
"scaleway_edge_services_route_stage": edgeservices.ResourceRouteStage(),
"scaleway_edge_services_tls_stage": edgeservices.ResourceTLSStage(),
"scaleway_edge_services_waf_stage": edgeservices.ResourceWAFStage(),
"scaleway_file_filesystem": file.ResourceFileSystem(),
"scaleway_flexible_ip": flexibleip.ResourceIP(),
"scaleway_flexible_ip_mac_address": flexibleip.ResourceMACAddress(),
"scaleway_function": function.ResourceFunction(),
Expand Down
212 changes: 212 additions & 0 deletions internal/services/file/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package file

import (
"context"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
file "github.com/scaleway/scaleway-sdk-go/api/file/v1alpha1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/account"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/types"
)

func ResourceFileSystem() *schema.Resource {
return &schema.Resource{
CreateContext: ResourceFileSystemCreate,
ReadContext: ResourceFileSystemRead,
UpdateContext: ResourceFileSystemUpdate,
DeleteContext: ResourceFileSystemDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(defaultFileSystemTimeout),
Read: schema.DefaultTimeout(defaultFileSystemTimeout),
Delete: schema.DefaultTimeout(defaultFileSystemTimeout),
Default: schema.DefaultTimeout(defaultFileSystemTimeout),
},
SchemaVersion: 0,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Computed: true,
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.",
},
"tags": {
Type: schema.TypeList,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
Description: "The list of tags assigned to the filesystem",
},
"project_id": account.ProjectIDSchema(),
"organization_id": account.OrganizationIDSchema(),
"region": regional.Schema(),
"status": {
Type: schema.TypeString,
Computed: true,
Description: "The Current status of the filesystem (e.g. creating, available, ...)",
},
"number_of_attachments": {
Type: schema.TypeInt,
Computed: true,
Description: "The current number of attachments (mounts) that the filesystem has",
},
"created_at": {
Type: schema.TypeString,
Computed: true,
Description: "The creation date of the filesystem",
},
"updated_at": {
Type: schema.TypeString,
Computed: true,
Description: "The last update date of the properties of the filesystem",
},
},
}
}

func ResourceFileSystemCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api, region, err := fileSystemAPIWithZone(d, m)
if err != nil {
return diag.FromErr(err)
}

req := &file.CreateFileSystemRequest{
Region: region,
Name: types.ExpandOrGenerateString(d.Get("name").(string), "file"),
ProjectID: d.Get("project_id").(string),
Size: *types.ExpandUint64Ptr(d.Get("size")),
Tags: types.ExpandStrings(d.Get("tags")),
}

file, err := api.CreateFileSystem(req, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

d.SetId(regional.NewIDString(region, file.ID))

_, err = waitForFileSystem(ctx, api, region, file.ID, d.Timeout(schema.TimeoutCreate))
if err != nil {
return diag.FromErr(err)
}

return ResourceFileSystemRead(ctx, d, m)
}

func ResourceFileSystemRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api, region, id, err := NewAPIWithRegionAndID(m, d.Id())
if err != nil {
return diag.FromErr(err)
}

fileSystem, err := waitForFileSystem(ctx, api, region, id, d.Timeout(schema.TimeoutRead))
if err != nil {
if httperrors.Is404(err) {
d.SetId("")

return nil
}

return diag.FromErr(err)
}

_ = d.Set("name", fileSystem.Name)
_ = d.Set("project_id", fileSystem.ProjectID)
_ = d.Set("region", fileSystem.Region)
_ = d.Set("organization_id", fileSystem.OrganizationID)
_ = d.Set("status", fileSystem.Status)
_ = d.Set("size", int64(fileSystem.Size))
_ = d.Set("tags", fileSystem.Tags)
_ = d.Set("created_at", fileSystem.CreatedAt.Format(time.RFC3339))
_ = d.Set("updated_at", fileSystem.UpdatedAt.Format(time.RFC3339))
_ = d.Set("number_of_attachments", int64(fileSystem.NumberOfAttachments))

return nil
}

func ResourceFileSystemUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api, region, id, err := NewAPIWithRegionAndID(m, d.Id())
if err != nil {
return diag.FromErr(err)
}

fileSystem, err := waitForFileSystem(ctx, api, region, id, d.Timeout(schema.TimeoutUpdate))
if err != nil {
if httperrors.Is404(err) {
d.SetId("")

return nil
}

return diag.FromErr(err)
}

req := &file.UpdateFileSystemRequest{
Region: region,
FilesystemID: fileSystem.ID,
}

if d.HasChange("name") {
req.Name = types.ExpandUpdatedStringPtr(d.Get("name"))
}

if d.HasChange("size") {
req.Size = types.ExpandUint64Ptr(d.Get("size"))
}

if d.HasChange("tags") {
req.Tags = types.ExpandStringsPtr(d.Get("tags"))
}

if _, err := api.UpdateFileSystem(req, scw.WithContext(ctx)); err != nil {
return diag.FromErr(err)
}

return ResourceFileSystemRead(ctx, d, m)
}

func ResourceFileSystemDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
api, region, id, err := NewAPIWithRegionAndID(m, d.Id())
if err != nil {
return diag.FromErr(err)
}

_, err = waitForFileSystem(ctx, api, region, id, d.Timeout(schema.TimeoutDelete))
if err != nil {
if httperrors.Is404(err) {
d.SetId("")

return nil
}

return diag.FromErr(err)
}

err = api.DeleteFileSystem(&file.DeleteFileSystemRequest{
Region: region,
FilesystemID: id,
}, scw.WithContext(ctx))
if err != nil {
return diag.FromErr(err)
}

_, err = waitForFileSystem(ctx, api, region, id, d.Timeout(schema.TimeoutDelete))
if err != nil && !httperrors.Is404(err) {
return diag.FromErr(err)
}

return nil
}
Loading
Loading