diff options
author | Mike Crute <mike@crute.us> | 2017-11-12 23:55:09 +0000 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2017-11-12 23:55:09 +0000 |
commit | 52fbeb09019836edbc4938129c9022c57dfb2ec4 (patch) | |
tree | ebd037d8f111f8a70bebb2233dab25588df7d08b | |
download | aws-tools-52fbeb09019836edbc4938129c9022c57dfb2ec4.tar.bz2 aws-tools-52fbeb09019836edbc4938129c9022c57dfb2ec4.tar.xz aws-tools-52fbeb09019836edbc4938129c9022c57dfb2ec4.zip |
Add ECS AMI mapper
-rw-r--r-- | .gitignore | 1 | ||||
-rwxr-xr-x | make_ecs_ami_yaml.py | 75 |
2 files changed, 76 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34422ef --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1 @@ | |||
/.py3 | |||
diff --git a/make_ecs_ami_yaml.py b/make_ecs_ami_yaml.py new file mode 100755 index 0000000..dda23da --- /dev/null +++ b/make_ecs_ami_yaml.py | |||
@@ -0,0 +1,75 @@ | |||
1 | #!/usr/bin/env python3 | ||
2 | # | ||
3 | # Create a YAML mapping that is sutible for use in a CloudFormation template of | ||
4 | # the current ECS AMIs based on those published in the documentation. The | ||
5 | # script attempts to be as fault-tolerant as possible while still producing | ||
6 | # sane data. | ||
7 | # | ||
8 | # Assumptions: | ||
9 | # The script looks for a table where the first row (td) contains a set of | ||
10 | # headers (th), one of which has the text 'AMI ID' and the other of which is | ||
11 | # 'Region'. Given these it will extract the region/ami-id pairs. | ||
12 | # | ||
13 | |||
14 | import re | ||
15 | import yaml | ||
16 | import requests | ||
17 | from bs4 import BeautifulSoup | ||
18 | |||
19 | AMI_URL = ("https://docs.aws.amazon.com/AmazonECS/latest/" | ||
20 | "developerguide/ecs-optimized_AMI.html") | ||
21 | |||
22 | AMI_RE = re.compile("^ami-[0-9a-f]+$") | ||
23 | |||
24 | soup = BeautifulSoup(requests.get(AMI_URL).text, "html.parser") | ||
25 | |||
26 | # Find the AMI table and column indicies | ||
27 | ami_table, id_index, region_index = None, None, None | ||
28 | for table in soup.find_all("table"): | ||
29 | # Only want header rows for identification | ||
30 | ths = table.tr.find_all('th') | ||
31 | if len(ths) < 2: | ||
32 | continue | ||
33 | |||
34 | # Pick out the column mappings and hold onto their indicies | ||
35 | for i, th in enumerate(ths): | ||
36 | if th.text.lower() == "region": | ||
37 | region_index = i | ||
38 | |||
39 | if th.text.lower() == "ami id": | ||
40 | ami_table = table | ||
41 | id_index = i | ||
42 | |||
43 | # Indicies may be zero | ||
44 | if ami_table and region_index != None and id_index != None: | ||
45 | break | ||
46 | |||
47 | # Indicies may be zero | ||
48 | if ami_table == None or id_index == None or region_index == None: | ||
49 | raise Exception("No AMI table found") | ||
50 | |||
51 | # Build the AMI map | ||
52 | ami_map = {} | ||
53 | for row in ami_table.find_all("tr"): | ||
54 | # Must not be a header (th) row | ||
55 | tds = row.find_all("td") | ||
56 | if len(tds) < max(id_index, region_index): | ||
57 | continue | ||
58 | |||
59 | region = tds[region_index].text | ||
60 | ami_id = tds[id_index].text | ||
61 | |||
62 | # Sanity check the AMI ID in-case we mis-identified a row | ||
63 | if not AMI_RE.match(ami_id): | ||
64 | continue | ||
65 | |||
66 | ami_map[region] = {"AMI": ami_id} | ||
67 | |||
68 | # Validate that there at least enough AMIs (min 4 because there are currently 4 | ||
69 | # big US regions) | ||
70 | if len(ami_map) < 4: | ||
71 | raise Exception("Not enough AMIs found") | ||
72 | |||
73 | # Output AMI map as YAML | ||
74 | print(yaml.dump({"ECSRegionImages": ami_map}, | ||
75 | default_flow_style=False, explicit_start=True)) | ||