Maybe related: azurerm_resource_group_template_deployment ignoring parameter file
I would like to use the resource azurerm_resource_group_template_deployment
from Terraform version 0.37. But there is the problem that Terraform wants to reapply the resource every month, so I thought I could tell to ignore changes to start date and end date, but this would (opposite to the deprecated resource azurerm_template_deployment
) need a compute operation, namely jsondecode
, which is not allowed. I.e. the following code would not work.
terraform {
required_version = "~> 0.13.0"
required_providers {
azurerm = "~> 2.37.0"
}
}
provider azurerm {
features {}
}
locals {
budget_start_date = formatdate("YYYY-MM-01", timestamp())
budget_end_date = formatdate("YYYY-MM-01", timeadd(timestamp(), "17568h"))
budget_params = jsonencode({
"budgetName" = "budgettest",
"amount" = "4000",
"timeGrain" = "Annually",
"startDate" = local.budget_start_date,
"endDate" = local.budget_end_date,
"firstThreshold" = "75",
"secondThreshold" = "100",
"thirdThreshold" = "50",
"contactGroups" = ""
})
}
resource "azurerm_resource_group" "rg" {
# A subscription cannot have more than 980 resource groups:
# https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits
name = "example-rg"
location = "westeurope"
}
resource "azurerm_resource_group_template_deployment" "dsw_budget" {
name = "test-budget-template"
resource_group_name = azurerm_resource_group.rg[0].name
deployment_mode = "Incremental"
template_content = file("${path.module}/arm/budget_deploy.json")
parameters_content = local.budget_params
lifecycle {
ignore_changes = [
jsondecode(parameters_content)["startDate"],
jsondecode(parameters_content)["endDate"]
]
}
}
For the sake of completeness, content of budget_deploy.json
:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"budgetName": {
"type": "string",
"defaultValue": "MyBudget"
},
"amount": {
"type": "string",
"defaultValue": "1000"
},
"timeGrain": {
"type": "string",
"defaultValue": "Monthly",
"allowedValues": [
"Monthly",
"Quarterly",
"Annually"
]
},
"startDate": {
"type": "string"
},
"endDate": {
"type": "string"
},
"firstThreshold": {
"type": "string",
"defaultValue": "90"
},
"secondThreshold": {
"type": "string",
"defaultValue": "110"
},
"thirdThreshold": {
"type": "string",
"defaultValue": "80"
},
"contactEmails": {
"type": "string",
"defaultValue": ""
},
"contactGroups": {
"type": "string",
"defaultValue": ""
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]"
}
},
"variables": {
"groups": "[split(parameters('contactGroups'),',')]"
},
"resources": [
{
"name": "[parameters('budgetName')]",
"type": "Microsoft.Consumption/budgets",
"location": "[parameters('location')]",
"apiVersion": "2019-10-01",
"properties": {
"timePeriod": {
"startDate": "[parameters('startDate')]",
"endDate": "[parameters('endDate')]"
},
"timeGrain": "[parameters('timeGrain')]",
"amount": "[parameters('amount')]",
"category": "Cost",
"notifications": {
"NotificationForExceededBudget1": {
"enabled": true,
"operator": "GreaterThan",
"threshold": "[parameters('firstThreshold')]",
"contactGroups": "[variables('groups')]"
},
"NotificationForExceededBudget2": {
"enabled": true,
"operator": "GreaterThan",
"threshold": "[parameters('secondThreshold')]",
"contactGroups": "[variables('groups')]"
},
"NotificationForExceededBudget3": {
"enabled": true,
"operator": "GreaterThan",
"threshold": "[parameters('thirdThreshold')]",
"contactGroups": "[variables('groups')]"
}
}
}
}
]
}
Is there any way that I can still achieve my goal? - thank you!
I resorted to use tags for the end and start date for the budget. The ignore_changes
would work for the deprecated azurerm_template_deployment
as parameters is of type map
in that case and not of json
type, like so:
terraform {
required_version = "~> 0.13.0"
required_providers {
azurerm = "~> 2.37.0"
}
}
provider azurerm {
features {}
}
locals {
budget_start_date = formatdate("YYYY-MM-01", timestamp())
budget_end_date = formatdate("YYYY-MM-01", timeadd(timestamp(), "17568h"))
budget_params = {
"budgetName" = "budgettest",
"amount" = "4000",
"timeGrain" = "Annually",
"startDate" = local.budget_start_date,
"endDate" = local.budget_end_date,
"firstThreshold" = "75",
"secondThreshold" = "100",
"thirdThreshold" = "50",
"contactGroups" = ""
}
}
resource "azurerm_resource_group" "rg" {
# A subscription cannot have more than 980 resource groups:
# https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits
name = "example-rg"
location = "westeurope"
}
resource "azurerm_template_deployment" "dsw_budget" {
name = "test-budget-template"
resource_group_name = azurerm_resource_group.rg[0].name
deployment_mode = "Incremental"
template_content = file("${path.module}/arm/budget_deploy.json")
parameters_content = local.budget_params
lifecycle {
ignore_changes = [
parameters["startDate"],
parameters["endDate"]
]
}
}
Now this is not possible anymore with azurerm_resource_group_template_deployment
, as json content is has to passed and therefore in ignore_changes
a json-decoding which is a computation operation would have to be made, which is not allowed.
Therefore to solve my problem of fixating start and end dates, I resorted to using tags for start and end date and a data source querying them:
terraform {
required_version = "~> 0.13.0"
required_providers {
azurerm = "~> 2.37.0"
}
}
provider azurerm {
features {
template_deployment {
delete_nested_items_during_deletion = false
}
}
}
data "azurerm_resources" "aml" {
resource_group_name = "${var.tk_name_id}-${local.stage}-rg"
type = "Microsoft.MachineLearningServices/workspaces"
}
locals {
budget_start_date_tag = try(element(data.azurerm_resources.aml.resources[*].tags.budget_start_date, 0), "NA")
budget_end_date_tag = try(element(data.azurerm_resources.aml.resources[*].tags.budget_end_date, 0), "NA")
should_test_budget = local.is_test_stage_boolean && var.test_budget
budget_start_date = local.budget_start_date_tag != "NA" ? local.budget_start_date_tag : (local.should_test_budget ? "START DATE FAIL!" : formatdate("YYYY-MM-01", timestamp()))
budget_end_date = local.budget_end_date_tag != "NA" ? local.budget_end_date_tag : (local.should_test_budget ? "END DATE FAIL!" : formatdate("YYYY-MM-01", timeadd(timestamp(), "17568h")))
budget_date_tags = {
"budget_start_date" : local.budget_start_date,
"budget_end_date" : local.budget_end_date
}
}
#--------------------------------------------------------------------------------------------------------------------
# DSW: Resource Group
# --------------------------------------------------------------------------------------------------------------------
resource "azurerm_resource_group" "rg" {
# A subscription cannot have more than 980 resource groups:
# https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits
count = local.no_addresses_available_boolean ? 0 : 1
name = "test-rg"
location = var.location
tags = local.budget_date_tags
}
resource "azurerm_machine_learning_workspace" "aml_workspace" {
name = local.aml_ws_name
resource_group_name = azurerm_resource_group.rg[0].name
location = azurerm_resource_group.rg[0].location
application_insights_id = azurerm_application_insights.aml_insights.id
key_vault_id = azurerm_key_vault.aml_kv.id
storage_account_id = azurerm_storage_account.aml_st.id
container_registry_id = azurerm_container_registry.aml_acr.id
sku_name = "Basic"
tags = merge(var.azure_tags, local.budget_date_tags)
identity {
type = "SystemAssigned"
}
}
@Charles Xu I did not quite test it yet and I am also not sure if this is the best solution?
EDIT: Now I actually run into cyclic dependency because the data source does obviously not exist before resource group is created: https://github.com/hashicorp/terraform/issues/16380.