===============
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")


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")