-1

I have been banging my head against this seemingly simple issue for awhile now. I have some Terraform code which sets up an ECR repository, policy and lifecycle policy.

provider "aws" {
    region = "${var.region_id}"
}

terraform {
   required_version = "0.11.13"
}

resource "aws_ecr_repository" "frontend_ecr_repo_creation" {
  name = "${var.app_image}"
}

resource "aws_ecr_repository_policy" "frontend_ecr_policy" {
  repository = "${aws_ecr_repository.frontend_ecr_repo_creation.name}"

  policy = <<EOF
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "new policy",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability",
                "ecr:PutImage",
                "ecr:InitiateLayerUpload",
                "ecr:UploadLayerPart",
                "ecr:CompleteLayerUpload",
                "ecr:DescribeRepositories",
                "ecr:GetRepositoryPolicy",
                "ecr:ListImages",
                "ecr:DeleteRepository",
                "ecr:BatchDeleteImage",
                "ecr:SetRepositoryPolicy",
                "ecr:DeleteRepositoryPolicy"
            ]
        }
    ]
}
EOF
}

resource "aws_ecr_lifecycle_policy" "frontend_ecr_lifecycle_policy" {
  repository = "${aws_ecr_repository.frontend_ecr_repo_creation.name}"

  policy = <<EOF
{
    "rules": [
        {
            "rulePriority": 1,
            "description": "Keep last 3 images",
            "selection": {
                "tagStatus": "any",
                "countType": "imageCountMoreThan",
                "countNumber": 3
            },
            "action": {
                "type": "expire"
            }
        }
    ]
}
EOF
}

This runs perfectly fine, however subsequent runs fail with:

 aws_ecr_repository.frontend_ecr_repo_creation: error creating ECR repository: RepositoryAlreadyExistsException: The repository with name 'cwyo/master' already exists in the registry with id '720734997891'
    status code: 400, request id: cf59815c-7c9d-11e9-965d-0b326e93dee5

I would expect Terraform plan no changes, instead it attempts to recreate the repository. This shows all of the signs of an incorrect remote state, however I run a Terraform init in my pipeline beforehand and I am satisfied that it is correct.

I have been working around this by adding GitLab CI's inbuilt $COMMIT_SHA variable as a prefix, this works well except lifecycle policies cannot be applied therefore I ended up with 100's of useless repositories.

I have looked in to a data structure to check if the repository exists and add a depends_on to the resource but no luck...

How do I ensure the aws_ecr_repository resource uses an existing repository if it already exists?

2
  • UPDATE: I have since been using terraform import to find the existing ECR repository. This works, of course, but it does add a potential manual step in that if the ECR repository is ever deleted or we switch AWS accounts, our Terraform will fail until we manually recreate said repository... – jto Jul 2 '19 at 12:38
  • ' incorrect remote state, however'...'I am satisfied that it is correct.' --> It is important to add some information about the remote state in this question. It would also be very helpful to include terraform state show <some resources> – Alexandre Jul 3 '19 at 14:17
1
+50

In your terraform {...} section you need a backend directive to store your state somewhere: https://www.terraform.io/docs/state/remote.html (OP later explain that the code above is just a module imported from a main file).

S3 backends might be the easiest to use and probably to most commonly used backends to store remote state across different executions of Terraform:

terraform {
  backend "s3" {
    bucket = "mybucket"
    key    = "path/to/my/key"
    region = "us-east-1"
  }
}

Please note that Terraform init will not import existing resources into a state (there's Terraform import for that). It will therefore try to create new ones and you will get a conflict on the name. The Terraform documentation gives some pointers on how to use Terraform in automation and that includes using remote state.

It is possible to prevent the creation of the ECR through a data block as you hinted (with count = ...), but doing so would feel like a hack to me.

Once you have your remote backend configured, you can double check that everything works as expected by using the terraform state command in your pipeline. I would suggest using the show subcommand on a resource you expect to be there in order to validate that the state indeed contains the resource:

terraform init -input=false
terraform state show module.name-of-your-module.aws_ecr_repository.frontend_ecr_repo_creation
3
  • My Terraform code listed above is a module which is referenced by my main.tf file in the root directory of my Terraform repository which defines the terraform backend directive - As mentioned in my OP, I am satisfied that my state file is being updated correctly. – jto Jul 3 '19 at 8:36
  • 1
    I've used your code locally and everything works as expected for me. The only way I was able to reproduce your issue is by deleting the remote state. You say you are satisfied that your state file is being updated correctly, but it really looks like it isn't. Can you run terraform state show module.name-of-your-module.aws_ecr_repository.frontend_ecr_repo_creation right after your init? – Alexandre Jul 3 '19 at 14:04
  • Apologies, you were indeed correct. I can't believe I overlooked that - Easiest bounty ever haha - This section of code wasn't part of the module I thought it was (unfamiliar codebase) and was instead in it's own directory without a state file! – jto Jul 5 '19 at 13:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.