Search code examples
amazon-web-servicesterraformterraform-provider-awsterraform-modules

The argument "ami" is required, but no definition was found


I am new to terraform, I am learning modules. I am stuck in a problem.

I have modules folder as root which contain two folders EC2 and IAM and they have terraform code in them. In the same modules folder I have main.tf file which is a module file for calling EC2 instance terraform code.

For your information, EC2 instance folder contain two files one for instance resource and second is for defining variables.

My EC2 file looks like this.

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

# Configure the AWS Provider

provider "aws" {
  region = "us-east-1"
}

resource "aws_instance" "web" {
  count         = "${var.ec2_count}"
  ami           = "${var.ami}"
  instance_type = "${var.instance_type}"

  tags = {
    Name = "App_Instance"
  }
}

My Variable.tf file looks like this.

variable "ec2_count" {
    type = number
    default = 1
}

variable "ami" {
  type = string
}

variable "instance_type" {
  type = string
}

My main.tf file looks like this.

module "EC2" {
    source = "./EC2"
}

Now I want that when I type terraform plan command, it should take input at the command prompt but it is showing me below error.

PS: I don't want to pass the value of the variable in the module.

C:\Users\PC\Desktop\AWS_Modules\Modules>terraform plan
╷
│ Error: Missing required argument
│
│   on main.tf line 1, in module "EC2":
│    1: module "EC2" {
│
│ The argument "ami" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│   on main.tf line 1, in module "EC2":
│    1: module "EC2" {
│
│ The argument "instance_type" is required, but no definition was found.

Solution

  • Since you are new to modules, there are a few things to consider:

    1. Where are you defining the variables
    2. How are you passing the values to variables required by the module

    Ideally, you would pass the values to variables when calling the module:

    module "EC2" {
        source = "./EC2"
        
        ami           = "ami-gafadfafa"
        instance_type = "t3.micro"
    }
    

    However, since you said you do not want to do that, then you need to assign the default values to variables on the module level. This can be achieved with:

    variable "ec2_count" {
      type = number
      default = 1
    }
    
    variable "ami" {
      type    = string
      default = "ami-gafadfafa"
    }
    
    variable "instance_type" {
      type    = string
      default = "t3.micro" 
    }
    
    

    This way, if you do not provide values when calling the module, the instance will be created and you are still leaving the option to provide the values if someone else were to use your module.

    The third option is to have a separate variables.tf file in the root module (i.e., the same directory where you are calling the module from) and not define the values for variables. It would be basically a copy+paste of the file you have on the module level without defining any default values. Here is an example:

    # variables.tf on the root module level
    variable "ec2_count" {
      type = number
    }
    
    variable "ami" {
      type = string
    }
    
    variable "instance_type" {
      type = string
    }
    

    However, in this case, it is impossible not to use the input variable names when calling the module. For this to work with providing the values on the CLI, the code would have to change to:

    module "EC2" {
        source = "./EC2"
        
        ec2_count     = var.ec2_count
        ami           = var.ami
        instance_type = var.instance_type
    }
    

    There is no other way the module can know how to map the values you want it to consume without actually setting those variables to a certain value when calling the module.