Decommission a Host

Full teardown of an ansible-managed EC2 host. Companion to ansible/provision-arm-host. Steps must run in order. awsdecomhost.py handles most of it; steps 2-4 are manual extras it does not cover.

Step 1 — Decommission via awsdecomhost.py

Terminates the instance, comments out /etc/hosts entry, removes from hosts.ini, removes known_hosts entries, deletes the .pem key file, and marks the host terminated in the hosts note.

HOST = input("Host name: ").strip()
REGION = input("Region (e.g. eu-central-1): ").strip() or "eu-central-1"
if not HOST:
    raise ValueError("Host name cannot be empty")
print(f"Host:   {HOST}")
print(f"Region: {REGION}")
import subprocess
result = subprocess.run(
    ["python3", "/home/john/aws/awsdecomhost.py", HOST, "--region", REGION],
    input="yes\n", text=True
)
if result.returncode != 0:
    raise RuntimeError("awsdecomhost.py failed")

Step 2 — Delete EC2 Key Pair

awsdecomhost.py prints a TODO for this but does not do it. The aws CLI is not installed on pomelo so use boto3 directly.

import boto3
ec2 = boto3.client('ec2', region_name=REGION)
ec2.delete_key_pair(KeyName=HOST)
print(f"Key pair '{HOST}' deleted")

Step 3 — Remove Stunnel Client Section

Removes the [socks5h-HOST] block from pomelo's /etc/stunnel/stunnel.conf.

import subprocess, re

with open("/etc/stunnel/stunnel.conf") as f:
    conf = f.read()

pattern = rf"\[socks5h-{re.escape(HOST)}\][^\[]*"
if re.search(pattern, conf):
    conf = re.sub(pattern, "", conf)
    r = subprocess.run(["sudo", "tee", "/etc/stunnel/stunnel.conf"], input=conf, capture_output=True, text=True)
    if r.returncode != 0:
        raise RuntimeError(f"Failed to write stunnel.conf: {r.stderr}")
    print(f"Removed [socks5h-{HOST}] from stunnel.conf")
else:
    print(f"[socks5h-{HOST}] not found — nothing to remove")

Step 4 — Restart Stunnel and Clean Up Socket

Kills the running stunnel daemon, cleans up the unix socket in ~/.sockets/, and starts fresh.

import subprocess, os, time

socket_path = f"/home/john/.sockets/socks5h-{HOST}"
if os.path.exists(socket_path):
    os.remove(socket_path)
    print(f"Removed socket {socket_path}")
else:
    print(f"Socket {socket_path} already gone")

pids = subprocess.run(["pgrep", "stunnel"], capture_output=True, text=True).stdout.split()
if pids:
    subprocess.run(["sudo", "kill"] + pids, check=True)
    time.sleep(1)

subprocess.run(["sudo", "stunnel", "/etc/stunnel/stunnel.conf"], check=True)
time.sleep(1)

out = subprocess.run(["pgrep", "-a", "stunnel"], capture_output=True, text=True).stdout.strip()
print(f"stunnel running: {out}")
version 1  ·  created 2026-06-10  ·  updated 2026-06-10  ·  tags ['ansible', 'ec2', 'infrastructure', 'runnable']