Skip to content

Commit 4b05b36

Browse files
committed
feat: add mongodb instance snapshot action
1 parent b919f45 commit 4b05b36

File tree

6 files changed

+980
-0
lines changed

6 files changed

+980
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
subcategory: "MongoDB"
3+
page_title: "Scaleway: scaleway_mongodb_instance_snapshot_action"
4+
---
5+
6+
# scaleway_mongodb_instance_snapshot_action (Action)
7+
8+
<!-- action schema generated by tfplugindocs -->
9+
## Schema
10+
11+
### Required
12+
13+
- `expires_at` (String) Expiration date of the snapshot in RFC3339 format (ISO 8601).
14+
- `instance_id` (String) MongoDB instance ID to snapshot. Can be a plain UUID or a regional ID.
15+
16+
### Optional
17+
18+
- `name` (String) Name of the snapshot. If not set, a name will be generated.
19+
- `region` (String) Region of the MongoDB instance. If not set, the region is derived from the instance_id when possible or from the provider configuration.
20+
- `wait` (Boolean) Wait for the snapshot to reach a terminal state before returning.
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package mongodb
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
9+
"github.com/hashicorp/terraform-plugin-framework/action"
10+
"github.com/hashicorp/terraform-plugin-framework/action/schema"
11+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
12+
"github.com/hashicorp/terraform-plugin-framework/types"
13+
mongodb "github.com/scaleway/scaleway-sdk-go/api/mongodb/v1"
14+
"github.com/scaleway/scaleway-sdk-go/scw"
15+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
16+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
17+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
18+
)
19+
20+
var (
21+
_ action.Action = (*InstanceSnapshotAction)(nil)
22+
_ action.ActionWithConfigure = (*InstanceSnapshotAction)(nil)
23+
)
24+
25+
// InstanceSnapshotAction creates a snapshot for a MongoDB instance.
26+
type InstanceSnapshotAction struct {
27+
mongodbAPI *mongodb.API
28+
}
29+
30+
func (a *InstanceSnapshotAction) Configure(_ context.Context, req action.ConfigureRequest, resp *action.ConfigureResponse) {
31+
if req.ProviderData == nil {
32+
return
33+
}
34+
35+
m, ok := req.ProviderData.(*meta.Meta)
36+
if !ok {
37+
resp.Diagnostics.AddError(
38+
"Unexpected Action Configure Type",
39+
fmt.Sprintf("Expected *meta.Meta, got: %T. Please report this issue to the provider developers.", req.ProviderData),
40+
)
41+
42+
return
43+
}
44+
45+
a.mongodbAPI = newAPI(m)
46+
}
47+
48+
func (a *InstanceSnapshotAction) Metadata(_ context.Context, req action.MetadataRequest, resp *action.MetadataResponse) {
49+
resp.TypeName = req.ProviderTypeName + "_mongodb_instance_snapshot_action"
50+
}
51+
52+
type InstanceSnapshotActionModel struct {
53+
InstanceID types.String `tfsdk:"instance_id"`
54+
Region types.String `tfsdk:"region"`
55+
Name types.String `tfsdk:"name"`
56+
ExpiresAt types.String `tfsdk:"expires_at"`
57+
Wait types.Bool `tfsdk:"wait"`
58+
}
59+
60+
// NewInstanceSnapshotAction returns a new MongoDB instance snapshot action.
61+
func NewInstanceSnapshotAction() action.Action {
62+
return &InstanceSnapshotAction{}
63+
}
64+
65+
func (a *InstanceSnapshotAction) Schema(_ context.Context, _ action.SchemaRequest, resp *action.SchemaResponse) {
66+
resp.Schema = schema.Schema{
67+
Attributes: map[string]schema.Attribute{
68+
"instance_id": schema.StringAttribute{
69+
Required: true,
70+
Description: "MongoDB instance ID to snapshot. Can be a plain UUID or a regional ID.",
71+
Validators: []validator.String{
72+
stringvalidator.LengthAtLeast(1),
73+
},
74+
},
75+
"region": schema.StringAttribute{
76+
Optional: true,
77+
Description: "Region of the MongoDB instance. If not set, the region is derived from the instance_id when possible or from the provider configuration.",
78+
},
79+
"name": schema.StringAttribute{
80+
Optional: true,
81+
Description: "Name of the snapshot. If not set, a name will be generated.",
82+
},
83+
"expires_at": schema.StringAttribute{
84+
Required: true,
85+
Description: "Expiration date of the snapshot in RFC3339 format (ISO 8601).",
86+
},
87+
"wait": schema.BoolAttribute{
88+
Optional: true,
89+
Description: "Wait for the snapshot to reach a terminal state before returning.",
90+
},
91+
},
92+
}
93+
}
94+
95+
func (a *InstanceSnapshotAction) Invoke(ctx context.Context, req action.InvokeRequest, resp *action.InvokeResponse) {
96+
var data InstanceSnapshotActionModel
97+
98+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
99+
100+
if resp.Diagnostics.HasError() {
101+
return
102+
}
103+
104+
if a.mongodbAPI == nil {
105+
resp.Diagnostics.AddError(
106+
"Unconfigured mongodbAPI",
107+
"The action was not properly configured. The Scaleway client is missing. "+
108+
"This is usually a bug in the provider. Please report it to the maintainers.",
109+
)
110+
111+
return
112+
}
113+
114+
if data.InstanceID.IsNull() || data.InstanceID.ValueString() == "" {
115+
resp.Diagnostics.AddError(
116+
"Missing instance_id",
117+
"The instance_id attribute is required to create a MongoDB snapshot.",
118+
)
119+
120+
return
121+
}
122+
123+
instanceID := locality.ExpandID(data.InstanceID.ValueString())
124+
125+
var (
126+
region scw.Region
127+
err error
128+
)
129+
130+
if !data.Region.IsNull() && data.Region.ValueString() != "" {
131+
region = scw.Region(data.Region.ValueString())
132+
} else {
133+
// Try to derive region from the instance_id if it is a regional ID.
134+
if derivedRegion, id, parseErr := regional.ParseID(data.InstanceID.ValueString()); parseErr == nil {
135+
region = derivedRegion
136+
instanceID = id
137+
}
138+
}
139+
140+
snapshotName := data.Name.ValueString()
141+
if snapshotName == "" {
142+
snapshotName = "tf-mongodb-snapshot"
143+
}
144+
145+
expirationRaw := data.ExpiresAt.ValueString()
146+
147+
expirationTime, err := time.Parse(time.RFC3339, expirationRaw)
148+
if err != nil {
149+
resp.Diagnostics.AddError(
150+
"Invalid expires_at value",
151+
fmt.Sprintf("The expires_at attribute must be a valid RFC3339 timestamp. Got %q: %s", expirationRaw, err),
152+
)
153+
154+
return
155+
}
156+
157+
createReq := &mongodb.CreateSnapshotRequest{
158+
InstanceID: instanceID,
159+
Name: snapshotName,
160+
ExpiresAt: &expirationTime,
161+
}
162+
163+
if region != "" {
164+
createReq.Region = region
165+
}
166+
167+
snapshot, err := a.mongodbAPI.CreateSnapshot(createReq, scw.WithContext(ctx))
168+
if err != nil {
169+
resp.Diagnostics.AddError(
170+
"Error executing MongoDB CreateSnapshot action",
171+
fmt.Sprintf("Failed to create snapshot for instance %s: %s", instanceID, err),
172+
)
173+
174+
return
175+
}
176+
177+
if data.Wait.ValueBool() {
178+
waitRegion := snapshot.Region
179+
if waitRegion == "" && region != "" {
180+
waitRegion = region
181+
}
182+
183+
if waitRegion == "" {
184+
resp.Diagnostics.AddError(
185+
"Missing region for wait operation",
186+
"Could not determine region to wait for MongoDB snapshot completion.",
187+
)
188+
189+
return
190+
}
191+
192+
_, err = waitForSnapshot(ctx, a.mongodbAPI, waitRegion, instanceID, snapshot.ID, defaultMongodbSnapshotTimeout)
193+
if err != nil {
194+
resp.Diagnostics.AddError(
195+
"Error waiting for MongoDB snapshot completion",
196+
fmt.Sprintf("Snapshot %s for instance %s did not reach a terminal state: %s", snapshot.ID, instanceID, err),
197+
)
198+
199+
return
200+
}
201+
}
202+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package mongodb_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
7+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/acctest"
8+
)
9+
10+
func TestAccActionMongoDBInstanceSnapshot_Basic(t *testing.T) {
11+
if acctest.IsRunningOpenTofu() {
12+
t.Skip("Skipping TestAccActionMongoDBInstanceSnapshot_Basic because actions are not yet supported on OpenTofu")
13+
}
14+
15+
tt := acctest.NewTestTools(t)
16+
defer tt.Cleanup()
17+
18+
resource.ParallelTest(t, resource.TestCase{
19+
ProtoV6ProviderFactories: tt.ProviderFactories,
20+
Steps: []resource.TestStep{
21+
{
22+
Config: `
23+
resource "scaleway_mongodb_instance" "main" {
24+
name = "test-mongodb-action-snapshot"
25+
version = "7.0.12"
26+
node_type = "MGDB-PLAY2-NANO"
27+
node_number = 1
28+
user_name = "my_initial_user"
29+
password = "thiZ_is_v&ry_s3cret"
30+
31+
lifecycle {
32+
action_trigger {
33+
events = [after_create]
34+
actions = [action.scaleway_mongodb_instance_snapshot_action.main]
35+
}
36+
}
37+
}
38+
39+
action "scaleway_mongodb_instance_snapshot_action" "main" {
40+
config {
41+
instance_id = scaleway_mongodb_instance.main.id
42+
name = "tf-acc-mongodb-instance-snapshot-action"
43+
expires_at = "2026-11-01T00:00:00Z"
44+
wait = true
45+
}
46+
}
47+
`,
48+
},
49+
},
50+
})
51+
}

0 commit comments

Comments
 (0)