Add additional backup configurations to MongoDB Flex instance resource (#486)

* Extend resource and datasource

* Extend acc test

* Extend example

* Generate docs

* Fix linter

* Update stackit/internal/services/mongodbflex/instance/datasource.go

Co-authored-by: GokceGK <161626272+GokceGK@users.noreply.github.com>

---------

Co-authored-by: GokceGK <161626272+GokceGK@users.noreply.github.com>
This commit is contained in:
João Palet 2024-07-31 10:55:14 +01:00 committed by GitHub
parent 6140769506
commit 2810545ef7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 556 additions and 56 deletions

View file

@ -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,
},
},
},

View file

@ -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)
}

View file

@ -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