From 0d1c5cae2c7ebd7c605b900ff55e453f42c33d4e Mon Sep 17 00:00:00 2001 From: Manuel Pedrozo Date: Thu, 13 Nov 2025 10:32:13 +0100 Subject: [PATCH 1/4] Generate alert configuration resource and add acc tests --- .github/workflows/acceptance-tests-runner.yml | 1 + .../alertconfigurationapi/main_test.go | 15 + .../alertconfigurationapi/resource.go | 149 ++++ .../alertconfigurationapi/resource_schema.go | 351 ++++++++ .../alertconfigurationapi/resource_test.go | 748 ++++++++++++++++++ tools/codegen/config.yml | 50 ++ .../models/alert_configuration_api.yaml | 579 ++++++++++++++ 7 files changed, 1893 insertions(+) create mode 100644 internal/serviceapi/alertconfigurationapi/main_test.go create mode 100755 internal/serviceapi/alertconfigurationapi/resource.go create mode 100755 internal/serviceapi/alertconfigurationapi/resource_schema.go create mode 100644 internal/serviceapi/alertconfigurationapi/resource_test.go create mode 100755 tools/codegen/models/alert_configuration_api.yaml diff --git a/.github/workflows/acceptance-tests-runner.yml b/.github/workflows/acceptance-tests-runner.yml index 0b62ee35c0..f7f5ebf8dc 100644 --- a/.github/workflows/acceptance-tests-runner.yml +++ b/.github/workflows/acceptance-tests-runner.yml @@ -299,6 +299,7 @@ jobs: - 'internal/provider/*.go' autogen_fast: - 'internal/common/autogen/*.go' + - 'internal/serviceapi/alertconfigurationapi/*.go' - 'internal/serviceapi/auditingapi/*.go' - 'internal/serviceapi/customdbroleapi/*.go' - 'internal/serviceapi/databaseuserapi/*.go' diff --git a/internal/serviceapi/alertconfigurationapi/main_test.go b/internal/serviceapi/alertconfigurationapi/main_test.go new file mode 100644 index 0000000000..2a45fcfe4f --- /dev/null +++ b/internal/serviceapi/alertconfigurationapi/main_test.go @@ -0,0 +1,15 @@ +package alertconfigurationapi_test + +import ( + "os" + "testing" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" +) + +func TestMain(m *testing.M) { + cleanup := acc.SetupSharedResources() + exitCode := m.Run() + cleanup() + os.Exit(exitCode) +} diff --git a/internal/serviceapi/alertconfigurationapi/resource.go b/internal/serviceapi/alertconfigurationapi/resource.go new file mode 100755 index 0000000000..f87930a417 --- /dev/null +++ b/internal/serviceapi/alertconfigurationapi/resource.go @@ -0,0 +1,149 @@ +// Code generated by terraform-provider-mongodbatlas using `make generate-resource`. DO NOT EDIT. + +package alertconfigurationapi + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/config" +) + +var _ resource.ResourceWithConfigure = &rs{} +var _ resource.ResourceWithImportState = &rs{} + +const apiVersionHeader = "application/vnd.atlas.2023-01-01+json" + +func Resource() resource.Resource { + return &rs{ + RSCommon: config.RSCommon{ + ResourceName: "alert_configuration_api", + }, + } +} + +type rs struct { + config.RSCommon +} + +func (r *rs) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = ResourceSchema(ctx) + conversion.UpdateSchemaDescription(&resp.Schema) +} + +func (r *rs) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan TFModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + pathParams := map[string]string{ + "groupId": plan.GroupId.ValueString(), + } + callParams := config.APICallParams{ + VersionHeader: apiVersionHeader, + RelativePath: "/api/atlas/v2/groups/{groupId}/alertConfigs", + PathParams: pathParams, + Method: "POST", + } + reqHandle := autogen.HandleCreateReq{ + Resp: resp, + Client: r.Client, + Plan: &plan, + CallParams: &callParams, + } + autogen.HandleCreate(ctx, reqHandle) +} + +func (r *rs) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state TFModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + reqHandle := autogen.HandleReadReq{ + Resp: resp, + Client: r.Client, + State: &state, + CallParams: readAPICallParams(&state), + } + autogen.HandleRead(ctx, reqHandle) +} + +func (r *rs) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan TFModel + var state TFModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + // Path params are grabbed from state as they may be computed-only and not present in the plan + pathParams := map[string]string{ + "groupId": state.GroupId.ValueString(), + "id": state.Id.ValueString(), + } + callParams := config.APICallParams{ + VersionHeader: apiVersionHeader, + RelativePath: "/api/atlas/v2/groups/{groupId}/alertConfigs/{id}", + PathParams: pathParams, + Method: "PUT", + } + reqHandle := autogen.HandleUpdateReq{ + Resp: resp, + Client: r.Client, + Plan: &plan, + CallParams: &callParams, + } + autogen.HandleUpdate(ctx, reqHandle) +} + +func (r *rs) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state TFModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + reqHandle := deleteRequest(r.Client, &state, &resp.Diagnostics) + autogen.HandleDelete(ctx, *reqHandle) +} + +func (r *rs) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + idAttributes := []string{"group_id", "id"} + autogen.HandleImport(ctx, idAttributes, req, resp) +} + +func readAPICallParams(model any) *config.APICallParams { + m := model.(*TFModel) + pathParams := map[string]string{ + "groupId": m.GroupId.ValueString(), + "id": m.Id.ValueString(), + } + return &config.APICallParams{ + VersionHeader: apiVersionHeader, + RelativePath: "/api/atlas/v2/groups/{groupId}/alertConfigs/{id}", + PathParams: pathParams, + Method: "GET", + } +} + +func deleteRequest(client *config.MongoDBClient, model *TFModel, diags *diag.Diagnostics) *autogen.HandleDeleteReq { + pathParams := map[string]string{ + "groupId": model.GroupId.ValueString(), + "id": model.Id.ValueString(), + } + return &autogen.HandleDeleteReq{ + Client: client, + State: model, + Diags: diags, + CallParams: &config.APICallParams{ + VersionHeader: apiVersionHeader, + RelativePath: "/api/atlas/v2/groups/{groupId}/alertConfigs/{id}", + PathParams: pathParams, + Method: "DELETE", + }, + } +} diff --git a/internal/serviceapi/alertconfigurationapi/resource_schema.go b/internal/serviceapi/alertconfigurationapi/resource_schema.go new file mode 100755 index 0000000000..cade116f51 --- /dev/null +++ b/internal/serviceapi/alertconfigurationapi/resource_schema.go @@ -0,0 +1,351 @@ +// Code generated by terraform-provider-mongodbatlas using `make generate-resource`. DO NOT EDIT. + +package alertconfigurationapi + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen/customtypes" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/customplanmodifier" +) + +func ResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "created": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Date and time when MongoDB Cloud created the alert configuration. This parameter expresses its value in the ISO 8601 timestamp format in UTC.", + }, + "enabled": schema.BoolAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "Flag that indicates whether someone enabled this alert configuration for the specified project.", + }, + "event_type_name": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Event type that triggers an alert.", + }, + "group_id": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access.\n\n**NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups.", + PlanModifiers: []planmodifier.String{customplanmodifier.CreateOnly()}, + }, + "id": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies this alert configuration.", + }, + "links": schema.ListNestedAttribute{ + Computed: true, + MarkdownDescription: "List of one or more Uniform Resource Locators (URLs) that point to API sub-resources, related API resources, or both. RFC 5988 outlines these relationships.", + CustomType: customtypes.NewNestedListType[TFLinksModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "href": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Uniform Resource Locator (URL) that points another API resource to which this response has some relationship. This URL often begins with `https://cloud.mongodb.com/api/atlas`.", + }, + "rel": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Uniform Resource Locator (URL) that defines the semantic relationship between this resource and another API resource. This URL often begins with `https://cloud.mongodb.com/api/atlas`.", + }, + }, + }, + }, + "matchers": schema.ListNestedAttribute{ + Optional: true, + MarkdownDescription: "List of rules that determine whether MongoDB Cloud checks an object for the alert configuration.", + CustomType: customtypes.NewNestedListType[TFMatchersModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "field_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Name of the parameter in the target object that MongoDB Cloud checks. The parameter must match all rules for MongoDB Cloud to check for alert configurations.", + }, + "operator": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Comparison operator to apply when checking the current metric value against **matcher[n].value**.", + }, + "value": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Value to match or exceed using the specified **matchers.operator**.", + }, + }, + }, + }, + "metric_threshold": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "Threshold for the metric that, when exceeded, triggers an alert. The metric threshold pertains to event types which reflects changes of measurements and metrics about the serverless database.", + CustomType: customtypes.NewObjectType[TFMetricThresholdModel](ctx), + Attributes: map[string]schema.Attribute{ + "metric_name": schema.StringAttribute{ + Required: true, + MarkdownDescription: "Human-readable label that identifies the metric against which MongoDB Cloud checks the configured **metricThreshold.threshold**.", + }, + "mode": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "MongoDB Cloud computes the current metric value as an average.", + }, + "operator": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Comparison operator to apply when checking the current metric value.", + }, + "threshold": schema.Float64Attribute{ + Optional: true, + MarkdownDescription: "Value of metric that, when exceeded, triggers an alert.", + }, + "units": schema.StringAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "Element used to express the quantity. This can be an element of time, storage capacity, and the like.", + }, + }, + }, + "notifications": schema.ListNestedAttribute{ + Optional: true, + MarkdownDescription: "List that contains the targets that MongoDB Cloud sends notifications.", + CustomType: customtypes.NewNestedListType[TFNotificationsModel](ctx), + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "api_token": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Slack API token or Bot token that MongoDB Cloud needs to send alert notifications via Slack. The resource requires this parameter when `\"notifications.[n].typeName\" : \"SLACK\"`. If the token later becomes invalid, MongoDB Cloud sends an email to the project owners. If the token remains invalid, MongoDB Cloud removes the token. \n\n**NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you:\n\n* View or edit the alert through the Atlas UI.\n\n* Query the alert for the notification through the Atlas Administration API.", + Sensitive: true, + }, + "channel_name": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Name of the Slack channel to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `\"notifications.[n].typeName\" : \"SLACK\"`.", + }, + "datadog_api_key": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Datadog API Key that MongoDB Cloud needs to send alert notifications to Datadog. You can find this API key in the Datadog dashboard. The resource requires this parameter when `\"notifications.[n].typeName\" : \"DATADOG\"`.\n\n**NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you:\n\n* View or edit the alert through the Atlas UI.\n\n* Query the alert for the notification through the Atlas Administration API.", + Sensitive: true, + }, + "datadog_region": schema.StringAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "Datadog region that indicates which API Uniform Resource Locator (URL) to use. The resource requires this parameter when `\"notifications.[n].typeName\" : \"DATADOG\"`.", + }, + "delay_min": schema.Int64Attribute{ + Computed: true, + Optional: true, + MarkdownDescription: "Number of minutes that MongoDB Cloud waits after detecting an alert condition before it sends out the first notification.", + }, + "email_address": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Email address to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `\"notifications.[n].typeName\" : \"EMAIL\"`. You don't need to set this value to send emails to individual or groups of MongoDB Cloud users including:\n\n- specific MongoDB Cloud users (`\"notifications.[n].typeName\" : \"USER\"`)\n- MongoDB Cloud users with specific project roles (`\"notifications.[n].typeName\" : \"GROUP\"`)\n- MongoDB Cloud users with specific organization roles (`\"notifications.[n].typeName\" : \"ORG\"`)\n- MongoDB Cloud teams (`\"notifications.[n].typeName\" : \"TEAM\"`)\n\nTo send emails to one MongoDB Cloud user or grouping of users, set the `notifications.[n].emailEnabled` parameter.", + }, + "email_enabled": schema.BoolAttribute{ + Optional: true, + MarkdownDescription: "Flag that indicates whether MongoDB Cloud should send email notifications. The resource requires this parameter when one of the following values have been set:\n\n- `\"notifications.[n].typeName\" : \"ORG\"`\n- `\"notifications.[n].typeName\" : \"GROUP\"`\n- `\"notifications.[n].typeName\" : \"USER\"`", + }, + "integration_id": schema.StringAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "The id of the associated integration, the credentials of which to use for requests.", + }, + "interval_min": schema.Int64Attribute{ + Computed: true, + Optional: true, + MarkdownDescription: "Number of minutes to wait between successive notifications. MongoDB Cloud sends notifications until someone acknowledges the unacknowledged alert.\n\nPagerDuty, VictorOps, and OpsGenie notifications don't return this element. Configure and manage the notification interval within each of those services.", + }, + "microsoft_teams_webhook_url": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Microsoft Teams Webhook Uniform Resource Locator (URL) that MongoDB Cloud needs to send this notification via Microsoft Teams. The resource requires this parameter when `\"notifications.[n].typeName\" : \"MICROSOFT_TEAMS\"`. If the URL later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it.\n\n**NOTE**: When you view or edit the alert for a Microsoft Teams notification, the URL appears partially redacted.", + Sensitive: true, + }, + "mobile_number": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Mobile phone number to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `\"notifications.[n].typeName\" : \"SMS\"`.", + }, + "notification_token": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "HipChat API token that MongoDB Cloud needs to send alert notifications to HipChat. The resource requires this parameter when `\"notifications.[n].typeName\" : \"HIP_CHAT\"`\". If the token later becomes invalid, MongoDB Cloud sends an email to the project owners. If the token remains invalid, MongoDB Cloud removes it.\n\n**NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you:\n\n* View or edit the alert through the Atlas UI.\n\n* Query the alert for the notification through the Atlas Administration API.", + Sensitive: true, + }, + "notifier_id": schema.StringAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "The notifierId is a system-generated unique identifier assigned to each notification method. This is needed when updating third-party notifications without requiring explicit authentication credentials.", + }, + "ops_genie_api_key": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "API Key that MongoDB Cloud needs to send this notification via Opsgenie. The resource requires this parameter when `\"notifications.[n].typeName\" : \"OPS_GENIE\"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it.\n\n**NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you:\n\n* View or edit the alert through the Atlas UI.\n\n* Query the alert for the notification through the Atlas Administration API.", + Sensitive: true, + }, + "ops_genie_region": schema.StringAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "Opsgenie region that indicates which API Uniform Resource Locator (URL) to use.", + }, + "region": schema.StringAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "PagerDuty region that indicates which API Uniform Resource Locator (URL) to use.", + }, + "roles": schema.ListAttribute{ + Optional: true, + MarkdownDescription: "List that contains the one or more organization roles that receive the configured alert. This parameter is available when `\"notifications.[n].typeName\" : \"GROUP\"` or `\"notifications.[n].typeName\" : \"ORG\"`. If you include this parameter, MongoDB Cloud sends alerts only to users assigned the roles you specify in the array. If you omit this parameter, MongoDB Cloud sends alerts to users assigned any role.", + CustomType: customtypes.NewListType[types.String](ctx), + ElementType: types.StringType, + }, + "room_name": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "HipChat API room name to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `\"notifications.[n].typeName\" : \"HIP_CHAT\"`\".", + }, + "service_key": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "PagerDuty service key that MongoDB Cloud needs to send notifications via PagerDuty. The resource requires this parameter when `\"notifications.[n].typeName\" : \"PAGER_DUTY\"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it.\n\n**NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you:\n\n* View or edit the alert through the Atlas UI.\n\n* Query the alert for the notification through the Atlas Administration API.", + Sensitive: true, + }, + "sms_enabled": schema.BoolAttribute{ + Optional: true, + MarkdownDescription: "Flag that indicates whether MongoDB Cloud should send text message notifications. The resource requires this parameter when one of the following values have been set:\n\n- `\"notifications.[n].typeName\" : \"ORG\"`\n- `\"notifications.[n].typeName\" : \"GROUP\"`\n- `\"notifications.[n].typeName\" : \"USER\"`", + }, + "team_id": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Unique 24-hexadecimal digit string that identifies one MongoDB Cloud team. The resource requires this parameter when `\"notifications.[n].typeName\" : \"TEAM\"`.", + }, + "team_name": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Name of the MongoDB Cloud team that receives this notification. The resource requires this parameter when `\"notifications.[n].typeName\" : \"TEAM\"`.", + }, + "type_name": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Human-readable label that displays the alert notification type.", + }, + "username": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "MongoDB Cloud username of the person to whom MongoDB Cloud sends notifications. Specify only MongoDB Cloud users who belong to the project that owns the alert configuration. The resource requires this parameter when `\"notifications.[n].typeName\" : \"USER\"`.", + }, + "victor_ops_api_key": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "API key that MongoDB Cloud needs to send alert notifications to Splunk On-Call. The resource requires this parameter when `\"notifications.[n].typeName\" : \"VICTOR_OPS\"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it.\n\n**NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you:\n\n* View or edit the alert through the Atlas UI.\n\n* Query the alert for the notification through the Atlas Administration API.", + Sensitive: true, + }, + "victor_ops_routing_key": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Routing key that MongoDB Cloud needs to send alert notifications to Splunk On-Call. The resource requires this parameter when `\"notifications.[n].typeName\" : \"VICTOR_OPS\"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it.", + }, + "webhook_secret": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Authentication secret for a webhook-based alert.\n\nAtlas returns this value if you set `\"notifications.[n].typeName\" :\"WEBHOOK\"` and either:\n* You set `notification.[n].webhookSecret` to a non-empty string\n* You set a default webhookSecret either on the Integrations page, or with the [Integrations API](#tag/Third-Party-Service-Integrations/operation/createIntegration)\n\n**NOTE**: When you view or edit the alert for a webhook notification, the secret appears completely redacted.", + Sensitive: true, + }, + "webhook_url": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Target URL for a webhook-based alert.\n\nAtlas returns this value if you set `\"notifications.[n].typeName\" :\"WEBHOOK\"` and either:\n* You set `notification.[n].webhookURL` to a non-empty string\n* You set a default webhookUrl either on the [Integrations](https://www.mongodb.com/docs/atlas/tutorial/third-party-service-integrations/#std-label-third-party-integrations) page, or with the [Integrations API](#tag/Third-Party-Service-Integrations/operation/createIntegration)\n\n**NOTE**: When you view or edit the alert for a Webhook URL notification, the URL appears partially redacted.", + Sensitive: true, + }, + }, + }, + }, + "severity_override": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Severity of the event.", + }, + "threshold": schema.SingleNestedAttribute{ + Optional: true, + MarkdownDescription: "Threshold for the metric that, when exceeded, triggers an alert. The metric threshold pertains to event types which reflects changes of measurements and metrics in stream processors.", + CustomType: customtypes.NewObjectType[TFThresholdModel](ctx), + Attributes: map[string]schema.Attribute{ + "metric_name": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Human-readable label that identifies the metric against which MongoDB Cloud checks the configured **metricThreshold.threshold**.", + }, + "mode": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "MongoDB Cloud computes the current metric value as an average.", + }, + "operator": schema.StringAttribute{ + Optional: true, + MarkdownDescription: "Comparison operator to apply when checking the current metric value.", + }, + "threshold": schema.Float64Attribute{ + Optional: true, + MarkdownDescription: "Value of metric that, when exceeded, triggers an alert.", + }, + "units": schema.StringAttribute{ + Computed: true, + Optional: true, + MarkdownDescription: "Element used to express the quantity. This can be an element of time, storage capacity, and the like.", + }, + }, + }, + "updated": schema.StringAttribute{ + Computed: true, + MarkdownDescription: "Date and time when someone last updated this alert configuration. This parameter expresses its value in the ISO 8601 timestamp format in UTC.", + }, + }, + } +} + +type TFModel struct { + Links customtypes.NestedListValue[TFLinksModel] `tfsdk:"links" autogen:"omitjson"` + Matchers customtypes.NestedListValue[TFMatchersModel] `tfsdk:"matchers"` + Notifications customtypes.NestedListValue[TFNotificationsModel] `tfsdk:"notifications"` + Created types.String `tfsdk:"created" autogen:"omitjson"` + EventTypeName types.String `tfsdk:"event_type_name"` + GroupId types.String `tfsdk:"group_id" autogen:"omitjson"` + Id types.String `tfsdk:"id" autogen:"omitjson"` + MetricThreshold customtypes.ObjectValue[TFMetricThresholdModel] `tfsdk:"metric_threshold"` + SeverityOverride types.String `tfsdk:"severity_override"` + Threshold customtypes.ObjectValue[TFThresholdModel] `tfsdk:"threshold"` + Updated types.String `tfsdk:"updated" autogen:"omitjson"` + Enabled types.Bool `tfsdk:"enabled"` +} +type TFLinksModel struct { + Href types.String `tfsdk:"href" autogen:"omitjson"` + Rel types.String `tfsdk:"rel" autogen:"omitjson"` +} +type TFMatchersModel struct { + FieldName types.String `tfsdk:"field_name"` + Operator types.String `tfsdk:"operator"` + Value types.String `tfsdk:"value"` +} +type TFMetricThresholdModel struct { + MetricName types.String `tfsdk:"metric_name"` + Mode types.String `tfsdk:"mode"` + Operator types.String `tfsdk:"operator"` + Threshold types.Float64 `tfsdk:"threshold"` + Units types.String `tfsdk:"units"` +} +type TFNotificationsModel struct { + Roles customtypes.ListValue[types.String] `tfsdk:"roles"` + OpsGenieRegion types.String `tfsdk:"ops_genie_region"` + TeamId types.String `tfsdk:"team_id"` + DatadogRegion types.String `tfsdk:"datadog_region"` + WebhookUrl types.String `tfsdk:"webhook_url" autogen:"sensitive"` + EmailAddress types.String `tfsdk:"email_address"` + WebhookSecret types.String `tfsdk:"webhook_secret" autogen:"sensitive"` + IntegrationId types.String `tfsdk:"integration_id"` + ApiToken types.String `tfsdk:"api_token" autogen:"sensitive"` + MicrosoftTeamsWebhookUrl types.String `tfsdk:"microsoft_teams_webhook_url" autogen:"sensitive"` + MobileNumber types.String `tfsdk:"mobile_number"` + NotificationToken types.String `tfsdk:"notification_token" autogen:"sensitive"` + Region types.String `tfsdk:"region"` + DatadogApiKey types.String `tfsdk:"datadog_api_key" autogen:"sensitive"` + VictorOpsRoutingKey types.String `tfsdk:"victor_ops_routing_key"` + NotifierId types.String `tfsdk:"notifier_id"` + ChannelName types.String `tfsdk:"channel_name"` + RoomName types.String `tfsdk:"room_name"` + ServiceKey types.String `tfsdk:"service_key" autogen:"sensitive"` + VictorOpsApiKey types.String `tfsdk:"victor_ops_api_key" autogen:"sensitive"` + OpsGenieApiKey types.String `tfsdk:"ops_genie_api_key" autogen:"sensitive"` + TeamName types.String `tfsdk:"team_name"` + TypeName types.String `tfsdk:"type_name"` + Username types.String `tfsdk:"username"` + IntervalMin types.Int64 `tfsdk:"interval_min"` + DelayMin types.Int64 `tfsdk:"delay_min"` + SmsEnabled types.Bool `tfsdk:"sms_enabled"` + EmailEnabled types.Bool `tfsdk:"email_enabled"` +} +type TFThresholdModel struct { + MetricName types.String `tfsdk:"metric_name"` + Mode types.String `tfsdk:"mode"` + Operator types.String `tfsdk:"operator"` + Threshold types.Float64 `tfsdk:"threshold"` + Units types.String `tfsdk:"units"` +} diff --git a/internal/serviceapi/alertconfigurationapi/resource_test.go b/internal/serviceapi/alertconfigurationapi/resource_test.go new file mode 100644 index 0000000000..449e2c51fd --- /dev/null +++ b/internal/serviceapi/alertconfigurationapi/resource_test.go @@ -0,0 +1,748 @@ +package alertconfigurationapi_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/conversion" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/testutil/acc" +) + +const ( + resourceName = "mongodbatlas_alert_configuration_api.test" +) + +func TestAccAlertConfigurationAPI_basic(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: configBasic(projectID, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckResourceAttr(resourceName, "notifications.#", "2"), + resource.TestCheckNoResourceAttr(resourceName, "severity_override"), + resource.TestCheckResourceAttrSet(resourceName, "notifications.0.notifier_id"), + resource.TestCheckResourceAttr(resourceName, "matchers.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "metric_threshold.metric_name"), + ), + }, + { + Config: configBasic(projectID, false), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckResourceAttr(resourceName, "notifications.#", "2"), + resource.TestCheckNoResourceAttr(resourceName, "severity_override"), + resource.TestCheckResourceAttrSet(resourceName, "notifications.0.notifier_id"), + resource.TestCheckResourceAttr(resourceName, "matchers.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "metric_threshold.metric_name"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: importStateProjectIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"group_id", "updated"}, + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_withEmptyMetricThresholdConfig(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: configWithEmptyMetricThresholdConfig(projectID, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckResourceAttr(resourceName, "notifications.#", "1"), + ), + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_withEmptyMatcherMetricThresholdConfig(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: configWithEmptyMatcherMetricThresholdConfig(projectID, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckResourceAttr(resourceName, "notifications.#", "1"), + ), + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_withMatchers(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: configWithMatchers(projectID, true, false, true, + map[string]interface{}{ + "fieldName": "TYPE_NAME", + "operator": "EQUALS", + "value": "SECONDARY", + }, + map[string]interface{}{ + "fieldName": "TYPE_NAME", + "operator": "CONTAINS", + "value": "MONGOS", + }), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + { + Config: configWithMatchers(projectID, false, true, false, + map[string]interface{}{ + "fieldName": "TYPE_NAME", + "operator": "NOT_EQUALS", + "value": "SECONDARY", + }, + map[string]interface{}{ + "fieldName": "HOSTNAME", + "operator": "EQUALS", + "value": "PRIMARY", + }), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_withMetricUpdated(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: configWithMetricUpdated(projectID, true, 99.0), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + { + Config: configWithMetricUpdated(projectID, true, 89.7), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + }, + }) +} + +// dummy keys used for credential values in third party notifications +const dummy32CharKey = "11111111111111111111111111111111" +const dummy36CharKey = "11111111-1111-1111-1111-111111111111" + +func TestAccAlertConfigurationAPI_updatePagerDutyWithNotifierId(t *testing.T) { + var ( + projectID = acc.ProjectIDExecution(t) + serviceKey = dummy32CharKey + notifierID = "651dd9336afac13e1c112222" + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(t) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: checkDestroy(), + Steps: []resource.TestStep{ + { + Config: configWithPagerDutyNotifierID(projectID, notifierID, serviceKey, 10), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckResourceAttr(resourceName, "notifications.0.delay_min", "10"), + resource.TestCheckResourceAttr(resourceName, "notifications.0.service_key", serviceKey), + ), + }, + { + Config: configWithPagerDutyNotifierID(projectID, notifierID, serviceKey, 15), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckResourceAttr(resourceName, "notifications.0.delay_min", "15"), + resource.TestCheckResourceAttr(resourceName, "notifications.0.service_key", serviceKey), + ), + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_withDataDog(t *testing.T) { + resource.Test(t, *datadogTestCase(t)) // not run in parallel so acc and mig tests don't interfere +} + +func datadogTestCase(t *testing.T) *resource.TestCase { + t.Helper() + + var ( + projectID = acc.ProjectIDExecution(t) + ddAPIKey = dummy32CharKey + ddRegion = "US" + + ddNotificationMap = map[string]string{ + "type_name": "DATADOG", + "interval_min": "5", + "delay_min": "0", + "datadog_api_key": ddAPIKey, + "datadog_region": ddRegion, + } + + ddNotificationUpdatedMap = map[string]string{ + "type_name": "DATADOG", + "interval_min": "6", + "delay_min": "0", + "datadog_api_key": ddAPIKey, + "datadog_region": ddRegion, + } + ) + + return &resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(t) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: checkDestroy(), + Steps: []resource.TestStep{ + { + Config: configWithDataDog(projectID, ddAPIKey, ddRegion, true, ddNotificationMap), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "notifications.*", ddNotificationMap), + ), + }, + { + Config: configWithDataDog(projectID, ddAPIKey, ddRegion, true, ddNotificationUpdatedMap), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "notifications.*", ddNotificationUpdatedMap), + ), + }, + }, + } +} + +func TestAccAlertConfigurationAPI_withPagerDuty(t *testing.T) { + var ( + projectID = acc.ProjectIDExecution(t) + serviceKey = dummy32CharKey + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(t) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: checkDestroy(), + Steps: []resource.TestStep{ + { + Config: configWithPagerDuty(projectID, serviceKey, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: importStateProjectIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + // service key is not returned by api in import operation + // integration_id is not returned during Create + ImportStateVerifyIgnore: []string{"updated", "notifications.0.service_key", "notifications.0.integration_id"}, + }, + }, + }) +} + +func TestAccAlertConfiguration_withEmailToPagerDuty(t *testing.T) { + var ( + projectID = acc.ProjectIDExecution(t) + serviceKey = dummy32CharKey + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(t) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: checkDestroy(), + Steps: []resource.TestStep{ + { + Config: configWithEmail(projectID, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + { + Config: configWithPagerDuty(projectID, serviceKey, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: importStateProjectIDFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + // service_key is not returned by api in import operation + // integration_id is not returned during Create + ImportStateVerifyIgnore: []string{"updated", "notifications.0.service_key", "notifications.0.integration_id"}, + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_withOpsGenie(t *testing.T) { + var ( + projectID = acc.ProjectIDExecution(t) + apiKey = dummy36CharKey + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(t) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: checkDestroy(), + Steps: []resource.TestStep{ + { + Config: configWithOpsGenie(projectID, apiKey, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_withVictorOps(t *testing.T) { + var ( + projectID = acc.ProjectIDExecution(t) + apiKey = dummy36CharKey + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acc.PreCheckBasic(t) }, + ProtoV6ProviderFactories: acc.TestAccProviderV6Factories, + CheckDestroy: checkDestroy(), + Steps: []resource.TestStep{ + { + Config: configWithVictorOps(projectID, apiKey, true), + Check: resource.ComposeAggregateTestCheckFunc( + checkExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "group_id", projectID), + ), + }, + }, + }) +} + +func TestAccAlertConfigurationAPI_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"), + ), + }, + // 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"), + // ), + // }, + }, + }) +} + +func checkExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + id := rs.Primary.Attributes["id"] + projectID := rs.Primary.Attributes["group_id"] + if id == "" || projectID == "" { + return fmt.Errorf("checkExists, attributes not found for: %s", resourceName) + } + _, _, err := acc.ConnV2().AlertConfigurationsApi.GetAlertConfig(context.Background(), projectID, id).Execute() + if err != nil { + return fmt.Errorf("the Alert Configuration(%s) does not exist", id) + } + return nil + } +} + +func checkDestroy() resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "mongodbatlas_alert_configuration_api" { + continue + } + id := rs.Primary.Attributes["id"] + projectID := rs.Primary.Attributes["group_id"] + if id == "" || projectID == "" { + return fmt.Errorf("checkDestroy, attributes not found for: %s", resourceName) + } + alert, _, err := acc.ConnV2().AlertConfigurationsApi.GetAlertConfig(context.Background(), projectID, id).Execute() + if alert != nil { + return fmt.Errorf("the Project Alert Configuration(%s) still exists %s", id, err) + } + } + return nil + } +} + +func importStateProjectIDFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("not found: %s", resourceName) + } + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["group_id"], rs.Primary.ID), nil + } +} + +func configBasic(projectID string, enabled bool) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[2]t + event_type_name = "OUTSIDE_METRIC_THRESHOLD" + + notifications = [{ + type_name = "GROUP" + interval_min = 5 + delay_min = 0 + sms_enabled = false + email_enabled = true + roles = ["GROUP_DATA_ACCESS_READ_ONLY", "GROUP_CLUSTER_MANAGER", "GROUP_DATA_ACCESS_ADMIN"] + }, { + type_name = "ORG" + interval_min = 5 + delay_min = 0 + sms_enabled = true + email_enabled = false + }] + + matchers = [{ + field_name = "HOSTNAME_AND_PORT" + operator = "EQUALS" + value = "SECONDARY" + }] + + metric_threshold = { + metric_name = "ASSERT_REGULAR" + operator = "LESS_THAN" + threshold = 99.0 + units = "RAW" + mode = "AVERAGE" + } + } + `, projectID, enabled) +} + +func configWithMatchers(projectID string, enabled, smsEnabled, emailEnabled bool, m1, m2 map[string]interface{}) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[2]t + event_type_name = "HOST_DOWN" + + notifications = [{ + type_name = "GROUP" + interval_min = 5 + delay_min = 0 + sms_enabled = %[3]t + email_enabled = %[4]t + roles = ["GROUP_DATA_ACCESS_READ_ONLY", "GROUP_CLUSTER_MANAGER"] + }] + + matchers = [{ + field_name = %[5]q + operator = %[6]q + value = %[7]q + }, { + field_name = %[8]q + operator = %[9]q + value = %[10]q + }] + } + `, projectID, enabled, smsEnabled, emailEnabled, + m1["fieldName"], m1["operator"], m1["value"], + m2["fieldName"], m2["operator"], m2["value"]) +} + +func configWithMetricUpdated(projectID string, enabled bool, threshold float64) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[2]t + event_type_name = "OUTSIDE_METRIC_THRESHOLD" + + notifications = [{ + type_name = "GROUP" + interval_min = 5 + delay_min = 0 + sms_enabled = false + email_enabled = true + roles = ["GROUP_DATA_ACCESS_READ_ONLY"] + }] + + matchers = [{ + field_name = "HOSTNAME_AND_PORT" + operator = "EQUALS" + value = "SECONDARY" + }] + + metric_threshold = { + metric_name = "ASSERT_REGULAR" + operator = "LESS_THAN" + threshold = %[3]f + units = "RAW" + mode = "AVERAGE" + } + } + `, projectID, enabled, threshold) +} + +func configWithDataDog(projectID, dataDogAPIKey, dataDogRegion string, enabled bool, ddNotificationMap map[string]string) string { + return fmt.Sprintf(` + resource "mongodbatlas_third_party_integration" "atlas_datadog" { + project_id = %[1]q + api_key = %[2]q + region = %[3]q + type = "DATADOG" + } + + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = mongodbatlas_third_party_integration.atlas_datadog.project_id + event_type_name = "REPLICATION_OPLOG_WINDOW_RUNNING_OUT" + enabled = %[4]t + + notifications = [{ + type_name = %[5]q + datadog_api_key = mongodbatlas_third_party_integration.atlas_datadog.api_key + datadog_region = mongodbatlas_third_party_integration.atlas_datadog.region + interval_min = %[6]v + delay_min = %[7]v + }] + + matchers = [{ + field_name = "REPLICA_SET_NAME" + operator = "EQUALS" + value = "SECONDARY" + }] + + threshold = { + operator = "LESS_THAN" + threshold = 72 + units = "HOURS" + } + } + `, projectID, dataDogAPIKey, dataDogRegion, enabled, ddNotificationMap["type_name"], ddNotificationMap["interval_min"], ddNotificationMap["delay_min"]) +} + +func configWithPagerDuty(projectID, serviceKey string, enabled bool) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[3]t + event_type_name = "NO_PRIMARY" + + notifications = [{ + type_name = "PAGER_DUTY" + service_key = %[2]q + delay_min = 0 + }] + } + `, projectID, serviceKey, enabled) +} + +func configWithEmail(projectID string, enabled bool) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[2]t + event_type_name = "NO_PRIMARY" + + notifications = [{ + type_name = "EMAIL" + interval_min = 60 + email_address = "test@mongodbtest.com" + }] + } + `, projectID, enabled) +} + +func configWithPagerDutyNotifierID(projectID, notifierID, serviceKey string, delayMin int) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = true + event_type_name = "NO_PRIMARY" + + notifications = [{ + type_name = "PAGER_DUTY" + notifier_id = %[2]q + service_key = %[3]q + delay_min = %[4]d + }] + } + `, projectID, notifierID, serviceKey, delayMin) +} + +func configWithOpsGenie(projectID, apiKey string, enabled bool) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[3]t + event_type_name = "NO_PRIMARY" + + notifications = [{ + type_name = "OPS_GENIE" + ops_genie_api_key = %[2]q + ops_genie_region = "US" + delay_min = 0 + }] + } + `, projectID, apiKey, enabled) +} + +func configWithVictorOps(projectID, apiKey string, enabled bool) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[3]t + event_type_name = "NO_PRIMARY" + + notifications = [{ + type_name = "VICTOR_OPS" + victor_ops_api_key = %[2]q + victor_ops_routing_key = "testing" + delay_min = 0 + }] + } + `, projectID, apiKey, enabled) +} + +func configWithEmptyMetricThresholdConfig(projectID string, enabled bool) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[2]t + event_type_name = "CLUSTER_MONGOS_IS_MISSING" + + notifications =[{ + type_name = "GROUP" + interval_min = 60 + delay_min = 0 + sms_enabled = true + email_enabled = false + roles = ["GROUP_OWNER"] + }] + } + `, projectID, enabled) +} + +func configWithEmptyMatcherMetricThresholdConfig(projectID string, enabled bool) string { + return fmt.Sprintf(` + resource "mongodbatlas_alert_configuration_api" "test" { + group_id = %[1]q + enabled = %[2]t + event_type_name = "CLUSTER_MONGOS_IS_MISSING" + + notifications = [{ + type_name = "GROUP" + interval_min = 60 + delay_min = 0 + sms_enabled = true + email_enabled = false + roles = ["GROUP_OWNER"] + }] + } + `, projectID, enabled) +} + +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_api" "test" { + group_id = %[1]q + enabled = true + event_type_name = "NO_PRIMARY" + %[2]s + + notifications = [{ + type_name = "EMAIL" + interval_min = 60 + email_address = "test@mongodbtest.com" + }] + } + `, projectID, severityOverride) +} diff --git a/tools/codegen/config.yml b/tools/codegen/config.yml index bf8aee266c..d743c7f61b 100644 --- a/tools/codegen/config.yml +++ b/tools/codegen/config.yml @@ -543,3 +543,53 @@ resources: sensitive: true roles: type: set + + alert_configuration_api: + read: + path: /api/atlas/v2/groups/{groupId}/alertConfigs/{alertConfigId} + method: GET + create: + path: /api/atlas/v2/groups/{groupId}/alertConfigs + method: POST + update: + path: /api/atlas/v2/groups/{groupId}/alertConfigs/{alertConfigId} + method: PUT + delete: + path: /api/atlas/v2/groups/{groupId}/alertConfigs/{alertConfigId} + method: DELETE + schema: + aliases: + alertConfigId: id # path param name does not match the API response property + overrides: + notifications.notifier_id: + computability: + optional: true + computed: true + notifications.delay_min: + computability: + optional: true + computed: true + notifications.interval_min: + computability: + optional: true + computed: true + notifications.integration_id: + computability: + optional: true + computed: true + notifications.datadog_api_key: + sensitive: true + notifications.service_key: + sensitive: true + notifications.api_token: + sensitive: true + notifications.victor_ops_api_key: + sensitive: true + notifications.notification_token: + sensitive: true + notifications.microsoft_teams_webhook_url: + sensitive: true + notifications.webhook_url: + sensitive: true + notifications.ops_genie_api_key: + sensitive: true diff --git a/tools/codegen/models/alert_configuration_api.yaml b/tools/codegen/models/alert_configuration_api.yaml new file mode 100755 index 0000000000..795f5fa6e7 --- /dev/null +++ b/tools/codegen/models/alert_configuration_api.yaml @@ -0,0 +1,579 @@ +schema: + description: |- + Creates one alert configuration for the specified project. Alert configurations define the triggers and notification methods for alerts. To use this resource, the requesting Service Account or API Key must have the Organization Owner or Project Owner role. + + This resource remains under revision and may change. + attributes: + - string: {} + description: Date and time when MongoDB Cloud created the alert configuration. This parameter expresses its value in the ISO 8601 timestamp format in UTC. + computed_optional_required: computed + tf_schema_name: created + tf_model_name: Created + req_body_usage: omit_always + sensitive: false + create_only: false + - bool: + default: false + description: Flag that indicates whether someone enabled this alert configuration for the specified project. + computed_optional_required: computed_optional + tf_schema_name: enabled + tf_model_name: Enabled + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Event type that triggers an alert. + computed_optional_required: optional + tf_schema_name: event_type_name + tf_model_name: EventTypeName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + Unique 24-hexadecimal digit string that identifies your project. Use the [/groups](#tag/Projects/operation/listProjects) endpoint to retrieve all projects to which the authenticated user has access. + + **NOTE**: Groups and projects are synonymous terms. Your group id is the same as your project id. For existing groups, your group/project id remains the same. The resource and corresponding endpoints use the term groups. + computed_optional_required: required + tf_schema_name: group_id + tf_model_name: GroupId + req_body_usage: omit_always + sensitive: false + create_only: true + - string: {} + description: Unique 24-hexadecimal digit string that identifies this alert configuration. + computed_optional_required: computed + tf_schema_name: id + tf_model_name: Id + req_body_usage: omit_always + sensitive: false + create_only: false + - list_nested: + nested_object: + attributes: + - string: {} + description: Uniform Resource Locator (URL) that points another API resource to which this response has some relationship. This URL often begins with `https://cloud.mongodb.com/api/atlas`. + computed_optional_required: computed + tf_schema_name: href + tf_model_name: Href + req_body_usage: omit_always + sensitive: false + create_only: false + - string: {} + description: Uniform Resource Locator (URL) that defines the semantic relationship between this resource and another API resource. This URL often begins with `https://cloud.mongodb.com/api/atlas`. + computed_optional_required: computed + tf_schema_name: rel + tf_model_name: Rel + req_body_usage: omit_always + sensitive: false + create_only: false + description: List of one or more Uniform Resource Locators (URLs) that point to API sub-resources, related API resources, or both. RFC 5988 outlines these relationships. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFLinksModel] + schema: customtypes.NewNestedListType[TFLinksModel](ctx) + computed_optional_required: computed + tf_schema_name: links + tf_model_name: Links + req_body_usage: omit_always + sensitive: false + create_only: false + - list_nested: + nested_object: + attributes: + - string: {} + description: Name of the parameter in the target object that MongoDB Cloud checks. The parameter must match all rules for MongoDB Cloud to check for alert configurations. + computed_optional_required: required + tf_schema_name: field_name + tf_model_name: FieldName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Comparison operator to apply when checking the current metric value against **matcher[n].value**. + computed_optional_required: required + tf_schema_name: operator + tf_model_name: Operator + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Value to match or exceed using the specified **matchers.operator**. + computed_optional_required: required + tf_schema_name: value + tf_model_name: Value + req_body_usage: all_request_bodies + sensitive: false + create_only: false + description: List of rules that determine whether MongoDB Cloud checks an object for the alert configuration. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFMatchersModel] + schema: customtypes.NewNestedListType[TFMatchersModel](ctx) + computed_optional_required: optional + tf_schema_name: matchers + tf_model_name: Matchers + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - single_nested: + nested_object: + attributes: + - string: {} + description: Human-readable label that identifies the metric against which MongoDB Cloud checks the configured **metricThreshold.threshold**. + computed_optional_required: required + tf_schema_name: metric_name + tf_model_name: MetricName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: MongoDB Cloud computes the current metric value as an average. + computed_optional_required: optional + tf_schema_name: mode + tf_model_name: Mode + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Comparison operator to apply when checking the current metric value. + computed_optional_required: optional + tf_schema_name: operator + tf_model_name: Operator + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - float64: {} + description: Value of metric that, when exceeded, triggers an alert. + computed_optional_required: optional + tf_schema_name: threshold + tf_model_name: Threshold + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: + default: HOURS + description: Element used to express the quantity. This can be an element of time, storage capacity, and the like. + computed_optional_required: computed_optional + tf_schema_name: units + tf_model_name: Units + req_body_usage: all_request_bodies + sensitive: false + create_only: false + description: Threshold for the metric that, when exceeded, triggers an alert. The metric threshold pertains to event types which reflects changes of measurements and metrics about the serverless database. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFMetricThresholdModel] + schema: customtypes.NewObjectType[TFMetricThresholdModel](ctx) + computed_optional_required: optional + tf_schema_name: metric_threshold + tf_model_name: MetricThreshold + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - list_nested: + nested_object: + attributes: + - string: {} + description: "Slack API token or Bot token that MongoDB Cloud needs to send alert notifications via Slack. The resource requires this parameter when `\"notifications.[n].typeName\" : \"SLACK\"`. If the token later becomes invalid, MongoDB Cloud sends an email to the project owners. If the token remains invalid, MongoDB Cloud removes the token. \n\n**NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you:\n\n* View or edit the alert through the Atlas UI.\n\n* Query the alert for the notification through the Atlas Administration API." + computed_optional_required: optional + tf_schema_name: api_token + tf_model_name: ApiToken + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - string: {} + description: 'Name of the Slack channel to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `"notifications.[n].typeName" : "SLACK"`.' + computed_optional_required: optional + tf_schema_name: channel_name + tf_model_name: ChannelName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + Datadog API Key that MongoDB Cloud needs to send alert notifications to Datadog. You can find this API key in the Datadog dashboard. The resource requires this parameter when `"notifications.[n].typeName" : "DATADOG"`. + + **NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you: + + * View or edit the alert through the Atlas UI. + + * Query the alert for the notification through the Atlas Administration API. + computed_optional_required: optional + tf_schema_name: datadog_api_key + tf_model_name: DatadogApiKey + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - string: + default: US + description: 'Datadog region that indicates which API Uniform Resource Locator (URL) to use. The resource requires this parameter when `"notifications.[n].typeName" : "DATADOG"`.' + computed_optional_required: computed_optional + tf_schema_name: datadog_region + tf_model_name: DatadogRegion + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - int64: {} + description: Number of minutes that MongoDB Cloud waits after detecting an alert condition before it sends out the first notification. + computed_optional_required: computed_optional + tf_schema_name: delay_min + tf_model_name: DelayMin + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + Email address to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `"notifications.[n].typeName" : "EMAIL"`. You don't need to set this value to send emails to individual or groups of MongoDB Cloud users including: + + - specific MongoDB Cloud users (`"notifications.[n].typeName" : "USER"`) + - MongoDB Cloud users with specific project roles (`"notifications.[n].typeName" : "GROUP"`) + - MongoDB Cloud users with specific organization roles (`"notifications.[n].typeName" : "ORG"`) + - MongoDB Cloud teams (`"notifications.[n].typeName" : "TEAM"`) + + To send emails to one MongoDB Cloud user or grouping of users, set the `notifications.[n].emailEnabled` parameter. + computed_optional_required: optional + tf_schema_name: email_address + tf_model_name: EmailAddress + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - bool: {} + description: |- + Flag that indicates whether MongoDB Cloud should send email notifications. The resource requires this parameter when one of the following values have been set: + + - `"notifications.[n].typeName" : "ORG"` + - `"notifications.[n].typeName" : "GROUP"` + - `"notifications.[n].typeName" : "USER"` + computed_optional_required: optional + tf_schema_name: email_enabled + tf_model_name: EmailEnabled + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: The id of the associated integration, the credentials of which to use for requests. + computed_optional_required: computed_optional + tf_schema_name: integration_id + tf_model_name: IntegrationId + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - int64: {} + description: |- + Number of minutes to wait between successive notifications. MongoDB Cloud sends notifications until someone acknowledges the unacknowledged alert. + + PagerDuty, VictorOps, and OpsGenie notifications don't return this element. Configure and manage the notification interval within each of those services. + computed_optional_required: computed_optional + tf_schema_name: interval_min + tf_model_name: IntervalMin + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + Microsoft Teams Webhook Uniform Resource Locator (URL) that MongoDB Cloud needs to send this notification via Microsoft Teams. The resource requires this parameter when `"notifications.[n].typeName" : "MICROSOFT_TEAMS"`. If the URL later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it. + + **NOTE**: When you view or edit the alert for a Microsoft Teams notification, the URL appears partially redacted. + computed_optional_required: optional + tf_schema_name: microsoft_teams_webhook_url + tf_model_name: MicrosoftTeamsWebhookUrl + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - string: {} + description: 'Mobile phone number to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `"notifications.[n].typeName" : "SMS"`.' + computed_optional_required: optional + tf_schema_name: mobile_number + tf_model_name: MobileNumber + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + HipChat API token that MongoDB Cloud needs to send alert notifications to HipChat. The resource requires this parameter when `"notifications.[n].typeName" : "HIP_CHAT"`". If the token later becomes invalid, MongoDB Cloud sends an email to the project owners. If the token remains invalid, MongoDB Cloud removes it. + + **NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you: + + * View or edit the alert through the Atlas UI. + + * Query the alert for the notification through the Atlas Administration API. + computed_optional_required: optional + tf_schema_name: notification_token + tf_model_name: NotificationToken + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - string: {} + description: The notifierId is a system-generated unique identifier assigned to each notification method. This is needed when updating third-party notifications without requiring explicit authentication credentials. + computed_optional_required: computed_optional + tf_schema_name: notifier_id + tf_model_name: NotifierId + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + API Key that MongoDB Cloud needs to send this notification via Opsgenie. The resource requires this parameter when `"notifications.[n].typeName" : "OPS_GENIE"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it. + + **NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you: + + * View or edit the alert through the Atlas UI. + + * Query the alert for the notification through the Atlas Administration API. + computed_optional_required: optional + tf_schema_name: ops_genie_api_key + tf_model_name: OpsGenieApiKey + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - string: + default: US + description: Opsgenie region that indicates which API Uniform Resource Locator (URL) to use. + computed_optional_required: computed_optional + tf_schema_name: ops_genie_region + tf_model_name: OpsGenieRegion + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: + default: US + description: PagerDuty region that indicates which API Uniform Resource Locator (URL) to use. + computed_optional_required: computed_optional + tf_schema_name: region + tf_model_name: Region + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - list: + element_type: 4 + description: 'List that contains the one or more organization roles that receive the configured alert. This parameter is available when `"notifications.[n].typeName" : "GROUP"` or `"notifications.[n].typeName" : "ORG"`. If you include this parameter, MongoDB Cloud sends alerts only to users assigned the roles you specify in the array. If you omit this parameter, MongoDB Cloud sends alerts to users assigned any role.' + custom_type: + package: customtypes + model: customtypes.ListValue[types.String] + schema: customtypes.NewListType[types.String](ctx) + computed_optional_required: optional + tf_schema_name: roles + tf_model_name: Roles + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: 'HipChat API room name to which MongoDB Cloud sends alert notifications. The resource requires this parameter when `"notifications.[n].typeName" : "HIP_CHAT"`".' + computed_optional_required: optional + tf_schema_name: room_name + tf_model_name: RoomName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + PagerDuty service key that MongoDB Cloud needs to send notifications via PagerDuty. The resource requires this parameter when `"notifications.[n].typeName" : "PAGER_DUTY"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it. + + **NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you: + + * View or edit the alert through the Atlas UI. + + * Query the alert for the notification through the Atlas Administration API. + computed_optional_required: optional + tf_schema_name: service_key + tf_model_name: ServiceKey + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - bool: {} + description: |- + Flag that indicates whether MongoDB Cloud should send text message notifications. The resource requires this parameter when one of the following values have been set: + + - `"notifications.[n].typeName" : "ORG"` + - `"notifications.[n].typeName" : "GROUP"` + - `"notifications.[n].typeName" : "USER"` + computed_optional_required: optional + tf_schema_name: sms_enabled + tf_model_name: SmsEnabled + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: 'Unique 24-hexadecimal digit string that identifies one MongoDB Cloud team. The resource requires this parameter when `"notifications.[n].typeName" : "TEAM"`.' + computed_optional_required: optional + tf_schema_name: team_id + tf_model_name: TeamId + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: 'Name of the MongoDB Cloud team that receives this notification. The resource requires this parameter when `"notifications.[n].typeName" : "TEAM"`.' + computed_optional_required: optional + tf_schema_name: team_name + tf_model_name: TeamName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Human-readable label that displays the alert notification type. + computed_optional_required: optional + tf_schema_name: type_name + tf_model_name: TypeName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: 'MongoDB Cloud username of the person to whom MongoDB Cloud sends notifications. Specify only MongoDB Cloud users who belong to the project that owns the alert configuration. The resource requires this parameter when `"notifications.[n].typeName" : "USER"`.' + computed_optional_required: optional + tf_schema_name: username + tf_model_name: Username + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + API key that MongoDB Cloud needs to send alert notifications to Splunk On-Call. The resource requires this parameter when `"notifications.[n].typeName" : "VICTOR_OPS"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it. + + **NOTE**: After you create a notification which requires an API or integration key, the key appears partially redacted when you: + + * View or edit the alert through the Atlas UI. + + * Query the alert for the notification through the Atlas Administration API. + computed_optional_required: optional + tf_schema_name: victor_ops_api_key + tf_model_name: VictorOpsApiKey + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - string: {} + description: 'Routing key that MongoDB Cloud needs to send alert notifications to Splunk On-Call. The resource requires this parameter when `"notifications.[n].typeName" : "VICTOR_OPS"`. If the key later becomes invalid, MongoDB Cloud sends an email to the project owners. If the key remains invalid, MongoDB Cloud removes it.' + computed_optional_required: optional + tf_schema_name: victor_ops_routing_key + tf_model_name: VictorOpsRoutingKey + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: |- + Authentication secret for a webhook-based alert. + + Atlas returns this value if you set `"notifications.[n].typeName" :"WEBHOOK"` and either: + * You set `notification.[n].webhookSecret` to a non-empty string + * You set a default webhookSecret either on the Integrations page, or with the [Integrations API](#tag/Third-Party-Service-Integrations/operation/createIntegration) + + **NOTE**: When you view or edit the alert for a webhook notification, the secret appears completely redacted. + computed_optional_required: optional + tf_schema_name: webhook_secret + tf_model_name: WebhookSecret + req_body_usage: all_request_bodies + sensitive: true + create_only: false + - string: {} + description: |- + Target URL for a webhook-based alert. + + Atlas returns this value if you set `"notifications.[n].typeName" :"WEBHOOK"` and either: + * You set `notification.[n].webhookURL` to a non-empty string + * You set a default webhookUrl either on the [Integrations](https://www.mongodb.com/docs/atlas/tutorial/third-party-service-integrations/#std-label-third-party-integrations) page, or with the [Integrations API](#tag/Third-Party-Service-Integrations/operation/createIntegration) + + **NOTE**: When you view or edit the alert for a Webhook URL notification, the URL appears partially redacted. + computed_optional_required: optional + tf_schema_name: webhook_url + tf_model_name: WebhookUrl + req_body_usage: all_request_bodies + sensitive: true + create_only: false + description: List that contains the targets that MongoDB Cloud sends notifications. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFNotificationsModel] + schema: customtypes.NewNestedListType[TFNotificationsModel](ctx) + computed_optional_required: optional + tf_schema_name: notifications + tf_model_name: Notifications + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Severity of the event. + computed_optional_required: optional + tf_schema_name: severity_override + tf_model_name: SeverityOverride + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - single_nested: + nested_object: + attributes: + - string: {} + description: Human-readable label that identifies the metric against which MongoDB Cloud checks the configured **metricThreshold.threshold**. + computed_optional_required: optional + tf_schema_name: metric_name + tf_model_name: MetricName + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: MongoDB Cloud computes the current metric value as an average. + computed_optional_required: optional + tf_schema_name: mode + tf_model_name: Mode + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Comparison operator to apply when checking the current metric value. + computed_optional_required: optional + tf_schema_name: operator + tf_model_name: Operator + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - float64: {} + description: Value of metric that, when exceeded, triggers an alert. + computed_optional_required: optional + tf_schema_name: threshold + tf_model_name: Threshold + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: + default: RAW + description: Element used to express the quantity. This can be an element of time, storage capacity, and the like. + computed_optional_required: computed_optional + tf_schema_name: units + tf_model_name: Units + req_body_usage: all_request_bodies + sensitive: false + create_only: false + description: Threshold for the metric that, when exceeded, triggers an alert. The metric threshold pertains to event types which reflects changes of measurements and metrics in stream processors. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFThresholdModel] + schema: customtypes.NewObjectType[TFThresholdModel](ctx) + computed_optional_required: optional + tf_schema_name: threshold + tf_model_name: Threshold + req_body_usage: all_request_bodies + sensitive: false + create_only: false + - string: {} + description: Date and time when someone last updated this alert configuration. This parameter expresses its value in the ISO 8601 timestamp format in UTC. + computed_optional_required: computed + tf_schema_name: updated + tf_model_name: Updated + req_body_usage: omit_always + sensitive: false + create_only: false +operations: + delete: + http_method: DELETE + path: /api/atlas/v2/groups/{groupId}/alertConfigs/{id} + create: + http_method: POST + path: /api/atlas/v2/groups/{groupId}/alertConfigs + read: + http_method: GET + path: /api/atlas/v2/groups/{groupId}/alertConfigs/{id} + update: + http_method: PUT + path: /api/atlas/v2/groups/{groupId}/alertConfigs/{id} + version_header: application/vnd.atlas.2023-01-01+json +name: alert_configuration_api +packageName: alertconfigurationapi From 8a878796bb970170c167c39ad13861380ca39ebc Mon Sep 17 00:00:00 2001 From: Manuel Pedrozo Date: Thu, 13 Nov 2025 12:00:56 +0100 Subject: [PATCH 2/4] Pinning fieldalignment version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5a5756d4f4..68a6f72e48 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ tools: ## Install the dev tools (dependencies) go install github.com/icholy/gomajor@latest go install github.com/terraform-linters/tflint@v0.52.0 go install github.com/rhysd/actionlint/cmd/actionlint@latest - go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest + go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@v0.38.0 # Pinning version since v0.39.0 fails to fix files with large structs. See versions at https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/fieldalignment?tab=versions go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@latest go install github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi@latest go install github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework@latest From 006b01d7f05204f8793c8f67e92fe71b393349e4 Mon Sep 17 00:00:00 2001 From: Manuel Pedrozo Date: Thu, 13 Nov 2025 14:32:06 +0100 Subject: [PATCH 3/4] Remove unnecessary ignore --- internal/service/alertconfiguration/resource_test.go | 6 +++--- internal/serviceapi/alertconfigurationapi/resource_test.go | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/internal/service/alertconfiguration/resource_test.go b/internal/service/alertconfiguration/resource_test.go index bebeab3093..98bd5f206d 100644 --- a/internal/service/alertconfiguration/resource_test.go +++ b/internal/service/alertconfiguration/resource_test.go @@ -74,7 +74,7 @@ func TestAccConfigRSAlertConfiguration_basic(t *testing.T) { ImportStateIdFunc: importStateProjectIDFunc(resourceName), ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"project_id", "updated"}, + ImportStateVerifyIgnore: []string{"updated"}, }, }, }) @@ -147,7 +147,7 @@ func TestAccConfigRSAlertConfiguration_withNotifications(t *testing.T) { ImportStateIdFunc: importStateProjectIDFunc(resourceName), ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"project_id", "updated"}, + ImportStateVerifyIgnore: []string{"updated"}, }, }, }) @@ -263,7 +263,7 @@ func TestAccConfigRSAlertConfiguration_withThreshold(t *testing.T) { ImportStateIdFunc: importStateProjectIDFunc(resourceName), ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"project_id", "updated", "matcher.0.field_name"}, + ImportStateVerifyIgnore: []string{"updated", "matcher.0.field_name"}, }, }, }) diff --git a/internal/serviceapi/alertconfigurationapi/resource_test.go b/internal/serviceapi/alertconfigurationapi/resource_test.go index 449e2c51fd..b769e0bb6d 100644 --- a/internal/serviceapi/alertconfigurationapi/resource_test.go +++ b/internal/serviceapi/alertconfigurationapi/resource_test.go @@ -55,7 +55,7 @@ func TestAccAlertConfigurationAPI_basic(t *testing.T) { ImportStateIdFunc: importStateProjectIDFunc(resourceName), ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"group_id", "updated"}, + ImportStateVerifyIgnore: []string{"updated"}, }, }, }) @@ -426,8 +426,7 @@ func checkExists(resourceName string) resource.TestCheckFunc { if id == "" || projectID == "" { return fmt.Errorf("checkExists, attributes not found for: %s", resourceName) } - _, _, err := acc.ConnV2().AlertConfigurationsApi.GetAlertConfig(context.Background(), projectID, id).Execute() - if err != nil { + if _, _, err := acc.ConnV2().AlertConfigurationsApi.GetAlertConfig(context.Background(), projectID, id).Execute(); err != nil { return fmt.Errorf("the Alert Configuration(%s) does not exist", id) } return nil From 6da4587b3295d342f33c4fe9f3620776aefb8125 Mon Sep 17 00:00:00 2001 From: Manuel Pedrozo Date: Thu, 13 Nov 2025 15:20:33 +0100 Subject: [PATCH 4/4] Remove interval_min override --- internal/serviceapi/alertconfigurationapi/resource_schema.go | 1 - tools/codegen/config.yml | 4 ---- tools/codegen/models/alert_configuration_api.yaml | 2 +- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/internal/serviceapi/alertconfigurationapi/resource_schema.go b/internal/serviceapi/alertconfigurationapi/resource_schema.go index cade116f51..67623acca0 100755 --- a/internal/serviceapi/alertconfigurationapi/resource_schema.go +++ b/internal/serviceapi/alertconfigurationapi/resource_schema.go @@ -147,7 +147,6 @@ func ResourceSchema(ctx context.Context) schema.Schema { MarkdownDescription: "The id of the associated integration, the credentials of which to use for requests.", }, "interval_min": schema.Int64Attribute{ - Computed: true, Optional: true, MarkdownDescription: "Number of minutes to wait between successive notifications. MongoDB Cloud sends notifications until someone acknowledges the unacknowledged alert.\n\nPagerDuty, VictorOps, and OpsGenie notifications don't return this element. Configure and manage the notification interval within each of those services.", }, diff --git a/tools/codegen/config.yml b/tools/codegen/config.yml index d743c7f61b..a29db90804 100644 --- a/tools/codegen/config.yml +++ b/tools/codegen/config.yml @@ -569,10 +569,6 @@ resources: computability: optional: true computed: true - notifications.interval_min: - computability: - optional: true - computed: true notifications.integration_id: computability: optional: true diff --git a/tools/codegen/models/alert_configuration_api.yaml b/tools/codegen/models/alert_configuration_api.yaml index 795f5fa6e7..209bc8120e 100755 --- a/tools/codegen/models/alert_configuration_api.yaml +++ b/tools/codegen/models/alert_configuration_api.yaml @@ -264,7 +264,7 @@ schema: Number of minutes to wait between successive notifications. MongoDB Cloud sends notifications until someone acknowledges the unacknowledged alert. PagerDuty, VictorOps, and OpsGenie notifications don't return this element. Configure and manage the notification interval within each of those services. - computed_optional_required: computed_optional + computed_optional_required: optional tf_schema_name: interval_min tf_model_name: IntervalMin req_body_usage: all_request_bodies