0

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

2
  • Are the shell scripts in the same directory as the terraform code? Commented Oct 31, 2022 at 8:17
  • Yes, same directory as terraform code Commented Oct 31, 2022 at 8:21

3 Answers 3

2

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

Sign up to request clarification or add additional context in comments.

17 Comments

path.module goes to the child folder whereas the shell scripts are in parent folder where I am calling the modules
Ok, that's why I asked. Edited the answer.
This gives below error: Error: read /git/import_resources/XXXXX/EC2/: is a directory\n\n on aws-ec2-application/main.tf line 74, in data \"local_file\" \"user_data\":\n 74: data \"local_file\" \"user_data\" {\n\n\n\n
@MarkoE There shoudn't be a file in filename. Otherwise entire content of a file is treated as a filename.
Ah, my bad, thanks, will fix that.
|
2

You do not need file. Just the path is enough:

filename = "${path.module}/${each.value.user_data}"

2 Comments

I tried this, it's giving error: Error: read ./: is a directory\n\n on aws-ec2-application/main.tf line 74, in data \"local_file\" \"user_data\"
@MayaRay Then I would suggest starting with providing valid TF code. Your ec2_instances variable is not a valid TF code. This suggest that your real code is different that what you posted in the question, thus its not clear what you are actually doing.
0

I was able to do this by doing below. I didn't need data source. Just added below:

user_data = each.value.user_data != "" ? file("${path.module}/../${each.value.user_data}") : null

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.