206 lines · 8.0 KB · Text
RawDownload
#!/usr/bin/env bash## Builds the Integration-channel Oz CLI for Linux x86_64 (musl) and uploads it# to the SSH integration testing VM so that remote-server integration tests run# against the binary built from the current branch.## This script is intended to be run once by CI before the integration test# suite, not by individual test functions. The binary is placed at the# versioned Integration channel path on the remote host, which is where the# Integration channel's `check_binary` looks.## Prerequisites (same as script/deploy_remote_server):#   On Linux, install curl, sha256sum, tar, and sshpass.#   rustup target add x86_64-unknown-linux-musl#   gcloud CLI authenticated for the warp-ssh-integration-testing project## Usage:#   script/deploy_remote_server_to_test_vm set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" TARGET="x86_64-unknown-linux-musl"CARGO_PROFILE="dev-remote"FEATURES="crash_reporting,standalone,agent_mode_debug,remote_codebase_indexing"WARP_BIN="integration"# The integration test runner uses Channel::Integration, which maps to# cli_command_name() = "oz-integration", remote_server_dir() = "~/.warp-dev/remote-server",# and remote_server_binary() = "oz-integration-${pinned_version}".# See crates/warp_core/src/channel/mod.rs, crates/remote_server/src/setup.rs,# and crates/integration/src/bin/integration.rs.## We intentionally build app/src/bin/integration.rs instead of the normal# Local-channel app binary. The Local-channel release bundle requires# warp-channel-config to generate local_config.json at compile time, but this CI# path should not depend on private channel config. The Integration-channel# binary embeds a static non-secret config instead.REMOTE_DIR=".warp-dev/remote-server" # Dedicated remote-server test VM, configured similarly to the SSH integration# test VM but isolated from the general SSH integration suite.REMOTE_USERS=(bash zsh)REMOTE_HOST="ssh-remote-server-testing"REMOTE_PORT="22"PROXY_COMMAND="gcloud compute start-iap-tunnel ssh-remote-server-testing ${REMOTE_PORT} --listen-on-stdin --project=warp-ssh-integration-testing --zone=us-east4-b"  app_version() {  if [[ -n "${GIT_RELEASE_TAG:-}" ]]; then    echo "$GIT_RELEASE_TAG"    return  fi   cargo metadata --no-deps --format-version 1 \    | python3 -c 'import json, sys; print(next(p["version"] for p in json.load(sys.stdin)["packages"] if p["name"] == "remote_server" and p["manifest_path"].endswith("/crates/remote_server/Cargo.toml")))'} # ── Preflight checks ──────────────────────────────────────────────source "$SCRIPT_DIR/linux/configure_musl_toolchain" "$TARGET" if ! rustup target list --installed 2>/dev/null | grep -q "$TARGET"; then  echo "Error: $TARGET target not installed." >&2  echo "Install it with: rustup target add $TARGET" >&2  exit 1fi BUNDLE_VERSION="$(app_version)"BUNDLE_BINARY_NAME="oz-integration"BINARY_NAME="$BUNDLE_BINARY_NAME-$BUNDLE_VERSION" # ── Build ───────────────────────────────────────────────────────── CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-$WORKSPACE_ROOT/target}"OUTPUT_DIR="$CARGO_TARGET_DIR/$TARGET/$CARGO_PROFILE"BUILT_BINARY="$OUTPUT_DIR/$WARP_BIN"LOCAL_BUNDLE_DIR="$OUTPUT_DIR/remote-server-integration-bundle"LOCAL_BUNDLE_TARBALL="$OUTPUT_DIR/remote-server-integration-bundle.tar.gz" echo "==> Building Integration-channel Oz CLI for $TARGET (profile=$CARGO_PROFILE)" cargo build \    -p warp \    --bin "$WARP_BIN" \    --target "$TARGET" \    --profile "$CARGO_PROFILE" \    --features "$FEATURES" if [[ ! -f "$BUILT_BINARY" ]]; then  echo "Error: Expected binary not found at $BUILT_BINARY" >&2  exit 1fi BINARY_SIZE=$(du -h "$BUILT_BINARY" | cut -f1)echo "==> Build complete ($BINARY_SIZE)" rm -rf "$LOCAL_BUNDLE_DIR"mkdir -p "$LOCAL_BUNDLE_DIR"cp "$BUILT_BINARY" "$LOCAL_BUNDLE_DIR/$BUNDLE_BINARY_NAME"SKIP_SETTINGS_SCHEMA=1 "$WORKSPACE_ROOT/script/prepare_bundled_resources" \  "$LOCAL_BUNDLE_DIR/resources" \  integrationtar -czf "$LOCAL_BUNDLE_TARBALL" -C "$LOCAL_BUNDLE_DIR" . # ── Upload via SCP through GCP IAP tunnel ─────────────────────────# The test VM uses password auth (same as the SSH integration tests).# sshpass provides the password non-interactively for SSH/SCP.SSH_PASSWORD="password"SSH_OPTS=(-p "$REMOTE_PORT" -o "ProxyCommand=$PROXY_COMMAND" -o PreferredAuthentications=password -o PubkeyAuthentication=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null) if command -v sshpass &>/dev/null; then  export SSHPASS="$SSH_PASSWORD"  SSH_CMD=(sshpass -e ssh)  SCP_CMD=(sshpass -e scp)else  echo "Warning: sshpass not found, SSH/SCP will prompt for password interactively." >&2  if [[ "$(uname -s)" == "Darwin" ]]; then    echo "Install it with: brew install hudochenkov/sshpass/sshpass" >&2  elif [[ "$(uname -s)" == "Linux" ]]; then    echo "Install it with: sudo apt-get install sshpass" >&2  fi  SSH_CMD=(ssh)  SCP_CMD=(scp)fi for REMOTE_USER in "${REMOTE_USERS[@]}"; do  echo "==> Ensuring remote directory exists for ${REMOTE_USER}"  "${SSH_CMD[@]}" "${SSH_OPTS[@]}" "${REMOTE_USER}@${REMOTE_HOST}" "mkdir -p ~/$REMOTE_DIR"  echo "==> Stopping stale remote server daemons for ${REMOTE_USER}"  "${SSH_CMD[@]}" "${SSH_OPTS[@]}" "${REMOTE_USER}@${REMOTE_HOST}" "bash -s -- '$REMOTE_DIR'" <<'REMOTE_SCRIPT'set -euo pipefail REMOTE_ROOT="$HOME/$1"mkdir -p "$REMOTE_ROOT" shopt -s nullglobfor PID_FILE in "$REMOTE_ROOT"/*/server.pid; do  DAEMON_DIR="$(dirname "$PID_FILE")"  PID="$(cat "$PID_FILE" 2>/dev/null || true)"   if [[ "$PID" =~ ^[0-9]+$ ]] && [[ -d "/proc/$PID" ]]; then    CMDLINE="$(tr '\0' ' ' < "/proc/$PID/cmdline" 2>/dev/null || true)"    if [[ "$CMDLINE" == *remote-server-daemon* ]]; then      echo "Stopping stale remote-server daemon pid $PID"      kill "$PID" 2>/dev/null || true       for _ in {1..50}; do        if ! kill -0 "$PID" 2>/dev/null; then          break        fi        sleep 0.1      done       if kill -0 "$PID" 2>/dev/null; then        echo "Force-stopping stale remote-server daemon pid $PID"        kill -9 "$PID" 2>/dev/null || true      fi    fi  fi   rm -f "$DAEMON_DIR/server.sock" "$DAEMON_DIR/server.pid"done rm -f "$REMOTE_ROOT"/remote-server-integration-bundle-*.tar.gzREMOTE_SCRIPT   TMP_BUNDLE_NAME="remote-server-integration-bundle-${GITHUB_RUN_ID:-local}-$$-${REMOTE_USER}.tar.gz"  echo "==> Uploading bundle to ${REMOTE_USER}@${REMOTE_HOST}:~/$REMOTE_DIR/$TMP_BUNDLE_NAME"  "${SCP_CMD[@]}" -P "$REMOTE_PORT" \    -o "ProxyCommand=$PROXY_COMMAND" \    -o PreferredAuthentications=password \    -o PubkeyAuthentication=no \    -o StrictHostKeyChecking=no \    -o UserKnownHostsFile=/dev/null \    "$LOCAL_BUNDLE_TARBALL" \    "${REMOTE_USER}@${REMOTE_HOST}:~/$REMOTE_DIR/$TMP_BUNDLE_NAME"   echo "==> Installing binary and resources for ${REMOTE_USER}"  # Args: <remote dir> <tarball name> <binary name in tarball> <installed name>.  # The tarball ships the unversioned binary beside its resources/ tree; the  # installed binary carries the version suffix the Integration channel  # launches. The resources tree lands at `bundled_resources`, the global  # version-independent location the daemon reads (must match  # BUNDLED_RESOURCES_DIR_NAME in crates/remote_server/src/setup.rs).  "${SSH_CMD[@]}" "${SSH_OPTS[@]}" "${REMOTE_USER}@${REMOTE_HOST}" \    "bash -s -- '$REMOTE_DIR' '$TMP_BUNDLE_NAME' '$BUNDLE_BINARY_NAME' '$BINARY_NAME'" <<'REMOTE_SCRIPT'set -euo pipefail cd "$HOME/$1"tar -xzf "$2"rm -f "$2" rm -rf bundled_resourcesmv resources bundled_resources chmod 755 "$3"mv -f "$3" "$4""./$4" dump-settings-schema bundled_resources/settings_schema.json"./$4" --versionREMOTE_SCRIPTdone echo ""echo "==> Done! Binary deployed to ${REMOTE_HOST}:~/$REMOTE_DIR/$BINARY_NAME for users: ${REMOTE_USERS[*]}"echo "    Bundled resources: ~/$REMOTE_DIR/bundled_resources"