From eef17eb5919a37a8881bbacb96e790d19345ec4d Mon Sep 17 00:00:00 2001 From: Richard Zink Date: Mon, 9 Nov 2026 12:54:21 +0100 Subject: [PATCH] move-server.sh: --tools-dir for agent installs and /tmp on a separate disk Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ++++++ README.md | 3 +++ scripts/move-server.sh | 31 +++++++++++++++++++++++++++---- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bfecfc..c66db65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to CodeCraft. Versions follow [Semantic Versioning](https://semver.org/); until 1.0, minor versions may contain breaking changes. +## [Unreleased] + +### Added + +- `scripts/move-server.sh --tools-dir DIR`: agent home, users' homes and `/tmp` on a separate disk. + ## [v202611-00005] – 2026-11-09 ### Fixed diff --git a/README.md b/README.md index 0d34729..34bcb44 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,9 @@ copies the workspace, stops CodeCraft, streams the data volume to `/data`, `docker-compose.yml` (and a `start.sh` for hosts without Compose) with bind mounts, starts the published image there and runs `scripts/smoke-test.sh`. The old container is only stopped, so you can roll back. `--help` lists the options (owner, port, bind address, dry run). +`--tools-dir /mnt/disks/ssd/codecraft` puts everything agents install or download – the agent +home (`/data/home`: toolchains, pip/npm/cargo packages, caches), the users' homes and `/tmp` – on +a separate disk; the data folder keeps only the database, configuration and backups. ## How it works diff --git a/scripts/move-server.sh b/scripts/move-server.sh index 24db8a5..28c6262 100755 --- a/scripts/move-server.sh +++ b/scripts/move-server.sh @@ -23,6 +23,9 @@ # # Options: # --workspace DIR project folder on the target (default /workspace) +# --tools-dir DIR separate disk for what agents install and download: the agent home +# (/data/home), the users' homes (/data/users) and /tmp are bind +# mounts from DIR/home, DIR/users and DIR/tmp (default: inside /data) # --uid N --gid N owner of data and workspace on the target (default: UID/GID of .env) # --port N host port on the target (default: PORT of .env) # --bind ADDR bind address on the target (default: BIND_ADDR of .env or 127.0.0.1) @@ -34,11 +37,12 @@ # --dry-run show the steps only set -euo pipefail -target="" ws_target="" uid="" gid="" port="" bind="" name="codecraft" +target="" ws_target="" tools_dir="" uid="" gid="" port="" bind="" name="codecraft" src_container="codecraft" src_volume="codecraft-data" ws_source="" stop=1 dry=0 while (($#)); do case "$1" in --workspace) ws_target="$2"; shift ;; + --tools-dir) tools_dir="$2"; shift ;; --uid) uid="$2"; shift ;; --gid) gid="$2"; shift ;; --port) port="$2"; shift ;; @@ -97,10 +101,15 @@ step "Checking source and target" docker volume inspect "$src_volume" >/dev/null || fail "volume $src_volume not found" [[ -d "$ws_source" ]] || fail "workspace $ws_source not found" echo "source: container $src_container, volume $src_volume, workspace $ws_source" -echo "target: $host:$dir (data in $dir/data, workspace $ws_target), uid $uid:$gid, ${bind}:${port}, image $image_repo:$version" +tools_dir="${tools_dir%/}" +echo "target: $host:$dir (data in $dir/data, workspace $ws_target${tools_dir:+, agent installs and /tmp in $tools_dir}), uid $uid:$gid, ${bind}:${port}, image $image_repo:$version" remote "command -v docker >/dev/null && command -v tar >/dev/null && command -v rsync >/dev/null" || fail "the target needs docker, tar and rsync" remote "mkdir -p $(q "$dir/data") $(q "$dir/docker") $(q "$ws_target") && test -z \"\$(ls -A $(q "$dir/data"))\"" \ || fail "$dir/data on the target is not empty – refusing to overwrite (move it away first)" +if [[ -n "$tools_dir" ]]; then + remote "mkdir -p $(q "$tools_dir") && test ! -e $(q "$tools_dir/home") && test ! -e $(q "$tools_dir/users")" \ + || fail "$tools_dir already has home/ or users/ – refusing to overwrite (move them away first)" +fi step "Copying the workspace (first pass, CodeCraft keeps running)" sync_workspace @@ -118,9 +127,22 @@ else | remote "tar -C $(q "$dir/data") -xpf -" fi +if [[ -n "$tools_dir" ]]; then + step "Moving the agent home and the users' homes to $tools_dir" + remote "mkdir -p $(q "$tools_dir/tmp") $(q "$dir/data/home") $(q "$dir/data/users") \ + && mv $(q "$dir/data/home") $(q "$tools_dir/home") && mv $(q "$dir/data/users") $(q "$tools_dir/users") \ + && mkdir -p $(q "$dir/data/home") $(q "$dir/data/users") && chmod 1777 $(q "$tools_dir/tmp")" +fi + step "Copying the workspace (changes since the first pass)" sync_workspace -remote "chown -R $uid:$gid $(q "$dir/data") $(q "$ws_target") 2>/dev/null || echo 'note: could not chown (not root) – check file owners'" +remote "chown -R $uid:$gid $(q "$dir/data") $(q "$ws_target") ${tools_dir:+$(q "$tools_dir/home") $(q "$tools_dir/users")} 2>/dev/null || echo 'note: could not chown (not root) – check file owners'" +# Bind mounts for the tools disk (compose lines and docker run flags). +tool_mounts="" tool_flags="" +if [[ -n "$tools_dir" ]]; then + tool_mounts=$(printf ' - %s/home:/data/home\n - %s/users:/data/users\n - %s/tmp:/tmp\n' "$tools_dir" "$tools_dir" "$tools_dir") + tool_flags="-v $tools_dir/home:/data/home -v $tools_dir/users:/data/users -v $tools_dir/tmp:/tmp " +fi step "Writing docker-compose.yml, .env and start.sh" put_file "$dir/docker/seccomp-sandbox.json" /dev/null 2>&1 || true exec docker run -d --name $name --restart unless-stopped --user "\$(val UID):\$(val GID)" \\ -p "\$(val BIND_ADDR):\$(val PORT):8787" --env-file .env \\ - -v $dir/data:/data -v "\$(val WORKSPACE):/workspace" \\ + -v $dir/data:/data -v "\$(val WORKSPACE):/workspace" $tool_flags\\ --add-host host.docker.internal:host-gateway --shm-size 1g \\ --security-opt seccomp=$dir/docker/seccomp-sandbox.json \\ --security-opt apparmor=unconfined --security-opt systempaths=unconfined \\