Common Patterns¶
This guide shows what infrahouse-core simplifies compared to raw boto3, and documents deprecated constructor parameters.
From boto3 to infrahouse-core¶
infrahouse-core is a convenience layer on top of boto3, not a replacement. boto3 is still the engine underneath – infrahouse-core simplifies common operations by providing sensible defaults, role assumption, and property-based access to resource attributes.
You don’t need to stop using boto3. Use infrahouse-core where it saves you boilerplate, and drop down to boto3 directly when you need full control.
EC2 instance metadata¶
Before (boto3):
import boto3
ec2 = boto3.client("ec2")
response = ec2.describe_instances(InstanceIds=["i-abc123"])
instance = response["Reservations"][0]["Instances"][0]
state = instance["State"]["Name"]
private_ip = instance.get("PrivateIpAddress")
tags = {t["Key"]: t["Value"] for t in instance.get("Tags", [])}
After (infrahouse-core):
from infrahouse_core.aws.ec2_instance import EC2Instance
instance = EC2Instance("i-abc123", region="us-east-1")
state = instance.state
private_ip = instance.private_ip
tags = instance.tags
Running commands via SSM¶
Before (boto3):
import boto3
from time import sleep
ssm = boto3.client("ssm")
response = ssm.send_command(
InstanceIds=["i-abc123"],
DocumentName="AWS-RunShellScript",
Parameters={"commands": ["hostname"]},
)
command_id = response["Command"]["CommandId"]
# ... poll for completion, handle retries, parse output ...
After (infrahouse-core):
instance = EC2Instance("i-abc123", region="us-east-1")
exit_code, stdout, stderr = instance.execute_command("hostname")
Secrets Manager¶
Before (boto3):
import boto3
client = boto3.client("secretsmanager")
response = client.get_secret_value(SecretId="my-secret")
value = response["SecretString"]
After (infrahouse-core):
from infrahouse_core.aws.secretsmanager import Secret
secret = Secret("my-secret", region="us-east-1")
value = secret.value
The Secret class also provides ensure_present() and ensure_absent()
for idempotent create/delete operations.
DynamoDB distributed locking¶
Before (boto3) – manual conditional writes, retry loops, TTL management.
After (infrahouse-core):
from infrahouse_core.aws.dynamodb import DynamoDBTable
table = DynamoDBTable("my-locks", region="us-east-1")
with table.lock("deploy-service", timeout=60, ttl=600):
run_deployment()
Cross-account access¶
All resource classes accept role_arn for cross-account operations:
secret = Secret("my-secret", role_arn="arn:aws:iam::123456789012:role/Reader")
instance = EC2Instance("i-abc123", role_arn="arn:aws:iam::123456789012:role/Admin")
Breaking Changes¶
GitHubActions: runners / find_runners_by_label are now iterators¶
Changed in: v1.0.0
GitHubActions.runners and GitHubActions.find_runners_by_label() now
return Iterator[GitHubActionsRunner] instead of List[GitHubActionsRunner].
Pages are fetched from the GitHub API lazily as the iterator advances, keeping
memory usage bounded to a single API page. This fixes OOM crashes in 128 MB
AWS Lambda functions running against large organizations.
Code that iterated over the results keeps working unchanged:
for runner in gha.runners:
...
for runner in gha.find_runners_by_label("instance_id:i-abc123"):
...
Code that relied on list semantics must wrap with list():
Before:
all_runners = gha.runners
count = len(all_runners)
first = all_runners[0]
matches = gha.find_runners_by_label("alpha")
if matches == []:
...
After:
all_runners = list(gha.runners)
count = len(all_runners)
first = all_runners[0]
matches = list(gha.find_runners_by_label("alpha"))
if not matches:
...
Deprecated Parameters¶
EC2Instance: ec2_client and ssm_client¶
Deprecated in: v0.20+
The ec2_client and ssm_client constructor parameters are deprecated.
Use role_arn instead – the class creates its own clients internally.
Before (deprecated):
import boto3
from infrahouse_core.aws.ec2_instance import EC2Instance
ec2_client = boto3.client("ec2", region_name="us-east-1")
ssm_client = boto3.client("ssm", region_name="us-east-1")
instance = EC2Instance("i-abc123", ec2_client=ec2_client, ssm_client=ssm_client)
After:
from infrahouse_core.aws.ec2_instance import EC2Instance
instance = EC2Instance("i-abc123", region="us-east-1")
# For cross-account access:
instance = EC2Instance("i-abc123", role_arn="arn:aws:iam::123456789012:role/MyRole")