Python boto3 EC2 Report Lab
Build an EC2 report locally, then connect it to a paginated AWS response.
Prerequisites
Complete the production scripting bridge. This exercise initially uses only Python. The optional live extension needs boto3, configured AWS credentials, a region, and ec2:DescribeInstances permission.
Sample input
Use this simulated API page; no instance needs to be created:
sample = {"Reservations": [{"Instances": [
{"InstanceId": "i-example1", "State": {"Name": "running"},
"InstanceType": "t3.micro", "Tags": [{"Key": "Name", "Value": "web-01"}]},
{"InstanceId": "i-example2", "State": {"Name": "stopped"},
"InstanceType": "t3.micro"}
]}]}
Task and expected output
Write rows_from_pages(pages, tag_key=None) to process every page, return normalized rows sorted by state and ID, support a tag-key filter, and use unnamed when the Name tag is absent.
running | i-example1 | web-01 | t3.micro
stopped | i-example2 | unnamed | t3.micro
With tag_key="Name", only the first row remains.
Hint
Iterate through pages, reservations, and instances. Convert tags into a dictionary and keep client creation separate from transformation.Show solution
def rows_from_pages(pages, tag_key=None):
rows = []
for page in pages:
for reservation in page.get("Reservations", []):
for instance in reservation.get("Instances", []):
tags = {tag["Key"]: tag["Value"]
for tag in instance.get("Tags", [])}
if tag_key is not None and tag_key not in tags:
continue
rows.append({
"id": instance["InstanceId"],
"state": instance["State"]["Name"],
"type": instance["InstanceType"],
"name": tags.get("Name", "unnamed"),
})
return sorted(rows, key=lambda row: (row["state"], row["id"]))
# Put the sample definition above this call.
for row in rows_from_pages([sample]):
print(f"{row['state']} | {row['id']} | {row['name']} | {row['type']}")
Check your work
- Empty Reservations returns no rows.
- Splitting the sample across two pages still returns both instances.
- Filtering by an absent tag returns no rows.
- Reversing page order does not change report order.
- Missing tags do not raise an exception.
Optional live extension
Pass client.get_paginator("describe_instances").paginate() to your function. Configure timeouts and bounded SDK retries as shown in the bridge. A single API response may not cover the fleet; see the DescribeInstances paginator.
Live output depends on your account and region. Credential and permission errors are failures, not empty inventories. The capstone includes a complete CLI and error handling.
Challenge
Filter running instances missing an Owner tag. Explain the difference between a missing tag and a present tag with an empty value. Export rows as CSV and test against the local sample.
Add More Questions to This Guide
Know a question that should be here? Share it and help the community!
Open Google Form