Home > Blockchain >  Terraform for_each nested solution
Terraform for_each nested solution

Time:10-28

I need to access the elements of a nested map but I can't do it and I get an error Can't access attributes on a primitive-typed value (string).

# GLUE
locals {
  glue_catalog_resources = {
    uni = {
      name = "mst_business_units",
      description = "Unidades de negocios"
      columns = [
        {
          name = "codigouni"
          type = "int"
          comment = "Code"
        },{
          name = "descuni"
          type = "varchar(256)"
          comment = "Description"
        },{
          name = "estado"
          type = "varchar(256)"
          comment = "Current status"
        }
      ]
    }
  }
}

resource "aws_glue_catalog_table" "glue_catalogs_redshift" {
  for_each      = local.glue_catalog_resources
  name          = each.value.name
  database_name = aws_glue_catalog_database.cl_sales.name
  description   = each.value.description
  retention     = 0
  table_type    = "EXTERNAL_TABLE"

  parameters = {
    EXTERNAL         = "TRUE"
    "classification" = "parquet"
  }

  storage_descriptor {
    location = ""
    input_format = "org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat"
    output_format = "org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat"
    number_of_buckets = 0
    compressed = "false"
    stored_as_sub_directories = "false"

    ser_de_info {
      serialization_library = "org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe"

      parameters = {
        "serialization.format" = 1
      }
    }

    parameters = {
      "typeOfData": "kinesis"
    }

    columns {
      name = [ for column in each.value.columns: [ for row in column: row.name ] ]
      type = [ for column in each.value.columns: [ for row in column: row.type ] ]
      comment = [ for column in each.value.columns: [ for row in column: row.comment ] ]
    }

  }
}

I need to include in the columns tag columns name, type and comment reading it from the map above and I can't do it, what would be the correct way to read it

columns {
      name = [ for column in each.column.value: [ for row in column: row.name ] [ for row in column: row.name ] [ for row in column: row.name ] [ for row in column: row.name
      type = [ for column in each.value.columns: [ for row in column: row.type ]
      comment = [ for column in each.value.columns: [ for row in column: row.comment ] ] ]
    }

CodePudding user response:

In this case, columns is a list of key value pairs, so you need to adjust the second for a bit:

  name    = [for column in local.columns : [for k, v in column : v if k == "name"]]
  type    = [for column in local.columns : [for k, v in column : v if k == "type"]]
  comment = [for column in local.columns : [for k, v in column : v if k == "comment"]]

EDIT: The first part of the answer resolves the issue with accessing the list elements. However, in order for this to work as you would want to, I would suggest a couple of changes. In the local variable, you can change columns to be a map of objects:

locals {
  glue_catalog_resources = {
    uni = {
      name        = "mst_business_units",
      description = "Unidades de negocios"
      columns = {
        "codigouni" = {
          name    = "codigouni"
          type    = "int"
          comment = "Code"
        },
        "descuni" = {
          name    = "descuni"
          type    = "varchar(256)"
          comment = "Description"
        },
        "estado " = {
          name    = "estado"
          type    = "varchar(256)"
          comment = "Current status"
        }
      }
    }
  }
}

Then, in the columns block you would do the following:

resource "aws_glue_catalog_table" "glue_catalogs_redshift" {
  for_each      = local.glue_catalog_resources
  name          = each.value.name
  database_name = aws_glue_catalog_database.cl_sales.name
  description   = each.value.description
  retention     = 0
  table_type    = "EXTERNAL_TABLE"

  parameters = {
    EXTERNAL         = "TRUE"
    "classification" = "parquet"
  }

  storage_descriptor {
    location                  = ""
    input_format              = "org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat"
    output_format             = "org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat"
    number_of_buckets         = 0
    compressed                = "false"
    stored_as_sub_directories = "false"

    ser_de_info {
      serialization_library = "org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe"

      parameters = {
        "serialization.format" = 1
      }
    }

    parameters = {
      "typeOfData" : "kinesis"
    }

    dynamic "columns" {
      for_each = each.value.columns
      content {
        name    = columns.value.name
        type    = columns.value.type
        comment = columns.value.comment
      }
    }
  }
}

This approach is using dynamic [1] and for_each [2] to iterate over all of the columns and assign the wanted values to arguments.


[1] https://developer.hashicorp.com/terraform/language/expressions/dynamic-blocks

[2] https://developer.hashicorp.com/terraform/language/meta-arguments/for_each

  • Related