Quick-reference recipe card - copy-paste ready.
A small provisioning CLI that ensures S3, SQS, and IAM policy attachments with structured logging.
"""provision.py - idempotent AWS resource bootstrap."""
from __future__ import annotations
import json
import logging
from dataclasses import dataclass
import boto3
from botocore.exceptions import ClientError
logging.basicConfig( level = logging. INFO , format = " %(message)s " )
log = logging.getLogger( "provision" )
@dataclass ( frozen = True )
class ProvisionSpec :
bucket: str
queue: str
tags: dict[ str , str ]
def ensure_bucket (s3, name: str , tags: dict[ str , str ]) -> str :
buckets = {b[ "Name" ] for b in s3.list_buckets().get( "Buckets" , [])}
if name not in buckets:
s3.create_bucket( Bucket = name)
log.info(json.dumps({ "action" : "create" , "resource" : "s3" , "name" : name}))
s3.put_bucket_tagging( Bucket = name, Tagging = { "TagSet" : [{ "Key" : k, "Value" : v} for k, v in tags.items()]})
return name
def ensure_queue (sqs, name: str ) -> str :
try :
return sqs.get_queue_url( QueueName = name)[ "QueueUrl" ]
except ClientError as exc:
if exc.response[ "Error" ][ "Code" ] != "AWS.SimpleQueueService.NonExistentQueue" :
raise
url = sqs.create_queue( QueueName = name)[ "QueueUrl" ]
log.info(json.dumps({ "action" : "create" , "resource" : "sqs" , "name" : name}))
return url
def main () -> None :
spec = ProvisionSpec(
bucket = "company-events-dev" ,
queue = "company-events-dev" ,
tags = { "Environment" : "dev" , "Owner" : "platform" },
)
session = boto3.Session()
s3 = session.client( "s3" )
sqs = session.client( "sqs" )
ensure_bucket(s3, spec.bucket, spec.tags)
ensure_queue(sqs, spec.queue)
log.info(json.dumps({ "status" : "ok" , "bucket" : spec.bucket, "queue" : spec.queue}))
if __name__ == "__main__" :
main()
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+ , Django 5.2 , Flask 3.1 , Pydantic 2 , PyTorch 2.6+ , pandas 2.2+ , Polars 1.x , ruff 0.9+ , and uv 0.6+ .