Skip to content
Draft
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
20 changes: 17 additions & 3 deletions internal/services/block/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/dsf"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/identity"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
Expand All @@ -34,6 +35,7 @@ func ResourceSnapshot() *schema.Resource {
},
SchemaVersion: 0,
SchemaFunc: snapshotSchema,
Identity: identity.DefaultZonal(),
}
}

Expand Down Expand Up @@ -153,7 +155,10 @@ func ResourceBlockSnapshotCreate(ctx context.Context, d *schema.ResourceData, m
}
}

d.SetId(zonal.NewIDString(zone, snapshot.ID))
err = identity.SetZonalIdentity(d, snapshot.Zone, snapshot.ID)
if err != nil {
return diag.FromErr(err)
}

_, err = waitForBlockSnapshot(ctx, api, zone, snapshot.ID, d.Timeout(schema.TimeoutCreate))
if err != nil {
Expand Down Expand Up @@ -194,6 +199,17 @@ func ResourceBlockSnapshotRead(ctx context.Context, d *schema.ResourceData, m an
return diag.FromErr(err)
}

setSnapshotState(d, snapshot)

err = identity.SetZonalIdentity(d, snapshot.Zone, snapshot.ID)
if err != nil {
return diag.FromErr(err)
}

return nil
}

func setSnapshotState(d *schema.ResourceData, snapshot *block.Snapshot) {
_ = d.Set("name", snapshot.Name)
_ = d.Set("zone", snapshot.Zone)
_ = d.Set("project_id", snapshot.ProjectID)
Expand All @@ -205,8 +221,6 @@ func ResourceBlockSnapshotRead(ctx context.Context, d *schema.ResourceData, m an
}

_ = d.Set("tags", snapshot.Tags)

return nil
}

func ResourceBlockSnapshotUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
Expand Down
19 changes: 13 additions & 6 deletions internal/services/block/snapshot_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
block "github.com/scaleway/scaleway-sdk-go/api/block/v1alpha1"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/datasource"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/types"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)
Expand Down Expand Up @@ -72,14 +73,20 @@ func DataSourceBlockSnapshotRead(ctx context.Context, d *schema.ResourceData, m
return diag.FromErr(err)
}

diags := ResourceBlockSnapshotRead(ctx, d, m)
if diags != nil {
return append(diags, diag.Errorf("failed to read snapshot state")...)
}
// Wait for the snapshot and use it to set the state
snapshot, err := waitForBlockSnapshot(ctx, api, zone, snapshotID.(string), d.Timeout(schema.TimeoutRead))
if err != nil {
Comment on lines +76 to +78
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waitForBlockSnapshot is called with snapshotID.(string), but snapshot_id is stored in state as a zoned ID (e.g. fr-par-1/<uuid>). On subsequent reads (or when the user provides a localized ID), this will pass the localized form to the Block API, which expects the raw UUID, and it also ignores the zone embedded in the ID. Parse the zoned ID (e.g. via zonal.ParseID / locality.ExpandID) and use the extracted id (and zone if present) when calling waitForBlockSnapshot.

Copilot uses AI. Check for mistakes.
if httperrors.Is404(err) {
d.SetId("")

return nil
Comment on lines +80 to +82
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a data source, swallowing a 404 by clearing d.SetId("") and returning nil will typically lead to confusing downstream behavior (empty/unknown data) instead of a clear failure. The rest of the codebase’s data sources return a "... not found" diagnostic when the remote object doesn’t exist; consider returning a diag.Errorf here (including the zoned ID) rather than silently succeeding.

Suggested change
d.SetId("")
return nil
return diag.Errorf("snapshot %s not found", zoneID)

Copilot uses AI. Check for mistakes.
}

if d.Id() == "" {
return diag.Errorf("snapshot (%s) not found", zoneID)
return diag.FromErr(err)
}

// Set the state using the snapshot from waitForBlockSnapshot
setSnapshotState(d, snapshot)

return nil
}
20 changes: 17 additions & 3 deletions internal/services/block/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/dsf"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/identity"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/account"
Expand Down Expand Up @@ -38,6 +39,7 @@ func ResourceVolume() *schema.Resource {
customDiffSnapshot("snapshot_id"),
customDiffCannotShrink("size_in_gb"),
),
Identity: identity.DefaultZonal(),
}
}

Expand Down Expand Up @@ -138,7 +140,10 @@ func ResourceBlockVolumeCreate(ctx context.Context, d *schema.ResourceData, m an
}
}

d.SetId(zonal.NewIDString(zone, volume.ID))
err = identity.SetZonalIdentity(d, volume.Zone, volume.ID)
if err != nil {
return diag.FromErr(err)
}

_, err = waitForBlockVolume(ctx, api.BlockAPI, zone, volume.ID, d.Timeout(schema.TimeoutCreate))
if err != nil {
Expand All @@ -165,6 +170,17 @@ func ResourceBlockVolumeRead(ctx context.Context, d *schema.ResourceData, m any)
return diag.FromErr(err)
}

setVolumeState(d, volume, api, zone)

err = identity.SetZonalIdentity(d, volume.Zone, volume.ID)
if err != nil {
return diag.FromErr(err)
}

return nil
}

func setVolumeState(d *schema.ResourceData, volume *block.Volume, api *block.API, zone scw.Zone) {
_ = d.Set("name", volume.Name)

if volume.Specs != nil {
Expand All @@ -189,8 +205,6 @@ func ResourceBlockVolumeRead(ctx context.Context, d *schema.ResourceData, m any)
}

_ = d.Set("snapshot_id", snapshotID)

return nil
}

func ResourceBlockVolumeUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
Expand Down
19 changes: 13 additions & 6 deletions internal/services/block/volume_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
block "github.com/scaleway/scaleway-sdk-go/api/block/v1alpha1"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/datasource"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/httperrors"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/types"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
)
Expand Down Expand Up @@ -71,14 +72,20 @@ func DataSourceBlockVolumeRead(ctx context.Context, d *schema.ResourceData, m an
return diag.FromErr(err)
}

diags := ResourceBlockVolumeRead(ctx, d, m)
if diags != nil {
return append(diags, diag.Errorf("failed to read volume state")...)
}
// Wait for the volume and use it to set the state
volume, err := waitForBlockVolume(ctx, api, zone, volumeID.(string), d.Timeout(schema.TimeoutRead))
if err != nil {
Comment on lines +75 to +77
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waitForBlockVolume is called with volumeID.(string), but volume_id is stored in state as a zoned ID (e.g. fr-par-1/<uuid>). On subsequent reads (or when the user provides a localized ID), this will pass the localized form to the Block API, which expects the raw UUID, and it also ignores the zone embedded in the ID. Parse the zoned ID (e.g. via zonal.ParseID / locality.ExpandID) and use the extracted id (and zone if present) when calling waitForBlockVolume.

Copilot uses AI. Check for mistakes.
if httperrors.Is404(err) {
d.SetId("")

return nil
Comment on lines +79 to +81
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a data source, swallowing a 404 by clearing d.SetId("") and returning nil will typically lead to confusing downstream behavior (empty/unknown data) instead of a clear failure. The rest of the codebase’s data sources return a "... not found" diagnostic when the remote object doesn’t exist; consider returning a diag.Errorf here (including the zoned ID) rather than silently succeeding.

Suggested change
d.SetId("")
return nil
return diag.Errorf("block volume %s not found", zoneID)

Copilot uses AI. Check for mistakes.
}

if d.Id() == "" {
return diag.Errorf("volume (%s) not found", zoneID)
return diag.FromErr(err)
}

// Set the state using the volume from waitForBlockVolume
setVolumeState(d, volume, api, zone)

return nil
}
2 changes: 0 additions & 2 deletions provider/sdkv2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ func TestSDKProvider_ResourceIdentityNotEmpty(t *testing.T) {
"scaleway_autoscaling_instance_policy",
"scaleway_autoscaling_instance_template",
"scaleway_baremetal_server",
"scaleway_block_snapshot",
"scaleway_block_volume",
"scaleway_cockpit",
"scaleway_cockpit_source",
"scaleway_cockpit_grafana_user",
Expand Down
Loading