"""Own one disposable local PostgreSQL container and its synthetic volume.""" from pathlib import Path import argparse import json import subprocess import time import uuid HERE = Path(__file__).resolve().parent parser = argparse.ArgumentParser() parser.add_argument('action', choices=['start', 'ready', 'restart', 'cleanup']) parser.add_argument('--attempt', type=int, default=1) args = parser.parse_args() suffix = '' if args.attempt == 1 else '-attempt' + str(args.attempt) WORK = Path('/tmp/custodian-forgejo-postgres-r1' + suffix) if args.action == 'start': WORK.mkdir(exist_ok=True) (WORK / 'home').mkdir(exist_ok=True) (WORK / 'docker-config').mkdir(exist_ok=True) ENV = {'PATH': '/usr/bin:/bin', 'HOME': str(WORK / 'home'), 'DOCKER_CONFIG': str(WORK / 'docker-config'), 'DOCKER_HOST': 'unix:///var/run/docker.sock'} def docker(*arguments): result = subprocess.run(['docker', *arguments], env=ENV, capture_output=True, text=True, timeout=90) assert result.returncode == 0, 'local synthetic database command refused' return result.stdout.strip() def inspect(cid): return json.loads(docker('inspect', '--format', '{{json .}}', cid)) def owned(state): item = inspect(state['container_id']) assert item['Config']['Labels']['custodian.source-test'] == state['trial'] assert item['HostConfig']['NetworkMode'] == 'none' assert not item['HostConfig']['Privileged'] and not item['HostConfig']['PortBindings'] assert item['Image'] == state['image_id'] mounts = item['Mounts'] assert len(mounts) == 2 assert any(m['Type'] == 'volume' and m['Name'] == state['volume'] and m['Destination'] == '/var/lib/postgresql/data' for m in mounts) assert any(m['Type'] == 'bind' and m['Source'] == str(WORK / 'socket') and m['Destination'] == '/socket' for m in mounts) return item def ready(state): for _ in range(30): # pg_isready can succeed against the entrypoint's temporary init server, # before the requested database exists. Require final PID 1 plus a real # query in that exact synthetic database instead. process = subprocess.run(['docker', 'exec', state['container_id'], 'cat', '/proc/1/comm'], env=ENV, capture_output=True, text=True, timeout=5) result = subprocess.run(['docker', 'exec', state['container_id'], 'psql', '-h', '/socket', '-U', 'custodian_test', '-d', 'custodian_source', '-At', '-c', 'SHOW server_version_num'], env=ENV, capture_output=True, text=True, timeout=5) if process.returncode == result.returncode == 0 and process.stdout.strip() == 'postgres' and result.stdout.strip().isdecimal(): break time.sleep(1) else: raise AssertionError('synthetic PostgreSQL did not become ready; retained') version = result.stdout.strip() assert version.isdecimal() and int(version) // 10000 == 16 state['server_version_num'] = int(version) state_path = HERE / ('database-runtime' + suffix + '.json') if args.action == 'start': assert not state_path.exists() trial = 'custodian-forgejo-pg-' + uuid.uuid4().hex[:12] image = json.loads((HERE / 'public-database-image.json').read_text())['image_id'] volume = trial + '-data' socket = WORK / 'socket' socket.mkdir(mode=0o777) socket.chmod(0o777) # Synthetic Unix socket only, in this new /tmp trial. docker('volume', 'create', '--label', 'custodian.source-test=' + trial, volume) argv = ['create', '--name', trial, '--label', 'custodian.source-test=' + trial, '--network', 'none', '--memory', '512m', '--cpus', '1', '--pids-limit', '128', '--shm-size', '64m', '--mount', 'type=volume,source=' + volume + ',target=/var/lib/postgresql/data', '--mount', 'type=bind,source=' + str(socket) + ',target=/socket', '--env', 'POSTGRES_USER=custodian_test', '--env', 'POSTGRES_DB=custodian_source', '--env', 'PGHOST=/socket', '--env', 'POSTGRES_HOST_AUTH_METHOD=trust', image, 'postgres', '-c', 'listen_addresses=', '-c', 'unix_socket_directories=/var/run/postgresql,/socket', '-c', 'unix_socket_permissions=0777', '-c', 'log_statement=none', '-c', 'log_min_error_statement=panic'] cid = docker(*argv) state = dict(trial=trial, container_id=cid, volume=volume, image_id=image, creation_argv=['docker', *argv], synthetic_data_only=True, real_credentials=False, network='none', ports_published=False, authentication='trust on private synthetic Unix-socket fixture; not a custody/authentication proof') state_path.write_text(json.dumps(state, indent=2) + '\n') owned(state) docker('start', cid) ready(state) state['status'] = 'ready' state_path.write_text(json.dumps(state, indent=2) + '\n') else: state = json.loads(state_path.read_text()) owned(state) if args.action == 'ready': assert inspect(state['container_id'])['State']['Running'] ready(state) state['status'] = 'ready' state_path.write_text(json.dumps(state, indent=2) + '\n') elif args.action == 'restart': docker('restart', '--time', '10', state['container_id']) ready(state) (HERE / ('database-restart' + suffix + '.json')).write_text(json.dumps(dict( status='ready_after_actual_server_restart', container_id=state['container_id'], retained_volume=state['volume'], server_version_num=state['server_version_num'], synthetic_data_only=True), indent=2) + '\n') else: docker('stop', '--time', '10', state['container_id']) owned(state) docker('rm', state['container_id']) volume = json.loads(docker('volume', 'inspect', '--format', '{{json .}}', state['volume'])) assert volume['Labels']['custodian.source-test'] == state['trial'] docker('volume', 'rm', state['volume']) (HERE / ('database-cleanup' + suffix + '.json')).write_text(json.dumps(dict( exact_owned_container_removed=True, exact_owned_volume_removed=True, container_id=state['container_id'], volume=state['volume'], real_credentials=False), indent=2) + '\n') print(json.dumps({'action': args.action, 'trial': state['trial'], 'synthetic_data_only': True}))