# Deployment preflight tests Run the deployment preflight on every new node after its qBittorrent and Syncthing stacks are running, but before starting the Archive Control daemon for normal operation or creating any routes/jobs. It is read-only: it does not contact the control daemon, alter Syncthing/qBittorrent state, or print secret contents. The script is [`scripts/preflight-deployment.py`](../scripts/preflight-deployment.py). It deliberately takes paths and container names as arguments rather than assuming hostnames, compose project names, mount paths, credentials, or roles. It can therefore be used unchanged on cache and archive nodes. ## Requirements - Run it on the Docker host being checked. - Use Python 3.8 or newer. The script reads the mounted configuration through the client image, so it does not depend on the host Python TOML library. - Have Docker CLI access to the daemon. - Have the checkout containing the script available on that host, or copy only this script into the node's compose directory. - Bring up qBittorrent and Syncthing first. Do not start the normal Archive Control daemon yet. The disposable client container below uses the exact `archive-client` service image, mounts, environment, and network specified by that node's compose file. Consequently its qB/Syncthing API probes validate the same runtime environment the daemon will use, not the host shell's network namespace. ## New-node procedure The example uses generic names. Replace paths, compose project directories, service names, and real container names for the node being deployed. ```sh # 1. Bring up only the local dependencies. cd /srv/compose/syncthing-node && docker compose up -d cd /srv/compose/qbittorrent-node && docker compose up -d # 2. Create a temporary client from the exact production image/config, without # running the daemon or registering it with control. cd /srv/compose/ArchiveControl-archive docker compose run -d --no-deps --name archive-control-preflight \ --entrypoint sleep archive-client infinity # 3. Discover the real dependency container names if needed. docker ps --format '{{.Names}}' # 4. Run the read-only checks. python3 /path/to/archive-clients/scripts/preflight-deployment.py \ --client-config /srv/compose/ArchiveControl-archive/client.toml \ --client-container archive-control-preflight \ --syncthing-container syncthing-node-syncthing-1 \ --qbittorrent-container qbittorrent-node-qbittorrent-1 # 5. Remove the temporary container, then start the real daemon only after a # successful result. docker rm -f archive-control-preflight docker compose up -d archive-client ``` If the real client configuration is mounted somewhere other than the standard `/etc/archive-control/client.toml`, pass that in-container location explicitly: ```sh python3 scripts/preflight-deployment.py ... \ --container-config /custom/path/client.toml ``` ## Required arguments | Argument | Meaning | | --- | --- | | `--client-config` | Host path to the exact `client.toml` that will be mounted into the daemon. | | `--client-container` | Running disposable or already-running client container to inspect and probe. | | `--syncthing-container` | Running Syncthing container for this node. | | `--qbittorrent-container` | Running qBittorrent container for this node. | | `--container-config` | Optional `client.toml` path inside the client container; defaults to `/etc/archive-control/client.toml`. | ## What it checks - The future automatic `routes/` path resolves through Docker mounts to the same host path as its client-side mapping. - That future route path and qBittorrent content root use one client bind mount, so hard-link staging remains possible rather than silently falling back to a space-consuming copy. - The token, qB password, and Syncthing API-key files are non-empty regular files with no group/world permissions. - The client image can read its configuration and reports usable permissions, sparse-file support, and filesystem capabilities for both roots. - qBittorrent authentication/version compatibility and Syncthing authentication/device identity are healthy from the client container. In particular, if `syncthing.api_root` is the Syncthing configuration root, bind its `routes` subdirectory from a dedicated directory beneath qB's data root and add a `local_path_overrides` mapping for that exact API path. This prevents automatic route folders being created on a small configuration filesystem while the client expects to hardlink from the qB data mount. ## Failure handling Treat a nonzero exit status as a deployment blocker. Correct the compose mounts, `client.toml`, secret permissions, service credentials, or service image/version that the message identifies, then rerun the same command. Do not work around a mapping failure by creating route folders manually: the route provisioner relies on those API/local path mappings being exact.