Files
openwork/scripts/create-daytona-openwork-snapshot.sh
T

128 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
DOCKERFILE="$ROOT_DIR/ee/apps/den-worker-runtime/Dockerfile.daytona-snapshot"
DAYTONA_ENV_FILE="${DAYTONA_ENV_FILE:-$ROOT_DIR/.env.daytona}"
if ! command -v docker >/dev/null 2>&1; then
echo "docker is required" >&2
exit 1
fi
if ! command -v daytona >/dev/null 2>&1; then
echo "daytona CLI is required" >&2
exit 1
fi
if [ -f "$DAYTONA_ENV_FILE" ]; then
set -a
# shellcheck disable=SC1090
source "$DAYTONA_ENV_FILE"
set +a
fi
if [ -n "${DAYTONA_API_KEY:-}" ]; then
echo "Authenticating Daytona CLI" >&2
daytona login --api-key "$DAYTONA_API_KEY" >/dev/null
fi
SNAPSHOT_NAME="${1:-${DAYTONA_SNAPSHOT_NAME:-openwork-runtime}}"
SNAPSHOT_REGION="${DAYTONA_SNAPSHOT_REGION:-${DAYTONA_TARGET:-}}"
SNAPSHOT_CPU="${DAYTONA_SNAPSHOT_CPU:-1}"
SNAPSHOT_MEMORY="${DAYTONA_SNAPSHOT_MEMORY:-2}"
SNAPSHOT_DISK="${DAYTONA_SNAPSHOT_DISK:-8}"
LOCAL_IMAGE_TAG="${DAYTONA_LOCAL_IMAGE_TAG:-openwork-daytona-snapshot:${SNAPSHOT_NAME//[^a-zA-Z0-9_.-]/-}}"
OPENWORK_SERVER_VERSION="${OPENWORK_SERVER_VERSION:-$(node -e 'const fs=require("fs"); const pkg=JSON.parse(fs.readFileSync(process.argv[1], "utf8")); process.stdout.write(String(pkg.version));' "$ROOT_DIR/apps/server/package.json")}"
OPENCODE_VERSION="$(node -e 'const fs=require("fs"); const parsed=JSON.parse(fs.readFileSync(process.argv[1], "utf8")); process.stdout.write(String(parsed.opencodeVersion || "").trim().replace(/^v/, ""));' "$ROOT_DIR/constants.json")"
# The image is always linux/amd64 because that is what Daytona runs. The
# Dockerfile's runtime asserts execute the installed binaries, which only works
# when the build host is also x86_64; under emulation on an arm64 machine they
# die with "Illegal instruction". Disable them for that cross-build case, which
# is exactly the path the Dockerfile documents as "verified on target hardware".
case "$(uname -m)" in
x86_64 | amd64) RUNTIME_ASSERTS="${RUNTIME_ASSERTS:-1}" ;;
*) RUNTIME_ASSERTS="${RUNTIME_ASSERTS:-0}" ;;
esac
echo "Building local image $LOCAL_IMAGE_TAG" >&2
echo "- openwork-server@$OPENWORK_SERVER_VERSION" >&2
echo "- opencode@$OPENCODE_VERSION" >&2
echo "- runtime asserts: $RUNTIME_ASSERTS (host $(uname -m))" >&2
docker buildx build \
--platform linux/amd64 \
-t "$LOCAL_IMAGE_TAG" \
-f "$DOCKERFILE" \
--build-arg "OPENWORK_SERVER_VERSION=$OPENWORK_SERVER_VERSION" \
--build-arg "OPENCODE_VERSION=$OPENCODE_VERSION" \
--build-arg "RUNTIME_ASSERTS=$RUNTIME_ASSERTS" \
--load \
"$ROOT_DIR"
args=(snapshot push "$LOCAL_IMAGE_TAG" --name "$SNAPSHOT_NAME" --cpu "$SNAPSHOT_CPU" --memory "$SNAPSHOT_MEMORY" --disk "$SNAPSHOT_DISK")
if [ -n "$SNAPSHOT_REGION" ]; then
args+=(--region "$SNAPSHOT_REGION")
fi
EXISTING_SNAPSHOT_ID="$({
daytona snapshot list --format json | node -e '
const fs = require("fs");
const target = process.argv[1];
const raw = fs.readFileSync(0, "utf8").trim();
if (!raw || !target) {
process.exit(0);
}
let data;
try {
data = JSON.parse(raw);
} catch (error) {
console.error(`Failed to parse Daytona snapshot list JSON: ${error.message}`);
process.exit(1);
}
const stack = [data];
while (stack.length > 0) {
const value = stack.pop();
if (!value || typeof value !== "object") {
continue;
}
if (Array.isArray(value)) {
for (const item of value) {
stack.push(item);
}
continue;
}
const name = typeof value.name === "string" ? value.name : "";
const id = typeof value.id === "string" ? value.id : "";
if (name === target) {
process.stdout.write(id || name);
process.exit(0);
}
for (const child of Object.values(value)) {
stack.push(child);
}
}
' "$SNAPSHOT_NAME";
} )"
if [ -n "$EXISTING_SNAPSHOT_ID" ]; then
echo "Deleting existing Daytona snapshot $SNAPSHOT_NAME" >&2
daytona snapshot delete "$EXISTING_SNAPSHOT_ID"
fi
echo "Pushing Daytona snapshot $SNAPSHOT_NAME" >&2
daytona "${args[@]}"
echo >&2
echo "Snapshot ready: $SNAPSHOT_NAME" >&2
echo "Set DAYTONA_SNAPSHOT=$SNAPSHOT_NAME in .env.daytona before starting Den." >&2