Issue with dynamic block in resource

I have resource:

resource "oci_core_volume" "block" {
  for_each             = var.instance_params
  availability_domain = oci_core_instance.this[each.value.instance_name].availability_domain
  compartment_id      = var.compartment_id
  dynamic "params_disco" {
    for_each = each.value.block_volume_params
    iterator = bvp
    content {
      display_name        = "${var.prefijo_cliente}-${bvp.value.hostname}-${bvp.value.display_name}"
      size_in_gbs         = bvp.value.bv_size
    }
  }
}

I’m getting this error:

│ **Error:** **Unsupported block type**
│ on ../../modules/core-instance/main.tf line 117, in resource "oci_core_volume" "block":
│ 117: dynamic "params_disco" {
│ Blocks of type "params_disco" are not expected here.

I have tried in several ways and I don’t know why. Can you help me?

Thanks in advance.

Hi @TonyD!

Can you share an example of you var.instance_params and a single instance of the oci_core_volume you are trying to create?

Dynamic blocks are explained here in the docs, and based on a quick lookup I think you should rename params_disco to a valid block within a oci_core_volume, like block_volume_replicas or use a for_each loop only to create your resources.

Sure!

variable "instance_params" {
  description = "parameters"
  type = map(object({
    hostname             = string
    ad                   = number
    shape                = string
    instance_ocpus       = number
    instance_ram         = number
    os                   = string
    boot_volume_size     = number
    preserve_boot_volume = bool
    assign_public_ip     = bool
    private_ip           = string
    subnet_name          = string
    nsg_name             = string
    vnic_params          = list(object({
      vnic_name              = string
      display_name           = string
      private_ip             = string
      skip_source_dest_check = bool
      subnet_name            = string
      nsg_name               = string
    }))
    block_volume_params   = list(object({
      ad           = number
      display_name = string
      bv_size      = number
      device_name  = string
      volume_type  = string
    }))
  }))
}


instance_params = {
  GATEWAY = {
    hostname             = "SRV-GATEWAY"
    ad                   = 1
    shape                = "VM.Standard.E4.Flex"
    instance_ocpus       = 1
    instance_ram         = 2
    os                   = "canonical_ubuntu_20_4"
    boot_volume_size     = 50 # gbs
    preserve_boot_volume = false
    assign_public_ip     = true
    private_ip           = "172.16.23.20"
    subnet_name          = "DMZ"
    nsg_name             = "gateway_srv_nsg"
    vnic_params = [
      {
        vnic_name              = "NIC"
        display_name           = "NIC"
        private_ip             = "172.16.123.2"
        skip_source_dest_check = true
        subnet_name            = "LAN"
        nsg_name               = "gateway_srv_nsg"
    }]
    block_volume_params = []
  },
  BDPRODUCCION = {
    hostname             = "SRVORACLE19C-1"
    ad                   = 1
    shape                = "VM.Standard.E4.Flex"
    instance_ocpus       = 2
    instance_ram         = 16
    os                   = "oracle_linux_8_4"
    boot_volume_size     = 50 # gbs
    preserve_boot_volume = false
    assign_public_ip     = false
    private_ip           = "172.16.123.11"
    subnet_name          = "LAN"
    nsg_name             = "srvoracle19c_1_nsg"
    vnic_params          = []
    block_volume_params = [
      {
        ad           = 1
        display_name = "u01"
        bv_size      = 50 # gbs
        device_name  = ""
        volume_type  = ""
      },
      {
        ad           = 1
        display_name = "u02"
        bv_size      = 200 # gbs
        device_name  = ""
        volume_type  = ""
      },
      {
        ad           = 1
        display_name = "DATOS-1"
        bv_size      = 200 # gbs
        device_name  = ""
        volume_type  = ""
      },
      {
        ad           = 1
        display_name = "FRA-1"
        bv_size      = 50 # gbs
        device_name  = ""
        volume_type  = ""
      }
    ]
  }
}

Sorry, but could you please ease reading your config by using ```hcl before and ``` after your code block and use indentation?

I cannot format it myself, as it seems invalid terraform configuration

variable "instance_params" {
  description = "parameters"
  type = map(object({
    hostname             = string
    ad                   = number
    shape                = string
    instance_ocpus       = number
    instance_ram         = number
    os                   = string
    boot_volume_size     = number
    preserve_boot_volume = bool
    assign_public_ip     = bool
    private_ip           = string
    subnet_name          = string
    nsg_name             = string
    vnic_params = list(object({
      vnic_name              = string
      display_name           = string
      private_ip             = string
      skip_source_dest_check = bool
      subnet_name            = string
      nsg_name               = string
    }))
    block_volume_params = list(object({
      ad           = number
      display_name = string
      bv_size      = number
      device_name  = string
      volume_type  = string
    }))
  }))
}

Sorry…

instance_params = {
  GATEWAY = {
    hostname             = "SRV-GATEWAY"
    ad                   = 1
    shape                = "VM.Standard.E4.Flex"
    instance_ocpus       = 1
    instance_ram         = 2
    os                   = "canonical_ubuntu_20_4"
    boot_volume_size     = 50 # gbs
    preserve_boot_volume = false
    assign_public_ip     = true
    private_ip           = "172.16.23.20"
    subnet_name          = "DMZ"
    nsg_name             = "gateway_srv_nsg"
    vnic_params = [
      {
        vnic_name              = "NIC"
        display_name           = "NIC"
        private_ip             = "172.16.123.2"
        skip_source_dest_check = true
        subnet_name            = "LAN"
        nsg_name               = "gateway_srv_nsg"
    }]
    block_volume_params = []
  },
  BDPRODUCCION = {
    hostname             = "SRVORACLE19C-1"
    ad                   = 1
    shape                = "VM.Standard.E4.Flex"
    instance_ocpus       = 2
    instance_ram         = 16
    os                   = "oracle_linux_8_4"
    boot_volume_size     = 50 # gbs
    preserve_boot_volume = false
    assign_public_ip     = false
    private_ip           = "172.16.123.11"
    subnet_name          = "LAN"
    nsg_name             = "srvoracle19c_1_nsg"
    vnic_params          = []
    block_volume_params = [
      {
        ad           = 1
        display_name = "u01"
        bv_size      = 50 # gbs
        device_name  = ""
        volume_type  = ""
      },
      {
        ad           = 1
        display_name = "u02"
        bv_size      = 200 # gbs
        device_name  = ""
        volume_type  = ""
      },
      {
        ad           = 1
        display_name = "DATOS-1"
        bv_size      = 200 # gbs
        device_name  = ""
        volume_type  = ""
      },
      {
        ad           = 1
        display_name = "FRA-1"
        bv_size      = 50 # gbs
        device_name  = ""
        volume_type  = ""
      }
    ]
  }

variable "instance_params" {
  description = "parameters"
  type = map(object({
    hostname             = string
    ad                   = number
    shape                = string
    instance_ocpus       = number
    instance_ram         = number
    os                   = string
    boot_volume_size     = number
    preserve_boot_volume = bool
    assign_public_ip     = bool
    private_ip           = string
    subnet_name          = string
    nsg_name             = string
    vnic_params          = list(object({
      vnic_name              = string
      display_name           = string
      private_ip             = string
      skip_source_dest_check = bool
      subnet_name            = string
      nsg_name               = string
    }))
    block_volume_params   = list(object({
      ad           = number
      display_name = string
      bv_size      = number
      device_name  = string
      volume_type  = string
    }))
  }))
}


So you’ve multiple vm instances, with each potentially multiple NICs and block volumes.

Is it an option to make it into a module or would you prefer to keep it as is? If the latter is the case, you can take a look at list_of_maps.tf · GitHub, which does the same but in a different context.

You can loop over the output with your for_each.

Do you mind to explain “to make it into a module”?

Sure! By making an instance module, you can loop for_each per instance over the instances module, and loop over the blocks in the module itself.

Flatten all the blocks to keep it similar to your current setup would look like this:

variable "instance_params" {
  description = "parameters"

  type = map(object({
    hostname             = string
    ad                   = number
    shape                = string
    instance_ocpus       = number
    instance_ram         = number
    os                   = string
    boot_volume_size     = number
    preserve_boot_volume = bool
    assign_public_ip     = bool
    private_ip           = string
    subnet_name          = string
    nsg_name             = string
    vnic_params = list(object({
      vnic_name              = string
      display_name           = string
      private_ip             = string
      skip_source_dest_check = bool
      subnet_name            = string
      nsg_name               = string
    }))
    block_volume_params = list(object({
      ad           = number
      display_name = string
      bv_size      = number
      device_name  = string
      volume_type  = string
    }))
  }))
  default = {
    GATEWAY = {
      hostname             = "SRV-GATEWAY"
      ad                   = 1
      shape                = "VM.Standard.E4.Flex"
      instance_ocpus       = 1
      instance_ram         = 2
      os                   = "canonical_ubuntu_20_4"
      boot_volume_size     = 50 # gbs
      preserve_boot_volume = false
      assign_public_ip     = true
      private_ip           = "172.16.23.20"
      subnet_name          = "DMZ"
      nsg_name             = "gateway_srv_nsg"
      vnic_params = [
        {
          vnic_name              = "NIC"
          display_name           = "NIC"
          private_ip             = "172.16.123.2"
          skip_source_dest_check = true
          subnet_name            = "LAN"
          nsg_name               = "gateway_srv_nsg"
      }]
      block_volume_params = []
    },
    BDPRODUCCION = {
      hostname             = "SRVORACLE19C-1"
      ad                   = 1
      shape                = "VM.Standard.E4.Flex"
      instance_ocpus       = 2
      instance_ram         = 16
      os                   = "oracle_linux_8_4"
      boot_volume_size     = 50 # gbs
      preserve_boot_volume = false
      assign_public_ip     = false
      private_ip           = "172.16.123.11"
      subnet_name          = "LAN"
      nsg_name             = "srvoracle19c_1_nsg"
      vnic_params          = []
      block_volume_params = [
        {
          ad           = 1
          display_name = "u01"
          bv_size      = 50 # gbs
          device_name  = ""
          volume_type  = ""
        },
        {
          ad           = 1
          display_name = "u02"
          bv_size      = 200 # gbs
          device_name  = ""
          volume_type  = ""
        },
        {
          ad           = 1
          display_name = "DATOS-1"
          bv_size      = 200 # gbs
          device_name  = ""
          volume_type  = ""
        },
        {
          ad           = 1
          display_name = "FRA-1"
          bv_size      = 50 # gbs
          device_name  = ""
          volume_type  = ""
        }
      ]
    }
  }
}

locals {
  block_volumes = flatten([for instance, dict in var.instance_params : [
    for block_volume, value in toset(dict.block_volume_params) : merge({ "instance" = instance, "hostname" = dict.hostname }, value)
  ]])
}

output "block_volumes" {
  value = local.block_volumes
}

terraform apply:

Changes to Outputs:
  + block_volumes = [
      + {
          + ad           = 1
          + bv_size      = 200
          + device_name  = ""
          + display_name = "DATOS-1"
          + hostname     = "SRVORACLE19C-1"
          + instance     = "BDPRODUCCION"
          + volume_type  = ""
        },
      + {
          + ad           = 1
          + bv_size      = 200
          + device_name  = ""
          + display_name = "u02"
          + hostname     = "SRVORACLE19C-1"
          + instance     = "BDPRODUCCION"
          + volume_type  = ""
        },
      + {
          + ad           = 1
          + bv_size      = 50
          + device_name  = ""
          + display_name = "FRA-1"
          + hostname     = "SRVORACLE19C-1"
          + instance     = "BDPRODUCCION"
          + volume_type  = ""
        },
      + {
          + ad           = 1
          + bv_size      = 50
          + device_name  = ""
          + display_name = "u01"
          + hostname     = "SRVORACLE19C-1"
          + instance     = "BDPRODUCCION"
          + volume_type  = ""
        },
    ]

You can now loop over the blocks with a for_each

THANK You! I wasn’t able to do it with a for_each but I was able to do it with a count.

I have to improve my knowledge of TF :slight_smile:

1 Like