Skip to content

Commit cf6b9af

Browse files
Add remove-stale-locks to ecs cleanup pipeline
1 parent f6990ca commit cf6b9af

File tree

5 files changed

+130
-45
lines changed

5 files changed

+130
-45
lines changed

Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@ endif
4040

4141
ansible: guard-cmd
4242
@account=$(account) poetry run make --no-print-directory -C ansible $(cmd)
43+
44+
45+
remove-stale-locks:
46+
@poetry run python ./scripts/terraform_force_unlock.py

azure/components/cleanup-ecs-pr-proxies-job.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ steps:
99
profile: "apm_ptl"
1010

1111
- bash: |
12+
make remove-stale-locks
1213
export retain_hours=72
1314
ANSIBLE_FORCE_COLOR=yes make -C ansible remove-old-ecs-pr-deploys > /tmp/err.txt
1415
ERROR_CODE=$?

poetry.lock

Lines changed: 59 additions & 45 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ gitpython = "^3.1.11"
2525
pytest-xdist = "^1.10.0"
2626
lxml = "^4.6.2"
2727
docker = "^5.0.3"
28+
boto3 = "^1.26.20"
2829

2930
[tool.poetry.dev-dependencies]
3031
ansible-lint = "^4.2.0"

scripts/terraform_force_unlock.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Script to force unlock locks in terraform with a given prefix and of a certain age.
3+
4+
Warning this script should be used with care.
5+
6+
CLI arguments:
7+
--min-age-hr
8+
--key-prefix
9+
--table-name
10+
--profile
11+
12+
Example usage:
13+
14+
python ./terraform_force_unlock.py --min-age-hr=8 --key-prefix=nhsd-apm-management-ptl-terraform/env:/api-deployment:ptl: --table-name=terraform-state-lock --profile=apm_ptl
15+
16+
"""
17+
18+
import boto3
19+
import dateutil
20+
import datetime
21+
import click
22+
23+
24+
@click.command()
25+
@click.option("--min-age-hr", type=int, default=8)
26+
@click.option("--key-prefix", type=str, default="nhsd-apm-management-ptl-terraform/env:/api-deployment:ptl:")
27+
@click.option("--table-name", type=str, default="terraform-state-lock")
28+
@click.option("--profile", type=str, default="apm_ptl")
29+
def main(min_age_hr, key_prefix, table_name, profile):
30+
31+
accepted_envs = ["apm_ptl", "apm_prod"]
32+
33+
if profile not in accepted_envs:
34+
raise ValueError("Profile must be apm_ptl or apm_prod")
35+
36+
terraform_lock_table = boto3.Session(profile_name=profile).resource("dynamodb").Table(table_name)
37+
38+
filter_expr = "begins_with(#n0, :v0) AND attribute_exists(#n1)"
39+
40+
ExpressionAttributeNames = {"#n0": "LockID", "#n1": "Info"}
41+
ExpressionAttributeValues = {
42+
":v0": "nhsd-apm-management-ptl-terraform/env:/api-deployment:ptl:"
43+
}
44+
items = terraform_lock_table.scan(FilterExpression=filter_expr, ExpressionAttributeNames=ExpressionAttributeNames, ExpressionAttributeValues=ExpressionAttributeValues)
45+
print(f"Found {len(items['Items'])} locks which start with key prefix '{key_prefix}'")
46+
47+
removed_count = 0
48+
for lock_item in items["Items"]:
49+
lock_item_info = lock_item["Info"]
50+
lock_id = lock_item["LockID"]
51+
created_at = dateutil.parser.parse(lock_item_info["Created"])
52+
53+
if datetime.datetime.now(datetime.timezone.utc) - created_at > datetime.timedelta(hours=min_age_hr):
54+
print(f"{lock_id} {created_at=} is more than {min_age_hr} hours old, deleting lock...")
55+
terraform_lock_table.delete_item(Key={"LockID": lock_id})
56+
removed_count += 1
57+
58+
else:
59+
print(f"{lock_id} {created_at=} is not more than {min_age_hr} hours old, leaving it alone!")
60+
61+
print(f"Removed {removed_count} locks")
62+
63+
64+
if __name__ == "__main__":
65+
main()

0 commit comments

Comments
 (0)