Search code examples
amazon-web-servicesamazon-ec2terraformterraform-provider-awsec2-userdata

Add user_data in ec2 instance using terraform with file variable


I am trying to create multiple ec2 instance using terraform modules. As every instance will have different user data, I want to do this but it's giving error

data "local_file" "user_data" {
  for_each = { for ec2 in var.ec2_instances : ec2.name => ec2 }
  filename = "${path.cwd}/${each.value.user_data}"
}

resource "aws_instance" "instances" {
  for_each = { for instance in var.ec2_instances : instance.name => instance }

  ami                    = each.value.ami
  instance_type          = each.value.type
  cpu_core_count         = each.value.cpu_core
  user_data_base64  = base64encode(data.local_file.user_data[each.value.name].rendered)
}

module.tf

module "ec2_app_demo" {
  source = "./aws-ec2-application/"

  ec2_instances     = var.ec2_instances
}

In the tfvars file

ec2_instances= [
{
name = test1
user_data = ec2_1.sh
},
{
name = test2
user_data = ec2_2.sh
}
]

Error:

Error: Invalid function argument\n\n on main.tf line 76, in data "local_file" "linux-vm-cloud-init":\n 76: filename = file("${each.value.user_data}")\n

Please let me know if the file name can be used a variable.

The folder structure is below: enter image description here


Solution

  • Since the shell files are in the same directory, it should be easy to achieve what you want. Additionally, the variable has to use quoted values:

    ec2_instances= [
      {
        name = "test1"
        user_data = "ec2_1.sh"
      },
      {
        name = "test2"
        user_data = "ec2_2.sh"
      }
    ]
    

    The file built-in function expect you to provide a path to the file [1], it has no knowledge if the file is in the same directory or not:

    file reads the contents of a file at the given path and returns them as a string.

    As per the comments (h/t: @Marcin) in order for the code to work, the data source should be changed to this (the file is not required):

    data "local_file" "user_data" {
      for_each = { for ec2 in var.ec2_instances : ec2.name => ec2 }
      filename = "${path.module}/../${each.value.user_data}"
    }
    

    EDIT: Based on the comments, the shell script is named differently compared to what was originally posted in the question for the variable value. For this to work, the variable value has to change to:

    ec2_instances= [
      {
        name = "test1"
        user_data = "tmosquid02.sh"
      }
    ]
    

    [1] https://developer.hashicorp.com/terraform/language/functions/file