Skip to content

Commit c830cde

Browse files
committed
feat(mongodb): add snapshot and test
1 parent cead9b1 commit c830cde

File tree

9 files changed

+571
-214
lines changed

9 files changed

+571
-214
lines changed

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ func Provider(config *Config) plugin.ProviderFunc {
188188
"scaleway_mnq_sqs_credentials": mnq.ResourceSQSCredentials(),
189189
"scaleway_mnq_sqs_queue": mnq.ResourceSQSQueue(),
190190
"scaleway_mongodb_instance": mongodb.ResourceInstance(),
191+
"scaleway_mongodb_snapshot": mongodb.ResourceSnapshot(),
191192
"scaleway_object": object.ResourceObject(),
192193
"scaleway_object_bucket": object.ResourceBucket(),
193194
"scaleway_object_bucket_acl": object.ResourceBucketACL(),

internal/services/mongodb/helpers.go

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package redis
1+
package mongodb
22

33
import (
44
"bytes"
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1111
mongodb "github.com/scaleway/scaleway-sdk-go/api/mongodb/v1alpha1"
12-
"github.com/scaleway/scaleway-sdk-go/api/redis/v1"
1312
"github.com/scaleway/scaleway-sdk-go/scw"
1413
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
1514
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
@@ -19,8 +18,13 @@ import (
1918
)
2019

2120
const (
22-
defaultRedisClusterTimeout = 15 * time.Minute
23-
defaultWaitRedisClusterRetryInterval = 5 * time.Second
21+
defaultMongodbInstanceTimeout = 15 * time.Minute
22+
defaultMongodbSnapshotTimeout = 15 * time.Minute
23+
defaultWaitMongodbInstanceRetryInterval = 5 * time.Second
24+
)
25+
26+
const (
27+
defaultVolumeSize = 5
2428
)
2529

2630
func newAPI(m interface{}) *mongodb.API {
@@ -36,34 +40,83 @@ func newAPIWithZone(d *schema.ResourceData, m interface{}) (*mongodb.API, scw.Zo
3640
return newAPI(m), zone, nil
3741
}
3842

43+
func newAPIWithZoneAndRegion(d *schema.ResourceData, m interface{}) (*mongodb.API, scw.Zone, scw.Region, error) {
44+
zone, err := meta.ExtractZone(d, m)
45+
if err != nil {
46+
return nil, "", "", err
47+
}
48+
region, err := meta.ExtractRegion(d, m)
49+
if err != nil {
50+
return nil, "", "", err
51+
}
52+
return newAPI(m), zone, region, nil
53+
}
54+
55+
func newAPIWithRegion(d *schema.ResourceData, m interface{}) (*mongodb.API, scw.Region, error) {
56+
region, err := meta.ExtractRegion(d, m)
57+
if err != nil {
58+
return nil, "", err
59+
}
60+
return newAPI(m), region, nil
61+
}
62+
3963
// NewAPIWithZoneAndID returns a Redis API with zone and ID extracted from the state
40-
func NewAPIWithZoneAndID(m interface{}, id string) (*redis.API, scw.Zone, string, error) {
64+
func NewAPIWithZoneAndID(m interface{}, id string) (*mongodb.API, scw.Zone, string, error) {
4165
zone, ID, err := zonal.ParseID(id)
4266
if err != nil {
4367
return nil, "", "", err
4468
}
4569
return newAPI(m), zone, ID, nil
4670
}
4771

48-
func waitForInstance(ctx context.Context, api *mongodb.API, zone scw.Zone, id string, timeout time.Duration) (*redis.Cluster, error) {
49-
retryInterval := defaultWaitRedisClusterRetryInterval
72+
func NewAPIWithRegionAndID(m interface{}, id string) (*mongodb.API, scw.Region, string, error) {
73+
zone, ID, err := zonal.ParseID(id)
74+
if err != nil {
75+
return nil, "", "", err
76+
}
77+
region, err := zone.Region()
78+
if err != nil {
79+
return nil, "", "", err
80+
}
81+
return newAPI(m), region, ID, nil
82+
}
83+
84+
func NewAPIWithID(m interface{}, id string) (*mongodb.API, scw.Region, string, error) {
85+
zone, ID, err := zonal.ParseID(id)
86+
if err != nil {
87+
return nil, "", "", err
88+
}
89+
region, err := zone.Region()
90+
if err != nil {
91+
return nil, "", "", err
92+
}
93+
return newAPI(m), region, ID, nil
94+
}
95+
96+
func waitForInstance(ctx context.Context, api *mongodb.API, region scw.Region, id string, timeout time.Duration) (*mongodb.Instance, error) {
97+
retryInterval := defaultWaitMongodbInstanceRetryInterval
5098
if transport.DefaultWaitRetryInterval != nil {
5199
retryInterval = *transport.DefaultWaitRetryInterval
52100
}
53-
54-
return api.WaitForInstance()
101+
return api.WaitForInstance(&mongodb.WaitForInstanceRequest{
102+
Timeout: scw.TimeDurationPtr(timeout),
103+
InstanceID: id,
104+
Region: region,
105+
RetryInterval: &retryInterval,
106+
}, scw.WithContext(ctx))
55107
}
56108

57-
func waitForCluster(ctx context.Context, api *redis.API, zone scw.Zone, id string, timeout time.Duration) (*redis.Cluster, error) {
58-
retryInterval := defaultWaitRedisClusterRetryInterval
109+
func waitForSnapshot(ctx context.Context, api *mongodb.API, region scw.Region, instanceID string, snapshotID string, timeout time.Duration) (*mongodb.Snapshot, error) {
110+
retryInterval := defaultWaitMongodbInstanceRetryInterval
59111
if transport.DefaultWaitRetryInterval != nil {
60112
retryInterval = *transport.DefaultWaitRetryInterval
61113
}
62114

63-
return api.WaitForCluster(&redis.WaitForClusterRequest{
64-
Zone: zone,
115+
return api.WaitForSnapshot(&mongodb.WaitForSnapshotRequest{
65116
Timeout: scw.TimeDurationPtr(timeout),
66-
ClusterID: id,
117+
InstanceID: instanceID,
118+
SnapshotID: snapshotID,
119+
Region: region,
67120
RetryInterval: &retryInterval,
68121
}, scw.WithContext(ctx))
69122
}

internal/services/mongodb/instance.go

Lines changed: 90 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package mongodb
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"strings"
78
"time"
89

@@ -48,12 +49,12 @@ func ResourceInstance() *schema.Resource {
4849
},
4950
"version": {
5051
Type: schema.TypeString,
51-
Required: true,
52+
Optional: true,
5253
Description: "Mongodb version of the instance",
5354
},
5455
"node_number": {
5556
Type: schema.TypeInt,
56-
Required: true,
57+
Optional: true,
5758
Description: "number of node in the instance",
5859
},
5960
"node_type": {
@@ -64,13 +65,13 @@ func ResourceInstance() *schema.Resource {
6465
},
6566
"user_name": {
6667
Type: schema.TypeString,
67-
Required: true,
68+
Optional: true,
6869
Description: "Name of the user created when the cluster is created",
6970
},
7071
"password": {
7172
Type: schema.TypeString,
7273
Sensitive: true,
73-
Required: true,
74+
Optional: true,
7475
Description: "Password of the user",
7576
},
7677
// volume
@@ -87,6 +88,12 @@ func ResourceInstance() *schema.Resource {
8788
Description: "Volume size (in GB)",
8889
ValidateFunc: validation.IntDivisibleBy(5),
8990
},
91+
"snapshot_id": {
92+
Type: schema.TypeString,
93+
Optional: true,
94+
ForceNew: true,
95+
Description: "Snapshot id",
96+
},
9097
//endpoint
9198
"private_network": {
9299
Type: schema.TypeSet,
@@ -189,14 +196,33 @@ func ResourceInstance() *schema.Resource {
189196
"updated_at": {
190197
Type: schema.TypeString,
191198
Computed: true,
192-
Description: "The date and time of the last update of the Redis cluster",
199+
Description: "The date and time of the last update of the Mongodb instance",
193200
},
194201
// Common
195202
"region": regional.Schema(),
196203
"project_id": account.ProjectIDSchema(),
197204
},
198205
CustomizeDiff: customdiff.All(
199206
cdf.LocalityCheck("private_network.#.id"),
207+
func(ctx context.Context, diff *schema.ResourceDiff, v interface{}) error {
208+
snapshotID := diff.Get("snapshot_id")
209+
210+
if snapshotID == nil || snapshotID == "" {
211+
if diff.Get("user_name") == nil || diff.Get("user_name") == "" {
212+
return fmt.Errorf("`user_name` must be provided when `snapshot_id` is not set")
213+
}
214+
if diff.Get("password") == nil || diff.Get("password") == "" {
215+
return fmt.Errorf("`password` must be provided when `snapshot_id` is not set")
216+
}
217+
if diff.Get("version") == nil || diff.Get("version") == "" {
218+
return fmt.Errorf("`version` must be provided when `snapshot_id` is not set")
219+
}
220+
if diff.Get("node_number") == nil || diff.Get("node_number") == "" {
221+
return fmt.Errorf("`node_number` must be provided when `snapshot_id` is not set")
222+
}
223+
}
224+
return nil
225+
},
200226
),
201227
}
202228
}
@@ -209,52 +235,70 @@ func ResourceInstanceCreate(ctx context.Context, d *schema.ResourceData, m inter
209235
}
210236

211237
nodeNumber := scw.Uint32Ptr(uint32(d.Get("node_number").(int)))
212-
createReq := &mongodb.CreateInstanceRequest{
213-
ProjectID: d.Get("project_id").(string),
214-
Name: types.ExpandOrGenerateString(d.Get("name"), "mongodb"),
215-
Version: d.Get("version").(string),
216-
NodeType: d.Get("node_type").(string),
217-
NodeNumber: *nodeNumber,
218-
UserName: d.Get("user_name").(string),
219-
Password: d.Get("password").(string),
220-
}
221238

222-
volumeRequestDetails := &mongodb.CreateInstanceRequestVolumeDetails{
223-
VolumeType: mongodb.VolumeType(d.Get("volume_type").(string)),
224-
}
225-
volumeSize, volumeSizeExist := d.GetOk("volume_size_in_gb")
226-
if volumeSizeExist {
227-
volumeRequestDetails.VolumeSize = scw.Size(uint64(volumeSize.(int)) * uint64(scw.GB))
239+
snapshotID, exist := d.GetOk("snapshot_id")
240+
res := &mongodb.Instance{}
241+
if exist {
242+
volume := &mongodb.RestoreSnapshotRequestVolumeDetails{
243+
VolumeType: mongodb.VolumeType(d.Get("volume_type").(string)),
244+
}
245+
restoreSnapshotRequest := &mongodb.RestoreSnapshotRequest{
246+
SnapshotID: snapshotID.(string),
247+
InstanceName: types.ExpandOrGenerateString(d.Get("name"), "mongodb"),
248+
NodeType: d.Get("node_type").(string),
249+
Volume: volume,
250+
}
251+
res, err = mongodbAPI.RestoreSnapshot(restoreSnapshotRequest, scw.WithContext(ctx))
252+
if err != nil {
253+
return diag.FromErr(err)
254+
}
228255
} else {
229-
volumeRequestDetails.VolumeSize = scw.Size(defaultVolumeSize * uint64(scw.GB))
230-
}
231-
createReq.Volume = volumeRequestDetails
232256

233-
tags, tagsExist := d.GetOk("tags")
234-
if tagsExist {
235-
createReq.Tags = types.ExpandStrings(tags)
236-
}
257+
createReq := &mongodb.CreateInstanceRequest{
258+
ProjectID: d.Get("project_id").(string),
259+
Name: types.ExpandOrGenerateString(d.Get("name"), "mongodb"),
260+
Version: d.Get("version").(string),
261+
NodeType: d.Get("node_type").(string),
262+
NodeNumber: *nodeNumber,
263+
UserName: d.Get("user_name").(string),
264+
Password: d.Get("password").(string),
265+
}
266+
267+
volumeRequestDetails := &mongodb.CreateInstanceRequestVolumeDetails{
268+
VolumeType: mongodb.VolumeType(d.Get("volume_type").(string)),
269+
}
270+
volumeSize, volumeSizeExist := d.GetOk("volume_size_in_gb")
271+
if volumeSizeExist {
272+
volumeRequestDetails.VolumeSize = scw.Size(uint64(volumeSize.(int)) * uint64(scw.GB))
273+
} else {
274+
volumeRequestDetails.VolumeSize = scw.Size(defaultVolumeSize * uint64(scw.GB))
275+
}
276+
createReq.Volume = volumeRequestDetails
237277

238-
pn, pnExists := d.GetOk("private_network")
239-
if pnExists {
240-
pnSpecs, err := expandPrivateNetwork(pn.(*schema.Set).List())
278+
tags, tagsExist := d.GetOk("tags")
279+
if tagsExist {
280+
createReq.Tags = types.ExpandStrings(tags)
281+
}
282+
283+
pn, pnExists := d.GetOk("private_network")
284+
if pnExists {
285+
pnSpecs, err := expandPrivateNetwork(pn.(*schema.Set).List())
286+
if err != nil {
287+
return diag.FromErr(err)
288+
}
289+
createReq.Endpoints = pnSpecs
290+
} else {
291+
epSpecs := make([]*mongodb.EndpointSpec, 0, 1)
292+
spec := &mongodb.EndpointSpecPublicDetails{}
293+
createReq.Endpoints = append(epSpecs, &mongodb.EndpointSpec{Public: spec})
294+
}
295+
296+
res, err = mongodbAPI.CreateInstance(createReq, scw.WithContext(ctx))
241297
if err != nil {
242298
return diag.FromErr(err)
243299
}
244-
createReq.Endpoints = pnSpecs
245-
} else {
246-
epSpecs := make([]*mongodb.EndpointSpec, 0, 1)
247-
spec := &mongodb.EndpointSpecPublicDetails{}
248-
createReq.Endpoints = append(epSpecs, &mongodb.EndpointSpec{Public: spec})
249300
}
250-
251-
res, err := mongodbAPI.CreateInstance(createReq, scw.WithContext(ctx))
252-
if err != nil {
253-
return diag.FromErr(err)
254-
}
255-
256301
d.SetId(zonal.NewIDString(zone, res.ID))
257-
258302
_, err = waitForInstance(ctx, mongodbAPI, res.Region, res.ID, d.Timeout(schema.TimeoutCreate))
259303
if err != nil {
260304
return diag.FromErr(err)
@@ -294,7 +338,7 @@ func ResourceInstanceRead(ctx context.Context, d *schema.ResourceData, m interfa
294338

295339
if instance.Volume != nil {
296340
_ = d.Set("volume_type", instance.Volume.Type)
297-
_ = d.Set("volume_size_in_gb", instance.Volume.Size)
341+
_ = d.Set("volume_size_in_gb", int(instance.Volume.Size/scw.GB))
298342
}
299343

300344
privateNetworkEndpoints, privateNetworkExists := flattenPrivateNetwork(instance.Endpoints)
@@ -338,7 +382,7 @@ func ResourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter
338382
if newSize%5 != 0 {
339383
return diag.FromErr(errors.New("volume_size_in_gb must be a multiple of 5"))
340384
}
341-
size := scw.Size(newSize)
385+
size := scw.Size(newSize * uint64(scw.GB))
342386

343387
upgradeInstanceRequests := mongodb.UpgradeInstanceRequest{
344388
InstanceID: ID,
@@ -350,6 +394,8 @@ func ResourceInstanceUpdate(ctx context.Context, d *schema.ResourceData, m inter
350394
if err != nil {
351395
return diag.FromErr(err)
352396
}
397+
_, err = waitForInstance(ctx, mongodbAPI, region, ID, d.Timeout(schema.TimeoutUpdate))
398+
353399
}
354400

355401
req := &mongodb.UpdateInstanceRequest{

0 commit comments

Comments
 (0)