terragrunt icon indicating copy to clipboard operation
terragrunt copied to clipboard

Terragrunt not running init with backend false when a module has a dependency

Open abhinaba-chakraborty-by opened this issue 4 years ago • 6 comments

I am having a project structure as follows: . ├── README.md ├── modules │ ├── function-app-consumption │ │ ├── locals.tf │ │ ├── main.tf │ │ ├── output.tf │ │ └── variables.tf │ └── storage-account │ ├── main.tf │ ├── output.tf │ └── variables.tf └── sandbox ├── eastus │ ├── regional.tfvars │ ├── functionapp-svc │ │ └── terragrunt.hcl │ └── storageaccount-function │ └── terragrunt.hcl ├── environment.tfvars └── terragrunt.hcl

I want to deploy the infrastructure in "sandbox" environment. the root terragrunt.hcl file for that env. looks like this:

generate "provider" {
  path      = "_provider.tf"
  if_exists = "overwrite"
  contents  = <<EOF

provider "azurerm" {
  features {

  }
}

EOF
}

remote_state {
  backend = "azurerm"

  disable_init = tobool(get_env("TERRAGRUNT_DISABLE_INIT", "false"))

  generate = {
    path      = "_backend.tf"
    if_exists = "overwrite"
  }

  config = {
    resource_group_name  = "my-sandbox-rg"
    storage_account_name = "mysbxtfbackend"
    container_name       = "tfstate"
    key                  = "${path_relative_to_include()}/terraform.tfstate"
  }
}

I am using the TERRAGRUNT_DISABLE_INIT environment variable to disable backend initialization while running the validate-all command. like this:

cd sanbox/
export TERRAGRUNT_DISABLE_INIT=true
terragrunt validate-all

It works fine when there is no dependency defined in any of the modules. But when a module has a dependency like this:

terraform {
  source = "../../../modules//function-app-consumption"

  extra_arguments "custom_vars" {
    commands = get_terraform_commands_that_need_vars()

    arguments = [
      "-var-file=${get_terragrunt_dir()}/../regional.tfvars",
      "-var-file=${get_terragrunt_dir()}/../../environment.tfvars"
    ]
  }

}

dependency "storage_account" {
  config_path                             = "../storageaccount-function"
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
  mock_outputs = {
    storage_account_name       = "mockstgacc"
    storage_primary_access_key = "mockaccesskey"
  }
}

dependencies {
  paths = ["../storageaccount-function"]
}

include {
  path = find_in_parent_folders()
}


inputs = {

  function_app_name          = "func-my-sbx-svc"
  function_version           = "~3"
  reserved                   = true
  os_type                    = "linux"
  storage_account_name       = dependency.storage_account.outputs.storage_account_name
  storage_account_access_key = dependency.storage_account.outputs.storage_primary_access_key

  app_settings = {
    "FUNCTIONS_WORKER_RUNTIME" = "java",
    "WEBSITE_RUN_FROM_PACKAGE" = "1"
  }
}

It starts failing , complaining that it requires backend initialization.

[terragrunt] [/Users/abhi/codes/infra/sandbox/eastus/functionapp-svc] 2021/02/17 16:28:38 Running module /Users/abhi/codes/infra/sandbox/eastus/functionapp-svc now
[terragrunt] [/Users/abhi/codes/infra/sandbox/eastus/functionapp-svc] 2021/02/17 16:28:38 Running command: terraform --version
[terragrunt] [/Users/abhi/codes/infra/sandbox/eastus/functionapp-svc] 2021/02/17 16:28:38 Terraform version: 0.14.4
[terragrunt] [/Users/abhi/codes/infra/sandbox/eastus/functionapp-svc] 2021/02/17 16:28:38 Reading Terragrunt config file at /Users/abhi/codes/infra/sandbox/eastus/functionapp-svc/terragrunt.hcl
[terragrunt] [/Users/abhi/codes/infra/sandbox/eastus/storageaccount-function] 2021/02/17 16:28:38 Generated file /Users/abhi/codes/infra/sandbox/eastus/storageaccount-function/.terragrunt-cache/644837049/_backend.tf.
[terragrunt] [/Users/abhi/codes/infra/sandbox/eastus/storageaccount-function] 2021/02/17 16:28:38 Running command: terraform init -get=false -get-plugins=false
[terragrunt] [/Users/abhi/codes/infra/sandbox/eastus/storageaccount-function] 2021/02/17 16:28:40 Running command: terraform output -json

Error: Initialization required. Please see the error message above.

As we can see from the logs, the command terraform init -backend=false is not run , instead, the command terraform init -get=false -get-plugins=false gets executed. This seems to be a bug.

abhinaba-chakraborty-by avatar Feb 17 '21 11:02 abhinaba-chakraborty-by

Ah yes that does look like a bug, specifically, it should skip the direct remote state based dependency fetching when disable_init is true. We're a bit buried at the moment to implement this, but if anyone wants to submit a PR, the function in question is here: https://github.com/gruntwork-io/terragrunt/blob/579258163dd05878f2b3cfa53611c0f5fb8a728e/config/dependency.go#L427

As far as workarounds go, does it work if you add disable_dependency_optimization = tobool(get_env("TERRAGRUNT_DISABLE_INIT", "false")) to the remote_state block?

yorinasub17 avatar Feb 17 '21 12:02 yorinasub17

No @yorinasub17 , I tried adding disable_dependency_optimization = tobool(get_env("TERRAGRUNT_DISABLE_INIT", "false")) to the remote_state block , but it was of no help.

abhinaba-chakraborty-by avatar Feb 17 '21 13:02 abhinaba-chakraborty-by

Ah upon further inspection, I see that we are handling errors from the output command and special casing when there is no output to return the mocks. That is sort of expected behavior given that the dependency handlers are assuming a clean output call, and output depends on being able to read the state properly (e.g. we don't want to silently fail and return mocks for auth issues).

Does it work if you have skip_outputs = tobool(get_env("TERRAGRUNT_DISABLE_INIT", "false")) on the dependency block?

yorinasub17 avatar Feb 17 '21 13:02 yorinasub17

Yep it worked!! Thanks a lot for the workaround :-) @yorinasub17

abhinaba-chakraborty-by avatar Feb 18 '21 06:02 abhinaba-chakraborty-by

can something like this be fixed please?

bitsofinfo avatar Dec 14 '21 18:12 bitsofinfo

I have fixed this issue by just adding init command in mock_outputs_allowed_terraform_commands:

dependency "network" {
  config_path = "../network"

  mock_outputs_allowed_terraform_commands = ["validate", "init"]
  mock_outputs = {
    private_subnets_ids = [
        "subnet-xxxxxxxxxxxxxxxxx"
    ]
    nat_public_ips      = [
        "xx.xxx.xxx.xxx"
    ]
  }
}

dependencies {
  paths = ["../network"]
}

inputs = {
  private_subnets_ids = dependency.network.outputs.private_subnets_ids
  nat_public_ips      = dependency.network.outputs.nat_public_ips
}

mariadb-PlamenKovachev avatar Jun 28 '22 13:06 mariadb-PlamenKovachev

Running into this issue too :(

ThePinzon avatar Dec 06 '22 23:12 ThePinzon

Happy to pick up on this if not assigned, btw is the preferred flow picking from the To Do pile?

lplazas avatar Nov 24 '23 13:11 lplazas