Rodriguez
Rodriguez

Reputation: 236

How to manage S3 bucket objects in Terraform Cloud in Remote execution mode

I have a working Terraform project that manages S3 buckets and objects referencing the local file system with the usage of the hashicorp/dir/template module as follows:

module "bucket_objects" {
  source = "hashicorp/dir/template"
  base_dir = "${path.module}/../dist"
}

resource "aws_s3_object" "object" {
  for_each     = module.bucket_objects.files
  bucket       = aws_s3_bucket.bucket.id
  key          = "dist/${each.key}"
  content_type = each.value.content_type
  source       = each.value.source_path
  etag         = each.value.digests.md5
}

When I migrated my Terraform state to the Cloud, the following terraform plan wanted to delete all the objects:

# module.datafiles.aws_s3_object.file["453.f0b8f6f5.js"] will be destroyed
# (because key ["453.f0b8f6f5.js"] is not in for_each map)

I understand that Terraform Cloud in Remote execution mode is unable to see the files in my local machine. How can I reference the files for this particular resource in order to have them as S3 objects managed by Terraform?

Upvotes: 0

Views: 143

Answers (2)

Helder Sepulveda
Helder Sepulveda

Reputation: 17664

If I had to design an infrastructure like yours I might take a different approach...

What do we know

The "453.f0b8f6f5.js" and similar files are generated in every build with a different id for caching invalidation, with that I believe these are minified bundles, so I will refer to the that file as "the bundle", (better than calling it the weird file)

Alternatives

1 - Do not use aws_s3_object

If the bundle file is not committed to the repo, I see no need to keep those in terraform

  • remove the aws_s3_object resource
  • instead upload the bundle via AWS cli in the same step that generates it

2 - Keep a common name

I'm not a fan of using different names just because you need to invalidate the cache

  • use project_bundle.js and do commit to your repo
  • enable bucket version to be able to retrieve old versions
  • invalidate the cache using some other way

Here is a popular project that uses common names for the bundles:
https://github.com/swagger-api/swagger-ui/tree/master/dist

Why

I'm designing the project with a few things in mind:

  • when it grows and other developers join, when they clone the repo they will have everything they need, all is either in the repo or in AWS, no dependencies to a local machine
  • keeping many similar files with different filenames is wasteful, if we push them to repo it creates a lot of duplication, in terraform it is more stuff in your state, the larger your state the slower the plan and apply will be.

Upvotes: 0

Martin Atkins
Martin Atkins

Reputation: 74694

This plan shows that Terraform did still manage to evaluate the module.bucket_objects results -- or else there would've been an error related to something in that module -- but that the result was an empty map instead of describing all of the files as you had intended.

The module call refers to ${path.module}/../dist which suggests that this module is expecting to find files outside of its own directory prefix. Therefore I think the most likely explanation is that Terraform CLI is uploading to Terraform Cloud everything under the module's own directory but not uploading the ../dist directory, because Terraform doesn't realize that directory is treated as being part of the module. (Files used directly by a module should typically be in the same directory as the module, or in a subdirectory of the module.)

If you can't rearrange this so that the files being managed live in a subdirectory of path.module, then you'll need to reconfigure HCP Terraform (formerly Terraform Cloud) to better understand your directory layout. You can do this by changing the Working Directory setting, as described in Parent Directory Uploads.


In your specific case, you should set the working directory to whatever is the directory name containing the Terraform source file you included in your question. For example, if your directory were called "buckets" then you'd enter the working directory as "buckets".

With that setting, when you run remote operations from the "buckets" directory Terraform CLI will know that it needs to upload the parent directory -- the one containing "buckets" as a subdirectory -- and then in the remote operation run something equivalent to cd buckets; terraform plan.

The dist directory should then be uploaded as a sibling of the "buckets" directory, and so all of the needed files will be available in HCP Terraform's remote execution environment.

Upvotes: 0

Related Questions