From c6a27bb32d455ab301770b44d8dfbbff6d5ed21b Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 21 Mar 2025 20:28:14 +0000 Subject: [PATCH 01/11] example --- .../mongodbatlas_maintenance_window/README.md | 11 ++++++++++ .../mongodbatlas_maintenance_window/main.tf | 21 +++++++++++++++++++ .../provider.tf | 4 ++++ .../variables.tf | 12 +++++++++++ .../versions.tf | 9 ++++++++ 5 files changed, 57 insertions(+) create mode 100644 examples/mongodbatlas_maintenance_window/README.md create mode 100644 examples/mongodbatlas_maintenance_window/main.tf create mode 100644 examples/mongodbatlas_maintenance_window/provider.tf create mode 100644 examples/mongodbatlas_maintenance_window/variables.tf create mode 100644 examples/mongodbatlas_maintenance_window/versions.tf diff --git a/examples/mongodbatlas_maintenance_window/README.md b/examples/mongodbatlas_maintenance_window/README.md new file mode 100644 index 0000000000..27f98b72f6 --- /dev/null +++ b/examples/mongodbatlas_maintenance_window/README.md @@ -0,0 +1,11 @@ +# MongoDB Atlas Provider - Atlas Cluster with dedicated Search Nodes Deployment + +This example shows how you can configure maintenance windows for your Atlas project in Terraform. + +Variables required to be set: + +- `public_key`: Atlas public key +- `private_key`: Atlas private key +- `org_id`: Organization ID where the project and cluster will be created. + +For additional information you can visit the [Maintenance Window Documentation](https://www.mongodb.com/docs/atlas/tutorial/cluster-maintenance-window/). \ No newline at end of file diff --git a/examples/mongodbatlas_maintenance_window/main.tf b/examples/mongodbatlas_maintenance_window/main.tf new file mode 100644 index 0000000000..0b5ea6b8a8 --- /dev/null +++ b/examples/mongodbatlas_maintenance_window/main.tf @@ -0,0 +1,21 @@ +resource "mongodbatlas_project" "example" { + name = "project-name" + org_id = var.org_id +} + +resource "mongodbatlas_maintenance_window" "example" { + project_id = mongodbatlas_project.example.id + auto_defer_once_enabled = true + hour_of_day = 23 + start_asap = true + day_of_week = 1 + protected_hours { + start_hour_of_day = 9 + end_hour_of_day = 17 + } +} + +data "mongodbatlas_maintenance_window" "example" { + project_id = mongodbatlas_maintenance_window.example.project_id +} + diff --git a/examples/mongodbatlas_maintenance_window/provider.tf b/examples/mongodbatlas_maintenance_window/provider.tf new file mode 100644 index 0000000000..e5aeda8033 --- /dev/null +++ b/examples/mongodbatlas_maintenance_window/provider.tf @@ -0,0 +1,4 @@ +provider "mongodbatlas" { + public_key = var.public_key + private_key = var.private_key +} \ No newline at end of file diff --git a/examples/mongodbatlas_maintenance_window/variables.tf b/examples/mongodbatlas_maintenance_window/variables.tf new file mode 100644 index 0000000000..503476e252 --- /dev/null +++ b/examples/mongodbatlas_maintenance_window/variables.tf @@ -0,0 +1,12 @@ +variable "public_key" { + description = "Public API key to authenticate to Atlas" + type = string +} +variable "private_key" { + description = "Private API key to authenticate to Atlas" + type = string +} +variable "org_id" { + description = "Atlas Organization ID" + type = string +} \ No newline at end of file diff --git a/examples/mongodbatlas_maintenance_window/versions.tf b/examples/mongodbatlas_maintenance_window/versions.tf new file mode 100644 index 0000000000..1888453805 --- /dev/null +++ b/examples/mongodbatlas_maintenance_window/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + mongodbatlas = { + source = "mongodb/mongodbatlas" + version = "~> 1.0" + } + } + required_version = ">= 1.0" +} From 3e55caabfbca67168110d149bf0030b05ee8cd84 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 21 Mar 2025 20:30:39 +0000 Subject: [PATCH 02/11] init resource changes --- .../data_source_maintenance_window.go | 32 ++++++++ .../data_source_maintenance_window_test.go | 4 +- .../resource_maintenance_window.go | 74 ++++++++++++++++++- .../resource_maintenance_window_test.go | 8 +- 4 files changed, 114 insertions(+), 4 deletions(-) diff --git a/internal/service/maintenancewindow/data_source_maintenance_window.go b/internal/service/maintenancewindow/data_source_maintenance_window.go index 311af7794a..a3440cfa9c 100644 --- a/internal/service/maintenancewindow/data_source_maintenance_window.go +++ b/internal/service/maintenancewindow/data_source_maintenance_window.go @@ -2,9 +2,11 @@ package maintenancewindow import ( "context" + "fmt" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/config" ) @@ -36,6 +38,26 @@ func DataSource() *schema.Resource { Type: schema.TypeBool, Computed: true, }, + "time_zone_id": { + Type: schema.TypeString, + Computed: true, + }, + "protected_hours": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_hour_of_day": { + Type: schema.TypeInt, + Computed: true, + }, + "start_hour_of_day": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, }, } } @@ -69,6 +91,16 @@ func dataSourceRead(ctx context.Context, d *schema.ResourceData, meta any) diag. return diag.Errorf(errorMaintenanceRead, projectID, err) } + if err := d.Set("time_zone_id", maintenance.GetTimeZoneId()); err != nil { + return diag.FromErr(fmt.Errorf(errorMaintenanceRead, projectID, err)) + } + + if maintenance.ProtectedHours != nil { + if err := d.Set("protected_hours", flattenProtectedHours(maintenance.GetProtectedHours())); err != nil { + return diag.FromErr(fmt.Errorf(errorMaintenanceRead, projectID, err)) + } + } + d.SetId(projectID) return nil diff --git a/internal/service/maintenancewindow/data_source_maintenance_window_test.go b/internal/service/maintenancewindow/data_source_maintenance_window_test.go index 6d44f7377d..79e8fd9cce 100644 --- a/internal/service/maintenancewindow/data_source_maintenance_window_test.go +++ b/internal/service/maintenancewindow/data_source_maintenance_window_test.go @@ -6,8 +6,9 @@ import ( "testing" "github.com/hashicorp/terraform-plugin-testing/helper/resource" - "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" "github.com/spf13/cast" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" ) const dataSourceName = "mongodbatlas_maintenance_window.test" @@ -32,6 +33,7 @@ func TestAccConfigDSMaintenanceWindow_basic(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "day_of_week", cast.ToString(dayOfWeek)), resource.TestCheckResourceAttr(dataSourceName, "hour_of_day", cast.ToString(hourOfDay)), resource.TestCheckResourceAttr(dataSourceName, "auto_defer_once_enabled", "true"), + resource.TestCheckResourceAttrSet(dataSourceName, "time_zone_id"), ), }, }, diff --git a/internal/service/maintenancewindow/resource_maintenance_window.go b/internal/service/maintenancewindow/resource_maintenance_window.go index 5bd7705e10..627347b74b 100644 --- a/internal/service/maintenancewindow/resource_maintenance_window.go +++ b/internal/service/maintenancewindow/resource_maintenance_window.go @@ -4,13 +4,15 @@ import ( "context" "fmt" + "go.mongodb.org/atlas-sdk/v20250219001/admin" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/spf13/cast" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/validate" "github.com/mongodb/terraform-provider-mongodbatlas/internal/config" - "github.com/spf13/cast" - "go.mongodb.org/atlas-sdk/v20250219001/admin" ) const ( @@ -84,6 +86,27 @@ func Resource() *schema.Resource { Optional: true, Computed: true, }, + "time_zone_id": { + Type: schema.TypeString, + Computed: true, + }, + "protected_hours": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end_hour_of_day": { + Type: schema.TypeInt, + Required: true, + }, + "start_hour_of_day": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, }, } } @@ -110,6 +133,8 @@ func resourceCreate(ctx context.Context, d *schema.ResourceData, meta any) diag. params.AutoDeferOnceEnabled = conversion.Pointer(autoDeferOnceEnabled.(bool)) } + params.ProtectedHours = newProtectedHours(d) + _, _, err := connV2.MaintenanceWindowsApi.UpdateMaintenanceWindow(ctx, projectID, params).Execute() if err != nil { return diag.FromErr(fmt.Errorf(errorMaintenanceCreate, projectID, err)) @@ -127,6 +152,19 @@ func resourceCreate(ctx context.Context, d *schema.ResourceData, meta any) diag. return resourceRead(ctx, d, meta) } +func newProtectedHours(d *schema.ResourceData) *admin.ProtectedHours { + if protectedHours, ok := d.Get("protected_hours").([]any); ok && conversion.HasElementsSliceOrMap(protectedHours) { + item := protectedHours[0].(map[string]any) + + return &admin.ProtectedHours{ + EndHourOfDay: conversion.IntPtr(item["end_hour_of_day"].(int)), + StartHourOfDay: conversion.IntPtr(item["start_hour_of_day"].(int)), + } + } + + return nil +} + func resourceRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { connV2 := meta.(*config.MongoDBClient).AtlasV2 projectID := d.Id() @@ -165,9 +203,27 @@ func resourceRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Di return diag.FromErr(fmt.Errorf(errorMaintenanceRead, projectID, err)) } + if err := d.Set("time_zone_id", maintenanceWindow.GetTimeZoneId()); err != nil { + return diag.FromErr(fmt.Errorf(errorMaintenanceRead, projectID, err)) + } + + if maintenanceWindow.ProtectedHours != nil { + if err := d.Set("protected_hours", flattenProtectedHours(maintenanceWindow.GetProtectedHours())); err != nil { + return diag.FromErr(fmt.Errorf(errorMaintenanceRead, projectID, err)) + } + } return nil } +func flattenProtectedHours(protectedHours admin.ProtectedHours) []map[string]int { + res := make([]map[string]int, 0) + res = append(res, map[string]int{ + "end_hour_of_day": protectedHours.GetEndHourOfDay(), + "start_hour_of_day": protectedHours.GetStartHourOfDay(), + }) + return res +} + func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { connV2 := meta.(*config.MongoDBClient).AtlasV2 projectID := d.Id() @@ -190,6 +246,20 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag. params.AutoDeferOnceEnabled = conversion.Pointer(d.Get("auto_defer_once_enabled").(bool)) } + if oldP, newP := d.GetChange("protected_hours"); d.HasChange("protected_hours") { + old := oldP.([]any) + new := newP.([]any) + + if len(old) == 1 && len(new) == 0 { + params.ProtectedHours = &admin.ProtectedHours{ + StartHourOfDay: nil, + EndHourOfDay: nil, + } + } else { + params.ProtectedHours = newProtectedHours(d) + } + } + _, _, err := connV2.MaintenanceWindowsApi.UpdateMaintenanceWindow(ctx, projectID, params).Execute() if err != nil { return diag.FromErr(fmt.Errorf(errorMaintenanceUpdate, projectID, err)) diff --git a/internal/service/maintenancewindow/resource_maintenance_window_test.go b/internal/service/maintenancewindow/resource_maintenance_window_test.go index bc21be4342..c171f49fd7 100644 --- a/internal/service/maintenancewindow/resource_maintenance_window_test.go +++ b/internal/service/maintenancewindow/resource_maintenance_window_test.go @@ -9,9 +9,10 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/spf13/cast" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" - "github.com/spf13/cast" ) const resourceName = "mongodbatlas_maintenance_window.test" @@ -146,6 +147,11 @@ func configBasic(orgID, projectName string, dayOfWeek int, hourOfDay *int) strin project_id = mongodbatlas_project.test.id day_of_week = %[3]d %[4]s + + protected_hours { + start_hour_of_day = 9 + end_hour_of_day = 17 + } }`, orgID, projectName, dayOfWeek, hourOfDayAttr) } From acefbe3b397c6746c63036534c1b8401e9db2dd9 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 21 Mar 2025 20:31:22 +0000 Subject: [PATCH 03/11] minor --- examples/mongodbatlas_maintenance_window/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/mongodbatlas_maintenance_window/README.md b/examples/mongodbatlas_maintenance_window/README.md index 27f98b72f6..2406b2ba4e 100644 --- a/examples/mongodbatlas_maintenance_window/README.md +++ b/examples/mongodbatlas_maintenance_window/README.md @@ -1,4 +1,4 @@ -# MongoDB Atlas Provider - Atlas Cluster with dedicated Search Nodes Deployment +# MongoDB Atlas Provider - Configure Maintenance Window This example shows how you can configure maintenance windows for your Atlas project in Terraform. From 331675fbceb1b1f07d41e22899c77d34372f21c0 Mon Sep 17 00:00:00 2001 From: Aastha Mahendru Date: Fri, 21 Mar 2025 20:39:12 +0000 Subject: [PATCH 04/11] docs --- docs/data-sources/maintenance_window.md | 8 ++++++++ docs/resources/maintenance_window.md | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/docs/data-sources/maintenance_window.md b/docs/data-sources/maintenance_window.md index 69cf2e639a..9f14e9fe33 100644 --- a/docs/data-sources/maintenance_window.md +++ b/docs/data-sources/maintenance_window.md @@ -44,4 +44,12 @@ In addition to all arguments above, the following attributes are exported: * `start_asap` - Flag indicating whether project maintenance has been directed to start immediately. If you request that maintenance begin immediately, this field returns true from the time the request was made until the time the maintenance event completes. * `number_of_deferrals` - Number of times the current maintenance event for this project has been deferred, there can be a maximum of 2 deferrals. * `auto_defer_once_enabled` - Flag that indicates whether you want to defer all maintenance windows one week they would be triggered. +* `protected_hours` - (Optional) Defines the a window where maintenance will not begin within.. See [Protected Hours](#protected-hours). +* `time_zone_id` - Identifier for the current time zone of the maintenance window. This can only be updated via the Project Settings UI. + +### Protected Hours +* `start_hour_of_day` - Zero-based integer that represents the beginning hour of the of the day that the maintenance will not begin in. +* `end_hour_of_day` - Zero-based integer that represents the end hour of the of the day that the maintenance will not begin in. + + For more information see: [MongoDB Atlas API Reference.](https://docs.atlas.mongodb.com/reference/api/maintenance-windows/) \ No newline at end of file diff --git a/docs/resources/maintenance_window.md b/docs/resources/maintenance_window.md index 83b89a6cb2..ee684129c0 100644 --- a/docs/resources/maintenance_window.md +++ b/docs/resources/maintenance_window.md @@ -21,6 +21,11 @@ Once maintenance is scheduled for your cluster, you cannot change your maintenan project_id = "" day_of_week = 3 hour_of_day = 4 + + protected_hours { + start_hour_of_day = 9 + end_hour_of_day = 17 + } } ``` @@ -41,14 +46,20 @@ Once maintenance is scheduled for your cluster, you cannot change your maintenan * `defer` - Defer the next scheduled maintenance for the given project for one week. * `auto_defer` - Defer any scheduled maintenance for the given project for one week. * `auto_defer_once_enabled` - Flag that indicates whether you want to defer all maintenance windows one week they would be triggered. +* `protected_hours` - (Optional) Defines the a window where maintenance will not begin within.. See [Protected Hours](#protected-hours). -> **NOTE:** The `start_asap` attribute can't be used because of breaks the Terraform flow, but you can enable via API. +### Protected Hours +* `start_hour_of_day` - Zero-based integer that represents the beginning hour of the of the day that the maintenance will not begin in. +* `end_hour_of_day` - Zero-based integer that represents the end hour of the of the day that the maintenance will not begin in. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: * `number_of_deferrals` - Number of times the current maintenance event for this project has been deferred, there can be a maximum of 2 deferrals. +* `time_zone_id` - Identifier for the current time zone of the maintenance window. This can only be updated via the Project Settings UI. ## Import From 27b7dea50a10335eb35519c69c7bbaf0d96306af Mon Sep 17 00:00:00 2001 From: Espen Albert Date: Mon, 21 Apr 2025 12:19:56 +0100 Subject: [PATCH 05/11] fix lint error --- .../maintenancewindow/resource_maintenance_window.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/maintenancewindow/resource_maintenance_window.go b/internal/service/maintenancewindow/resource_maintenance_window.go index a2cc4c3a91..79cbe54288 100644 --- a/internal/service/maintenancewindow/resource_maintenance_window.go +++ b/internal/service/maintenancewindow/resource_maintenance_window.go @@ -244,11 +244,11 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag. params.AutoDeferOnceEnabled = conversion.Pointer(d.Get("auto_defer_once_enabled").(bool)) } - if oldP, newP := d.GetChange("protected_hours"); d.HasChange("protected_hours") { - old := oldP.([]any) - new := newP.([]any) + if oldPAny, newPAny := d.GetChange("protected_hours"); d.HasChange("protected_hours") { + oldP := oldPAny.([]any) + newP := newPAny.([]any) - if len(old) == 1 && len(new) == 0 { + if len(oldP) == 1 && len(newP) == 0 { params.ProtectedHours = &admin.ProtectedHours{ StartHourOfDay: nil, EndHourOfDay: nil, From 65f7a09481795a8a05e78314db1e9fa494f91fbb Mon Sep 17 00:00:00 2001 From: Espen Albert Date: Mon, 21 Apr 2025 12:24:23 +0100 Subject: [PATCH 06/11] feat: Enhance maintenance window tests with protected hours configuration --- ...ource_maintenance_window_migration_test.go | 2 +- .../resource_maintenance_window_test.go | 65 +++++++++++++------ 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go b/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go index 01562a759f..63e5a69357 100644 --- a/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go +++ b/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go @@ -17,7 +17,7 @@ func TestMigConfigMaintenanceWindow_basic(t *testing.T) { projectName = acc.RandomProjectName() dayOfWeek = 7 hourOfDay = 3 - config = configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay)) + config = configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay), defaultProtectedHours) ) resource.ParallelTest(t, resource.TestCase{ diff --git a/internal/service/maintenancewindow/resource_maintenance_window_test.go b/internal/service/maintenancewindow/resource_maintenance_window_test.go index c171f49fd7..48776649cd 100644 --- a/internal/service/maintenancewindow/resource_maintenance_window_test.go +++ b/internal/service/maintenancewindow/resource_maintenance_window_test.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/spf13/cast" + "go.mongodb.org/atlas-sdk/v20250312002/admin" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" @@ -17,6 +18,17 @@ import ( const resourceName = "mongodbatlas_maintenance_window.test" +var ( + defaultProtectedHours = &admin.ProtectedHours{ + StartHourOfDay: conversion.Pointer(9), + EndHourOfDay: conversion.Pointer(17), + } + updatedProtectedHours = &admin.ProtectedHours{ + StartHourOfDay: conversion.Pointer(10), + EndHourOfDay: conversion.Pointer(15), + } +) + func TestAccConfigRSMaintenanceWindow_basic(t *testing.T) { var ( orgID = os.Getenv("MONGODB_ATLAS_ORG_ID") @@ -33,20 +45,20 @@ func TestAccConfigRSMaintenanceWindow_basic(t *testing.T) { Steps: []resource.TestStep{ { // testing hour_of_day set to 0 during creation phase does not return errors - Config: configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay)), - Check: checkBasic(dayOfWeek, hourOfDay), + Config: configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay), defaultProtectedHours), + Check: checkBasic(dayOfWeek, hourOfDay, defaultProtectedHours), }, { - Config: configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDayUpdated)), - Check: checkBasic(dayOfWeek, hourOfDayUpdated), + Config: configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDayUpdated), updatedProtectedHours), + Check: checkBasic(dayOfWeek, hourOfDayUpdated, updatedProtectedHours), }, { - Config: configBasic(orgID, projectName, dayOfWeekUpdated, conversion.Pointer(hourOfDay)), - Check: checkBasic(dayOfWeekUpdated, hourOfDay), + Config: configBasic(orgID, projectName, dayOfWeekUpdated, conversion.Pointer(hourOfDay), nil), + Check: checkBasic(dayOfWeekUpdated, hourOfDay, nil), }, { - Config: configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay)), - Check: checkBasic(dayOfWeek, hourOfDay), + Config: configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay), defaultProtectedHours), + Check: checkBasic(dayOfWeek, hourOfDay, defaultProtectedHours), }, { ResourceName: resourceName, @@ -70,8 +82,8 @@ func TestAccConfigRSMaintenanceWindow_emptyHourOfDay(t *testing.T) { ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, Steps: []resource.TestStep{ { - Config: configBasic(orgID, projectName, dayOfWeek, nil), - Check: checkBasic(dayOfWeek, 0), + Config: configBasic(orgID, projectName, dayOfWeek, nil, defaultProtectedHours), + Check: checkBasic(dayOfWeek, 0, defaultProtectedHours), }, }, }) @@ -133,11 +145,20 @@ func importStateIDFunc(resourceName string) resource.ImportStateIdFunc { } } -func configBasic(orgID, projectName string, dayOfWeek int, hourOfDay *int) string { +func configBasic(orgID, projectName string, dayOfWeek int, hourOfDay *int, protectedHours *admin.ProtectedHours) string { hourOfDayAttr := "" if hourOfDay != nil { hourOfDayAttr = fmt.Sprintf("hour_of_day = %d", *hourOfDay) } + protectedHoursStr := "" + if protectedHours != nil { + protectedHoursStr = fmt.Sprintf(` + protected_hours { + start_hour_of_day = %[1]d + end_hour_of_day = %[2]d + }`, *protectedHours.StartHourOfDay, *protectedHours.EndHourOfDay) + } + return fmt.Sprintf(` resource "mongodbatlas_project" "test" { name = %[2]q @@ -147,12 +168,9 @@ func configBasic(orgID, projectName string, dayOfWeek int, hourOfDay *int) strin project_id = mongodbatlas_project.test.id day_of_week = %[3]d %[4]s + %[5]s - protected_hours { - start_hour_of_day = 9 - end_hour_of_day = 17 - } - }`, orgID, projectName, dayOfWeek, hourOfDayAttr) + }`, orgID, projectName, dayOfWeek, hourOfDayAttr, protectedHoursStr) } func configWithAutoDeferEnabled(orgID, projectName string, dayOfWeek, hourOfDay int) string { @@ -169,12 +187,21 @@ func configWithAutoDeferEnabled(orgID, projectName string, dayOfWeek, hourOfDay }`, orgID, projectName, dayOfWeek, hourOfDay) } -func checkBasic(dayOfWeek, hourOfDay int) resource.TestCheckFunc { - return resource.ComposeAggregateTestCheckFunc( +func checkBasic(dayOfWeek, hourOfDay int, protectedHours *admin.ProtectedHours) resource.TestCheckFunc { + checks := []resource.TestCheckFunc{ checkExists(resourceName), resource.TestCheckResourceAttrSet(resourceName, "project_id"), resource.TestCheckResourceAttr(resourceName, "day_of_week", cast.ToString(dayOfWeek)), resource.TestCheckResourceAttr(resourceName, "hour_of_day", cast.ToString(hourOfDay)), resource.TestCheckResourceAttr(resourceName, "number_of_deferrals", "0"), - ) + } + if protectedHours != nil { + checks = append(checks, + resource.TestCheckResourceAttr(resourceName, "protected_hours.0.start_hour_of_day", cast.ToString(*protectedHours.StartHourOfDay)), + resource.TestCheckResourceAttr(resourceName, "protected_hours.0.end_hour_of_day", cast.ToString(*protectedHours.EndHourOfDay)), + ) + } else { + checks = append(checks, resource.TestCheckResourceAttr(resourceName, "protected_hours.#", "0")) + } + return resource.ComposeAggregateTestCheckFunc(checks...) } From 65b98e03c6125d6d2ae574808bb56a1dce18b9bc Mon Sep 17 00:00:00 2001 From: Espen Albert Date: Mon, 21 Apr 2025 16:25:10 +0100 Subject: [PATCH 07/11] test: Fix broken migration test --- .../resource_maintenance_window_migration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go b/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go index 63e5a69357..a6705dd74f 100644 --- a/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go +++ b/internal/service/maintenancewindow/resource_maintenance_window_migration_test.go @@ -17,7 +17,7 @@ func TestMigConfigMaintenanceWindow_basic(t *testing.T) { projectName = acc.RandomProjectName() dayOfWeek = 7 hourOfDay = 3 - config = configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay), defaultProtectedHours) + config = configBasic(orgID, projectName, dayOfWeek, conversion.Pointer(hourOfDay), nil) ) resource.ParallelTest(t, resource.TestCase{ From e783616ca6bd6e158c25abb84bce13f002841465 Mon Sep 17 00:00:00 2001 From: Espen Albert Date: Mon, 21 Apr 2025 16:29:12 +0100 Subject: [PATCH 08/11] fix: example maintenance window --- examples/mongodbatlas_maintenance_window/main.tf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/mongodbatlas_maintenance_window/main.tf b/examples/mongodbatlas_maintenance_window/main.tf index 0b5ea6b8a8..5c18db523d 100644 --- a/examples/mongodbatlas_maintenance_window/main.tf +++ b/examples/mongodbatlas_maintenance_window/main.tf @@ -7,7 +7,6 @@ resource "mongodbatlas_maintenance_window" "example" { project_id = mongodbatlas_project.example.id auto_defer_once_enabled = true hour_of_day = 23 - start_asap = true day_of_week = 1 protected_hours { start_hour_of_day = 9 @@ -16,6 +15,9 @@ resource "mongodbatlas_maintenance_window" "example" { } data "mongodbatlas_maintenance_window" "example" { - project_id = mongodbatlas_maintenance_window.example.project_id + project_id = mongodbatlas_maintenance_window.example.project_id } +output "time_zone_id" { + value = data.mongodbatlas_maintenance_window.example.time_zone_id +} \ No newline at end of file From 7b86a49b5ab9e89737bebe497e9266db53c74f0b Mon Sep 17 00:00:00 2001 From: Espen Albert Date: Mon, 21 Apr 2025 16:32:28 +0100 Subject: [PATCH 09/11] test: Add check for time_zone_id in auto defer activated test (already checked at resource) --- .../maintenancewindow/resource_maintenance_window_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/maintenancewindow/resource_maintenance_window_test.go b/internal/service/maintenancewindow/resource_maintenance_window_test.go index 48776649cd..b2054a7f42 100644 --- a/internal/service/maintenancewindow/resource_maintenance_window_test.go +++ b/internal/service/maintenancewindow/resource_maintenance_window_test.go @@ -110,6 +110,7 @@ func TestAccConfigRSMaintenanceWindow_autoDeferActivated(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "hour_of_day", cast.ToString(hourOfDay)), resource.TestCheckResourceAttr(resourceName, "number_of_deferrals", "0"), resource.TestCheckResourceAttr(resourceName, "auto_defer_once_enabled", "true"), + resource.TestCheckResourceAttrSet(resourceName, "time_zone_id"), ), }, }, From a8fff042f571c5e62f06a84c548678a8d8a4192c Mon Sep 17 00:00:00 2001 From: Espen Albert Date: Mon, 21 Apr 2025 16:38:01 +0100 Subject: [PATCH 10/11] feat: Add release notes for `protected_hours` and `time_zone_id` in maintenance window resources --- .changelog/3195.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/3195.txt diff --git a/.changelog/3195.txt b/.changelog/3195.txt new file mode 100644 index 0000000000..76447e66de --- /dev/null +++ b/.changelog/3195.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/mongodbatlas_maintenance_window: Adds `protected_hours` and `time_zone_id` +``` + +```release-note:enhancement +data-source/mongodbatlas_maintenance_window: Adds `protected_hours` and `time_zone_id` +``` From 3bd6f5cdcf4cc8643dfa8c6e1f58a435e7fe7363 Mon Sep 17 00:00:00 2001 From: Espen Albert Date: Mon, 21 Apr 2025 21:17:23 +0100 Subject: [PATCH 11/11] apply PR doc suggestions --- docs/data-sources/maintenance_window.md | 6 +++--- docs/resources/maintenance_window.md | 6 +++--- examples/mongodbatlas_maintenance_window/README.md | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/data-sources/maintenance_window.md b/docs/data-sources/maintenance_window.md index 9f14e9fe33..541d1d1db1 100644 --- a/docs/data-sources/maintenance_window.md +++ b/docs/data-sources/maintenance_window.md @@ -44,12 +44,12 @@ In addition to all arguments above, the following attributes are exported: * `start_asap` - Flag indicating whether project maintenance has been directed to start immediately. If you request that maintenance begin immediately, this field returns true from the time the request was made until the time the maintenance event completes. * `number_of_deferrals` - Number of times the current maintenance event for this project has been deferred, there can be a maximum of 2 deferrals. * `auto_defer_once_enabled` - Flag that indicates whether you want to defer all maintenance windows one week they would be triggered. -* `protected_hours` - (Optional) Defines the a window where maintenance will not begin within.. See [Protected Hours](#protected-hours). +* `protected_hours` - (Optional) Defines the time period during which there will be no standard updates to the clusters. See [Protected Hours](#protected-hours). * `time_zone_id` - Identifier for the current time zone of the maintenance window. This can only be updated via the Project Settings UI. ### Protected Hours -* `start_hour_of_day` - Zero-based integer that represents the beginning hour of the of the day that the maintenance will not begin in. -* `end_hour_of_day` - Zero-based integer that represents the end hour of the of the day that the maintenance will not begin in. +* `start_hour_of_day` - Zero-based integer that represents the beginning hour of the day for the protected hours window. +* `end_hour_of_day` - Zero-based integer that represents the end hour of the day for the protected hours window. For more information see: [MongoDB Atlas API Reference.](https://docs.atlas.mongodb.com/reference/api/maintenance-windows/) \ No newline at end of file diff --git a/docs/resources/maintenance_window.md b/docs/resources/maintenance_window.md index ee684129c0..bea1a9c461 100644 --- a/docs/resources/maintenance_window.md +++ b/docs/resources/maintenance_window.md @@ -46,13 +46,13 @@ Once maintenance is scheduled for your cluster, you cannot change your maintenan * `defer` - Defer the next scheduled maintenance for the given project for one week. * `auto_defer` - Defer any scheduled maintenance for the given project for one week. * `auto_defer_once_enabled` - Flag that indicates whether you want to defer all maintenance windows one week they would be triggered. -* `protected_hours` - (Optional) Defines the a window where maintenance will not begin within.. See [Protected Hours](#protected-hours). +* `protected_hours` - (Optional) Defines the time period during which there will be no standard updates to the clusters. See [Protected Hours](#protected-hours). -> **NOTE:** The `start_asap` attribute can't be used because of breaks the Terraform flow, but you can enable via API. ### Protected Hours -* `start_hour_of_day` - Zero-based integer that represents the beginning hour of the of the day that the maintenance will not begin in. -* `end_hour_of_day` - Zero-based integer that represents the end hour of the of the day that the maintenance will not begin in. +* `start_hour_of_day` - Zero-based integer that represents the beginning hour of the day for the protected hours window. +- `end_hour_of_day` - Zero-based integer that represents the end hour of the day for the protected hours window. ## Attributes Reference diff --git a/examples/mongodbatlas_maintenance_window/README.md b/examples/mongodbatlas_maintenance_window/README.md index 2406b2ba4e..3d988c7dc8 100644 --- a/examples/mongodbatlas_maintenance_window/README.md +++ b/examples/mongodbatlas_maintenance_window/README.md @@ -1,11 +1,11 @@ # MongoDB Atlas Provider - Configure Maintenance Window -This example shows how you can configure maintenance windows for your Atlas project in Terraform. +This example demonstrates how to configure maintenance windows for your Atlas project in Terraform. -Variables required to be set: +Required variables to set: - `public_key`: Atlas public key - `private_key`: Atlas private key -- `org_id`: Organization ID where the project and cluster will be created. +- `org_id`: Unique 24-hexadecimal digit string that identifies the organization that contains the project and cluster. For additional information you can visit the [Maintenance Window Documentation](https://www.mongodb.com/docs/atlas/tutorial/cluster-maintenance-window/). \ No newline at end of file