0

I have a request to setup budget alert on our resource groups located in different subscriptions. I am trying to decide if it make sense to do it thru PowerShell or Terraform to automate this process. My thinking is that management would update a .csv file quarterly with the budget amount and alert threshold for each of the RGs they want to set alerts form. The .csv will have the following fields/columns:

SubscriptionName, SubscriptionId, ResourcegGropu, StartDate, EndDate,TimeGrain,ContactEmails,Contact,BudgetAmount,budgetName, alertLevels

Any suggests? Thanks

Ultra GC
  • 311
  • 4
  • 15

1 Answers1

0

Using Terraform to perform the same operation on different Subscriptions will be difficult as for_each is not supported in provider blocks as shown in below image , so you will have to manually set up the provider blocks for all the subscriptions.

locals{
    budget=csvdecode(file("C:/Users/xxxxx/terraform/budgetalert/Budget.csv"))
}
provider "azurerm"{
    for_each ={ for i , user in local.budget : i => budget }
    features{}
    subscription_id = each.value.SubscriptionId
    alias = each.value.SubscriptionName
}

enter image description here

As a solution to do this from terraform you can create different .csv files for different subscriptions and call them in different resource provider blocks like below :

provider "azurerm"{
    features {}
    subscription_id = "b83-----xxxxxxxxxxx-xxxx-xxxxx----23f"
}
provider "azurerm" {
    features {}
  subscription_id = "948--------x--xxxxxxxxxxxxx-xxxxxxx-59b"
  alias = "Subscription2"
}

locals{
    budgetsub1=csvdecode(file("C:/Users/xxxx/terraform/budgetalert/Budget.csv"))
    budgetsub2=csvdecode(file("C:/Users/xxxx/terraform/budgetalert/budgetsub2.csv"))
}
output "local" {
  value=local.budgetsub1
}
output "local1" {
  value = local.budgetsub2
}

data "azurerm_resource_group" "rg_subscription1"{
    for_each = { for i , budget in local.budgetsub1 : i => budget }
    name= each.value.ResourceGroup
}
data "azurerm_resource_group" "rg_subscription2"{
    provider = azurerm.Subscription2
    for_each = { for i , budget in local.budgetsub2 : i => budget }
    name= each.value.ResourceGroup
}

resource "azurerm_consumption_budget_resource_group" "rg_budget_subscription1" {
    for_each = { for i , budget in local.budgetsub1 : i => budget }
  name       = each.value.budgetName
  amount     = each.value.BudgetAmount
  time_grain = each.value.TimeGrain
  time_period {
    start_date = each.value.StartDate
    end_date  = each.value.EndDate
  }
  resource_group_id = data.azurerm_resource_group.rg_subscription1[each.key].id
  notification {
      enabled = true
    threshold      = 80
    operator       = "GreaterThanOrEqualTo"
    contact_emails = ["${each.value.ContactEmails}"]
  }
  lifecycle {
    ignore_changes = [
      time_period
    ]
  }
}
resource "azurerm_consumption_budget_resource_group" "rg_budget_subscription2" {
    provider = azurerm.Subscription2
    for_each = { for i , budget in local.budgetsub2 : i => budget }
  name       = each.value.budgetName
  amount     = each.value.BudgetAmount
  time_grain = each.value.TimeGrain
  time_period {
    start_date = each.value.StartDate
    end_date  = each.value.EndDate
  }
  resource_group_id = data.azurerm_resource_group.rg_subscription2[each.key].id
  notification {
      enabled = true
    threshold      = 80
    operator       = "GreaterThanOrEqualTo"
    contact_emails = ["${each.value.ContactEmails}"]
  }
  lifecycle {
    ignore_changes = [
      time_period
    ]
  }
}

Output:

enter image description here

enter image description here enter image description here

Ansuman Bal
  • 9,705
  • 2
  • 10
  • 27
  • Hey Ansuman, thanks for the comments and the demo code. Really appreciate. Ya the switch of the subscriptions in TF was one of the concerns I have and glad you provided a workaround. I will test it out and get back to you. – Ultra GC Feb 07 '22 at 16:32
  • Hey Ansuman, your suggestion works as expected... but is is complaining about alert level: SubscriptionName,SubscriptionId,ResourceGroup,StartDate,EndDate,TimeGrain,ContactEmails,BudgetAmount,BudgetName,AlertLevels My Subscription,948---59b,RG1,2022-02-01,2022-12-31,Monthly,myemail1@contoso.com;myemail2@contoso.com,150,MyBudgetQA,75;85;95 As you can see, both fields contain multiple values separated by ";". It t is saying that it needs a number. Suggestions? – Ultra GC Feb 08 '22 at 00:52
  • Can you please post the complete error message to the post as well .. – Ansuman Bal Feb 08 '22 at 02:47
  • Sorry... here's the error message. I think it is because each alert level is one separate entry. Error: Incorrect attribute value type │ │ on AssignBudgetToRG.tf line 48, in resource "azurerm_consumption_budget_resource_group" "rg_budget_subscription_dev": │ 48: threshold = each.value.AlertLevels │ ├──────────────── │ │ each.value.AlertLevels is "50;75;95" │ │ Inappropriate value for attribute "threshold": a number is required. – Ultra GC Feb 08 '22 at 16:19
  • @UltraGC, Yes so alert level can be one only like either 50 or 75 or 95 not all..if you want dynamic configuration for setting multiple alert levels then you can use dynamic block for notification again . – Ansuman Bal Feb 08 '22 at 17:46