How to add two different files in user_data

Hello Everyone,
I have 2 files .sh and .yml file which I want to send it through user_data. Can anyone help me how I can do it?

Thank you

Hi @sunnythepatel ,

this should be feasible using HEREDOC strings.

Hi Everyone,
Ok, I can see HEREDOC strings can be useful but can anyone show me an example as I am not able to do it and send two files in user_data
Thank you and any help will be appreciated.

Regards,
Sunny Patel

Hi @sunnythepatel,

Unfortunately the answer to this question depends on how your AMI is set up, because as far as the API is concerned (and thus Terraform’s provider is concerned) user_data is just an opaque string which can be retrieved and interpreted by software running in the EC2 instance.

Fortunately though there is a de-facto standard approach to this: most official Linux distribution AMIs have cloud-init installed and configured to run on startup, and on those system’s it’ll be cloud-init’s job to retrieve the user_data string and decide what to do with it.

In the likely event that your AMI is using cloud-init, you can refer to the User-Data Formats documentation to see what formats cloud-init accepts and how it interprets each one. You’ll get the most flexibility from using the “Cloud Config Data” format, which is a YAML string starting with a special magic comment so that cloud-init can recognize it:

#cloud-config

The Cloud config examples page includes a large Cloud Config Data string which shows a variety of different capabilities of cloud-init, but since your question mentioned the problem of uploading files specifically I think you’ll be most interested in the Writing out arbitrary files example.

It’s important to keep in mind that the format of this file is entirely cloud-init’s concern and that Terraform has no special awareness of it, but if you are defining user_data within Terraform then you can at least use Terraform’s yamlencode function to help you dynamically construct a valid YAML document which might contain values from elsewhere in your configuration:

locals {
  image_user_data = {
    write_files = [
      {
        encoding = "b64"
        content  = filebase64("${path.module}/example1.yaml")
        path     = "/tmp/example1.yaml"
      },
      {
        encoding = "b64"
        content  = filebase64("${path.module}/example2.yaml")
        path     = "/tmp/example2.yaml"
      },
    ]
  }
}

resource "aws_instance" "example" {
  # (You didn't say which cloud vendor you're using here
  # and so I just picked aws_instance for example, but
  # this same principle applies to most other vendors
  # as long as your VM image includes cloud-init.)

  # ...
  user_data = <<-EOT
  #cloud-config
  ${yamlencode(local.instance_user_data)}
  EOT
}

In the above example I used filebase64 to read the contents of a file in the same directory as the module and encode it as Base64, which is what cloud-init expects when you set encoding: b64.

Since the details here are cloud-init’s rather than Terraform I’ll need to defer to cloud-init’s documentation and user support forums if you have more questions, but hopefully the above is a useful starting point.

1 Like

Hi @apparentlymart ,
Thank you and I was able to do it by cloud init thanks for the explanation.

Regards,
Sunny