diff --git a/infrastructure/modules/application-insights-availability-test/alerts.tf b/infrastructure/modules/application-insights-availability-test/alerts.tf new file mode 100644 index 00000000..72b84306 --- /dev/null +++ b/infrastructure/modules/application-insights-availability-test/alerts.tf @@ -0,0 +1,23 @@ +resource "azurerm_monitor_metric_alert" "this" { + name = "${var.name}-availability-alert" + resource_group_name = var.resource_group_name + + scopes = [azurerm_application_insights_standard_web_test.this.id, var.application_insights_id] + severity = 0 + + frequency = var.alert.frequency + window_size = var.alert.window_size + auto_mitigate = var.alert.auto_mitigate + + application_insights_web_test_location_availability_criteria { + web_test_id = azurerm_application_insights_standard_web_test.this.id + component_id = var.application_insights_id + failed_location_count = 2 + } + + description = var.alert.description + + action { + action_group_id = var.action_group_id + } +} diff --git a/infrastructure/modules/application-insights-availability-test/main.tf b/infrastructure/modules/application-insights-availability-test/main.tf index 71742f29..bce44e93 100644 --- a/infrastructure/modules/application-insights-availability-test/main.tf +++ b/infrastructure/modules/application-insights-availability-test/main.tf @@ -10,26 +10,27 @@ resource "azurerm_application_insights_standard_web_test" "this" { enabled = true request { - url = var.target_url - } - - geo_locations = var.geo_locations -} + url = var.target_url + http_verb = var.http_verb -resource "azurerm_monitor_metric_alert" "this" { - name = "${var.name}-availability-alert" - resource_group_name = var.resource_group_name - scopes = [azurerm_application_insights_standard_web_test.this.id, var.application_insights_id] - description = "availability test alert" - severity = 0 - - application_insights_web_test_location_availability_criteria { - web_test_id = azurerm_application_insights_standard_web_test.this.id - component_id = var.application_insights_id - failed_location_count = 2 + dynamic "header" { + for_each = var.headers + content { + name = header.key + value = header.value + } + } } - action { - action_group_id = var.action_group_id + # SSL validation rules + dynamic "validation_rules" { + for_each = var.ssl_validation != null ? [1] : [] + content { + expected_status_code = var.ssl_validation.expected_status_code + ssl_check_enabled = true + ssl_cert_remaining_lifetime = var.ssl_validation.ssl_cert_remaining_lifetime + } } + + geo_locations = var.geo_locations } diff --git a/infrastructure/modules/application-insights-availability-test/tfdocs.md b/infrastructure/modules/application-insights-availability-test/tfdocs.md index d1e33f84..edef5041 100644 --- a/infrastructure/modules/application-insights-availability-test/tfdocs.md +++ b/infrastructure/modules/application-insights-availability-test/tfdocs.md @@ -78,6 +78,61 @@ Type: `number` Default: `30` +### [http_verb](#input\_http\_verb) + +Description: The HTTP verb used for the request. + +Type: `string` + +Allowed values: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS + +Default: GET + +### [headers](#input\_headers) + +Description: A map of HTTP request headers (name => value). + +Type: `map(string)` + +Default: {} + +### [ssl_validation](#input\_ssl\_validation) + +Description: SSL validation configuration for the availability test. + +Type: +```hcl +object({ + expected_status_code = optional(number, null) + ssl_cert_remaining_lifetime = optional(number, null) +}) +``` + +Default: null + +Validations: +- expected_status_code must be 0 ('0' means 'response code < 400') or a valid HTTP status code (100–599) +- ssl_cert_remaining_lifetime must be null or between 1–365 + +### [alert](#input\_alert) + +Description: Configuration for the availability alert rule. + +Type: +```hcl +object({ + description = optional(string, "Availability test alert") + frequency = optional(string, "PT1M") + window_size = optional(string, "PT5M") + auto_mitigate = optional(bool, true) +}) +``` + +Defaults: {} + +Validations: +- frequency must be one of: PT1M, PT5M, PT15M, PT30M, PT1H +- window_size must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D ## Resources diff --git a/infrastructure/modules/application-insights-availability-test/variables.tf b/infrastructure/modules/application-insights-availability-test/variables.tf index 09775b91..9c53fe11 100644 --- a/infrastructure/modules/application-insights-availability-test/variables.tf +++ b/infrastructure/modules/application-insights-availability-test/variables.tf @@ -54,3 +54,77 @@ variable "target_url" { type = string description = "The target URL for the restful endpoint to hit to validate the application is available" } + +variable "http_verb" { + description = "HTTP verb (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)" + type = string + default = "GET" + validation { + condition = contains(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"], var.http_verb) + error_message = "http_verb must be one of GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS." + } +} + +variable "headers" { + description = "Map of request headers to send (name => value)" + type = map(string) + default = {} +} + +variable "ssl_validation" { + description = "SSL validation configuration for the availability test." + type = object({ + expected_status_code = optional(number, null) + ssl_cert_remaining_lifetime = optional(number, null) + }) + + validation { + condition = ( + var.ssl_validation == null || + try(var.ssl_validation.expected_status_code, 0) == 0 || + (try(var.ssl_validation.expected_status_code, 0) >= 100 && + try(var.ssl_validation.expected_status_code, 0) < 600) + ) + error_message = "The expected status code must be 0 ('0' means 'response code < 400') or a valid HTTP status code between 100 and 599." + } + + validation { + condition = ( + var.ssl_validation == null || + try(var.ssl_validation.ssl_cert_remaining_lifetime, null) == null || + (try(var.ssl_validation.ssl_cert_remaining_lifetime, 0) >= 1 && + try(var.ssl_validation.ssl_cert_remaining_lifetime, 0) <= 365) + ) + error_message = "The SSL certificate remaining lifetime must be null or an integer between 1 and 365." + } + + default = null + nullable = true +} + +variable "alert" { + type = object({ + description = optional(string, "Availability test alert") + frequency = optional(string, "PT1M") + window_size = optional(string, "PT5M") + auto_mitigate = optional(bool, true) + }) + + validation { + condition = contains( + ["PT1M", "PT5M", "PT15M", "PT30M", "PT1H"], + var.alert.frequency + ) + error_message = "Frequency must be one of: PT1M, PT5M, PT15M, PT30M, PT1H" + } + + validation { + condition = contains( + ["PT1M", "PT5M", "PT15M", "PT30M", "PT1H", "PT6H", "PT12H", "P1D"], + var.alert.window_size + ) + error_message = "Window size must be one of: PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H, P1D" + } + + default = {} +}