How to achieve resource creation and associated provisioner execution using different lists/maps

Hi,

I use a list to create the resource,

list_zones  = [
          "us-east1-a",
          "us-west2-c",
        ]

And a map to create the local-exec provisioner

flat_zones  = [
          {
              env_name = "stg-a1"
              zone     = "us-east1-a"
            },
          {
              env_name = "stg-a1"
              zone     = "us-west2-c"
            },
          {
              env_name = "stg-b1"
              zone     = "us-west2-c"
            },
        ]

Here’s the resource creation code,

resource "google_apigee_instance" "apigee" {
  for_each                 = toset(local.list_zones)
  name                     = "${each.value}-${random_id.random.dec}"
  location                 = each.value

  provisioner "local-exec" {
    for_each = { for idx, record in local.flat_zones : idx => record }
    when    = create
    command = <<EOF
curl -i -H "Authorization: Bearer ${data.google_client_config.current.access_token}"\
  "https://apigee.googleapis.com/v1/organizations/${var.project}/instances/${each.value.zone}-${random_id.random.dec}/attachments" \
  -X POST -H "content-type:application/json" \
  -d '{"environment":"${each.value.env_name}"}'
EOF
  }

  depends_on = [google_apigee_environment.apigee]
}

I know the for_each inside a provisioner is not allowed, but that’s just to show I need additional fields from the map to fulfill the curl.

Also, I am OK to use a null_resource as long as that null_resource gets executed as soon as the respective instance is created and not wait for all the instances to get created.

How to achieve this behavior?

Any help is appreciated.

Thanks,
Arun

I think the most practical answer to this question is to use a single local-exec provisioner with more than one statement in command, perhaps like this:

resource "google_apigee_instance" "apigee" {
  for_each = toset(local.list_zones)

  # ...

  provisioner "local-exec" {
    command = <<-EOF
      %{ for record in local.flat_zones }%{ if record.zone == each.key ~}
      curl -i ... "https://apigee.googleapis.com/v1/organizations/${var.project}/instances/${record.zone}-${random_id.random.dec}/attachments" ... \
        -d '{"environment":"${record.env_name}"}'
      %{ endif }%{ endfor ~}
    EOF
  }
}

I simplified this just to show the general structure I have in mind without repeating all of the stuff that’s unchanged here, but the general idea here is to make this generate a single script that has multiple curl calls. The structure of local.flat_zones made this a bit awkward, requiring an extra if directive, so if you can restructure that to be a more convenient data structure (e.g. a map where the keys are the zones) then you could simplify the template a little.

Yes, that’s a great suggestion and yes, I will simplify flat_zones, currently it’s

flat_zones = flatten([
    for zone_key, zone in var.deployments: flatten([
      for group_key, group in zone: [
        for env_key, env in group.envs: {
          env_name = env
          zone = zone_key
       }
      ]
    ])
  ])

Any easy way to make that a map like you suggested?

If you are too busy to answer that’s fine, I will google, that should be pretty simple.

Thanks,
Arun

If I’m understanding that expression correctly, it seems like you already have a suitable data structure for this in var.deployments, without the need to build this derived one:

  provisioner "local-exec" {
    command = <<-EOF
      %{ for env in var.deployments[each.key] }
      curl -i ... "https://apigee.googleapis.com/v1/organizations/${var.project}/instances/${each.key}-${random_id.random.dec}/attachments" ... \
        -d '{"environment":"${env}"}'
      %{ endfor ~}
    EOF
  }

For this I’m making the assumption that var.deployments is a data structure shaped like this:

{
  "us-east1-a" = {
    "stg-a1" = "something"
  }
  "us-west2-c" = {
    "stg-a1" = "something"
    "stg-b1" = "something"
  }
}

Even if I didn’t get that exactly right, hopefully it’s close enough that you can see what I mean.

Hi @apparentlymart, yes, thank you, makes sense. Appreciate your help.