diff --git a/.changelog/3795.txt b/.changelog/3795.txt new file mode 100644 index 0000000000..a4878a57a1 --- /dev/null +++ b/.changelog/3795.txt @@ -0,0 +1,11 @@ +```release-note:enhancement +data-source/mongodbatlas_alert_configuration: Adds `severity_override` attribute +``` + +```release-note:enhancement +data-source/mongodbatlas_alert_configurations: Adds `severity_override` attribute +``` + +```release-note:enhancement +resource/mongodbatlas_alert_configuration: Adds `severity_override` attribute +``` diff --git a/contributing/testing-best-practices.md b/contributing/testing-best-practices.md index c580354d37..eed8830659 100644 --- a/contributing/testing-best-practices.md +++ b/contributing/testing-best-practices.md @@ -31,6 +31,7 @@ - `Basic import tests` are done as the last step in the `basic acceptance tests`, not as a different test, e.g. [basicTestCase](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/66c44e62c9afe04ffe8be0dbccaec682bab830e6/internal/service/searchindex/resource_search_index_test.go#L211). Exceptions apply for more specific import tests, e.g. testing with incorrect IDs. [Import tests](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/import#resource-acceptance-testing-implementation) verify that the [Terraform Import](https://developer.hashicorp.com/terraform/cli/import) functionality is working fine. - Data sources are tested in the same tests as the resources, e.g. [commonChecks](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/66c44e62c9afe04ffe8be0dbccaec682bab830e6/internal/service/searchindex/resource_search_index_test.go#L262-L263). - Helper functions such as `resource.TestCheckTypeSetElemNestedAttrs` or `resource.TestCheckTypeSetElemAttr` can be used to check resource and data source attributes more easily, e.g. [resource_serverless_instance_test.go](https://github.com/mongodb/terraform-provider-mongodbatlas/blob/66c44e62c9afe04ffe8be0dbccaec682bab830e6/internal/service/serverlessinstance/resource_serverless_instance_test.go#L61). +- Note: before running the acceptance tests, set the environment variable `TF_ACC=1`. ### Cloud Gov tests diff --git a/docs/data-sources/alert_configuration.md b/docs/data-sources/alert_configuration.md index f19fbe3523..ed58009322 100644 --- a/docs/data-sources/alert_configuration.md +++ b/docs/data-sources/alert_configuration.md @@ -121,6 +121,7 @@ In addition to all arguments above, the following attributes are exported: * `metric_threshold_config` - The threshold that causes an alert to be triggered. Required if `event_type_name` : `OUTSIDE_METRIC_THRESHOLD` or `OUTSIDE_SERVERLESS_METRIC_THRESHOLD`. See [metric threshold config](#metric-threshold-config). * `threshold_config` - Threshold that triggers an alert. Required if `event_type_name` is any value other than `OUTSIDE_METRIC_THRESHOLD` or `OUTSIDE_SERVERLESS_METRIC_THRESHOLD`. See [threshold config](#threshold-config). * `notifications` - List of notifications to send when an alert condition is detected. See [notifications](#notifications). +* `severity_override` - Severity of the event. -> ***IMPORTANT:*** Event Type has many possible values. Details for both conditional and metric based alerts can be found by selecting the tabs on the [alert config page](https://www.mongodb.com/docs/api/doc/atlas-admin-api-v2/operation/operation-createalertconfiguration) and checking the latest eventTypeName options. diff --git a/docs/data-sources/alert_configurations.md b/docs/data-sources/alert_configurations.md index 5f6694b18b..ccc8d6770a 100644 --- a/docs/data-sources/alert_configurations.md +++ b/docs/data-sources/alert_configurations.md @@ -64,6 +64,7 @@ In addition to all arguments above, the following attributes are exported: * `metric_threshold_config` - The threshold that causes an alert to be triggered. Required if `event_type_name` : `OUTSIDE_METRIC_THRESHOLD` or `OUTSIDE_SERVERLESS_METRIC_THRESHOLD`. See [metric threshold config](#metric-threshold-config). * `threshold_config` - Threshold that triggers an alert. Required if `event_type_name` is any value other than `OUTSIDE_METRIC_THRESHOLD` or `OUTSIDE_SERVERLESS_METRIC_THRESHOLD`. See [threshold config](#threshold-config). * `notifications` - List of notifications to send when an alert condition is detected. See [notifications](#notifications). +* `severity_override` - Severity of the event. * `output` - Requested output string format for the alert configuration -> ***IMPORTANT:*** Event Type has many possible values. Details for both conditional and metric based alerts can be found by selecting the tabs on the [alert config page](https://www.mongodb.com/docs/api/doc/atlas-admin-api-v2/operation/operation-createalertconfiguration) and checking the latest eventTypeName options. diff --git a/docs/resources/alert_configuration.md b/docs/resources/alert_configuration.md index 6ef919656c..18514fd7e9 100644 --- a/docs/resources/alert_configuration.md +++ b/docs/resources/alert_configuration.md @@ -150,6 +150,7 @@ resource "mongodbatlas_alert_configuration" "test" { -> **NOTE:** If `event_type` is set to `OUTSIDE_METRIC_THRESHOLD` or `OUTSIDE_SERVERLESS_METRIC_THRESHOLD`, the `metric_threshold_config` field must also be configured. +* `severity_override` - (Optional) Severity of the event. For the list of accepted values please read the [Create One Alert Configuration in One Project](https://www.mongodb.com/docs/api/doc/atlas-admin-api-v2/operation/operation-creategroupalertconfig) API documentation. ### Matchers Rules to apply when matching an object against this alert configuration. Only entities that match all these rules are checked for an alert condition. You can filter using the matchers array only when the eventTypeName specifies an event for a host, replica set, or sharded cluster. diff --git a/internal/service/alertconfiguration/data_source.go b/internal/service/alertconfiguration/data_source.go index 517f77f7ef..0b0ad396a2 100644 --- a/internal/service/alertconfiguration/data_source.go +++ b/internal/service/alertconfiguration/data_source.go @@ -27,6 +27,7 @@ type TFAlertConfigurationDSModel struct { EventType types.String `tfsdk:"event_type"` Created types.String `tfsdk:"created"` Updated types.String `tfsdk:"updated"` + SeverityOverride types.String `tfsdk:"severity_override"` Matcher []TfMatcherModel `tfsdk:"matcher"` MetricThresholdConfig []TfMetricThresholdConfigModel `tfsdk:"metric_threshold_config"` ThresholdConfig []TfThresholdConfigModel `tfsdk:"threshold_config"` @@ -242,6 +243,9 @@ var alertConfigDSSchemaAttributes = map[string]schema.Attribute{ }, }, }, + "severity_override": schema.StringAttribute{ + Computed: true, + }, } func (d *alertConfigurationDS) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { @@ -339,6 +343,10 @@ func outputAlertConfigurationResourceHcl(label string, alert *admin.GroupAlertsC appendBlockWithCtyValues(resource, "notification", []string{}, convertNotificationToCtyValues(¬ifications[i])) } + if alert.SeverityOverride != nil { + resource.SetAttributeValue("severity_override", cty.StringVal(*alert.SeverityOverride)) + } + return string(f.Bytes()) } diff --git a/internal/service/alertconfiguration/model.go b/internal/service/alertconfiguration/model.go index a334da85d5..9b15019d2d 100644 --- a/internal/service/alertconfiguration/model.go +++ b/internal/service/alertconfiguration/model.go @@ -107,6 +107,7 @@ func NewTFAlertConfigurationModel(apiRespConfig *admin.GroupAlertsConfig, currSt ThresholdConfig: NewTFThresholdConfigModel(apiRespConfig.Threshold, currState.ThresholdConfig), Notification: NewTFNotificationModelList(apiRespConfig.GetNotifications(), currState.Notification), Matcher: NewTFMatcherModelList(apiRespConfig.GetMatchers(), currState.Matcher), + SeverityOverride: types.StringPointerValue(apiRespConfig.SeverityOverride), } } @@ -298,6 +299,7 @@ func NewTfAlertConfigurationDSModel(apiRespConfig *admin.GroupAlertsConfig, proj ThresholdConfig: NewTFThresholdConfigModel(apiRespConfig.Threshold, []TfThresholdConfigModel{}), Notification: NewTFNotificationModelList(apiRespConfig.GetNotifications(), []TfNotificationModel{}), Matcher: NewTFMatcherModelList(apiRespConfig.GetMatchers(), []TfMatcherModel{}), + SeverityOverride: types.StringPointerValue(apiRespConfig.SeverityOverride), } } diff --git a/internal/service/alertconfiguration/model_test.go b/internal/service/alertconfiguration/model_test.go index 4dde994c68..4403665b66 100644 --- a/internal/service/alertconfiguration/model_test.go +++ b/internal/service/alertconfiguration/model_test.go @@ -30,14 +30,12 @@ var ( ) func TestNotificationSDKToTFModel(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { SDKResp *[]admin.AlertsNotificationRootForGroup currentStateNotifications []alertconfiguration.TfNotificationModel expectedTFModel []alertconfiguration.TfNotificationModel }{ - { - name: "Complete SDK response", + "Complete SDK response": { SDKResp: &[]admin.AlertsNotificationRootForGroup{ { TypeName: admin.PtrString(group), @@ -78,8 +76,8 @@ func TestNotificationSDKToTFModel(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { resultModel := alertconfiguration.NewTFNotificationModelList(*tc.SDKResp, tc.currentStateNotifications) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) @@ -87,14 +85,12 @@ func TestNotificationSDKToTFModel(t *testing.T) { } func TestMetricThresholdSDKToTFModel(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { SDKResp *admin.FlexClusterMetricThreshold currentStateMetricThreshold []alertconfiguration.TfMetricThresholdConfigModel expectedTFModel []alertconfiguration.TfMetricThresholdConfigModel }{ - { - name: "Complete SDK response", + "Complete SDK response": { SDKResp: &admin.FlexClusterMetricThreshold{ MetricName: "ASSERT_REGULAR", Operator: admin.PtrString(operator), @@ -123,8 +119,8 @@ func TestMetricThresholdSDKToTFModel(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { resultModel := alertconfiguration.NewTFMetricThresholdConfigModel(tc.SDKResp, tc.currentStateMetricThreshold) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) @@ -132,14 +128,12 @@ func TestMetricThresholdSDKToTFModel(t *testing.T) { } func TestThresholdConfigSDKToTFModel(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { SDKResp *admin.StreamProcessorMetricThreshold currentStateThresholdConfig []alertconfiguration.TfThresholdConfigModel expectedTFModel []alertconfiguration.TfThresholdConfigModel }{ - { - name: "Complete SDK response", + "Complete SDK response": { SDKResp: &admin.StreamProcessorMetricThreshold{ Threshold: admin.PtrFloat64(1.0), Operator: admin.PtrString("LESS_THAN"), @@ -162,8 +156,8 @@ func TestThresholdConfigSDKToTFModel(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { resultModel := alertconfiguration.NewTFThresholdConfigModel(tc.SDKResp, tc.currentStateThresholdConfig) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) @@ -171,14 +165,12 @@ func TestThresholdConfigSDKToTFModel(t *testing.T) { } func TestMatcherSDKToTFModel(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { SDKResp []admin.StreamsMatcher currentStateMatcher []alertconfiguration.TfMatcherModel expectedTFModel []alertconfiguration.TfMatcherModel }{ - { - name: "Complete SDK response", + "Complete SDK response": { SDKResp: []admin.StreamsMatcher{{ FieldName: "HOSTNAME", Operator: "EQUALS", @@ -202,8 +194,8 @@ func TestMatcherSDKToTFModel(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { resultModel := alertconfiguration.NewTFMatcherModelList(tc.SDKResp, tc.currentStateMatcher) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) @@ -211,14 +203,12 @@ func TestMatcherSDKToTFModel(t *testing.T) { } func TestAlertConfigurationSDKToTFModel(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { SDKResp *admin.GroupAlertsConfig currentStateAlertConfiguration *alertconfiguration.TfAlertConfigurationRSModel expectedTFModel alertconfiguration.TfAlertConfigurationRSModel }{ - { - name: "Complete SKD response", + "Complete SDK response": { SDKResp: &admin.GroupAlertsConfig{ Enabled: admin.PtrBool(true), EventTypeName: admin.PtrString("EventType"), @@ -248,10 +238,43 @@ func TestAlertConfigurationSDKToTFModel(t *testing.T) { Enabled: types.BoolValue(true), }, }, + "Complete SDK response with SeverityOverride": { + SDKResp: &admin.GroupAlertsConfig{ + Enabled: admin.PtrBool(true), + EventTypeName: admin.PtrString("EventType"), + GroupId: admin.PtrString("projectId"), + Id: admin.PtrString("alertConfigurationId"), + SeverityOverride: admin.PtrString("WARNING"), + }, + currentStateAlertConfiguration: &alertconfiguration.TfAlertConfigurationRSModel{ + ID: types.StringValue("id"), + ProjectID: types.StringValue("projectId"), + AlertConfigurationID: types.StringValue("alertConfigurationId"), + EventType: types.StringValue("EventType"), + Matcher: []alertconfiguration.TfMatcherModel{}, + MetricThresholdConfig: []alertconfiguration.TfMetricThresholdConfigModel{}, + ThresholdConfig: []alertconfiguration.TfThresholdConfigModel{}, + Notification: []alertconfiguration.TfNotificationModel{}, + Enabled: types.BoolValue(true), + SeverityOverride: types.StringValue("WARNING"), + }, + expectedTFModel: alertconfiguration.TfAlertConfigurationRSModel{ + ID: types.StringValue("id"), + ProjectID: types.StringValue("projectId"), + AlertConfigurationID: types.StringValue("alertConfigurationId"), + EventType: types.StringValue("EventType"), + Matcher: []alertconfiguration.TfMatcherModel{}, + MetricThresholdConfig: []alertconfiguration.TfMetricThresholdConfigModel{}, + ThresholdConfig: []alertconfiguration.TfThresholdConfigModel{}, + Notification: []alertconfiguration.TfNotificationModel{}, + Enabled: types.BoolValue(true), + SeverityOverride: types.StringValue("WARNING"), + }, + }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { resultModel := alertconfiguration.NewTFAlertConfigurationModel(tc.SDKResp, tc.currentStateAlertConfiguration) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) @@ -259,13 +282,11 @@ func TestAlertConfigurationSDKToTFModel(t *testing.T) { } func TestNotificationTFModelToSDK(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { expectedSDKReq *[]admin.AlertsNotificationRootForGroup tfModel []alertconfiguration.TfNotificationModel }{ - { - name: "Complete TF model", + "Complete TF model": { tfModel: []alertconfiguration.TfNotificationModel{ { TypeName: types.StringValue(group), @@ -291,8 +312,8 @@ func TestNotificationTFModelToSDK(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { apiReqResult, _ := alertconfiguration.NewNotificationList(tc.tfModel) assert.Equal(t, *tc.expectedSDKReq, *apiReqResult, "created sdk model did not match expected output") }) @@ -300,18 +321,15 @@ func TestNotificationTFModelToSDK(t *testing.T) { } func TestThresholdTFModelToSDK(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { expectedSDKReq *admin.StreamProcessorMetricThreshold tfModel []alertconfiguration.TfThresholdConfigModel }{ - { - name: "Empty TF model", + "Empty TF model": { tfModel: []alertconfiguration.TfThresholdConfigModel{}, expectedSDKReq: nil, }, - { - name: "Complete TF model", + "Complete TF model": { tfModel: []alertconfiguration.TfThresholdConfigModel{ { Threshold: types.Float64Value(1.0), @@ -327,8 +345,8 @@ func TestThresholdTFModelToSDK(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { apiReqResult := alertconfiguration.NewThreshold(tc.tfModel) assert.Equal(t, tc.expectedSDKReq, apiReqResult, "created sdk model did not match expected output") }) @@ -336,18 +354,15 @@ func TestThresholdTFModelToSDK(t *testing.T) { } func TestMetricThresholdTFModelToSDK(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { expectedSDKReq *admin.FlexClusterMetricThreshold tfModel []alertconfiguration.TfMetricThresholdConfigModel }{ - { - name: "Empty TF model", + "Empty TF model": { tfModel: []alertconfiguration.TfMetricThresholdConfigModel{}, expectedSDKReq: nil, }, - { - name: "Complete TF model", + "Complete TF model": { tfModel: []alertconfiguration.TfMetricThresholdConfigModel{ { Threshold: types.Float64Value(threshold), @@ -367,8 +382,8 @@ func TestMetricThresholdTFModelToSDK(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { apiReqResult := alertconfiguration.NewMetricThreshold(tc.tfModel) assert.Equal(t, tc.expectedSDKReq, apiReqResult, "created sdk model did not match expected output") }) @@ -376,18 +391,15 @@ func TestMetricThresholdTFModelToSDK(t *testing.T) { } func TestMatcherTFModelToSDK(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { expectedSDKReq []admin.StreamsMatcher tfModel []alertconfiguration.TfMatcherModel }{ - { - name: "Empty TF model", + "Empty TF model": { tfModel: []alertconfiguration.TfMatcherModel{}, expectedSDKReq: make([]admin.StreamsMatcher, 0), }, - { - name: "Complete TF model", + "Complete TF model": { tfModel: []alertconfiguration.TfMatcherModel{ { FieldName: types.StringValue("HOSTNAME"), @@ -403,8 +415,8 @@ func TestMatcherTFModelToSDK(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { apiReqResult := *alertconfiguration.NewMatcherList(tc.tfModel) assert.Equal(t, tc.expectedSDKReq, apiReqResult, "created sdk model did not match expected output") }) @@ -412,14 +424,12 @@ func TestMatcherTFModelToSDK(t *testing.T) { } func TestAlertConfigurationSdkToTFDSModel(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { apiRespConfig *admin.GroupAlertsConfig projectID string expectedTFModel alertconfiguration.TFAlertConfigurationDSModel }{ - { - name: "Complete SDK model", + "Complete SDK model": { apiRespConfig: &admin.GroupAlertsConfig{ Enabled: admin.PtrBool(true), EventTypeName: admin.PtrString("EventType"), @@ -444,8 +454,8 @@ func TestAlertConfigurationSdkToTFDSModel(t *testing.T) { }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { resultModel := alertconfiguration.NewTfAlertConfigurationDSModel(tc.apiRespConfig, tc.projectID) assert.Equal(t, tc.expectedTFModel, resultModel, "created terraform model did not match expected output") }) @@ -453,15 +463,13 @@ func TestAlertConfigurationSdkToTFDSModel(t *testing.T) { } func TestAlertConfigurationSdkToDSModelList(t *testing.T) { - testCases := []struct { - name string + testCases := map[string]struct { projectID string definedOutputs []string alerts []admin.GroupAlertsConfig expectedTfModel []alertconfiguration.TFAlertConfigurationDSModel }{ - { - name: "Complete SDK model", + "Complete SDK model": { alerts: []admin.GroupAlertsConfig{ { Enabled: admin.PtrBool(true), @@ -490,16 +498,64 @@ func TestAlertConfigurationSdkToDSModelList(t *testing.T) { { Type: types.StringValue("resource_hcl"), Label: types.StringValue("EventType_0"), - Value: types.StringValue("resource \"mongodbatlas_alert_configuration\" \"EventType_0\" {\n project_id = \"projectId\"\n event_type = \"EventType\"\n enabled = true\n}\n"), + Value: types.StringValue(`resource "mongodbatlas_alert_configuration" "EventType_0" { + project_id = "projectId" + event_type = "EventType" + enabled = true +} +`), + }, + }, + }, + }, + }, + "Complete SDK model with SeverityOverride": { + alerts: []admin.GroupAlertsConfig{ + { + Enabled: admin.PtrBool(true), + EventTypeName: admin.PtrString("EventType"), + GroupId: admin.PtrString("projectId"), + Id: admin.PtrString("alertConfigurationId"), + SeverityOverride: admin.PtrString("WARNING"), + }, + }, + projectID: "projectId", + definedOutputs: []string{"resource_hcl"}, + expectedTfModel: []alertconfiguration.TFAlertConfigurationDSModel{ + { + ID: types.StringValue(conversion.EncodeStateID(map[string]string{ + "id": "alertConfigurationId", + "project_id": "projectId", + })), + ProjectID: types.StringValue("projectId"), + AlertConfigurationID: types.StringValue("alertConfigurationId"), + EventType: types.StringValue("EventType"), + Enabled: types.BoolValue(true), + Matcher: []alertconfiguration.TfMatcherModel{}, + MetricThresholdConfig: []alertconfiguration.TfMetricThresholdConfigModel{}, + ThresholdConfig: []alertconfiguration.TfThresholdConfigModel{}, + Notification: []alertconfiguration.TfNotificationModel{}, + Output: []alertconfiguration.TfAlertConfigurationOutputModel{ + { + Type: types.StringValue("resource_hcl"), + Label: types.StringValue("EventType_0"), + Value: types.StringValue(`resource "mongodbatlas_alert_configuration" "EventType_0" { + project_id = "projectId" + event_type = "EventType" + enabled = true + severity_override = "WARNING" +} +`), }, }, + SeverityOverride: types.StringValue("WARNING"), }, }, }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { resultModel := alertconfiguration.NewTFAlertConfigurationDSModelList(tc.alerts, tc.projectID, tc.definedOutputs) assert.Equal(t, tc.expectedTfModel, resultModel, "created terraform model did not match expected output") }) diff --git a/internal/service/alertconfiguration/resource.go b/internal/service/alertconfiguration/resource.go index 258dad0182..b9805a034b 100644 --- a/internal/service/alertconfiguration/resource.go +++ b/internal/service/alertconfiguration/resource.go @@ -59,6 +59,7 @@ type TfAlertConfigurationRSModel struct { EventType types.String `tfsdk:"event_type"` Created types.String `tfsdk:"created"` Updated types.String `tfsdk:"updated"` + SeverityOverride types.String `tfsdk:"severity_override"` Matcher []TfMatcherModel `tfsdk:"matcher"` MetricThresholdConfig []TfMetricThresholdConfigModel `tfsdk:"metric_threshold_config"` ThresholdConfig []TfThresholdConfigModel `tfsdk:"threshold_config"` @@ -154,6 +155,12 @@ func (r *alertConfigurationRS) Schema(ctx context.Context, req resource.SchemaRe boolplanmodifier.UseStateForUnknown(), }, }, + "severity_override": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, }, Blocks: map[string]schema.Block{ "matcher": schema.ListNestedBlock{ @@ -381,11 +388,12 @@ func (r *alertConfigurationRS) Create(ctx context.Context, req resource.CreateRe projectID := alertConfigPlan.ProjectID.ValueString() apiReq := &admin.GroupAlertsConfig{ - EventTypeName: alertConfigPlan.EventType.ValueStringPointer(), - Enabled: alertConfigPlan.Enabled.ValueBoolPointer(), - Matchers: NewMatcherList(alertConfigPlan.Matcher), - MetricThreshold: NewMetricThreshold(alertConfigPlan.MetricThresholdConfig), - Threshold: NewThreshold(alertConfigPlan.ThresholdConfig), + EventTypeName: alertConfigPlan.EventType.ValueStringPointer(), + Enabled: alertConfigPlan.Enabled.ValueBoolPointer(), + Matchers: NewMatcherList(alertConfigPlan.Matcher), + MetricThreshold: NewMetricThreshold(alertConfigPlan.MetricThresholdConfig), + Threshold: NewThreshold(alertConfigPlan.ThresholdConfig), + SeverityOverride: alertConfigPlan.SeverityOverride.ValueStringPointer(), } notifications, err := NewNotificationList(alertConfigPlan.Notification) @@ -488,6 +496,10 @@ func (r *alertConfigurationRS) Update(ctx context.Context, req resource.UpdateRe apiReq.Matchers = NewMatcherList(alertConfigPlan.Matcher) } + if !alertConfigPlan.SeverityOverride.Equal(alertConfigState.SeverityOverride) { + apiReq.SeverityOverride = alertConfigPlan.SeverityOverride.ValueStringPointer() + } + // Always refresh structure to handle service keys being obfuscated coming back from read API call notifications, err := NewNotificationList(alertConfigPlan.Notification) if err != nil { diff --git a/internal/service/alertconfiguration/resource_test.go b/internal/service/alertconfiguration/resource_test.go index a290b5b3fa..bebeab3093 100644 --- a/internal/service/alertconfiguration/resource_test.go +++ b/internal/service/alertconfiguration/resource_test.go @@ -39,6 +39,7 @@ func TestAccConfigRSAlertConfiguration_basic(t *testing.T) { checkExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), resource.TestCheckResourceAttr(resourceName, "notification.#", "2"), + resource.TestCheckNoResourceAttr(resourceName, "severity_override"), // Data source checks checkExists(dataSourceName), resource.TestCheckResourceAttr(dataSourceName, "project_id", projectID), @@ -47,6 +48,7 @@ func TestAccConfigRSAlertConfiguration_basic(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "matcher.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "metric_threshold_config.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "threshold_config.#", "0"), + resource.TestCheckNoResourceAttr(dataSourceName, "severity_override"), ), }, { @@ -55,6 +57,7 @@ func TestAccConfigRSAlertConfiguration_basic(t *testing.T) { checkExists(resourceName), resource.TestCheckResourceAttr(resourceName, "project_id", projectID), resource.TestCheckResourceAttr(resourceName, "notification.#", "2"), + resource.TestCheckNoResourceAttr(resourceName, "severity_override"), // Data source checks checkExists(dataSourceName), resource.TestCheckResourceAttr(dataSourceName, "project_id", projectID), @@ -63,6 +66,7 @@ func TestAccConfigRSAlertConfiguration_basic(t *testing.T) { resource.TestCheckResourceAttr(dataSourceName, "matcher.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "metric_threshold_config.#", "1"), resource.TestCheckResourceAttr(dataSourceName, "threshold_config.#", "0"), + resource.TestCheckNoResourceAttr(dataSourceName, "severity_override"), ), }, { @@ -566,6 +570,41 @@ func TestAccConfigRSAlertConfiguration_withVictorOps(t *testing.T) { }) } +func TestAccConfigRSAlertConfiguration_withSeverityOverride(t *testing.T) { + var ( + projectID = acc.ProjectIDExecution(t) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(t) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: checkDestroy(), + Steps: []resource.TestStep{ + { + Config: configWithSeverityOverride(projectID, conversion.StringPtr("ERROR")), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "severity_override", "ERROR"), + // Data source checks + checkExists(dataSourceName), + resource.TestCheckResourceAttr(dataSourceName, "severity_override", "ERROR"), + ), + }, + // TODO: Should check for no attr once CLOUDP-353933 is fixed. + // { + // Config: configWithSeverityOverride(projectID, nil), + // Check: resource.ComposeAggregateTestCheckFunc( + // checkExists(resourceName), + // resource.TestCheckNoResourceAttr(resourceName, "severity_override"), + // // Data source checks + // checkExists(dataSourceName), + // resource.TestCheckNoResourceAttr(resourceName, "severity_override"), + // ), + // }, + }, + }) +} + func checkExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -1039,6 +1078,33 @@ func configWithEmptyOptionalBlocks(projectID string) string { `, projectID) } +func configWithSeverityOverride(projectID string, severity *string) string { + severityOverride := "" + if severity != nil { + severityOverride = fmt.Sprintf("severity_override = %[1]q", *severity) + } + + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration" "test" { + project_id = %[1]q + enabled = true + event_type = "NO_PRIMARY" + %[2]s + + notification { + type_name = "EMAIL" + interval_min = 60 + email_address = "test@mongodbtest.com" + } + } + + data "mongodbatlas_alert_configuration" "test" { + project_id = mongodbatlas_alert_configuration.test.project_id + alert_configuration_id = mongodbatlas_alert_configuration.test.id + } + `, projectID, severityOverride) +} + func TestAccConfigDSAlertConfiguration_withOutput(t *testing.T) { var ( projectID = acc.ProjectIDExecution(t)