Skip to content

Commit 39ec8cc

Browse files
authored
Merge pull request #547 from NHSDigital/APM-6720-ecr-lifecycle-policies
APM-6720-ecr-lifecycle-policy
2 parents 18e60a0 + 80b2e47 commit 39ec8cc

File tree

14 files changed

+300
-15
lines changed

14 files changed

+300
-15
lines changed

ansible/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ create-build-env-vars: guard-build_label guard-out_dir
4343
@poetry run ansible-playbook -i local create-build-env-vars.yml
4444

4545
deploy-ecs-proxies: guard-account guard-build_label guard-service_id guard-APIGEE_ENVIRONMENT guard-PROXY_VARS_FILE
46-
@poetry run ansible-playbook -i local deploy-ecs-proxies.yml
46+
@poetry run ansible-playbook -i local deploy-ecs-proxies.yml \
47+
48+
deploy-ecs-proxies-retag: guard-build_label guard-service_id guard-PROXY_VARS_FILE
49+
@poetry run ansible-playbook -i local deploy-ecs-proxies-retag.yml
4750

4851
deploy-apigee-proxy: guard-FULLY_QUALIFIED_SERVICE_NAME guard-SERVICE_BASE_PATH guard-APIGEE_ENVIRONMENT guard-APIGEE_ORGANIZATION guard-APIGEE_ACCESS_TOKEN guard-PROXY_DIR guard-PING
4952
@poetry run ansible-playbook -i local deploy-apigee-proxy.yml
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
- name: deploy ecs proxies retag
2+
hosts: 127.0.0.1
3+
connection: local
4+
gather_facts: no
5+
6+
vars:
7+
service_id: "{{ lookup('env','service_id') }}"
8+
APIGEE_ENVIRONMENT: "{{ lookup('env','APIGEE_ENVIRONMENT') }}"
9+
account: "{{ lookup('env','account') }}"
10+
11+
pre_tasks:
12+
- name: include container vars
13+
include_vars:
14+
file: "{{ lookup('env', 'CONTAINER_VARS_FILE') | expandvars | expanduser | realpath }}"
15+
16+
roles:
17+
- setup-facts
18+
- deploy-ecs-proxies-retag

ansible/deploy-ecs-proxies.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@
4242
- name: include vars
4343
include_vars:
4444
file: "{{ lookup('env', 'PROXY_VARS_FILE') | expandvars | expanduser | realpath }}"
45+
46+
- name: load use_ecs_tag from environment
47+
set_fact:
48+
use_ecs_tag: "{{ lookup('env','use_ecs_tag') | default('false') }}"
49+
50+
- name: normalise use_ecs_tag to boolean
51+
set_fact:
52+
use_ecs_tag: "{{ use_ecs_tag | lower == 'true' }}"
53+
4554

4655
roles:
4756
- setup-facts
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"rules": [
3+
{
4+
"rulePriority": 1,
5+
"description": "Keep the 6 most recent ECS deployment images tagged ecs- (release images)",
6+
"selection": {
7+
"tagStatus": "tagged",
8+
"tagPrefixList": ["ecs-"],
9+
"countType": "imageCountMoreThan",
10+
"countNumber": 6
11+
},
12+
"action": { "type": "expire" }
13+
},
14+
{
15+
"rulePriority": 2,
16+
"description": "Never expire the 'latest' tag",
17+
"selection": {
18+
"tagStatus": "tagged",
19+
"tagPrefixList": ["latest"],
20+
"countType": "imageCountMoreThan",
21+
"countNumber": 9999
22+
},
23+
"action": { "type": "expire" }
24+
},
25+
{
26+
"rulePriority": 3,
27+
"description": "Keep the 6 most recent build images (all tags)",
28+
"selection": {
29+
"tagStatus": "any",
30+
"countType": "imageCountMoreThan",
31+
"countNumber": 6
32+
},
33+
"action": { "type": "expire" }
34+
}
35+
]
36+
}

ansible/roles/build-ecs-proxies/tasks/main.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,29 @@
3030
with_items: "{{ new_repos }}"
3131
when: new_repos
3232

33+
# TO DO- Add back in once confirmed lifecycle policy to be applied to all new repos.
34+
35+
# - name: Read lifecycle policy file
36+
# ansible.builtin.slurp:
37+
# src: "{{ playbook_dir }}/ecr-lifecycle/ecr_lifecycle.json"
38+
# register: desired_policy_raw
39+
# when: new_repos | length > 0
40+
41+
# - name: Decode lifecycle policy JSON
42+
# set_fact:
43+
# desired_policy_json: "{{ desired_policy_raw.content | b64decode | from_json }}"
44+
# when: new_repos | length > 0
45+
46+
# - name: Apply lifecycle policy to each new repo
47+
# ansible.builtin.command: >
48+
# {{ aws_cmd }} ecr put-lifecycle-policy
49+
# --repository-name {{ item }}
50+
# --lifecycle-policy-text '{{ desired_policy_json | to_json }}'
51+
# with_items: "{{ new_repos }}"
52+
# register: lifecycle_update
53+
# ignore_errors: yes
54+
# when: new_repos | length > 0
55+
3356
- name: ecr login
3457
shell: "eval $({{ aws_cmd }} ecr get-login --no-include-email)"
3558
changed_when: no

ansible/roles/create-api-deployment-pre-reqs/templates/terraform/iam.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ data "aws_iam_policy_document" "ecs-execution-role" {
6969
"ecr:DescribeRepositories",
7070
"ecr:ListImages",
7171
"ecr:DescribeImages",
72+
"ecr:GetLifecyclePolicy",
73+
"ecr:PutLifecyclePolicy",
7274
"s3:GetObject"
7375
]
7476

@@ -173,6 +175,18 @@ data "aws_iam_policy_document" "deploy-user" {
173175

174176
}
175177

178+
statement {
179+
actions = [
180+
"ecr:GetLifecyclePolicy",
181+
"ecr:PutLifecyclePolicy"
182+
]
183+
184+
resources = [
185+
"arn:aws:ecr:${local.region}:${local.account_id}:repository/${var.service_id}",
186+
"arn:aws:ecr:${local.region}:${local.account_id}:repository/${var.service_id}_*"
187+
]
188+
}
189+
176190
statement {
177191
actions = [
178192
"s3:ListBucket",

ansible/roles/create-ecr-build-role/vars/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ aws_ecs_policy:
4444
- "ecr:StartImageScan"
4545
- "ecr:StartLifecyclePolicyPreview"
4646
- "ecr:UploadLayerPart"
47+
- "ecr:PutLifecyclePolicy"
4748
Resource: [
4849
"arn:aws:ecr:{{ aws_region }}:{{ aws_account_id }}:repository/{{ service_id }}_*"
4950
]
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
- name: Ensure docker_containers is loaded
2+
include_vars:
3+
file: "{{ lookup('env', 'CONTAINER_VARS_FILE') }}"
4+
when: docker_containers is not defined
5+
6+
- name: Login to ECR
7+
shell: >
8+
{{ aws_cmd }} ecr get-login-password --region {{ aws_region }}
9+
| docker login --username AWS --password-stdin {{ ecr_registry }}
10+
11+
- name: Pulling ECR image
12+
debug:
13+
msg: "Pulling {{ item }}:{{ build_label }}"
14+
loop: "{{ repo_names }}"
15+
loop_control:
16+
label: "{{ item }}"
17+
18+
- name: Pull existing image
19+
ansible.builtin.command:
20+
cmd: >
21+
docker pull {{ ecr_registry }}/{{ item }}:{{ build_label }}
22+
loop: "{{ repo_names }}"
23+
loop_control:
24+
label: "{{ item }}"
25+
register: pull_results
26+
27+
- name: Retagging ECR image
28+
debug:
29+
msg: "Retagging {{ item.item }}:{{ build_label }} → ecs-{{ build_label }}"
30+
loop: "{{ pull_results.results }}"
31+
loop_control:
32+
label: "{{ item.item }}"
33+
when:
34+
- item.rc == 0
35+
- item.item == "canary_canary-api"
36+
37+
- name: Retag image
38+
ansible.builtin.command:
39+
cmd: >
40+
docker tag
41+
{{ ecr_registry }}/{{ item.item }}:{{ build_label }}
42+
{{ ecr_registry }}/{{ item.item }}:ecs-{{ build_label }}
43+
loop: "{{ pull_results.results }}"
44+
loop_control:
45+
label: "{{ item.item }}"
46+
when:
47+
- item.rc == 0
48+
- item.item == "canary_canary-api"
49+
50+
- name: Pushing ECR image
51+
debug:
52+
msg: "Pushing ecs-{{ build_label }} for {{ item.item }}"
53+
loop: "{{ pull_results.results }}"
54+
loop_control:
55+
label: "{{ item.item }}"
56+
when:
57+
- item.rc == 0
58+
- item.item == "canary_canary-api"
59+
60+
- name: Push new tag
61+
ansible.builtin.command:
62+
cmd: >
63+
docker push {{ ecr_registry }}/{{ item.item }}:ecs-{{ build_label }}
64+
loop: "{{ pull_results.results }}"
65+
loop_control:
66+
label: "{{ item.item }}"
67+
when:
68+
- item.rc == 0
69+
- item.item == "canary_canary-api"
70+
71+
# - name: Delete old tag from ECR
72+
# ansible.builtin.command:
73+
# cmd: >
74+
# aws ecr batch-delete-image
75+
# --repository-name {{ item.item }}
76+
# --image-ids imageTag={{ build_label }}
77+
# --region {{ aws_region }}
78+
# loop: "{{ pull_results.results }}"
79+
# loop_control:
80+
# label: "{{ item.item }}"
81+
# when:
82+
# - item.rc == 0
83+
# - item.item == "canary_canary-api"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
build_label: "{{ lookup('env', 'build_label') }}"
3+
containers: "{{ docker_containers | json_query('[].name') | unique | sort }}"
4+
repo_names: "{{ containers | map('regex_replace', '^(.*)$', service_id + '_\\1') | list }}"
5+
base_dir: "{{ playbook_dir }}/../.."
6+

ansible/roles/deploy-ecs-proxies/tasks/main.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,21 @@
7171
with_filetree: "{{ '../templates' }}"
7272
when: item.state == 'file'
7373

74+
- name: ansible use_ecs_tag before terraform
75+
debug:
76+
msg: >
77+
ANSIBLE: use_ecs_tag='{{ use_ecs_tag }}'
78+
TYPE={{ use_ecs_tag | type_debug }}
79+
TF_VAR_use_ecs_tag='{{ use_ecs_tag | ternary("true","false") }}'
80+
7481
- name: terraform plan
75-
shell: "make -C {{ out_dir }}/terraform clean plan args='-no-color -lock-timeout=30m -out tfplan.out'" # noqa 305
82+
shell: "TF_VAR_use_ecs_tag={{ use_ecs_tag | ternary('true','false') }} make -C {{ out_dir }}/terraform clean plan args='-no-color -lock-timeout=30m -out tfplan.out'" # noqa 305
7683
register: tfplan
7784
failed_when: tfplan.rc not in (0, 2)
7885
when: not do_not_terraform
7986

8087
- name: terraform apply
81-
shell: "make -C {{ out_dir }}/terraform apply-plan args='-no-color -lock-timeout=30m --auto-approve tfplan.out'" # noqa 305
88+
shell: "TF_VAR_use_ecs_tag={{ use_ecs_tag | ternary('true','false') }} make -C {{ out_dir }}/terraform apply-plan args='-no-color -lock-timeout=30m --auto-approve tfplan.out'" # noqa 305
8289
register: tfapply
8390
when: not do_not_terraform
8491

0 commit comments

Comments
 (0)