Sandbox Guide¶
This guide outlines how to deploy and manage sandboxes for the Whitebox project using Ansible and associated scripts. This includes setup instructions, feature descriptions, and additional information to aid new contributors.
Installation¶
-
Install Ansible:
- For Ubuntu:
sudo apt install ansible - For other systems, follow the official Ansible installation guide
- For Ubuntu:
-
Ensure your SSH keys are added to the server so you can log in without the usual
user:passmethod. -
Clone this repository and navigate to the
ansibledirectory: -
Install Ansible requirements:
Note: This command installs the required Ansible collections locally in your user's home directory (
~/.ansible/collections). -
Export
HCLOUD_TOKENbefore deploying or destroying sandboxes. The token must be able to read servers and manage firewalls in the Hetzner Cloud project that hosts the sandbox server. -
Configure your
hosts.ymlfile to specify the IP address of the server that Ansible will SSH into. For example:
Usage¶
The sandbox.sh script simplifies deploying and managing sandboxes.
Deploy and destroy reconcile a managed Hetzner Cloud firewall for the configured sandbox host. The firewall allows inbound SSH (22/tcp) and the frontend/backend TCP ports published by currently running sandbox containers. Ports for destroyed sandboxes are removed from the allowlist while ports for remaining sandboxes stay open; outbound firewall rules are not changed.
General Usage¶
> ./sandbox.sh
Usage: ./sandbox.sh <repo_url|remote_name> <commit_hash|branch_name> <action_type>
Actions: deploy, destroy
Examples:
./sandbox.sh https://gitlab.com/whitebox-aero/whitebox 09b1d86e deploy
./sandbox.sh origin feature/123 deploy
Note:
1. When given a commit hash while 'destroy', only the sandbox with that commit hash will be destroyed.
2. When given a branch name while 'destroy', all sandboxes with that branch will be destroyed.
Examples¶
# Deploy using a branch name:
./sandbox.sh origin feature/123 deploy
# Deploy using a commit hash:
./sandbox.sh https://gitlab.com/whitebox-aero/whitebox 09b1d86e deploy
# Destroy sandboxes for a branch:
./sandbox.sh origin feature/123 destroy
# Destroy a specific sandbox by commit hash:
./sandbox.sh https://gitlab.com/whitebox-aero/whitebox 09b1d86e destroy
Media storage and lifetime¶
Newly templated sandboxes share the Compose-project whitebox-media volume at
/opt/whitebox/media: backend is the sole read-write mounter; frontend's nginx
mount is read-only. A file seeded into the backend's mount is visible at
/media/<relative-path> on the frontend origin. Sharing preserves nginx's existing
direct serving instead of relying on Django's debug-only media route. That route
currently exists (DEBUG=True); media is unauthenticated through both frontend
and backend ports. Use only synthetic/non-sensitive media. The template starts
no recording/transfer daemon or RQ worker: sharing files does not produce recordings,
and testing seeded files does not validate recording.
- Volume name is
<deploy_tag>_whitebox-media, using the deployment-directory basename as the Compose project identity.deploy_tagis normally the first seven characters of the resolved full commit hash; eight-character input hashes can remain eight. Different project identities isolate storage, not branches or repository paths sharing a tag. - Files survive service recreation while the same volume remains. This preserves files, not database state or a complete recording environment. CI replacement does not preserve this volume when branch destroy selects its project.
- Commit destroy removes the Compose project's volumes only when its backend
container is found and has a Compose label; branch destroy discovers running
containers only. Neither guarantees orphan cleanup. Orphaned/same-tag volumes
may be reused, and image contents at
/opt/whitebox/mediamay be copied into a new volume on its first mount: empty initial storage is not guaranteed. Sandboxes are not archival storage.
Templates come from the invoking checkout. A direct deploy skips templating/start
when both services already run; changing the template alone does not repair that
running sandbox. CI instead runs branch destroy before deploy, removing selected
projects and their volumes before creating the next commit sandbox (see below).
Adding a mount does not migrate old backend writable-layer files and may hide them.
Recreating the old container removes that writable layer and its files. Preserve
needed data separately before any future recreation; this guide supplies no
migration procedure. Removing the mounts on rollback does not copy volume data
back into container layers, and destroying a sandbox is not a data-preserving upgrade.
There is no automatic media preservation across destroy or CI replacement.
Automatic Sandbox Deployment¶
The shared deploy job in .gitlab/config/shared-ci.yml selects
merge_request_event pipelines. Core's run_deploy_sandbox in .gitlab-ci.yml
extends it and depends on run_lfs_check. It is not gated by
need-product-review, and Draft status does not protect a sandbox from replacement.
An MR push can therefore trigger automatic branch destroy then deploy. Branch
destroy discovers running containers with the branch label and removes the selected
Compose projects and their volumes; this can delete existing sandbox media before
the next commit sandbox is created. It does not guarantee orphan cleanup or migrate
old media. This is different from direct deploy's both-services-running skip: do
not rely on the same volume surviving CI replacement or treat sandboxes as backups.
After deployment, an additional script update_sandbox_info.py updates the MR description with relevant URLs (e.g., frontend/backend access).
Deployment and MR-description updates are automated using GitLab CI/CD and Ansible; this automation does not preserve media from a destroyed sandbox.
Update Sandbox Info Script¶
The update_sandbox_info.py script updates MR descriptions after sandbox deployment with relevant URLs. This script is triggered automatically after the sandbox is deployed.
For running it over CI, the only requirement is to have GITLAB_TOKEN set in the CI/CD settings.
You can get the token from your GitLab account settings by:
- Going to
User Settings>Access Tokens. - Creating a new token with
apiscope.
For running it locally, you would need to set two additional environment variables:
CI_PROJECT_IDCI_MERGE_REQUEST_IID
CI_PROJECT_ID can be found by navigating to the project's Settings > General > Project ID. While CI_MERGE_REQUEST_IID can be found in the MR URL. That is the number after the ! in the URL.
You can set these variables in your local shell by first creating a .env file with the following content:
Then, you can set the environment variables by running:
Install the required packages by running:
Finally, you would write logs of ansible playbook to a file by appending 2>&1 | tee deploy.log in the end of the deploy command. Example:
And then run the script:
During development, you can run tests by running: