Guide Python Intermediate

Python boto3 EC2 Report Lab

Build an EC2 report locally, then connect it to a paginated AWS response.

2 min read

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.

HintIterate 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