Use local value in variables.tf - terraform

How to use local value in variables.tf?
I need to assign dynamically value to threshold for two of netapp volume metric alert and I get an error: Error: Variables not allowed. Each NetApp Volume has different storage quota in GB, that's why it needs to be dynamic.
NetApp Volume code:
main.tf
locals {
iops_80 = format("%.0f", (var.storage_quota_in_gb * 1.6))
}
resource "azurerm_netapp_volume" "netapp_volume" {
name = var.netapp_vol_name
resource_group_name = var.resource_group_name
location = var.location
account_name = var.account_name
pool_name = var.pool_name
volume_path = var.volume_path
service_level = var.service_level
subnet_id = var.subnet_id
storage_quota_in_gb = var.storage_quota_in_gb
protocols = var.protocols
dynamic "export_policy_rule" {
for_each = var.export_policy_rules
content {
rule_index = export_policy_rule.value.rule_index
allowed_clients = export_policy_rule.value.allowed_clients
protocols_enabled = export_policy_rule.value.protocols_enabled
unix_read_only = export_policy_rule.value.unix_read_only
unix_read_write = export_policy_rule.value.unix_read_write
}
}
tags = var.tags
}
resource "azurerm_monitor_metric_alert" "alert" {
depends_on = [azurerm_netapp_volume.netapp_volume]
count = length(var.criteria)
name = "HPG-ALRT-${var.netapp_vol_name}-001-${element(keys(var.criteria), count.index)}"
resource_group_name = var.resource_group_name
scopes = [azurerm_netapp_volume.netapp_volume.id]
enabled = var.enabled
auto_mitigate = var.auto_mitigate
description = lookup(var.criteria, element(keys(var.criteria), count.index), null)["description"]
frequency = var.frequency
severity = lookup(var.criteria, element(keys(var.criteria), count.index), null)["severity"]
window_size = var.window_size
criteria {
metric_namespace = lookup(var.criteria, element(keys(var.criteria), count.index), null)["metric_namespace"]
metric_name = lookup(var.criteria, element(keys(var.criteria), count.index), null)["metric_name"]
aggregation = lookup(var.criteria, element(keys(var.criteria), count.index), null)["aggregation"]
operator = lookup(var.criteria, element(keys(var.criteria), count.index), null)["operator"]
threshold = lookup(var.criteria, element(keys(var.criteria), count.index), null)["threshold"]
}
action {
action_group_id = var.action_group_id
}
}
variables.tf
variable "criteria" {
type = map
default = {
"ReadLATENCY5" = {
metric_namespace = "Microsoft.NetApp/netAppAccounts/capacityPools/volumes"
metric_name = "AverageReadLatency"
aggregation = "Average"
operator = "GreaterThan"
threshold = 5
description = "NetApp: Volume Read Latency over 5ms"
severity = 2
},
"ReadIOPS80" = {
metric_namespace = "Microsoft.NetApp/netAppAccounts/capacityPools/volumes"
metric_name = "ReadIops"
aggregation = "Average"
operator = "GreaterThan"
threshold = local.iops_80
description = "NetApp: Volume Read IOPS over TBD"
severity = 2
},
"WriteIops80" = {
metric_namespace = "Microsoft.NetApp/netAppAccounts/capacityPools/volumes"
metric_name = "WriteIops"
aggregation = "Average"
operator = "GreaterThan"
threshold = local.iops_80
description = "NetApp: Volume Write IOPS over TBD"
severity = 2
},
}
}
One way is to do another criteria map to define only alerts with iops_80 value and assign it in main.tf but is there any other way to do it?

It seems you cannot use the local values in the variables file. What you can do is that use the variables in the local, and use the local value and variables in the resource block. And you can also use the local values in another local.
So I think you need to use the variables to set the input and things would be changed. And quote the variables in the local or quote the local in another local. For example, maybe you can use the local to set the criteria instead of using a variable.

Related

In terraform making string variable optional in action block

Hi i am creating alert rules. For some of the alerts i dont need to send any notification using action group.For that i need to make action group variable (string) as optional.
I tried using condition like var.action_group_id != null action_group_id : "". But i am getting following error.
Error: Can not parse "action.0.action_group_id" as a resource id: Cannot parse Azure ID: parse "null": invalid URI for request
And i tried making action block as dynamic block but it is not iterable. for_each is not supporting dynamic block with single variable with one values.
resource "azurerm_monitor_metric_alert" "keyvault_alert" {
for_each = var.keyvault_alert_rules
name = "${var.kv_name} - ${each.value.severity}"
resource_group_name = var.resource_group_name
description = each.value.description
scopes = var.alert_scope
severity = each.value.severity
frequency = each.value.frequency
`window_size = each.value.windowsize`
# criteria block
criteria {
metric_namespace = "Microsoft.KeyVault/vaults"
threshold = each.value.threshold
metric_name = each.value.metric_name
aggregation = each.value.aggregation
operator = each.value.operator
# dimension block
dynamic "dimension" {
for_each = each.value.dimension != null ? each.value.dimension : []
content {
name = dimension.value.dimensionname
operator = dimension.value.dimensionoperator
values = dimension.value.dimensionvalues
}
}
}
action {
action_group_id = var.action_group_id
}
variable.tf
variable "action_group_id" {
type = string
description = "ID of the action group"
}
variable "resource_group_name" {
type = string
description = "name of the resource group"
}
/* in the variables i am passing warning as n input.is there any way i can append warning to alert name in the main.tf based on the severity value which is given down below*/
variable "kv_alert_rules" {
type = map(object({
display_name = string
# display_name = "(severity numeric equalent ex:warning)-(metric name)"
#------details for the alert criteria
metric_name = string
operator = string
threshold = number
aggregation = string
#------ dimension vaules----------
dimension = list(object({
dimensionname = string
dimensionoperator = string
dimensionvalues = list(string)
}))
#-----------------------------------
severity = number
frequency = string
windowsize = string
# window size must be gretar than Frequency values be PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H and P1D. Defaults to PT5M
description = string
}))
description = "This variable for alert criteria for key vault"
default = {
"Alert_1" = {
# display_name = "(severity numeric equalent ex:warning)-(generic word for metric name)"
display_name = "warning-used capacity"
severity = 2
dimension = null
metric_name = "SaturationShoebox"
aggregation = "Average"
frequency = "PT30M"
description = "Alert fires When Used vault capacity is GreaterThan 85"
windowsize = "PT1H"
operator = "GreaterThan"
threshold = 85
}
}
}
variable "kv_name" {
description = "key vault name "
type = string
}
module calling
module "keyvault" {
source = "../testing/key-vault-alert"
alert_scope = [data.azurerm_key_vault.examplekeyvault.id]
action_group_id = module.action-group.AGidout
resource_group_name = var.resource_group_name
kv_name = data.azurerm_key_vault.examplekeyvault.name
}
I would like to make action_group_id as optional variable.I dont wanna reference action group ID in some instances
If anyone knows a approach how to do that please guide me
Thanks
action is a dynamic block, so to make it optional you can do as follows:
dynamic "action" {
for_each = var.action_group_id != null ? [1] : []
content {
action_group_id = var.action_group_id
}
}

In terraform how to convert numeric value to a string of word based on variable

Hi i am trying to create the alert name based on the severity in the alert.In the input i have given numeric value for severity but i am trying to append equalent string(word) for that severity to the alert name
Critical = 0 Error= 1 Warning= 2 Informational = 3 Verbose = 4
I am getting alert name like keyvault - 0
I would like to get keyvault - critical
resource "azurerm_monitor_metric_alert" "keyvault_alert" {
for_each = var.keyvault_alert_rules
name = "${var.kv_name} - ${each.value.severity}"
resource_group_name = var.resource_group_name
description = each.value.description
scopes = var.alert_scope
severity = each.value.severity
frequency = each.value.frequency
`window_size = each.value.windowsize`
# criteria block
criteria {
metric_namespace = "Microsoft.KeyVault/vaults"
threshold = each.value.threshold
metric_name = each.value.metric_name
aggregation = each.value.aggregation
operator = each.value.operator
# dimension block
dynamic "dimension" {
for_each = each.value.dimension != null ? each.value.dimension : []
content {
name = dimension.value.dimensionname
operator = dimension.value.dimensionoperator
values = dimension.value.dimensionvalues
}
}
}
action {
action_group_id = var.action_group_id
}
variable.tf
variable "action_group_id" {
type = any
description = "ID of the action group"
}
variable "resource_group_name" {
type = string
description = "name of the resource group"
}
/* in the variables i am passing warning as n input.is there any way i can append warning to alert name in the main.tf based on the severity value which is given down below*/
variable "kv_alert_rules" {
type = map(object({
display_name = string
# display_name = "(severity numeric equalent ex:warning)-(metric name)"
#------details for the alert criteria
metric_name = string
operator = string
threshold = number
aggregation = string
#------ dimension vaules----------
dimension = list(object({
dimensionname = string
dimensionoperator = string
dimensionvalues = list(string)
}))
#-----------------------------------
severity = number
frequency = string
windowsize = string
# window size must be gretar than Frequency values be PT1M, PT5M, PT15M, PT30M, PT1H, PT6H, PT12H and P1D. Defaults to PT5M
description = string
}))
description = "This variable for alert criteria for key vault"
default = {
"Alert_1" = {
# display_name = "(severity numeric equalent ex:warning)-(generic word for metric name)"
display_name = "warning-used capacity"
severity = 2
dimension = null
metric_name = "SaturationShoebox"
aggregation = "Average"
frequency = "PT30M"
description = "Alert fires When Used vault capacity is GreaterThan 85"
windowsize = "PT1H"
operator = "GreaterThan"
threshold = 85
}
}
}
variable "kv_name" {
description = "key vault name "
type = string
}
module calling
module "keyvault" {
source = "../testing/key-vault-alert"
alert_scope = [data.azurerm_key_vault.examplekeyvault.id]
action_group_id = module.action-group.AGidout
resource_group_name = var.resource_group_name
kv_name = data.azurerm_key_vault.examplekeyvault.name
}
If anyone knows a approach how to do that please guide me
Thanks
Just create a new map in the locals section:
locals {
severity_alerts = {
0 = "Critical",
1 = "Error",
2 = "Warning"
}
}
Then update you're resource azurerm_monitor_metric_alert name attribute to:
format("%s - %s", var.kv_name, lookup(local.severity_alerts, each.value.severity))
By using the lookup function you can retrieve a value from a map by providing the key.

Is there a better way to create multiple cloudwatch alarms?

I'm trying to create cloudwatch alarms for some specific load balancers.
What if I have to create 100 cloudwatch alarms, do I need to populate the tfvars the way, I'm updating it currently, or is there any other way which is more optimized.
Following is my code.
main.tf
resource "aws_cloudwatch_metric_alarm" "UnHealthyHosts" {
for_each = var.cloudwatch_alarms_map
alarm_name = each.key
comparison_operator = var.cloudwatch_alarm_operator
evaluation_periods = var.cloudwatch_alarm_evaluation_periods
metric_name = var.cloudwatch_alarm_metric
namespace = each.value["alarm_namespace"]
period = var.cloudwatch_alarm_period
statistic = var.cloudwatch_alarm_statistic
threshold = var.cloudwatch_alarm_threshold
alarm_description = var.cloudwatch_alarm_description
actions_enabled = var.cloudwatch_alarm_actions_enabled
alarm_actions = [aws_sns_topic.sns.arn]
dimensions = {
TargetGroup = each.value["target_group_arn"]
LoadBalancer = each.value["load_balancer_arn"]
}
}
variables.tf
variable "cloudwatch_alarms_map" {
type = map(object({
alarm_namespace = string # eg: AWS/ApplicationELB
target_group_arn = string
load_balancer_arn = string
}))
default = {}
}
terraform.tfvars
cloudwatch_alarms_map = {
app1-unhealthy-alarm = {
target_group_arn_suffix = "targetgroup/sample-app1-tg/12de123e123123aa"
load_balancer_arn_suffix = "app/sample-alb-app1-lb/12c5732bd012e47a"
alarm_namespace = "AWS/ApplicationELB"
}
app2-unhealthy-alarm = {
target_group_arn_suffix = "targetgroup/sample-app2-tg/313e7f1ad4a2e373"
load_balancer_arn_suffix = "app/sample-alb-app2-lb/f2c5132bd012e47a"
alarm_namespace = "AWS/ApplicationELB"
}
}

How to create alert rule in terraform for SQL DB

I can't seem to find any examples and I am running into different errors depending on what I'm doing.
I'm trying to get this to work and it's just not happening... any thoughts?
resource "azurerm_monitor_metric_alert" "example" {
name = "example-metricalert"
resource_group_name = azurerm_resource_group.example.name
scopes = [azurerm_mssql_database.test.server_id]
description = "Action will be triggered when cpu is greater than 80%."
criteria {
metric_namespace = "Microsoft.Sql/servers/databases"
metric_name = "CPU_percentage"
aggregation = "Average"
operator = "GreaterThan"
threshold = 80
}
}
You can use the below code to create an metrics alert for SQL DB. I have tested it for an existing SQL DB, so used data blocks.
Main.tf
provider "azurerm" {
features {}
}
data "azurerm_mssql_server" "example" {
name = "ztestansumanserver"
resource_group_name = "yourresourcegroup"
}
data "azurerm_mssql_database" "dbtomonitor" {
name = "testansumandb"
server_id = data.azurerm_mssql_server.example.id
}
resource "azurerm_monitor_action_group" "example" {
name = "CriticalAlertsAction"
resource_group_name = data.azurerm_mssql_server.example.resource_group_name
short_name = "p0action"
email_receiver {
name = "sendtoadmin"
email_address = "youremailid"
use_common_alert_schema = true
}
}
resource "azurerm_monitor_metric_alert" "example" {
name = "example-metricalert"
resource_group_name = data.azurerm_mssql_server.example.resource_group_name
scopes = [data.azurerm_mssql_database.dbtomonitor.id]
description = "Action will be triggered when cpu percent is greater than 80."
criteria {
metric_namespace = "Microsoft.Sql/servers/databases"
metric_name = "cpu_percent"
aggregation = "Average"
operator = "GreaterThan"
threshold = 80
}
action {
action_group_id = azurerm_monitor_action_group.example.id
}
}
output:
Note: As per the above script alert is created successfully and it will also trigger a mail to you when the cpu_percent > 80 .
Reference:
Azure Monitor supported metrics by resource type - Azure Monitor | Microsoft Docs

How to create different metric type alerts for multiple resources of same resource type

I am working on to create the alerts in azure with Terraform scripts. I am trying to create different metric type alerts for different resources. (For example: functionapp01, functionapp02, logicapp01 and logicapp02 etc.)
This is the script:
terraform {
required_version = ">=0.12"
}
resource "azurerm_monitor_metric_alert" "metric_alert" {
name = var.metric_alert_name
resource_group_name = var.rg_name
scopes = [var.resource_id_01,var.resource_id_02]
description = var.metric_alert_description
tags = var.tags
frequency = var.frequency
severity = var.severity
window_size = var.window_size
enabled = var.is_enabled
criteria {
metric_namespace = var.metric_namespace
metric_name = var.metric_name
aggregation = var.aggregation
operator = var.operator
threshold = var.threshold
}
action {
action_group_id = var.action_group_id
}
}
Whenever I run the above script, then I am getting the below error:
Service returned an error. Status=400 Code="BadRequest" Message="Alerts are currently not supported with multi resource level for microsoft.web/sites
Reference Links:
azurerm_monitor_metric_alert
Metrics and Dimensions Supported
So, can anyone suggest me on this issue?
As the error show, the microsoft.web/sites resource type does not support Multi-resource alerts, refer to https://learn.microsoft.com/en-us/azure/azure-monitor/platform/alerts-metric-near-real-time#metrics-and-dimensions-supported
In this case, you have to create each monitor_metric_alert on each resource level.
For example, if you have created two functions, functionapp01, functionapp02. You can do it like this.
variable "function_apps" {
default = ["functionapp01","functionapp02"]
}
data "azurerm_function_app" "example" {
for_each = toset(var.function_apps)
name = each.value
resource_group_name = "funtions_rg"
}
resource "azurerm_monitor_metric_alert" "metric_alert" {
for_each = toset(var.function_apps)
name = "${each.value}-example-metricalert"
resource_group_name = var.rg_name
scopes = [data.azurerm_function_app.example[each.value].id]
description = var.metric_alert_description
tags = var.tags
frequency = var.frequency
severity = var.severity
window_size = var.window_size
enabled = var.is_enabled
criteria {
metric_namespace = var.metric_namespace
metric_name = var.metric_name
aggregation = var.aggregation
operator = var.operator
threshold = var.threshold
}
action {
action_group_id = var.action_group_id
}
}
Update
If you have function app resources is being created with Terraform, you can use them like this:
variable "function_apps" {
default = ["functionapp01","functionapp02"]
}
resource "azurerm_function_app" "example" {
for_each = toset(var.function_apps)
name = "${each.value}-example-funapp"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
app_service_plan_id = azurerm_app_service_plan.example.id
storage_account_name = azurerm_storage_account.example.name
storage_account_access_key = azurerm_storage_account.example.primary_access_key
app_settings = { }
version = "~3"
}
resource "azurerm_monitor_metric_alert" "test" {
for_each = toset(var.function_apps)
name = "${each.value}-example-metricalert"
resource_group_name = azurerm_resource_group.example.name
scopes = [azurerm_function_app.example[each.value].id]
description = var.metric_alert_description
severity = var.severity
window_size = var.window_size
enabled = var.is_enabled
criteria {
metric_namespace = var.metric_namespace
metric_name = var.metric_name
aggregation = var.aggregation
operator = var.operator
threshold = var.threshold
}
action {
action_group_id = var.action_group_id
}
}

Resources