skip to Main Content

I am trying to create a terraform for Azure Data Collection rule. Below is my variable declaration:

 variable "data_collection_rules" {
  type = map(object({
    location            = string
    name                = string
    resource_group_name = string
    data_flow = map(object({
      destinations = list(string)
      streams = list(string)
      built_in_transform = string
      output_stream = string
      transform_kql = string
    }))
    destinations = object({
      enable_azure_monitor_metrics = bool
      azure_monitor_metrics = object({
        name = string
      })
      enable_log_analytics = bool
      log_analytics = map(object({
        name = string
        log_analytics_workspace_variable_name = string
      }))
      enable_storage_blob = bool
      storage_blob = map(object({
        container_name = string
        name = string
        storage_account_variable_name = string
      }))
    })
  }))
}

variable "log_analytics_workspace_ids" {
  type = map(string)
}

variable "storage_account_ids" {
  type = map(string)
}

Below is my module declaration:

resource "azurerm_monitor_data_collection_rule" "data_collection_rule" {
    for_each = var.data_collection_rules
    location = each.value["location"]
    name = each.value["name"]
    resource_group_name = each.value["resource_group_name"]
    dynamic "data_flow" {
      for_each = each.value["data_flow"]
      content {
        destinations = data_flow.value["destinations"]
        streams = data_flow.value["streams"]
        built_in_transform = data_flow.value["built_in_transform"]
        output_stream = data_flow.value["output_stream"]
        transform_kql = data_flow.value["transform_kql"]
      }
    }
    destinations {
      dynamic "azure_monitor_metrics" {
         for_each = each.value.destinations["enable_azure_monitor_metrics"]  == true ? [1] : []
         content {
          name = each.value.destinations.azure_monitor_metrics["name"]
         }       
      }
      dynamic "log_analytics" {
         for_each = each.value.destinations["enable_log_analytics"]  == true ? [1] : []
         content {
          name = each.value.destinations.log_analytics["name"]
          workspace_resource_id = lookup(var.log_analytics_workspace_ids, each.value.destinations.log_analytics["log_analytics_workspace_variable_name"], null)
         } 
      }
      dynamic "storage_blob" {
        for_each = each.value.destinations["enable_storage_blob"]  == true ? [1] : []
        content {
          container_name = each.value.destinations.storage_blob["container_name"]
          name = each.value.destinations.storage_blob["name"]
          storage_account_id = lookup(var.storage_account_ids, each.value.destinations.storage_blob["storage_account_variable_name"], null)
         } 
      }
    }
}

I am passing the below value to it, where log_analytics_workspace_variable_name and storage_account_variable_name are the keys of map variables I used for creating a log anytics workspace and a storage account :

data_collection_rules = {
  data_collection_rule1 = {             
    location            = "canadacentral"  
    name                = "data_collection_rule1"   
    resource_group_name = "test-rg" 
    data_flow = {
      data_flow1 ={
        destinations = ["data-collection-destination-monitoring-matrics"] 
        streams = ["Microsoft-InsightsMetrics"] 
        built_in_transform = null 
        output_stream = null 
        transform_kql = null 
      },
      data_flow2 ={
        destinations = ["data-collection-destination-log-analytics-1"] 
        streams = ["Microsoft-Perf"] 
        built_in_transform = null 
        output_stream = null 
        transform_kql = null 
      },
      data_flow3 ={
        destinations = ["data-collection-destination-storage_blob"] 
        streams = ["Microsoft-Syslog"] 
        built_in_transform = null 
        output_stream = null 
        transform_kql = null 
      }
    }
      destinations = {
        enable_azure_monitor_metrics = true 
        azure_monitor_metrics = {
          name = "data-collection-destination-monitoring-matrics" 
        }
        enable_log_analytics = true             
        log_analytics = {
          log_analytics_1 = {
            name = "data-collection-destination-log-analytics-1" 
            log_analytics_workspace_variable_name = "log_analytics_workspace1"  
          }
        }
        enable_storage_blob = true 
        storage_blob = {
          storage_blob1 = {
            container_name = "sa-container1" 
            name = "data-collection-destination-storage_blob" 
            storage_account_variable_name = "sa1" 
          }
      }
    }
  }
}

I am getting the below error when I run terraform plan:
enter image description here

I am getting the same error for all elements inside "log_analytics" and "storage_blob" destinations.

I understand that the way I am calling the elements is causing the issue but I can’t quite figure out how I can resolve this.

2

Answers


  1. According to your specification log_analytics is of type:

    log_analytics = map(object({
      name = string
      log_analytics_workspace_variable_name = string
    }))
    

    Your each.value.destinations.log_analytics["name"] corresponds to the following type:

    log_analytics = object({
      name = string
      log_analytics_workspace_variable_name = string
    })
    

    Side note: although this is valid syntax, it is customary to use . syntax for accessing object values and [""] syntax for accessing map values. Since your variable value conforms to the type specification (according to the error message) it would be faster to insert the map key in the lookup namespace path instead of changing the type:

    each.value.destinations.log_analytics["<key>"].name
    

    where <key> is the key corresponding to the value of:

    object({
      name = string
      log_analytics_workspace_variable_name = string
    })
    

    Note you will need to make a similar fix for other lookups with the same issue e.g.:

    each.value.destinations.storage_blob["<key>"].name
    
    Login or Signup to reply.
  2. This is what is happening right now

    data_collection_rule1 = {      #  each.value  
      destinations = {             #  each.value.destinations
        log_analytics = {          #  each.value.destinations.log_analytics
          log_analytics_1 = {      #  each.value.destinations.log_analytics["name"]  <- error
            name = "data-collection-destination-log-analytics-1" 
            log_analytics_workspace_variable_name = "log_analytics_workspace1"  
          }
        }
      }
    }
    

    Since log_analytics is a map you need to specify the key of the object which you want to access.
    This should return "data-collection-destination-log-analytics-1"

    each.value.destinations.log_analytics.log_analytics_1.name
    

    It is not clear in your question, but I suspect what you actually want is to dynamically access each object in the log_analytics map.
    To do that you first need to change how you iterate in the dynamic block, because right now you can only have 0 or 1 of that object.

    dynamic "log_analytics" {
      # If enable_log_analytics is true you want to process every block specified
      for_each = each.value.destinations.enable_log_analytics  == true ? each.value.destinations.log_analytics : {}
      content {
        # When using a dynamic block you get an iterator with the same name as the block, it work the same as your regular each.
        name = log_analytics.value.name
        workspace_resource_id = lookup(var.log_analytics_workspace_ids, log_analytics.value.log_analytics.log_analytics_workspace_variable_name, null)
      } 
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search