potatopotato
potatopotato

Reputation: 1174

Terragrunt import resource created via for_each loop

I'm creating a GCP buckets with for_each loop, and wanted to import the existing buckets into my terraform state

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # google_storage_bucket.buckets["a-test-test-test"] will be created
  + resource "google_storage_bucket" "buckets" {
      + bucket_policy_only          = (known after apply)
      + force_destroy               = false
      + id                          = (known after apply)
      + location                    = "US"
      + name                        = "a-test-test-test"
      + project                     = "xxx"
      + self_link                   = (known after apply)
      + storage_class               = "STANDARD"
      + uniform_bucket_level_access = false
      + url                         = (known after apply)

      + versioning {
          + enabled = true
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  ~ urls = [
      - "gs://a-test-test-test",
      + (known after apply),
    ]

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

google_storage_bucket.buckets["a-test-test-test"]: Creating...

Error: googleapi: Error 409: You already own this bucket. Please select another name., conflict

The resource already exists but that's fine, I can just import it, question is how

because running it like this

MacBook-Pro% terragrunt import google_storage_bucket.buckets a-test-test-test
...
Acquiring state lock. This may take a few moments...
google_storage_bucket.buckets: Importing from ID "a-test-test-test"...
google_storage_bucket.buckets: Import prepared!
  Prepared google_storage_bucket for import
google_storage_bucket.buckets: Refreshing state... [id=a-test-test-test]

Import successful!

seems to work, but it imported it 'wrongly'

terragrunt state list
...
google_storage_bucket.buckets

its show in my tfstate, but it should be like this

google_storage_bucket.buckets["a-test-test-test"]

because if I run now apply - it says it wants to delete the google_storage_bucket.buckets and create google_storage_bucket.buckets["a-test-test-test"]

google_storage_bucket.buckets: Refreshing state... [id=a-test-test-test]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
  - destroy

Terraform will perform the following actions:

  # google_storage_bucket.buckets will be destroyed
  - resource "google_storage_bucket" "buckets" {
      - bucket_policy_only          = false -> null
      - default_event_based_hold    = false -> null
      - force_destroy               = false -> null
      - id                          = "a-test-test-test" -> null
      - labels                      = {} -> null
      - location                    = "US" -> null
      - name                        = "a-test-test-test" -> null
      - project                     = "xxx" -> null
      - requester_pays              = false -> null
      - self_link                   = "https://www.googleapis.com/storage/v1/b/a-test-test-test" -> null
      - storage_class               = "STANDARD" -> null
      - uniform_bucket_level_access = false -> null
      - url                         = "gs://a-test-test-test" -> null

      - versioning {
          - enabled = true -> null
        }
    }

  # google_storage_bucket.buckets["a-test-test-test"] will be created
  + resource "google_storage_bucket" "buckets" {
      + bucket_policy_only          = (known after apply)
      + force_destroy               = false
      + id                          = (known after apply)
      + location                    = "US"
      + name                        = "a-test-test-test"
      + project                     = "xxx"
      + self_link                   = (known after apply)
      + storage_class               = "STANDARD"
      + uniform_bucket_level_access = false
      + url                         = (known after apply)

      + versioning {
          + enabled = true
        }
    }

Plan: 1 to add, 0 to change, 1 to destroy.

Changes to Outputs:
  + urls = [
      + (known after apply),
    ]

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

Any thoughts how to import into a for_each in terragrunt ?

I tried the

terragrunt import google_storage_bucket.buckets a-test-test-test
terragrunt import google_storage_bucket.buckets.a-test-test-test a-test-test-test
terragrunt import google_storage_bucket.buckets["a-test-test-test"] a-test-test-test
terragrunt import google_storage_bucket.buckets[\"a-test-test-test\"] a-test-test-test

and noone work just leaving me with error

zsh: no matches found: google_storage_bucket.buckets["a-test-test-test"]

while the first option terragrunt import google_storage_bucket.buckets a-test-test-test , imported (aka. worked) but not the right way


The terraform code is like so:

inputs = {
  project_id  = "${local.project_id}"
    {
      name                        = "a-test-test-test"
      location                    = "US"
    }
}

locals {
  buckets        = {for b in jsondecode(var.buckets) : b.name => b }
}

variable "buckets" {
  description = "The name of the bucket."
}

resource "google_storage_bucket" "buckets" {
  for_each      = local.buckets
  name          = each.key
  project       = var.project_id
  location      = each.value.location

Upvotes: 8

Views: 8120

Answers (2)

Martin Atkins
Martin Atkins

Reputation: 74259

Importing into the full instance address (including the instance key index part) is the right approach, but the trick here is to determine the best way to work around the grammar of your shell so that the necessary characters can reach Terraform.

For Unix-style shells I typically recommend putting the address in single quotes to disable metacharacter interpretation, like this:

terragrunt import 'google_storage_bucket.buckets["a-test-test-test"]' a-test-test-test

I don't have much experience with zsh in particular but from referring to a copy of part of its documentation I get the impression that the above is valid zsh syntax too. If the above doesn't work, it might be worth trying with a different shell such as bash to see if you get a different result.

Although you specifically mentioned zsh, for completeness I'll also note that on Windows the rules are a little different: single quotes aren't supported under the conventional Windows command line syntax, and so unfortunately we must escape the quotes instead when running Terraform from the Windows command prompt:

terragrunt import google_storage_bucket.buckets[\"a-test-test-test\"] a-test-test-test

The important thing is that the quote characters " in the address make it through the shell to Terraform, so that Terraform can then successfully parse the argument as resource address syntax.

Upvotes: 14

Patrick Rodies
Patrick Rodies

Reputation: 1

I used data inside Terraform module to avoid this issue with variable called from Terragrunt in main.tf

data "azurerm_resource_group" "k8s" {
  name = var.resource_group_name
}

in terragrunt.hcl

resource_group_name = "rgpazewsmlit-sandbox-xxxxx"

Upvotes: 0

Related Questions