AWS & Cloud ← Back to blog

Controlling AWS Infrastructure from a Django View

04 May 2026 · Matt

How the infra_manager module wraps Terraform and boto3 to start/stop RDS and stream logs to the browser.

The Infra Dashboard

The Django cms_manager app exposes a dashboard that shows the current state of the AWS infrastructure — ECS service status, RDS instance state, and recent Terraform logs. Staff can trigger Terraform apply/destroy and start/stop the RDS instance directly from the browser.

Streaming Terraform Output

Terraform runs as a subprocess. The output is streamed line by line into the database so the browser can poll and display it in near real-time.

import subprocess

def terraform_action(action: str, site_slug: str):
    proc = subprocess.Popen(
        ["terraform", action, "-auto-approve"],
        cwd=tf_dir,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        text=True,
    )
    for line in proc.stdout:
        _append_log(site_slug, line.rstrip())
    proc.wait()
    return proc.returncode

def _append_log(slug: str, line: str):
    from cms_manager.models import SiteDeployLog
    SiteDeployLog.objects.filter(site__slug=slug).update(
        log=Concat("log", Value("\n" + line))
    )

RDS Start/Stop

RDS instances can be stopped when not in use to save cost. The start/stop calls are simple boto3 operations, but they're wrapped in a background thread so the HTTP response returns immediately.

def start_rds(db_identifier: str):
    client = boto3.client("rds", region_name=config("AWS_S3_REGION_NAME"), ...)
    try:
        client.start_db_instance(DBInstanceIdentifier=db_identifier)
    except client.exceptions.InvalidDBInstanceStateFault:
        pass  # already running

def site_deploy(request, site_id):
    site   = get_object_or_404(Site, pk=site_id)
    thread = threading.Thread(target=terraform_action, args=("apply", site.slug))
    thread.daemon = True
    thread.start()
    return JsonResponse({"status": "started"})
Tip: Using a daemon thread means the Terraform process is killed if the Django worker shuts down. For production use a proper task queue (Celery, SQS) instead — daemon threads are a pragmatic shortcut for a low-volume admin tool.