pkaramol
pkaramol

Reputation: 19422

Getting the error "root module does not declare a variable of that name." from Terraform even though I am specifying the command as an argument?

Here is my dir structure:

├── main.tf
├── modules
│   ├── subnets
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── variables.tf
│   └── vpc
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── outputs.tf
└── variables.tf

and my modules/vpc/main.tf

resource "aws_vpc" "env_vpc" {
  cidr_block           = "${var.vpc_cidr_block}"
  enable_dns_support   = "${var.vpc_enable_dns_support}"
  enable_dns_hostnames = "${var.vpc_enable_dns_hostnames}"

  tags = {
    Name        = "${var.env_name}-vpc"
    Provisioner = "Terraform"
  }

  lifecycle {
    create_before_destroy = true
  }
}

and my modules/vpc/variables.tf

variable "env_name" {
    description = "The name of the env the VPC will belong to"
    # no default provided
}

When I perform terraform plan

➢  terraform plan

Error: Missing required argument

  on main.tf line 1, in module "vpc":
   1: module "vpc" {

The argument "env_name" is required, but no definition was found.

When I pass the var in the cmd:

➢  terraform plan -var 'env_name=ffff'

Error: Value for undeclared variable

A variable named "env_name" was assigned on the command line, but the root
module does not declare a variable of that name. To use this value, add a
"variable" block to the configuration.

The problem does not go away even when I declare the variable in root variables.tf

as in

➢  cat variables.tf
variable "env_name" {}

any suggestions?

edit: When I provided a default value for that variable, the plan worked. It did ask me interactively for an env_name value but the plan output was with the default value. Why is that?

edit2: Clarification about the contents of the variables.tf files:

➢  ls
main.tf      modules      outputs.tf   variables.tf
➢  cat variables.tf
variable "env_name" {}

In the modules/vpc directory:

➢  ls
main.tf      outputs.tf   variables.tf
aws_vpc/modules/vpc  stand_alone_vpc ✗   

➢  cat variables.tf
variable "env_name" {
    description = "The name of the environment/microservice the VPC will belong to"
    default = "wbl"
}

It asks me to input the env_name value, but it ignores it and makes use of the default, as set in modules/vpc/variables.tf. Here is the plan:

➢  terraform plan
var.env_name
  Enter a value: foo

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.


------------------------------------------------------------------------

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:

  # module.vpc.aws_internet_gateway.env_igw will be created
  + resource "aws_internet_gateway" "env_igw" {
      + id       = (known after apply)
      + owner_id = (known after apply)
      + tags     = {
          + "Name"        = "wbl-igw"
          + "Provisioner" = "Terraform"
        }
      + vpc_id   = (known after apply)
    }

  # module.vpc.aws_vpc.env_vpc will be created
  + resource "aws_vpc" "env_vpc" {
      + arn                              = (known after apply)
      + assign_generated_ipv6_cidr_block = false
      + cidr_block                       = "10.0.0.0/16"
      + default_network_acl_id           = (known after apply)
      + default_route_table_id           = (known after apply)
      + default_security_group_id        = (known after apply)
      + dhcp_options_id                  = (known after apply)
      + enable_classiclink               = (known after apply)
      + enable_classiclink_dns_support   = (known after apply)
      + enable_dns_hostnames             = true
      + enable_dns_support               = true
      + id                               = (known after apply)
      + instance_tenancy                 = "default"
      + ipv6_association_id              = (known after apply)
      + ipv6_cidr_block                  = (known after apply)
      + main_route_table_id              = (known after apply)
      + owner_id                         = (known after apply)
      + tags                             = {
          + "Name"        = "wbl-vpc"
          + "Provisioner" = "Terraform"
        }
    }

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

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Upvotes: 1

Views: 10297

Answers (1)

pkaramol
pkaramol

Reputation: 19422

It seems that the way around this (i.e. to be able to override the default value set in the submodule's variable.tf) is the following:

1) declare the variable in the top (root) level variables.tf, as in

> $ cat variables.tf
variable "env_name" {
  default = "top-level"
}

2) set the variable value in the section of root's module main.tf that calls the submodule, as in:

module "vpc" {
  source = "./modules/vpc"
  # variables
  env_name = "${var.env_name}"
}

This way, the variable that will end up being passed to the submodule, is the one declared in the parent module's variables.tf

Upvotes: 4

Related Questions