diff --git a/docs/data-sources/mongodbflex_instance.md b/docs/data-sources/mongodbflex_instance.md
index 7a5419cb..a9f4a74a 100644
--- a/docs/data-sources/mongodbflex_instance.md
+++ b/docs/data-sources/mongodbflex_instance.md
@@ -55,7 +55,12 @@ Read-Only:
Read-Only:
-- `type` (String)
+- `daily_snapshot_retention_days` (Number) The number of days that daily backups will be retained.
+- `monthly_snapshot_retention_months` (Number) The number of months that monthly backups will be retained.
+- `point_in_time_window_hours` (Number) The number of hours back in time the point-in-time recovery feature will be able to recover.
+- `snapshot_retention_days` (Number) The number of days that continuous backups (controlled via the `backup_schedule`) will be retained.
+- `type` (String) Type of the MongoDB Flex instance.
+- `weekly_snapshot_retention_weeks` (Number) The number of weeks that weekly backups will be retained.
diff --git a/docs/resources/mongodbflex_instance.md b/docs/resources/mongodbflex_instance.md
index 0c7438ae..971e7957 100644
--- a/docs/resources/mongodbflex_instance.md
+++ b/docs/resources/mongodbflex_instance.md
@@ -26,9 +26,10 @@ resource "stackit_mongodbflex_instance" "example" {
class = "class"
size = 10
}
- version = "5.0"
+ version = "7.0"
options = {
- type = "Single"
+ type = "Single"
+ snapshot_retention_days = 3
}
backup_schedule = "0 0 * * *"
}
@@ -73,7 +74,15 @@ Read-Only:
Required:
-- `type` (String)
+- `type` (String) Type of the MongoDB Flex instance. Supported values are: `Replica`, `Sharded`, `Single`.
+
+Optional:
+
+- `daily_snapshot_retention_days` (Number) The number of days that daily backups will be retained.
+- `monthly_snapshot_retention_months` (Number) The number of months that monthly backups will be retained.
+- `point_in_time_window_hours` (Number) The number of hours back in time the point-in-time recovery feature will be able to recover.
+- `snapshot_retention_days` (Number) The number of days that continuous backups (controlled via the `backup_schedule`) will be retained.
+- `weekly_snapshot_retention_weeks` (Number) The number of weeks that weekly backups will be retained.
diff --git a/examples/resources/stackit_mongodbflex_instance/resource.tf b/examples/resources/stackit_mongodbflex_instance/resource.tf
index ef39003e..eaf16e62 100644
--- a/examples/resources/stackit_mongodbflex_instance/resource.tf
+++ b/examples/resources/stackit_mongodbflex_instance/resource.tf
@@ -11,9 +11,10 @@ resource "stackit_mongodbflex_instance" "example" {
class = "class"
size = 10
}
- version = "5.0"
+ version = "7.0"
options = {
- type = "Single"
+ type = "Single"
+ snapshot_retention_days = 3
}
backup_schedule = "0 0 * * *"
}
diff --git a/stackit/internal/services/mongodbflex/instance/datasource.go b/stackit/internal/services/mongodbflex/instance/datasource.go
index 15ab6072..e16f56b8 100644
--- a/stackit/internal/services/mongodbflex/instance/datasource.go
+++ b/stackit/internal/services/mongodbflex/instance/datasource.go
@@ -78,14 +78,20 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi
// Schema defines the schema for the data source.
func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
descriptions := map[string]string{
- "main": "MongoDB Flex instance data source schema. Must have a `region` specified in the provider configuration.",
- "id": "Terraform's internal data source. ID. It is structured as \"`project_id`,`instance_id`\".",
- "instance_id": "ID of the MongoDB Flex instance.",
- "project_id": "STACKIT project ID to which the instance is associated.",
- "name": "Instance name.",
- "acl": "The Access Control List (ACL) for the MongoDB Flex instance.",
- "backup_schedule": `The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *").`,
- "options": "Custom parameters for the MongoDB Flex instance.",
+ "main": "MongoDB Flex instance data source schema. Must have a `region` specified in the provider configuration.",
+ "id": "Terraform's internal data source ID. It is structured as \"`project_id`,`instance_id`\".",
+ "instance_id": "ID of the MongoDB Flex instance.",
+ "project_id": "STACKIT project ID to which the instance is associated.",
+ "name": "Instance name.",
+ "acl": "The Access Control List (ACL) for the MongoDB Flex instance.",
+ "backup_schedule": `The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *").`,
+ "options": "Custom parameters for the MongoDB Flex instance.",
+ "type": "Type of the MongoDB Flex instance.",
+ "snapshot_retention_days": "The number of days that continuous backups (controlled via the `backup_schedule`) will be retained.",
+ "daily_snapshot_retention_days": "The number of days that daily backups will be retained.",
+ "weekly_snapshot_retention_weeks": "The number of weeks that weekly backups will be retained.",
+ "monthly_snapshot_retention_months": "The number of months that monthly backups will be retained.",
+ "point_in_time_window_hours": "The number of hours back in time the point-in-time recovery feature will be able to recover.",
}
resp.Schema = schema.Schema{
@@ -163,7 +169,28 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques
Computed: true,
Attributes: map[string]schema.Attribute{
"type": schema.StringAttribute{
- Computed: true,
+ Description: descriptions["type"],
+ Computed: true,
+ },
+ "snapshot_retention_days": schema.Int64Attribute{
+ Description: descriptions["snapshot_retention_days"],
+ Computed: true,
+ },
+ "daily_snapshot_retention_days": schema.Int64Attribute{
+ Description: descriptions["daily_snapshot_retention_days"],
+ Computed: true,
+ },
+ "weekly_snapshot_retention_weeks": schema.Int64Attribute{
+ Description: descriptions["weekly_snapshot_retention_weeks"],
+ Computed: true,
+ },
+ "monthly_snapshot_retention_months": schema.Int64Attribute{
+ Description: descriptions["monthly_snapshot_retention_months"],
+ Computed: true,
+ },
+ "point_in_time_window_hours": schema.Int64Attribute{
+ Description: descriptions["point_in_time_window_hours"],
+ Computed: true,
},
},
},
diff --git a/stackit/internal/services/mongodbflex/instance/resource.go b/stackit/internal/services/mongodbflex/instance/resource.go
index bf93c15e..dd3e6bf3 100644
--- a/stackit/internal/services/mongodbflex/instance/resource.go
+++ b/stackit/internal/services/mongodbflex/instance/resource.go
@@ -5,6 +5,7 @@ import (
"fmt"
"net/http"
"regexp"
+ "strconv"
"strings"
"time"
@@ -22,6 +23,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -86,12 +88,22 @@ var storageTypes = map[string]attr.Type{
// Struct corresponding to Model.Options
type optionsModel struct {
- Type types.String `tfsdk:"type"`
+ Type types.String `tfsdk:"type"`
+ SnapshotRetentionDays types.Int64 `tfsdk:"snapshot_retention_days"`
+ PointInTimeWindowHours types.Int64 `tfsdk:"point_in_time_window_hours"`
+ DailySnapshotRetentionDays types.Int64 `tfsdk:"daily_snapshot_retention_days"`
+ WeeklySnapshotRetentionWeeks types.Int64 `tfsdk:"weekly_snapshot_retention_weeks"`
+ MonthlySnapshotRetentionMonths types.Int64 `tfsdk:"monthly_snapshot_retention_months"`
}
// Types corresponding to optionsModel
var optionsTypes = map[string]attr.Type{
- "type": basetypes.StringType{},
+ "type": basetypes.StringType{},
+ "snapshot_retention_days": basetypes.Int64Type{},
+ "point_in_time_window_hours": basetypes.Int64Type{},
+ "daily_snapshot_retention_days": basetypes.Int64Type{},
+ "weekly_snapshot_retention_weeks": basetypes.Int64Type{},
+ "monthly_snapshot_retention_months": basetypes.Int64Type{},
}
// NewInstanceResource is a helper function to simplify the provider implementation.
@@ -147,15 +159,23 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure
// Schema defines the schema for the resource.
func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
+ typeOptions := []string{"Replica", "Sharded", "Single"}
+
descriptions := map[string]string{
- "main": "MongoDB Flex instance resource schema. Must have a `region` specified in the provider configuration.",
- "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".",
- "instance_id": "ID of the MongoDB Flex instance.",
- "project_id": "STACKIT project ID to which the instance is associated.",
- "name": "Instance name.",
- "acl": "The Access Control List (ACL) for the MongoDB Flex instance.",
- "backup_schedule": `The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *").`,
- "options": "Custom parameters for the MongoDB Flex instance.",
+ "main": "MongoDB Flex instance resource schema. Must have a `region` specified in the provider configuration.",
+ "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".",
+ "instance_id": "ID of the MongoDB Flex instance.",
+ "project_id": "STACKIT project ID to which the instance is associated.",
+ "name": "Instance name.",
+ "acl": "The Access Control List (ACL) for the MongoDB Flex instance.",
+ "backup_schedule": `The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *").`,
+ "options": "Custom parameters for the MongoDB Flex instance.",
+ "type": fmt.Sprintf("Type of the MongoDB Flex instance. %s", utils.SupportedValuesDocumentation(typeOptions)),
+ "snapshot_retention_days": "The number of days that continuous backups (controlled via the `backup_schedule`) will be retained.",
+ "daily_snapshot_retention_days": "The number of days that daily backups will be retained.",
+ "weekly_snapshot_retention_weeks": "The number of weeks that weekly backups will be retained.",
+ "monthly_snapshot_retention_months": "The number of months that monthly backups will be retained.",
+ "point_in_time_window_hours": "The number of hours back in time the point-in-time recovery feature will be able to recover.",
}
resp.Schema = schema.Schema{
@@ -252,11 +272,52 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
Required: true,
Attributes: map[string]schema.Attribute{
"type": schema.StringAttribute{
- Required: true,
+ Description: descriptions["type"],
+ Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
+ "snapshot_retention_days": schema.Int64Attribute{
+ Description: descriptions["snapshot_retention_days"],
+ Optional: true,
+ Computed: true,
+ PlanModifiers: []planmodifier.Int64{
+ int64planmodifier.UseStateForUnknown(),
+ },
+ },
+ "daily_snapshot_retention_days": schema.Int64Attribute{
+ Description: descriptions["daily_snapshot_retention_days"],
+ Optional: true,
+ Computed: true,
+ PlanModifiers: []planmodifier.Int64{
+ int64planmodifier.UseStateForUnknown(),
+ },
+ },
+ "weekly_snapshot_retention_weeks": schema.Int64Attribute{
+ Description: descriptions["weekly_snapshot_retention_weeks"],
+ Optional: true,
+ Computed: true,
+ PlanModifiers: []planmodifier.Int64{
+ int64planmodifier.UseStateForUnknown(),
+ },
+ },
+ "monthly_snapshot_retention_months": schema.Int64Attribute{
+ Description: descriptions["monthly_snapshot_retention_months"],
+ Optional: true,
+ Computed: true,
+ PlanModifiers: []planmodifier.Int64{
+ int64planmodifier.UseStateForUnknown(),
+ },
+ },
+ "point_in_time_window_hours": schema.Int64Attribute{
+ Description: descriptions["point_in_time_window_hours"],
+ Optional: true,
+ Computed: true,
+ PlanModifiers: []planmodifier.Int64{
+ int64planmodifier.UseStateForUnknown(),
+ },
+ },
},
},
},
@@ -340,6 +401,24 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err))
return
}
+
+ backupScheduleOptionsPayload, err := toUpdateBackupScheduleOptionsPayload(ctx, &model, options)
+ if err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Creating API payload: %v", err))
+ return
+ }
+ backupScheduleOptions, err := r.client.UpdateBackupSchedule(ctx, projectId, instanceId).UpdateBackupSchedulePayload(*backupScheduleOptionsPayload).Execute()
+ if err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Updating options: %v", err))
+ return
+ }
+
+ err = mapOptions(&model, options, backupScheduleOptions)
+ if err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API response: %v", err))
+ return
+ }
+
// Set state to fully populated data
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
@@ -491,6 +570,24 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err))
return
}
+
+ backupScheduleOptionsPayload, err := toUpdateBackupScheduleOptionsPayload(ctx, &model, options)
+ if err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err))
+ return
+ }
+ backupScheduleOptions, err := r.client.UpdateBackupSchedule(ctx, projectId, instanceId).UpdateBackupSchedulePayload(*backupScheduleOptionsPayload).Execute()
+ if err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Updating options: %v", err))
+ return
+ }
+
+ err = mapOptions(&model, options, backupScheduleOptions)
+ if err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API response: %v", err))
+ return
+ }
+
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
@@ -631,11 +728,47 @@ func mapFields(ctx context.Context, resp *mongodbflex.GetInstanceResponse, model
var optionsValues map[string]attr.Value
if instance.Options == nil {
optionsValues = map[string]attr.Value{
- "type": options.Type,
+ "type": options.Type,
+ "snapshot_retention_days": types.Int64Null(),
+ "daily_snapshot_retention_days": types.Int64Null(),
+ "weekly_snapshot_retention_weeks": types.Int64Null(),
+ "monthly_snapshot_retention_months": types.Int64Null(),
+ "point_in_time_window_hours": types.Int64Null(),
}
} else {
+ snapshotRetentionDaysStr := (*instance.Options)["snapshotRetentionDays"]
+ snapshotRetentionDays, err := strconv.ParseInt(snapshotRetentionDaysStr, 10, 64)
+ if err != nil {
+ return fmt.Errorf("parse snapshot retention days: %w", err)
+ }
+ dailySnapshotRetentionDaysStr := (*instance.Options)["dailySnapshotRetentionDays"]
+ dailySnapshotRetentionDays, err := strconv.ParseInt(dailySnapshotRetentionDaysStr, 10, 64)
+ if err != nil {
+ return fmt.Errorf("parse daily snapshot retention days: %w", err)
+ }
+ weeklySnapshotRetentionWeeksStr := (*instance.Options)["weeklySnapshotRetentionWeeks"]
+ weeklySnapshotRetentionWeeks, err := strconv.ParseInt(weeklySnapshotRetentionWeeksStr, 10, 64)
+ if err != nil {
+ return fmt.Errorf("parse weekly snapshot retention weeks: %w", err)
+ }
+ monthlySnapshotRetentionMonthsStr := (*instance.Options)["monthlySnapshotRetentionMonths"]
+ monthlySnapshotRetentionMonths, err := strconv.ParseInt(monthlySnapshotRetentionMonthsStr, 10, 64)
+ if err != nil {
+ return fmt.Errorf("parse monthly snapshot retention months: %w", err)
+ }
+ pointInTimeWindowHoursStr := (*instance.Options)["pointInTimeWindowHours"]
+ pointInTimeWindowHours, err := strconv.ParseInt(pointInTimeWindowHoursStr, 10, 64)
+ if err != nil {
+ return fmt.Errorf("parse point in time window hours: %w", err)
+ }
+
optionsValues = map[string]attr.Value{
- "type": types.StringValue((*instance.Options)["type"]),
+ "type": types.StringValue((*instance.Options)["type"]),
+ "snapshot_retention_days": types.Int64Value(snapshotRetentionDays),
+ "daily_snapshot_retention_days": types.Int64Value(dailySnapshotRetentionDays),
+ "weekly_snapshot_retention_weeks": types.Int64Value(weeklySnapshotRetentionWeeks),
+ "monthly_snapshot_retention_months": types.Int64Value(monthlySnapshotRetentionMonths),
+ "point_in_time_window_hours": types.Int64Value(pointInTimeWindowHours),
}
}
optionsObject, diags := types.ObjectValue(optionsTypes, optionsValues)
@@ -668,6 +801,35 @@ func mapFields(ctx context.Context, resp *mongodbflex.GetInstanceResponse, model
return nil
}
+func mapOptions(model *Model, options *optionsModel, backupScheduleOptions *mongodbflex.BackupSchedule) error {
+ var optionsValues map[string]attr.Value
+ if backupScheduleOptions == nil {
+ optionsValues = map[string]attr.Value{
+ "type": options.Type,
+ "snapshot_retention_days": types.Int64Null(),
+ "daily_snapshot_retention_days": types.Int64Null(),
+ "weekly_snapshot_retention_weeks": types.Int64Null(),
+ "monthly_snapshot_retention_months": types.Int64Null(),
+ "point_in_time_window_hours": types.Int64Null(),
+ }
+ } else {
+ optionsValues = map[string]attr.Value{
+ "type": options.Type,
+ "snapshot_retention_days": types.Int64Value(*backupScheduleOptions.SnapshotRetentionDays),
+ "daily_snapshot_retention_days": types.Int64Value(*backupScheduleOptions.DailySnapshotRetentionDays),
+ "weekly_snapshot_retention_weeks": types.Int64Value(*backupScheduleOptions.WeeklySnapshotRetentionWeeks),
+ "monthly_snapshot_retention_months": types.Int64Value(*backupScheduleOptions.MonthlySnapshotRetentionMonths),
+ "point_in_time_window_hours": types.Int64Value(*backupScheduleOptions.PointInTimeWindowHours),
+ }
+ }
+ optionsTF, diags := types.ObjectValue(optionsTypes, optionsValues)
+ if diags.HasError() {
+ return fmt.Errorf("creating options: %w", core.DiagsToError(diags))
+ }
+ model.Options = optionsTF
+ return nil
+}
+
func toCreatePayload(model *Model, acl []string, flavor *flavorModel, storage *storageModel, options *optionsModel) (*mongodbflex.CreateInstancePayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")
@@ -746,6 +908,57 @@ func toUpdatePayload(model *Model, acl []string, flavor *flavorModel, storage *s
}, nil
}
+func toUpdateBackupScheduleOptionsPayload(ctx context.Context, model *Model, configuredOptions *optionsModel) (*mongodbflex.UpdateBackupSchedulePayload, error) {
+ if model == nil || configuredOptions == nil {
+ return nil, nil
+ }
+
+ var currOptions = &optionsModel{}
+ if !(model.Options.IsNull() || model.Options.IsUnknown()) {
+ diags := model.Options.As(ctx, currOptions, basetypes.ObjectAsOptions{})
+ if diags.HasError() {
+ return nil, fmt.Errorf("map current options: %w", core.DiagsToError(diags))
+ }
+ }
+
+ backupSchedule := conversion.StringValueToPointer(model.BackupSchedule)
+
+ snapshotRetentionDays := conversion.Int64ValueToPointer(configuredOptions.SnapshotRetentionDays)
+ if snapshotRetentionDays == nil {
+ snapshotRetentionDays = conversion.Int64ValueToPointer(currOptions.SnapshotRetentionDays)
+ }
+
+ dailySnapshotRetentionDays := conversion.Int64ValueToPointer(configuredOptions.DailySnapshotRetentionDays)
+ if dailySnapshotRetentionDays == nil {
+ dailySnapshotRetentionDays = conversion.Int64ValueToPointer(currOptions.DailySnapshotRetentionDays)
+ }
+
+ weeklySnapshotRetentionWeeks := conversion.Int64ValueToPointer(configuredOptions.WeeklySnapshotRetentionWeeks)
+ if weeklySnapshotRetentionWeeks == nil {
+ weeklySnapshotRetentionWeeks = conversion.Int64ValueToPointer(currOptions.WeeklySnapshotRetentionWeeks)
+ }
+
+ monthlySnapshotRetentionMonths := conversion.Int64ValueToPointer(configuredOptions.MonthlySnapshotRetentionMonths)
+ if monthlySnapshotRetentionMonths == nil {
+ monthlySnapshotRetentionMonths = conversion.Int64ValueToPointer(currOptions.MonthlySnapshotRetentionMonths)
+ }
+
+ pointInTimeWindowHours := conversion.Int64ValueToPointer(configuredOptions.PointInTimeWindowHours)
+ if pointInTimeWindowHours == nil {
+ pointInTimeWindowHours = conversion.Int64ValueToPointer(currOptions.PointInTimeWindowHours)
+ }
+
+ return &mongodbflex.UpdateBackupSchedulePayload{
+ // This is a PUT endpoint and all fields are required
+ BackupSchedule: backupSchedule,
+ SnapshotRetentionDays: snapshotRetentionDays,
+ DailySnapshotRetentionDays: dailySnapshotRetentionDays,
+ WeeklySnapshotRetentionWeeks: weeklySnapshotRetentionWeeks,
+ MonthlySnapshotRetentionMonths: monthlySnapshotRetentionMonths,
+ PointInTimeWindowHours: pointInTimeWindowHours,
+ }, nil
+}
+
type mongoDBFlexClient interface {
ListFlavorsExecute(ctx context.Context, projectId string) (*mongodbflex.ListFlavorsResponse, error)
}
diff --git a/stackit/internal/services/mongodbflex/instance/resource_test.go b/stackit/internal/services/mongodbflex/instance/resource_test.go
index 69710ac0..85041047 100644
--- a/stackit/internal/services/mongodbflex/instance/resource_test.go
+++ b/stackit/internal/services/mongodbflex/instance/resource_test.go
@@ -6,6 +6,7 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
+ "github.com/google/go-cmp/cmp/cmpopts"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
@@ -67,7 +68,12 @@ func TestMapFields(t *testing.T) {
"size": types.Int64Null(),
}),
Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
- "type": types.StringNull(),
+ "type": types.StringNull(),
+ "snapshot_retention_days": types.Int64Null(),
+ "daily_snapshot_retention_days": types.Int64Null(),
+ "weekly_snapshot_retention_weeks": types.Int64Null(),
+ "monthly_snapshot_retention_months": types.Int64Null(),
+ "point_in_time_window_hours": types.Int64Null(),
}),
Version: types.StringNull(),
},
@@ -104,7 +110,12 @@ func TestMapFields(t *testing.T) {
Size: utils.Ptr(int64(78)),
},
Options: &map[string]string{
- "type": "type",
+ "type": "type",
+ "snapshotRetentionDays": "5",
+ "dailySnapshotRetentionDays": "6",
+ "weeklySnapshotRetentionWeeks": "7",
+ "monthlySnapshotRetentionMonths": "8",
+ "pointInTimeWindowHours": "9",
},
Version: utils.Ptr("version"),
},
@@ -135,7 +146,12 @@ func TestMapFields(t *testing.T) {
"size": types.Int64Value(78),
}),
Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
- "type": types.StringValue("type"),
+ "type": types.StringValue("type"),
+ "snapshot_retention_days": types.Int64Value(5),
+ "daily_snapshot_retention_days": types.Int64Value(6),
+ "weekly_snapshot_retention_weeks": types.Int64Value(7),
+ "monthly_snapshot_retention_months": types.Int64Value(8),
+ "point_in_time_window_hours": types.Int64Value(9),
}),
Version: types.StringValue("version"),
},
@@ -164,7 +180,12 @@ func TestMapFields(t *testing.T) {
Status: utils.Ptr("status"),
Storage: nil,
Options: &map[string]string{
- "type": "type",
+ "type": "type",
+ "snapshotRetentionDays": "5",
+ "dailySnapshotRetentionDays": "6",
+ "weeklySnapshotRetentionWeeks": "7",
+ "monthlySnapshotRetentionMonths": "8",
+ "pointInTimeWindowHours": "9",
},
Version: utils.Ptr("version"),
},
@@ -203,7 +224,12 @@ func TestMapFields(t *testing.T) {
"size": types.Int64Value(78),
}),
Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
- "type": types.StringValue("type"),
+ "type": types.StringValue("type"),
+ "snapshot_retention_days": types.Int64Value(5),
+ "daily_snapshot_retention_days": types.Int64Value(6),
+ "weekly_snapshot_retention_weeks": types.Int64Value(7),
+ "monthly_snapshot_retention_months": types.Int64Value(8),
+ "point_in_time_window_hours": types.Int64Value(9),
}),
Version: types.StringValue("version"),
},
@@ -237,7 +263,12 @@ func TestMapFields(t *testing.T) {
Status: utils.Ptr("status"),
Storage: nil,
Options: &map[string]string{
- "type": "type",
+ "type": "type",
+ "snapshotRetentionDays": "5",
+ "dailySnapshotRetentionDays": "6",
+ "weeklySnapshotRetentionWeeks": "7",
+ "monthlySnapshotRetentionMonths": "8",
+ "pointInTimeWindowHours": "9",
},
Version: utils.Ptr("version"),
},
@@ -276,7 +307,12 @@ func TestMapFields(t *testing.T) {
"size": types.Int64Value(78),
}),
Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
- "type": types.StringValue("type"),
+ "type": types.StringValue("type"),
+ "snapshot_retention_days": types.Int64Value(5),
+ "daily_snapshot_retention_days": types.Int64Value(6),
+ "weekly_snapshot_retention_weeks": types.Int64Value(7),
+ "monthly_snapshot_retention_months": types.Int64Value(8),
+ "point_in_time_window_hours": types.Int64Value(9),
}),
Version: types.StringValue("version"),
},
@@ -328,6 +364,77 @@ func TestMapFields(t *testing.T) {
}
}
+func TestMapOptions(t *testing.T) {
+ tests := []struct {
+ description string
+ model *Model
+ options *optionsModel
+ backup *mongodbflex.BackupSchedule
+ expected *Model
+ isValid bool
+ }{
+ {
+ "default_values",
+ &Model{},
+ &optionsModel{},
+ nil,
+ &Model{
+ Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
+ "type": types.StringNull(),
+ "snapshot_retention_days": types.Int64Null(),
+ "daily_snapshot_retention_days": types.Int64Null(),
+ "weekly_snapshot_retention_weeks": types.Int64Null(),
+ "monthly_snapshot_retention_months": types.Int64Null(),
+ "point_in_time_window_hours": types.Int64Null(),
+ }),
+ },
+ true,
+ },
+ {
+ "simple_values",
+ &Model{},
+ &optionsModel{
+ Type: types.StringValue("type"),
+ },
+ &mongodbflex.BackupSchedule{
+ SnapshotRetentionDays: utils.Ptr(int64(1)),
+ DailySnapshotRetentionDays: utils.Ptr(int64(2)),
+ WeeklySnapshotRetentionWeeks: utils.Ptr(int64(3)),
+ MonthlySnapshotRetentionMonths: utils.Ptr(int64(4)),
+ PointInTimeWindowHours: utils.Ptr(int64(5)),
+ },
+ &Model{
+ Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
+ "type": types.StringValue("type"),
+ "snapshot_retention_days": types.Int64Value(1),
+ "daily_snapshot_retention_days": types.Int64Value(2),
+ "weekly_snapshot_retention_weeks": types.Int64Value(3),
+ "monthly_snapshot_retention_months": types.Int64Value(4),
+ "point_in_time_window_hours": types.Int64Value(5),
+ }),
+ },
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ err := mapOptions(tt.model, tt.options, tt.backup)
+ if !tt.isValid && err == nil {
+ t.Fatalf("Should have failed")
+ }
+ if tt.isValid && err != nil {
+ t.Fatalf("Should not have failed: %v", err)
+ }
+ if tt.isValid {
+ diff := cmp.Diff(tt.model, tt.expected, cmpopts.IgnoreFields(Model{}, "ACL", "Flavor", "Replicas", "Storage", "Version"))
+ if diff != "" {
+ t.Fatalf("Data does not match: %s", diff)
+ }
+ }
+ })
+ }
+}
+
func TestToCreatePayload(t *testing.T) {
tests := []struct {
description string
@@ -686,6 +793,130 @@ func TestToUpdatePayload(t *testing.T) {
}
}
+func TestToUpdateBackupScheduleOptionsPayload(t *testing.T) {
+ tests := []struct {
+ description string
+ model *Model
+ configuredOptions *optionsModel
+ expected *mongodbflex.UpdateBackupSchedulePayload
+ isValid bool
+ }{
+ {
+ "default_values",
+ &Model{},
+ &optionsModel{},
+ &mongodbflex.UpdateBackupSchedulePayload{
+ BackupSchedule: nil,
+ SnapshotRetentionDays: nil,
+ DailySnapshotRetentionDays: nil,
+ WeeklySnapshotRetentionWeeks: nil,
+ MonthlySnapshotRetentionMonths: nil,
+ PointInTimeWindowHours: nil,
+ },
+ true,
+ },
+ {
+ "config values override current values in model",
+ &Model{
+ BackupSchedule: types.StringValue("schedule"),
+ Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
+ "type": types.StringValue("type"),
+ "snapshot_retention_days": types.Int64Value(1),
+ "daily_snapshot_retention_days": types.Int64Value(2),
+ "weekly_snapshot_retention_weeks": types.Int64Value(3),
+ "monthly_snapshot_retention_months": types.Int64Value(4),
+ "point_in_time_window_hours": types.Int64Value(5),
+ }),
+ },
+ &optionsModel{
+ SnapshotRetentionDays: types.Int64Value(6),
+ DailySnapshotRetentionDays: types.Int64Value(7),
+ WeeklySnapshotRetentionWeeks: types.Int64Value(8),
+ MonthlySnapshotRetentionMonths: types.Int64Value(9),
+ PointInTimeWindowHours: types.Int64Value(10),
+ },
+ &mongodbflex.UpdateBackupSchedulePayload{
+ BackupSchedule: utils.Ptr("schedule"),
+ SnapshotRetentionDays: utils.Ptr(int64(6)),
+ DailySnapshotRetentionDays: utils.Ptr(int64(7)),
+ WeeklySnapshotRetentionWeeks: utils.Ptr(int64(8)),
+ MonthlySnapshotRetentionMonths: utils.Ptr(int64(9)),
+ PointInTimeWindowHours: utils.Ptr(int64(10)),
+ },
+ true,
+ },
+ {
+ "current values in model fill in missing values in config",
+ &Model{
+ BackupSchedule: types.StringValue("schedule"),
+ Options: types.ObjectValueMust(optionsTypes, map[string]attr.Value{
+ "type": types.StringValue("type"),
+ "snapshot_retention_days": types.Int64Value(1),
+ "daily_snapshot_retention_days": types.Int64Value(2),
+ "weekly_snapshot_retention_weeks": types.Int64Value(3),
+ "monthly_snapshot_retention_months": types.Int64Value(4),
+ "point_in_time_window_hours": types.Int64Value(5),
+ }),
+ },
+ &optionsModel{
+ SnapshotRetentionDays: types.Int64Value(6),
+ DailySnapshotRetentionDays: types.Int64Value(7),
+ WeeklySnapshotRetentionWeeks: types.Int64Null(),
+ MonthlySnapshotRetentionMonths: types.Int64Null(),
+ PointInTimeWindowHours: types.Int64Null(),
+ },
+ &mongodbflex.UpdateBackupSchedulePayload{
+ BackupSchedule: utils.Ptr("schedule"),
+ SnapshotRetentionDays: utils.Ptr(int64(6)),
+ DailySnapshotRetentionDays: utils.Ptr(int64(7)),
+ WeeklySnapshotRetentionWeeks: utils.Ptr(int64(3)),
+ MonthlySnapshotRetentionMonths: utils.Ptr(int64(4)),
+ PointInTimeWindowHours: utils.Ptr(int64(5)),
+ },
+ true,
+ },
+ {
+ "null_fields_and_int_conversions",
+ &Model{
+ BackupSchedule: types.StringNull(),
+ },
+ &optionsModel{
+ SnapshotRetentionDays: types.Int64Null(),
+ DailySnapshotRetentionDays: types.Int64Null(),
+ WeeklySnapshotRetentionWeeks: types.Int64Null(),
+ MonthlySnapshotRetentionMonths: types.Int64Null(),
+ PointInTimeWindowHours: types.Int64Null(),
+ },
+ &mongodbflex.UpdateBackupSchedulePayload{
+ BackupSchedule: nil,
+ SnapshotRetentionDays: nil,
+ DailySnapshotRetentionDays: nil,
+ WeeklySnapshotRetentionWeeks: nil,
+ MonthlySnapshotRetentionMonths: nil,
+ PointInTimeWindowHours: nil,
+ },
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ output, err := toUpdateBackupScheduleOptionsPayload(context.Background(), tt.model, tt.configuredOptions)
+ if !tt.isValid && err == nil {
+ t.Fatalf("Should have failed")
+ }
+ if tt.isValid && err != nil {
+ t.Fatalf("Should not have failed: %v", err)
+ }
+ if tt.isValid {
+ diff := cmp.Diff(output, tt.expected)
+ if diff != "" {
+ t.Fatalf("Data does not match: %s", diff)
+ }
+ }
+ })
+ }
+}
+
func TestLoadFlavorId(t *testing.T) {
tests := []struct {
description string
diff --git a/stackit/internal/services/mongodbflex/mongodbflex_acc_test.go b/stackit/internal/services/mongodbflex/mongodbflex_acc_test.go
index 33f2c711..50ccda2e 100644
--- a/stackit/internal/services/mongodbflex/mongodbflex_acc_test.go
+++ b/stackit/internal/services/mongodbflex/mongodbflex_acc_test.go
@@ -20,22 +20,25 @@ import (
// Instance resource data
var instanceResource = map[string]string{
- "project_id": testutil.ProjectId,
- "name": fmt.Sprintf("tf-acc-%s", acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum)),
- "acl": "192.168.0.0/16",
- "flavor_cpu": "2",
- "flavor_ram": "4",
- "flavor_description": "Small, Compute optimized",
- "replicas": "1",
- "storage_class": "premium-perf2-mongodb",
- "storage_size": "10",
- "version": "5.0",
- "version_updated": "6.0",
- "options_type": "Single",
- "flavor_id": "2.4",
- "backup_schedule": "00 6 * * *",
- "backup_schedule_updated": "00 12 * * *",
- "backup_schedule_read": "0 6 * * *",
+ "project_id": testutil.ProjectId,
+ "name": fmt.Sprintf("tf-acc-%s", acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum)),
+ "acl": "192.168.0.0/16",
+ "flavor_cpu": "2",
+ "flavor_ram": "4",
+ "flavor_description": "Small, Compute optimized",
+ "replicas": "1",
+ "storage_class": "premium-perf2-mongodb",
+ "storage_size": "10",
+ "version": "5.0",
+ "version_updated": "6.0",
+ "options_type": "Single",
+ "flavor_id": "2.4",
+ "backup_schedule": "00 6 * * *",
+ "backup_schedule_updated": "00 12 * * *",
+ "backup_schedule_read": "0 6 * * *",
+ "snapshot_retention_days": "4",
+ "snapshot_retention_days_updated": "3",
+ "daily_snapshot_retention_days": "1",
}
// User resource data
@@ -46,7 +49,7 @@ var userResource = map[string]string{
"project_id": instanceResource["project_id"],
}
-func configResources(version, backupSchedule string) string {
+func configResources(version, backupSchedule, snapshotRetentionDays string) string {
return fmt.Sprintf(`
%s
@@ -66,6 +69,8 @@ func configResources(version, backupSchedule string) string {
version = "%s"
options = {
type = "%s"
+ snapshot_retention_days = %s
+ daily_snapshot_retention_days = %s
}
backup_schedule = "%s"
}
@@ -89,6 +94,8 @@ func configResources(version, backupSchedule string) string {
instanceResource["storage_size"],
version,
instanceResource["options_type"],
+ snapshotRetentionDays,
+ instanceResource["daily_snapshot_retention_days"],
backupSchedule,
userResource["username"],
userResource["role"],
@@ -103,7 +110,7 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
Steps: []resource.TestStep{
// Creation
{
- Config: configResources(instanceResource["version"], instanceResource["backup_schedule"]),
+ Config: configResources(instanceResource["version"], instanceResource["backup_schedule"], instanceResource["snapshot_retention_days"]),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "project_id", instanceResource["project_id"]),
@@ -120,6 +127,8 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "storage.size", instanceResource["storage_size"]),
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "version", instanceResource["version"]),
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "options.type", instanceResource["options_type"]),
+ resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "options.snapshot_retention_days", instanceResource["snapshot_retention_days"]),
+ resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "options.daily_snapshot_retention_days", instanceResource["daily_snapshot_retention_days"]),
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "backup_schedule", instanceResource["backup_schedule"]),
// User
@@ -153,7 +162,7 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
user_id = stackit_mongodbflex_user.user.user_id
}
`,
- configResources(instanceResource["version"], instanceResource["backup_schedule"]),
+ configResources(instanceResource["version"], instanceResource["backup_schedule"], instanceResource["snapshot_retention_days"]),
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
@@ -180,6 +189,8 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
resource.TestCheckResourceAttr("data.stackit_mongodbflex_instance.instance", "flavor.ram", instanceResource["flavor_ram"]),
resource.TestCheckResourceAttr("data.stackit_mongodbflex_instance.instance", "replicas", instanceResource["replicas"]),
resource.TestCheckResourceAttr("data.stackit_mongodbflex_instance.instance", "options.type", instanceResource["options_type"]),
+ resource.TestCheckResourceAttr("data.stackit_mongodbflex_instance.instance", "options.snapshot_retention_days", instanceResource["snapshot_retention_days"]),
+ resource.TestCheckResourceAttr("data.stackit_mongodbflex_instance.instance", "options.daily_snapshot_retention_days", instanceResource["daily_snapshot_retention_days"]),
resource.TestCheckResourceAttr("data.stackit_mongodbflex_instance.instance", "backup_schedule", instanceResource["backup_schedule_read"]),
// User data
@@ -245,7 +256,7 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
},
// Update
{
- Config: configResources(instanceResource["version_updated"], instanceResource["backup_schedule_updated"]),
+ Config: configResources(instanceResource["version_updated"], instanceResource["backup_schedule_updated"], instanceResource["snapshot_retention_days_updated"]),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "project_id", instanceResource["project_id"]),
@@ -262,6 +273,7 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "storage.size", instanceResource["storage_size"]),
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "version", instanceResource["version_updated"]),
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "options.type", instanceResource["options_type"]),
+ resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "options.snapshot_retention_days", instanceResource["snapshot_retention_days_updated"]),
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "backup_schedule", instanceResource["backup_schedule_updated"]),
),
},
@@ -275,7 +287,9 @@ func testAccCheckMongoDBFlexDestroy(s *terraform.State) error {
var client *mongodbflex.APIClient
var err error
if testutil.MongoDBFlexCustomEndpoint == "" {
- client, err = mongodbflex.NewAPIClient()
+ client, err = mongodbflex.NewAPIClient(
+ config.WithRegion("eu01"),
+ )
} else {
client, err = mongodbflex.NewAPIClient(
config.WithEndpoint(testutil.MongoDBFlexCustomEndpoint),