Set backupSchedule as required in MongoDB Flex instance (#96)
* Set backupSchedule as required in MongoDB Flex instance * Update example and generate docs * Add regex explanation comment * Fix acceptance test * Fix map fields
This commit is contained in:
parent
59ee1b529e
commit
e61bfe09a5
5 changed files with 134 additions and 27 deletions
|
|
@ -30,6 +30,7 @@ resource "stackit_mongodbflex_instance" "example" {
|
|||
options = {
|
||||
type = "Single"
|
||||
}
|
||||
backup_schedule = "0 0 * * *"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -39,6 +40,7 @@ resource "stackit_mongodbflex_instance" "example" {
|
|||
### Required
|
||||
|
||||
- `acl` (List of String) The Access Control List (ACL) for the MongoDB Flex instance.
|
||||
- `backup_schedule` (String)
|
||||
- `flavor` (Attributes) (see [below for nested schema](#nestedatt--flavor))
|
||||
- `name` (String) Instance name.
|
||||
- `options` (Attributes) (see [below for nested schema](#nestedatt--options))
|
||||
|
|
@ -49,7 +51,6 @@ resource "stackit_mongodbflex_instance" "example" {
|
|||
|
||||
### Read-Only
|
||||
|
||||
- `backup_schedule` (String)
|
||||
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`".
|
||||
- `instance_id` (String) ID of the MongoDB Flex instance.
|
||||
|
||||
|
|
|
|||
|
|
@ -15,4 +15,5 @@ resource "stackit_mongodbflex_instance" "example" {
|
|||
options = {
|
||||
type = "Single"
|
||||
}
|
||||
backup_schedule = "0 0 * * *"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ import (
|
|||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/stackitcloud/stackit-sdk-go/core/config"
|
||||
|
|
@ -206,11 +205,7 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r
|
|||
Required: true,
|
||||
},
|
||||
"backup_schedule": schema.StringAttribute{
|
||||
Computed: true, // Update functionality for this field is currently not working properly on the API side
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.UseStateForUnknown(),
|
||||
},
|
||||
Default: stringdefault.StaticString(DefaultBackupSchedule), // Using the same default value as the Portal, as the field is required
|
||||
Required: true,
|
||||
},
|
||||
"flavor": schema.SingleNestedAttribute{
|
||||
Required: true,
|
||||
|
|
@ -637,6 +632,13 @@ func mapFields(resp *mongodbflex.GetInstanceResponse, model *Model, flavor *flav
|
|||
return fmt.Errorf("creating options: %w", core.DiagsToError(diags))
|
||||
}
|
||||
|
||||
simplifiedModelBackupSchedule := simplifyBackupSchedule(model.BackupSchedule.ValueString())
|
||||
// If the value returned by the API is different from the one in the model after simplification,
|
||||
// we update the model so that it causes an error in Terraform
|
||||
if simplifiedModelBackupSchedule != types.StringPointerValue(instance.BackupSchedule).ValueString() {
|
||||
model.BackupSchedule = types.StringPointerValue(instance.BackupSchedule)
|
||||
}
|
||||
|
||||
idParts := []string{
|
||||
model.ProjectId.ValueString(),
|
||||
instanceId,
|
||||
|
|
@ -647,7 +649,6 @@ func mapFields(resp *mongodbflex.GetInstanceResponse, model *Model, flavor *flav
|
|||
model.InstanceId = types.StringValue(instanceId)
|
||||
model.Name = types.StringPointerValue(instance.Name)
|
||||
model.ACL = aclList
|
||||
model.BackupSchedule = types.StringPointerValue(instance.BackupSchedule)
|
||||
model.Flavor = flavorObject
|
||||
model.Replicas = conversion.ToTypeInt64(instance.Replicas)
|
||||
model.Storage = storageObject
|
||||
|
|
@ -781,3 +782,17 @@ func loadFlavorId(ctx context.Context, client mongoDBFlexClient, model *Model, f
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove leading 0s from backup schedule numbers (e.g. "00 00 * * *" becomes "0 0 * * *")
|
||||
// Needed as the API does it internally and would otherwise cause inconsistent result in Terraform
|
||||
func simplifyBackupSchedule(schedule string) string {
|
||||
regex := regexp.MustCompile(`0+\d+`) // Matches series of one or more zeros followed by a series of one or more digits
|
||||
simplifiedSchedule := regex.ReplaceAllStringFunc(schedule, func(match string) string {
|
||||
simplified := strings.TrimLeft(match, "0")
|
||||
if simplified == "" {
|
||||
simplified = "0"
|
||||
}
|
||||
return simplified
|
||||
})
|
||||
return simplifiedSchedule
|
||||
}
|
||||
|
|
|
|||
|
|
@ -748,3 +748,75 @@ func TestLoadFlavorId(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimplifyBackupSchedule(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
"simple schedule",
|
||||
"0 0 * * *",
|
||||
"0 0 * * *",
|
||||
},
|
||||
{
|
||||
"schedule with leading zeros",
|
||||
"00 00 * * *",
|
||||
"0 0 * * *",
|
||||
},
|
||||
{
|
||||
"schedule with leading zeros 2",
|
||||
"00 001 * * *",
|
||||
"0 1 * * *",
|
||||
},
|
||||
{
|
||||
"schedule with leading zeros 3",
|
||||
"00 0010 * * *",
|
||||
"0 10 * * *",
|
||||
},
|
||||
{
|
||||
"simple schedule with slash",
|
||||
"0 0/6 * * *",
|
||||
"0 0/6 * * *",
|
||||
},
|
||||
{
|
||||
"schedule with leading zeros and slash",
|
||||
"00 00/6 * * *",
|
||||
"0 0/6 * * *",
|
||||
},
|
||||
{
|
||||
"schedule with leading zeros and slash 2",
|
||||
"00 001/06 * * *",
|
||||
"0 1/6 * * *",
|
||||
},
|
||||
{
|
||||
"simple schedule with comma",
|
||||
"0 10,15 * * *",
|
||||
"0 10,15 * * *",
|
||||
},
|
||||
{
|
||||
"schedule with leading zeros and comma",
|
||||
"0 010,0015 * * *",
|
||||
"0 10,15 * * *",
|
||||
},
|
||||
{
|
||||
"simple schedule with comma and slash",
|
||||
"0 0-11/10 * * *",
|
||||
"0 0-11/10 * * *",
|
||||
},
|
||||
{
|
||||
"schedule with leading zeros, comma, and slash",
|
||||
"00 000-011/010 * * *",
|
||||
"0 0-11/10 * * *",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
output := simplifyBackupSchedule(tt.input)
|
||||
if output != tt.expected {
|
||||
t.Fatalf("Data does not match: %s", output)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,19 +20,22 @@ 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",
|
||||
"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 * * *",
|
||||
}
|
||||
|
||||
// User resource data
|
||||
|
|
@ -43,7 +46,7 @@ var userResource = map[string]string{
|
|||
"project_id": instanceResource["project_id"],
|
||||
}
|
||||
|
||||
func configResources(version string) string {
|
||||
func configResources(version, backupSchedule string) string {
|
||||
return fmt.Sprintf(`
|
||||
%s
|
||||
|
||||
|
|
@ -64,6 +67,7 @@ func configResources(version string) string {
|
|||
options = {
|
||||
type = "%s"
|
||||
}
|
||||
backup_schedule = "%s"
|
||||
}
|
||||
|
||||
resource "stackit_mongodbflex_user" "user" {
|
||||
|
|
@ -85,6 +89,7 @@ func configResources(version string) string {
|
|||
instanceResource["storage_size"],
|
||||
version,
|
||||
instanceResource["options_type"],
|
||||
backupSchedule,
|
||||
userResource["username"],
|
||||
userResource["role"],
|
||||
userResource["database"],
|
||||
|
|
@ -98,7 +103,7 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
|
|||
Steps: []resource.TestStep{
|
||||
// Creation
|
||||
{
|
||||
Config: configResources(instanceResource["version"]),
|
||||
Config: configResources(instanceResource["version"], instanceResource["backup_schedule"]),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Instance
|
||||
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "project_id", instanceResource["project_id"]),
|
||||
|
|
@ -115,6 +120,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"]),
|
||||
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "options.type", instanceResource["options_type"]),
|
||||
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "backup_schedule", instanceResource["backup_schedule"]),
|
||||
|
||||
// User
|
||||
resource.TestCheckResourceAttrPair(
|
||||
|
|
@ -147,7 +153,7 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
|
|||
user_id = stackit_mongodbflex_user.user.user_id
|
||||
}
|
||||
`,
|
||||
configResources(instanceResource["version"]),
|
||||
configResources(instanceResource["version"], instanceResource["backup_schedule"]),
|
||||
),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Instance data
|
||||
|
|
@ -174,6 +180,7 @@ 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", "backup_schedule", instanceResource["backup_schedule_read"]),
|
||||
|
||||
// User data
|
||||
resource.TestCheckResourceAttr("data.stackit_mongodbflex_user.user", "project_id", userResource["project_id"]),
|
||||
|
|
@ -201,8 +208,18 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
|
|||
|
||||
return fmt.Sprintf("%s,%s", testutil.ProjectId, instanceId), nil
|
||||
},
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportState: true,
|
||||
ImportStateVerify: true,
|
||||
ImportStateVerifyIgnore: []string{"backup_schedule"},
|
||||
ImportStateCheck: func(s []*terraform.InstanceState) error {
|
||||
if len(s) != 1 {
|
||||
return fmt.Errorf("expected 1 state, got %d", len(s))
|
||||
}
|
||||
if s[0].Attributes["backup_schedule"] != instanceResource["backup_schedule_read"] {
|
||||
return fmt.Errorf("expected backup_schedule %s, got %s", instanceResource["backup_schedule_read"], s[0].Attributes["backup_schedule"])
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
ResourceName: "stackit_mongodbflex_user.user",
|
||||
|
|
@ -228,7 +245,7 @@ func TestAccMongoDBFlexFlexResource(t *testing.T) {
|
|||
},
|
||||
// Update
|
||||
{
|
||||
Config: configResources(instanceResource["version_updated"]),
|
||||
Config: configResources(instanceResource["version_updated"], instanceResource["backup_schedule_updated"]),
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
// Instance data
|
||||
resource.TestCheckResourceAttr("stackit_mongodbflex_instance.instance", "project_id", instanceResource["project_id"]),
|
||||
|
|
@ -245,6 +262,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", "backup_schedule", instanceResource["backup_schedule_updated"]),
|
||||
),
|
||||
},
|
||||
// Deletion is done by the framework implicitly
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue