Skip to main content

azure-ps-test-runner-vm

Create a throwaway Azure VM next to the HorizonDB server and run the full `./scripts/run-tests.sh --all-providers` suite on it, with credentials copied for one run only. Use when HorizonDB tests time out from a laptop far from the server, when GitHub runners are slow or unavailable, or when asked to set up, use or tear down a PilotSwarm test runner VM.

ソース情報

リポジトリ
microsoft/PilotSwarm
ソースの最終更新活動
2026年10月2日 22:09
検出された SKILL.md の言語
英語
スター
8
フォーク
4

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
azure-ps-test-runner-vm
description
Create a throwaway Azure VM next to the HorizonDB server and run the full `./scripts/run-tests.sh --all-providers` suite on it, with credentials copied for one run only. Use when HorizonDB tests time out from a laptop far from the server, when GitHub runners are slow or unavailable, or when asked to set up, use or tear down a PilotSwarm test runner VM.
# Azure test runner VM A plain Ubuntu VM in the same Azure region as the HorizonDB server. It runs the full all-providers suite from a clone of the repo. It is not a GitHub Actions runner; for that, see the `Manage Azure CI runner` workflow and `deploy/providers/azure/ci/runner/README.md`. ## Why The HorizonDB phase makes many short database calls in a row. Distance decides whether it passes: | Where the tests run | One `SELECT 1` | Result | |---|---|---| | A laptop on another continent | 130–160 ms | Most HorizonDB SDK tests hit their time limits | | A VM in the server's region | 0–1 ms | The full suite passes | Measure it first (step 6) when in doubt. ## What you need - Azure CLI signed in, with rights to create a resource group and a VM. - The repo's local test config files: `.env`, `.env.horizondb` and `.model_providers.json`. They hold credentials (a GitHub token, model keys, the HorizonDB connection). See "Credentials" below before copying them. Set these once in your shell. Use your own values: ```bash SUB=<subscription-id> RG=<resource-group> # a new, dedicated group, e.g. pilotswarm-testrunner-rg VM=<vm-name> # e.g. ps-testrunner LOC=<horizondb-region> # the region of your HorizonDB server KEY=~/.ssh/id_ed25519_ps_testrunner MYIP=$(curl -s https://api.ipify.org) ``` ## 1. SSH key and setup script ```bash [ -f "$KEY" ] || ssh-keygen -q -t ed25519 -N '' -C 'pilotswarm test runner' -f "$KEY" cat > cloud-init.yaml <<'EOF' #cloud-config package_update: true packages: [git, build-essential, python3, jq, ca-certificates, curl, docker.io, unzip] runcmd: - curl -fsSL https://deb.nodesource.com/setup_24.x | bash - - apt-get install -y nodejs - usermod -aG docker azureuser - systemctl enable --now docker EOF ``` ## 2. Create the VM Use 8 cores. The suite runs 8 test files at once, each with its own workers, plus PostgreSQL in Docker. On 4 cores the tests compete for CPU and hit their time limits. ```bash az group create --subscription "$SUB" -n "$RG" -l "$LOC" -o none az vm create --subscription "$SUB" -g "$RG" -n "$VM" \ --image Canonical:ubuntu-24_04-lts:server:latest \ --size Standard_D8s_v5 --os-disk-size-gb 128 --storage-sku Premium_LRS \ --admin-username azureuser --ssh-key-values "$KEY.pub" --authentication-type ssh \ --public-ip-sku Standard --nsg-rule NONE --custom-data cloud-init.yaml \ --query publicIpAddress -o tsv ``` Write down the IP it prints. ## 3. SSH from your IP only, and a nightly shutdown ```bash NSG=$(az network nsg list --subscription "$SUB" -g "$RG" --query '[0].name' -o tsv) az network nsg rule create --subscription "$SUB" -g "$RG" --nsg-name "$NSG" \ -n ssh-from-me --priority 1000 --direction Inbound --access Allow --protocol Tcp \ --source-address-prefixes "$MYIP/32" --destination-port-ranges 22 -o none az vm auto-shutdown --subscription "$SUB" -g "$RG" -n "$VM" --time 0200 -o none # UTC ``` Add an alias to `~/.ssh/config`: ``` Host ps-testrunner HostName <vm-ip> User azureuser IdentityFile ~/.ssh/id_ed25519_ps_testrunner IdentitiesOnly yes StrictHostKeyChecking accept-new ServerAliveInterval 30 ``` Then wait for the setup script: `ssh ps-testrunner 'cloud-init status --wait; node --version; docker --version'`. **If SSH times out** while the VM runs, check the security rules: `az network nsg rule list -g "$RG" --nsg-name "$NSG" -o table`. Some organizations add their own deny rule for port 22 from the internet, with a higher priority than yours. Do not edit those rules. Connect from the network they allow, or drive the VM with Run Command (see "Without SSH"). ## 4. The repo ```bash ssh ps-testrunner 'git clone -q https://github.com/microsoft/PilotSwarm.git pilotswarm cd pilotswarm && git checkout -q -B <branch> origin/<branch> && npm ci --no-audit --no-fund' ``` To test another commit later: `git fetch origin <branch> && git checkout -B <branch> origin/<branch> && npm ci`. ## 5. PostgreSQL The container's password must match `DATABASE_URL` in the `.env` you copy. `run-tests.sh` refuses to run with fewer than 1500 connections. ```bash ssh ps-testrunner 'docker run -d --name pilotswarm-pg --restart unless-stopped \ -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=<password-from-DATABASE_URL> \ -e POSTGRES_DB=pilotswarm -p 127.0.0.1:5432:5432 postgres:16 \ && sleep 5 \ && docker exec pilotswarm-pg psql -U postgres -qc "ALTER SYSTEM SET max_connections = 1500;" \ && docker restart pilotswarm-pg' ``` ## 6. Credentials: copy for one run, delete after The three config files hold real credentials. Keep them on the VM only while a run needs them: 1. Copy them right before the run. 2. In the same step, start a watcher that deletes them when the run ends. 3. Never leave them between runs. Ask the person before copying them to a machine that did not hold them before. **With SSH:** ```bash scp .env .env.horizondb .model_providers.json ps-testrunner:pilotswarm/ ssh ps-testrunner 'cd pilotswarm && chmod 600 .env .env.horizondb .model_providers.json grep -q "^HORIZON_DATABASE_URL=." .env.horizondb && echo "hdb config: ok"' ``` Check the HorizonDB latency once: ```bash ssh ps-testrunner 'cd pilotswarm && node --env-file=.env.horizondb -e " const pg = require(\"pg\"); (async () => { const u = new URL(process.env.HORIZON_DATABASE_URL); u.searchParams.delete(\"sslmode\"); u.searchParams.delete(\"uselibpqcompat\"); const c = new pg.Client({ connectionString: u.toString(), ssl: { rejectUnauthorized: false } }); await c.connect(); const t = []; for (let i = 0; i < 5; i++) { const s = Date.now(); await c.query(\"SELECT 1\"); t.push(Date.now() - s); } console.log(\"SELECT 1 ms:\", t.join(\", \")); await c.end(); })().catch((e) => console.log(\"error:\", e.code || e.message));"' ``` ## 7. Run the suite Start it detached, so it keeps going when your laptop sleeps. Then start the watcher that deletes the credentials when the run ends. `PS_TEST_SKIP_STALE_CLEANUP=1` skips the global sweep of old test schemas, so the run cannot drop schemas another run on the same HorizonDB still uses. ```bash ssh ps-testrunner 'cd pilotswarm PS_TEST_SKIP_STALE_CLEANUP=1 setsid nohup bash -c "./scripts/run-tests.sh --all-providers > ~/all-providers.log 2>&1; echo EXIT=\$? >> ~/all-providers.log" > /dev/null 2>&1 < /dev/null & sleep 3 setsid nohup bash -c "while pgrep -f \"[r]un-tests.sh --all-providers\" > /dev/null; do sleep 30; done; shred -u ~/pilotswarm/.env ~/pilotswarm/.env.horizondb ~/pilotswarm/.model_providers.json; echo \"credentials removed \$(date -u)\" >> ~/secrets-cleanup.log" > /dev/null 2>&1 < /dev/null & echo started' ``` Progress and result: ```bash ssh ps-testrunner 'sed "s/\x1b\[[0-9;]*m//g" ~/all-providers.log | grep -aE "Provider phase|Test Files|Tests |Combined provider result|EXIT="' ``` A full run takes about 35–40 minutes: the stock PostgreSQL pass (about 22), then the HorizonDB phase. To run only some files on HorizonDB: `./scripts/run-tests.sh --with-horizondb --suite=<name> --suite=<name>`. ## Without SSH: Run Command Use `az vm run-command invoke` for commands that carry no secret (status, logs, pkill). It returns the output, but Azure keeps the script, so **never put credentials in it**. To copy the credential files, use Run Command v2 with protected parameters. Azure stores them encrypted and never returns them: ```bash az vm run-command create --subscription "$SUB" -g "$RG" --vm-name "$VM" \ --name copy-and-run-$(date +%H%M%S) --location "$LOC" --timeout-in-seconds 600 \ --script "$(cat vm-run.sh)" \ --protected-parameters "PSENV=$(base64 < .env | tr -d '\n')" \ "PSHDB=$(base64 < .env.horizondb | tr -d '\n')" \ "PSMP=$(base64 < .model_providers.json | tr -d '\n')" az vm run-command delete --subscription "$SUB" -g "$RG" --vm-name "$VM" --name <that-name> --yes ``` - Do **not** pass `--run-as-user`: with it, the parameters do not reach the script. Run as root, and inside the script write the files, then `chown azureuser:azureuser` and `chmod 600` them. - The parameters arrive as environment variables: `printf '%s' "$PSENV" | base64 -d > .env`. - Start the run as the user: `sudo -u azureuser -H setsid nohup <script> &`. - Delete the run command afterwards. ## Gotchas - **`pkill -f run-tests.sh` over SSH kills your own SSH command,** whose text contains the pattern. Use `pkill -f "[r]un-tests.sh"`. - **zsh reads `$name:a` as a path modifier.** `"image-$svc:tag"` becomes a file path. Write `"image-${svc}:tag"`. - **Two HorizonDB tests sit close to their 60 s limit:** the first test of `delete-cascade` and of `pg-migrator` sets up a fresh schema (about 55 s). Under the full parallel load they can time out. Re-run them alone with `--with-horizondb --suite=delete-cascade --suite=pg-migrator` before calling it a failure. - **Which keys the run uses:** - Model calls go through the test catalog (`packages/sdk/test/fixtures/model-providers.test.json`), that is GitHub Copilot with `GITHUB_TOKEN`. - The HorizonDB phase also calls the embedding endpoint set by the `HORIZON_EMBED_*` values in `.env.horizondb`. - **A test that prints a database URL must hide the password.** `packages/sdk/test/helpers/local-env.js` does; keep it that way, because the run log stays on the VM. ## Tear down ```bash az group delete --subscription "$SUB" -n "$RG" --yes --no-wait ``` This deletes the VM, its disk, IP and network, and any credentials still on it. Remove the SSH alias and key if you will not create the VM again.
GitHubで見る