aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Crute <mike@crute.us>2017-12-25 04:53:29 +0000
committerMike Crute <mike@crute.us>2017-12-25 04:53:29 +0000
commit24cac6b1a44f67e721f48fa5d76d096c7fd77d1e (patch)
treed75ee41d7e333feea1553505fa00ab46767c8a32
parent638be8d8b674acfb56bf59d586859a4622b9ad22 (diff)
downloadalpine-ec2-ami-24cac6b1a44f67e721f48fa5d76d096c7fd77d1e.tar.bz2
alpine-ec2-ami-24cac6b1a44f67e721f48fa5d76d096c7fd77d1e.tar.xz
alpine-ec2-ami-24cac6b1a44f67e721f48fa5d76d096c7fd77d1e.zip
Add AMI scrub tool
-rw-r--r--.gitignore1
-rw-r--r--Makefile8
-rw-r--r--scrub-old-amis.py.in67
3 files changed, 74 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 98c621a..b9acab3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
1/build/ 1/build/
2/.py3/ 2/.py3/
3/variables.json 3/variables.json
4/scrub-old-amis.py
diff --git a/Makefile b/Makefile
index de19494..e7896ca 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ ami: build/convert
5 5
6build/convert: 6build/convert:
7 [ -d ".py3" ] || python3 -m venv .py3 7 [ -d ".py3" ] || python3 -m venv .py3
8 .py3/bin/pip install pyyaml 8 .py3/bin/pip install pyyaml boto3
9 9
10 [ -d "build" ] || mkdir build 10 [ -d "build" ] || mkdir build
11 11
@@ -17,6 +17,10 @@ build/convert:
17 @echo "json.dump(yaml.load(open(sys.argv[1])), sys.stdout, indent=4, separators=(',', ': '))" >> build/convert 17 @echo "json.dump(yaml.load(open(sys.argv[1])), sys.stdout, indent=4, separators=(',', ': '))" >> build/convert
18 @chmod +x build/convert 18 @chmod +x build/convert
19 19
20scrub-old-amis.py: scrub-old-amis.py.in
21 sed "s|@PYTHON@|#!`pwd`/.py3/bin/python|" $< > $@
22 chmod +x $@
23
20.PHONY: clean 24.PHONY: clean
21clean: 25clean:
22 rm -rf build .py3 26 rm -rf build .py3 scrub-old-amis.py
diff --git a/scrub-old-amis.py.in b/scrub-old-amis.py.in
new file mode 100644
index 0000000..756f537
--- /dev/null
+++ b/scrub-old-amis.py.in
@@ -0,0 +1,67 @@
1@PYTHON@
2
3import re
4import yaml
5import boto3
6
7
8# All Alpine AMIs should match this regex if they're valid
9AMI_RE = re.compile("^Alpine-(\d+\.\d+)(?:-r(\d+))?-Hardened-EC2")
10
11
12# Load current AMI version from config
13with open("alpine-ami.yaml") as fp:
14 ami_cfg = yaml.load(fp)["variables"]
15 current = (float(ami_cfg["alpine_release"]), int(ami_cfg["ami_release"]))
16
17
18# Fetch all matching AMIs
19amis = []
20
21for region in boto3.session.Session().get_available_regions("ec2"):
22 ec2 = boto3.client("ec2", region_name=region)
23
24 for image in ec2.describe_images(Owners=["self"])["Images"]:
25 match = AMI_RE.match(image["Name"])
26 if not match:
27 continue
28
29 os_rel, ami_rel = match.groups()
30 amis.append((
31 region, image["ImageId"], float(os_rel),
32 int(ami_rel) if ami_rel else 0))
33
34
35# Determine the set to discard based region and version
36ok_regions = set()
37discards = []
38
39# Cluster candidates by region/version pair, newest in a region first.
40# This should result in the first match for a region always being the newest
41# AMI for that region and all subsequent matches in the region being old.
42# Even so we must keep track of regions with current images on the off-chance
43# that a region only has old images. In that case we want to preserve the old
44# images till we can publish new ones manually so users can still launch
45# Alpine systems without interruption.
46candidates = sorted(amis, key=lambda i: (i[0], (i[1], i[2])), reverse=True)
47
48for ami in candidates:
49 (region, ami), version = ami[:2], ami[2:]
50
51 if version > current:
52 print("{} has AMI '{}' newer than current".format(region, ami))
53 continue
54 elif version == current:
55 ok_regions.add(region)
56 continue
57 elif version < current and region in ok_regions:
58 discards.append((region, ami))
59 else:
60 print("Not discarding old image in {}".format(region))
61 continue
62
63
64# Scrub the old ones
65for region, image in discards:
66 print("Removing image '{}' in {}".format(image, region))
67 boto3.client("ec2", region_name=region).deregister_image(ImageId=image)