diff --git a/Makefile b/Makefile index 8f55041..8f87fc3 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ LCAF_ENV_FILE = .lcafenv # Source repository for repo manifests REPO_MANIFESTS_URL ?= https://github.com/launchbynttdata/launch-common-automation-framework.git # Branch of source repository for repo manifests. Other tags not currently supported. -REPO_BRANCH ?= refs/tags/1.0.0 +REPO_BRANCH ?= refs/tags/1.8.1 # Path to seed manifest in repository referenced in REPO_MANIFESTS_URL REPO_MANIFEST ?= manifests/terraform_modules/seed/manifest.xml diff --git a/README.md b/README.md index 180e162..e324a56 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ If `make check` target is successful, developer is good to commit the code to pr - runs `conftests`. `conftests` make sure `policy` checks are successful. - runs `terratest`. This is integration test suit. - runs `opa` tests - + ## Requirements | Name | Version | @@ -124,6 +124,8 @@ No providers. | [signalr](#module\_signalr) | terraform.registry.launch.nttdata.com/module_primitive/signalr/azurerm | ~> 1.0 | | [log\_analytics\_workspace](#module\_log\_analytics\_workspace) | terraform.registry.launch.nttdata.com/module_primitive/log_analytics_workspace/azurerm | ~> 1.0 | | [diagnostic\_setting](#module\_diagnostic\_setting) | terraform.registry.launch.nttdata.com/module_primitive/monitor_diagnostic_setting/azurerm | ~> 1.0 | +| [monitor\_action\_group](#module\_monitor\_action\_group) | terraform.registry.launch.nttdata.com/module_primitive/monitor_action_group/azurerm | ~> 1.0.0 | +| [monitor\_metric\_alert](#module\_monitor\_metric\_alert) | terraform.registry.launch.nttdata.com/module_primitive/monitor_metric_alert/azurerm | ~> 2.0 | ## Resources @@ -163,6 +165,10 @@ No resources. | [enabled\_log](#input\_enabled\_log) | n/a |
list(object({
category_group = optional(string, "allLogs")
category = optional(string, null)
}))
| `null` | no | | [metric](#input\_metric) | n/a |
object({
category = optional(string)
enabled = optional(bool)
})
| `null` | no | | [tags](#input\_tags) | A mapping of tags to assign to the resource. | `map(string)` | `{}` | no | +| [action\_group](#input\_action\_group) | An action group object. Set to null to skip creation.

Each action group can have:
- name: (Required) full action group name
- short\_name: (Required) short name used by Azure
- arm\_role\_receivers: (Optional) List of ARM role receivers
- email\_receivers: (Optional) List of email receivers |
object({
name = string
short_name = string
arm_role_receivers = optional(list(object({
name = string
role_id = string
use_common_alert_schema = optional(bool)
})), [])
email_receivers = optional(list(object({
name = string
email_address = string
use_common_alert_schema = optional(bool)
})), [])
})
| `null` | no | +| [action\_group\_ids](#input\_action\_group\_ids) | Explicit list of existing action group IDs (strings) which will be included in alerts. | `list(string)` | `[]` | no | +| [metric\_alerts](#input\_metric\_alerts) | Map of metric alerts. Each key is the alert name and the value is an object describing the alert. |
map(object({
description = string
action_groups = optional(set(string), [])
frequency = optional(string, "PT1M")
severity = optional(number, 3)
enabled = optional(bool, true)
webhook_properties = optional(map(string), {})
criteria = optional(list(object({
metric_namespace = string
metric_name = string
aggregation = string
operator = string
threshold = number
skip_metric_validation = optional(bool, false)
dimensions = optional(list(object({
name = string
operator = string
values = list(string)
})), [])
})), null)
dynamic_criteria = optional(object({
metric_namespace = string
metric_name = string
aggregation = string
operator = string
alert_sensitivity = string
ignore_data_before = optional(string)
skip_metric_validation = optional(bool, false)
dimensions = optional(list(object({
name = string
operator = string
values = list(string)
})), [])
}), null)
}))
| `{}` | no | +| [resource\_group\_name](#input\_resource\_group\_name) | Specifies the Name of the Resource Group within which the Private Endpoint should exist. | `string` | n/a | yes | ## Outputs @@ -172,4 +178,4 @@ No resources. | [signalr\_name](#output\_signalr\_name) | n/a | | [location](#output\_location) | n/a | | [resource\_group\_name](#output\_resource\_group\_name) | n/a | - + diff --git a/examples/complete/README.md b/examples/complete/README.md index aae104c..21861f0 100644 --- a/examples/complete/README.md +++ b/examples/complete/README.md @@ -1,6 +1,6 @@ # with_cake - + ## Requirements | Name | Version | @@ -17,6 +17,8 @@ No providers. | Name | Source | Version | |------|--------|---------| | [signalr](#module\_signalr) | ../.. | n/a | +| [monitor\_action\_group](#module\_monitor\_action\_group) | terraform.registry.launch.nttdata.com/module_primitive/monitor_action_group/azurerm | ~> 1.0.0 | +| [monitor\_metric\_alert](#module\_monitor\_metric\_alert) | terraform.registry.launch.nttdata.com/module_primitive/monitor_metric_alert/azurerm | ~> 2.0 | ## Resources @@ -34,6 +36,10 @@ No resources. | [enabled\_log](#input\_enabled\_log) | n/a |
list(object({
category_group = optional(string, "allLogs")
category = optional(string, null)
}))
|
[
{
"category_group": "allLogs"
}
]
| no | | [metric](#input\_metric) | n/a |
object({
category = optional(string, "AllMetrics")
enabled = optional(bool, false)
})
|
{
"category": "AllMetrics"
}
| no | | [tags](#input\_tags) | A mapping of tags to assign to the resource. | `map(string)` | `{}` | no | +| [resource\_group\_name](#input\_resource\_group\_name) | Test resource group | `string` | `"test"` | no | +| [action\_group](#input\_action\_group) | n/a |
object({
name = string
short_name = string
arm_role_receivers = optional(list(object({
name = string
role_id = string
use_common_alert_schema = optional(bool)
})), [])
email_receivers = optional(list(object({
name = string
email_address = string
use_common_alert_schema = optional(bool)
})), [])
})
|
{
"arm_role_receivers": [],
"email_receivers": [
{
"email_address": "test@example.com",
"name": "oncall",
"use_common_alert_schema": true
}
],
"name": "ag-test-alerts",
"short_name": "agtest"
}
| no | +| [action\_group\_ids](#input\_action\_group\_ids) | n/a | `list(string)` | `[]` | no | +| [metric\_alerts](#input\_metric\_alerts) | n/a |
map(object({
description = string
action_groups = optional(set(string), [])
frequency = optional(string, "PT5M")
severity = optional(number, 2)
enabled = optional(bool, true)
webhook_properties = optional(map(string), {})
criteria = optional(list(object({
metric_namespace = string
metric_name = string
aggregation = string
operator = string
threshold = number
skip_metric_validation = optional(bool, false)
dimensions = optional(list(object({
name = string
operator = string
values = list(string)
})), [])
})), null)
dynamic_criteria = optional(object({
metric_namespace = string
metric_name = string
aggregation = string
operator = string
alert_sensitivity = string
ignore_data_before = optional(string)
skip_metric_validation = optional(bool, false)
dimensions = optional(list(object({
name = string
operator = string
values = list(string)
})), [])
}), null)
}))
|
{
"signalr-connections-high": {
"action_groups": [],
"criteria": [
{
"aggregation": "Maximum",
"dimensions": [],
"metric_name": "ConnectionCount",
"metric_namespace": "Microsoft.SignalRService/SignalR",
"operator": "GreaterThan",
"skip_metric_validation": false,
"threshold": 1000
}
],
"description": "High number of SignalR connections",
"dynamic_criteria": null,
"enabled": true,
"frequency": "PT5M",
"severity": 2,
"webhook_properties": {}
}
}
| no | ## Outputs @@ -43,4 +49,4 @@ No resources. | [signalr\_name](#output\_signalr\_name) | n/a | | [location](#output\_location) | n/a | | [resource\_group\_name](#output\_resource\_group\_name) | n/a | - + diff --git a/examples/complete/main.tf b/examples/complete/main.tf index bd844bb..3455229 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -21,10 +21,50 @@ module "signalr" { log_analytics_workspace_retention_in_days = var.log_analytics_workspace_retention_in_days log_analytics_workspace_identity = var.log_analytics_workspace_identity log_analytics_destination_type = var.log_analytics_destination_type - - enable_monitor_diagnostic_setting = true - enabled_log = var.enabled_log - metric = var.metric + resource_group_name = var.resource_group_name + enable_monitor_diagnostic_setting = true + enabled_log = var.enabled_log + metric = var.metric tags = local.tags } + +module "monitor_action_group" { + source = "terraform.registry.launch.nttdata.com/module_primitive/monitor_action_group/azurerm" + version = "~> 1.0" + + count = var.action_group != null ? 1 : 0 + action_group_name = var.action_group.name + resource_group_name = var.resource_group_name + short_name = var.action_group.short_name + arm_role_receivers = var.action_group.arm_role_receivers + email_receivers = var.action_group.email_receivers + tags = var.tags +} + +# Metric Alert +module "monitor_metric_alert" { + source = "terraform.registry.launch.nttdata.com/module_primitive/monitor_metric_alert/azurerm" + version = "~> 2.0" + + for_each = var.metric_alerts + name = each.key + resource_group_name = var.resource_group_name + + scopes = [module.signalr.signalr_id] + + description = each.value.description + frequency = each.value.frequency + severity = each.value.severity + enabled = each.value.enabled + + action_group_ids = concat( + var.action_group_ids, + try(tolist(each.value.action_groups), []), + var.action_group != null ? [module.monitor_action_group[0].action_group_id] : [] + ) + + webhook_properties = lookup(each.value, "webhook_properties", null) + criteria = each.value.criteria + dynamic_criteria = each.value.dynamic_criteria +} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index 9a7f578..f6aa7e6 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -68,3 +68,120 @@ variable "tags" { type = map(string) default = {} } + +variable "resource_group_name" { + description = "Test resource group" + type = string + default = "test" +} + + +variable "action_group" { + type = object({ + name = string + short_name = string + arm_role_receivers = optional(list(object({ + name = string + role_id = string + use_common_alert_schema = optional(bool) + })), []) + email_receivers = optional(list(object({ + name = string + email_address = string + use_common_alert_schema = optional(bool) + })), []) + }) + + default = { + name = "ag-test-alerts" + short_name = "agtest" + + email_receivers = [ + { + name = "oncall" + email_address = "test@example.com" + use_common_alert_schema = true + } + ] + + arm_role_receivers = [] + } +} + +variable "action_group_ids" { + type = list(string) + default = [] +} + +variable "metric_alerts" { + type = map(object({ + description = string + action_groups = optional(set(string), []) + frequency = optional(string, "PT5M") + severity = optional(number, 2) + enabled = optional(bool, true) + webhook_properties = optional(map(string), {}) + criteria = optional(list(object({ + metric_namespace = string + metric_name = string + aggregation = string + operator = string + threshold = number + skip_metric_validation = optional(bool, false) + dimensions = optional(list(object({ + name = string + operator = string + values = list(string) + })), []) + })), null) + dynamic_criteria = optional(object({ + metric_namespace = string + metric_name = string + aggregation = string + operator = string + alert_sensitivity = string + ignore_data_before = optional(string) + skip_metric_validation = optional(bool, false) + dimensions = optional(list(object({ + name = string + operator = string + values = list(string) + })), []) + }), null) + })) + + default = { + "signalr-connections-high" = { + description = "High number of SignalR connections" + action_groups = [] + + frequency = "PT5M" + severity = 2 + enabled = true + + criteria = [ + { + metric_namespace = "Microsoft.SignalRService/SignalR" + metric_name = "ConnectionCount" + aggregation = "Maximum" + operator = "GreaterThan" + threshold = 1000 + skip_metric_validation = false + dimensions = [] + } + ] + + dynamic_criteria = null + webhook_properties = {} + } + } + + validation { + condition = alltrue( + [for alert in values(var.metric_alerts) : + !(alert.criteria == null && alert.dynamic_criteria == null) + ] + ) + error_message = "Each metric alert must define at least one of 'criteria' or 'dynamic_criteria'." + } +} diff --git a/main.tf b/main.tf index dc25225..a3e4523 100644 --- a/main.tf +++ b/main.tf @@ -92,3 +92,48 @@ module "diagnostic_setting" { enabled_log = var.enabled_log metric = var.metric } + +# Optional: create an action group using your object variable "action_group" +module "monitor_action_group" { + source = "terraform.registry.launch.nttdata.com/module_primitive/monitor_action_group/azurerm" + version = "~> 1.0" + + count = var.action_group != null ? 1 : 0 + action_group_name = var.action_group != null ? var.action_group.name : null + resource_group_name = coalesce(var.resource_group_name, module.resource_names["resource_group"].standard) + short_name = var.action_group != null ? var.action_group.short_name : null + arm_role_receivers = var.action_group != null ? lookup(var.action_group, "arm_role_receivers", null) : null + email_receivers = var.action_group != null ? lookup(var.action_group, "email_receivers", null) : null + tags = merge(local.tags, var.tags) + + depends_on = [module.resource_group] +} + +# Metric alerts: for_each over the map var.metric_alerts +module "monitor_metric_alert" { + source = "terraform.registry.launch.nttdata.com/module_primitive/monitor_metric_alert/azurerm" + version = "~> 2.0" + + for_each = var.metric_alerts + name = each.key + resource_group_name = coalesce(var.resource_group_name, module.resource_names["resource_group"].standard) + + scopes = [module.signalr.signalr_id] + + description = each.value.description + frequency = each.value.frequency + severity = each.value.severity + enabled = each.value.enabled + + action_group_ids = concat( + coalesce(var.action_group_ids, []), + try(tolist(each.value.action_groups), []), + var.action_group != null ? [module.monitor_action_group[0].action_group_id] : [] + ) + + webhook_properties = lookup(each.value, "webhook_properties", null) + criteria = lookup(each.value, "criteria", null) + dynamic_criteria = lookup(each.value, "dynamic_criteria", null) + + depends_on = [module.signalr] +} diff --git a/variables.tf b/variables.tf index 8aced1a..1151ec2 100644 --- a/variables.tf +++ b/variables.tf @@ -246,3 +246,90 @@ variable "tags" { type = map(string) default = {} } + +variable "action_group" { + description = <