user4925383
user4925383

Reputation:

Intermittent Terraform failures trying to put object into a bucket

I'm seeing intermittent Terraform failures which look to me like a race condition internal to Terraform itself:

21:31:37 aws_s3_bucket.jar: Creation complete after 1s 
(ID: automatictester.co.uk-my-bucket)
...
21:31:38 * aws_s3_bucket_object.jar: Error putting object in S3 bucket
(automatictester.co.uk-my-bucket): NoSuchBucket: The specified bucket 
does not exist

As you can see in the above logs, TF first claims it has created a bucket at 21:31:37, and then says it can't put an object in that bucket because this does not exist at 21:31:38.

The code behind the above error:

resource "aws_s3_bucket" "jar" {
  bucket               = "${var.s3_bucket_jar}"
  acl                  = "private"
}
...
resource "aws_s3_bucket_object" "jar" {
  bucket               = "${var.s3_bucket_jar}"
  key                  = "my.jar"
  source               = "${path.module}/../target/my.jar"
  etag                 = "${md5(file("${path.module}/../target/my.jar"))}"
}

There clearly is an implicit dependency defined between these two, so the only reason for that failure that comes to my mind is the eventually consistent nature of Amazon S3.

How to handle such kind of errors? I believe explcitly defined dependency with depends-on will not provide any value over the implicit dependency which is already there.

Upvotes: 1

Views: 1699

Answers (1)

ydaetskcoR
ydaetskcoR

Reputation: 56877

Terraform can't see any dependency ordering at all there so is almost certainly trying to do the same 2 actions at the same time and is failing the object creation at pretty much the same time the bucket creates.

Instead you should properly define the dependency between the 2 resources by using either depends_on or better yet referring to the bucket resource's outputs in the object resource like this:

resource "aws_s3_bucket" "jar" {
  bucket = "${var.s3_bucket_jar}"
  acl    = "private"
}

resource "aws_s3_bucket_object" "jar" {
  bucket = "${aws_s3_bucket.jar.bucket}"
  key    = "my.jar"
  source = "${path.module}/../target/my.jar"
  etag   = "${md5(file("${path.module}/../target/my.jar"))}"
}

Terraform now knows that it needs to wait for the S3 bucket to be created and return before it attempts to create the S3 object in the bucket.

Upvotes: 6

Related Questions