diff --git a/ansible/ecr-lifecycle/ecr_lifecycle.json b/ansible/ecr-lifecycle/ecr_lifecycle.json new file mode 100644 index 000000000..cfdea1bdf --- /dev/null +++ b/ansible/ecr-lifecycle/ecr_lifecycle.json @@ -0,0 +1,36 @@ +{ + "rules": [ + { + "rulePriority": 1, + "description": "Keep the 10 most recent ECS deployment images - AMEND NUMBER AFTER TEST", + "selection": { + "tagStatus": "tagged", + "tagPrefixList": ["ecs-"], + "countType": "imageCountMoreThan", + "countNumber": 800 + }, + "action": { "type": "expire" } + }, + { + "rulePriority": 2, + "description": "Never expire the 'latest' tag", + "selection": { + "tagStatus": "tagged", + "tagPrefixList": ["latest"], + "countType": "imageCountMoreThan", + "countNumber": 9999 + }, + "action": { "type": "expire" } + }, + { + "rulePriority": 3, + "description": "Keep the 5 most recent build images (all tags) - AMEND NUMBER AFTER TEST", + "selection": { + "tagStatus": "any", + "countType": "imageCountMoreThan", + "countNumber": 800 + }, + "action": { "type": "expire" } + } + ] +} diff --git a/ansible/roles/build-ecs-proxies/tasks/build-container.yml b/ansible/roles/build-ecs-proxies/tasks/build-container.yml index 56be84bb0..7e90e04f7 100644 --- a/ansible/roles/build-ecs-proxies/tasks/build-container.yml +++ b/ansible/roles/build-ecs-proxies/tasks/build-container.yml @@ -31,3 +31,53 @@ ansible.builtin.command: cmd: "docker push {{ image_name }}" when: build_result.rc == 0 + +- name: Get existing lifecycle policy JSON for {{ service_id }}_{{ item }} + ansible.builtin.command: > + {{ aws_cmd }} ecr get-lifecycle-policy + --repository-name {{ service_id }}_{{ item }} + --query 'lifecyclePolicyText' + --output text + register: existing_policy_raw + failed_when: false + changed_when: false + +- name: Parse existing lifecycle policy JSON if present + set_fact: + existing_policy_json: "{{ existing_policy_raw.stdout | from_json }}" + when: + - existing_policy_raw.stdout is defined + - existing_policy_raw.stdout != "" + - existing_policy_raw.stdout != "None" + - existing_policy_raw.stdout != "null" + +- name: Ensure existing_policy_json always exists + set_fact: + existing_policy_json: {} + when: existing_policy_json is not defined + +- name: Read lifecycle policy from the shared file + ansible.builtin.slurp: + src: "{{ playbook_dir }}/ecr-lifecycle/ecr_lifecycle.json" + register: desired_policy_raw + +- name: Debug raw slurp output + debug: + var: desired_policy_raw + +- name: Show decoded lifecycle policy content + debug: + msg: "{{ desired_policy_raw.content | b64decode }}" + +- name: Decode lifecycle policy file + set_fact: + desired_policy_json: "{{ desired_policy_raw.content | b64decode | from_json }}" + +- name: Apply lifecycle policy to ecr {{ service_id }}_{{ item }} if different + ansible.builtin.command: > + {{ aws_cmd }} ecr put-lifecycle-policy + --repository-name {{ service_id }}_{{ item }} + --lifecycle-policy-text '{{ desired_policy_json | to_json }}' + when: + - existing_policy_json != desired_policy_json + diff --git a/ansible/roles/create-api-deployment-pre-reqs/templates/terraform/iam.tf b/ansible/roles/create-api-deployment-pre-reqs/templates/terraform/iam.tf index 29eb55a3e..775b01a11 100644 --- a/ansible/roles/create-api-deployment-pre-reqs/templates/terraform/iam.tf +++ b/ansible/roles/create-api-deployment-pre-reqs/templates/terraform/iam.tf @@ -69,6 +69,8 @@ data "aws_iam_policy_document" "ecs-execution-role" { "ecr:DescribeRepositories", "ecr:ListImages", "ecr:DescribeImages", + "ecr:GetLifecyclePolicy", + "ecr:PutLifecyclePolicy", "s3:GetObject" ] @@ -173,6 +175,18 @@ data "aws_iam_policy_document" "deploy-user" { } + statement { + actions = [ + "ecr:GetLifecyclePolicy", + "ecr:PutLifecyclePolicy" + ] + + resources = [ + "arn:aws:ecr:${local.region}:${local.account_id}:repository/${var.service_id}", + "arn:aws:ecr:${local.region}:${local.account_id}:repository/${var.service_id}_*" + ] + } + statement { actions = [ "s3:ListBucket", diff --git a/ansible/roles/create-ecr-build-role/vars/main.yml b/ansible/roles/create-ecr-build-role/vars/main.yml index c40db5b1a..817fd7bb0 100644 --- a/ansible/roles/create-ecr-build-role/vars/main.yml +++ b/ansible/roles/create-ecr-build-role/vars/main.yml @@ -44,6 +44,7 @@ aws_ecs_policy: - "ecr:StartImageScan" - "ecr:StartLifecyclePolicyPreview" - "ecr:UploadLayerPart" + - "ecr:PutLifecyclePolicy" Resource: [ "arn:aws:ecr:{{ aws_region }}:{{ aws_account_id }}:repository/{{ service_id }}_*" ] diff --git a/ansible/roles/deploy-ecs-proxies/tasks/main.yml b/ansible/roles/deploy-ecs-proxies/tasks/main.yml index 668c8cb0e..f70aa3456 100644 --- a/ansible/roles/deploy-ecs-proxies/tasks/main.yml +++ b/ansible/roles/deploy-ecs-proxies/tasks/main.yml @@ -82,6 +82,30 @@ register: tfapply when: not do_not_terraform + - name: Retag and promote ECS image (release pipelines only) + when: pr_number is not defined or pr_number == "" + vars: + PTL_REG: "{{ PTL_ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com" + PROD_REG: "{{ PROD_ACCOUNT_ID }}.dkr.ecr.eu-west-2.amazonaws.com" + IMG: "{{ service_id }}_{{ ecs_service[0].name }}" + TAG: "{{ build_label }}" + NEW: "ecs-{{ build_label }}" + shell: | + aws ecr get-login-password --region eu-west-2 \ + | docker login --username AWS --password-stdin {{ PTL_REG }} + + docker pull {{ PTL_REG }}/{{ IMG }}:{{ TAG }} + docker tag {{ PTL_REG }}/{{ IMG }}:{{ TAG }} {{ PTL_REG }}/{{ IMG }}:{{ NEW }} + docker push {{ PTL_REG }}/{{ IMG }}:{{ NEW }} + + aws ecr get-login-password --region eu-west-2 \ + | docker login --username AWS --password-stdin {{ PROD_REG }} + + docker tag {{ PTL_REG }}/{{ IMG }}:{{ NEW }} {{ PROD_REG }}/{{ IMG }}:{{ NEW }} + docker push {{ PROD_REG }}/{{ IMG }}:{{ NEW }} + args: + executable: /bin/bash + rescue: - name: output plan debug: diff --git a/ansible/roles/deploy-ecs-proxies/templates/terraform/locals.tf b/ansible/roles/deploy-ecs-proxies/templates/terraform/locals.tf index c01c869d5..9556883d4 100644 --- a/ansible/roles/deploy-ecs-proxies/templates/terraform/locals.tf +++ b/ansible/roles/deploy-ecs-proxies/templates/terraform/locals.tf @@ -49,7 +49,7 @@ locals { ( container | combine( - {'image': '${local.account_id}.dkr.ecr.eu-west-2.amazonaws.com/' + service_id + '_' + container.name + ':' + build_label } + {'image': '${local.account_id}.dkr.ecr.eu-west-2.amazonaws.com/' + service_id + '_' + container.name + ':ecs-' + build_label } ) ) | to_json }},