first cycle lab release
This commit is contained in:
Executable
+122
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env bash
|
||||
# Rollback an isolated copy over real SSH. Never selects the user's live root.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.."
|
||||
repository="$PWD"
|
||||
node_binary=$(command -v node)
|
||||
check=$(mktemp -d "$PWD/.tools/phase8-check.XXXXXX")
|
||||
printf '%s\n' "$check" > .tools/phase8-check-path
|
||||
mkdir -p "$check/evidence" "$check/ssh" "$check/bin"
|
||||
snapshot="$repository/.tools/phase7-check.6dbBak/host/backups/20261003T153844610Z-732a1d62-9bee-4a9c-a095-68bde6c8406f"
|
||||
./mcpack restore --backup "$snapshot" --destination "$check/host" > "$check/evidence/initial-restore.log"
|
||||
HOST_ROOT="$check/host" node --input-type=module <<'JS'
|
||||
import fs from 'node:fs';import {releaseName,deployableRelease} from './platform/deployment.mjs';
|
||||
const root=process.env.HOST_ROOT,release=deployableRelease(root+'/release'),name=releaseName(release.manifest);
|
||||
fs.mkdirSync(root+'/releases');fs.renameSync(root+'/release',root+'/releases/'+name);
|
||||
fs.writeFileSync(root+'/active-release',name+'\n');
|
||||
fs.writeFileSync(root+'/deployment-state.json',JSON.stringify({schema_version:1,id:'restored-phase8-fixture',phase:'complete',target_release:name}));
|
||||
fs.writeFileSync(root+'/.env','MC_EULA=TRUE\nMC_MEMORY=2G\nMC_PORT=25566\nMC_BIND_ADDRESS=0.0.0.0\nMC_UID=1000\nMC_GID=1000\nMC_PROJECT_NAME=minecraft-lab-phase7\n',{mode:0o600});
|
||||
fs.writeFileSync(root+'/runtime/world/phase8-progress.txt','snapshot-progress\n');
|
||||
fs.mkdirSync(root+'/runtime/mod-state',{recursive:true});fs.writeFileSync(root+'/runtime/mod-state/phase8-progress.txt','snapshot-progress\n');
|
||||
JS
|
||||
ssh-keygen -q -t ed25519 -N '' -f "$check/ssh/host-key"
|
||||
ssh-keygen -q -t ed25519 -N '' -f "$check/ssh/client-key"
|
||||
cp "$check/ssh/client-key.pub" "$check/ssh/authorized_keys"
|
||||
cat > "$check/ssh/sshd_config" <<CONFIG
|
||||
Port 22228
|
||||
ListenAddress 127.0.0.1
|
||||
HostKey $check/ssh/host-key
|
||||
PidFile $check/ssh/sshd.pid
|
||||
AuthorizedKeysFile $check/ssh/authorized_keys
|
||||
StrictModes no
|
||||
PermitRootLogin prohibit-password
|
||||
PubkeyAuthentication yes
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
UsePAM yes
|
||||
AllowUsers root
|
||||
CONFIG
|
||||
printf '[127.0.0.1]:22228 ' > "$check/ssh/known_hosts"
|
||||
cut -d ' ' -f 1-2 "$check/ssh/host-key.pub" >> "$check/ssh/known_hosts"
|
||||
cat > "$check/ssh/client_config" <<CONFIG
|
||||
Host phase8-fixture
|
||||
HostName 127.0.0.1
|
||||
Port 22228
|
||||
User root
|
||||
IdentityFile $check/ssh/client-key
|
||||
IdentitiesOnly yes
|
||||
UserKnownHostsFile $check/ssh/known_hosts
|
||||
CONFIG
|
||||
cat > "$check/bin/ssh" <<SCRIPT
|
||||
#!/bin/sh
|
||||
exec /usr/bin/ssh -F '$check/ssh/client_config' "\$@"
|
||||
SCRIPT
|
||||
chmod +x "$check/bin/ssh"
|
||||
export PATH="$check/bin:$PATH"
|
||||
/usr/sbin/sshd -D -e -f "$check/ssh/sshd_config" > "$check/evidence/sshd.log" 2>&1 &
|
||||
sshd_pid=$!
|
||||
cleanup(){
|
||||
if [[ -f "$check/host/.mcpack-runtime.json" ]]; then
|
||||
for release in "$check/host/releases/"*; do
|
||||
if MC_ROOT="$check/host" MC_RELEASE_DIR="$release" scripts/server.sh down > "$check/evidence/cleanup.log" 2>&1; then break; fi
|
||||
done
|
||||
fi
|
||||
kill "$sshd_pid" 2>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
sleep 0.3
|
||||
FIXTURE_ROOT="$check/host" FIXTURE_CONFIG="$check/config.yaml" node --input-type=module <<'JS'
|
||||
import fs from 'node:fs';import {parse,stringify} from 'yaml';
|
||||
const config=parse(fs.readFileSync('platform/config.yaml','utf8'));config.server.host='phase8-fixture';config.server.directory=process.env.FIXTURE_ROOT;
|
||||
fs.writeFileSync(process.env.FIXTURE_CONFIG,stringify(config));
|
||||
JS
|
||||
./mcpack deploy --config "$check/config.yaml" --artifact dist/minecraft-lab-neoforge-spike-0.0.5 --remote-node "$node_binary" > "$check/evidence/update-to-five.log" 2>&1
|
||||
rollback_snapshot=$(HOST_ROOT="$check/host" node --input-type=module <<'JS'
|
||||
import fs from 'node:fs';import path from 'node:path';
|
||||
console.log(path.basename(JSON.parse(fs.readFileSync(process.env.HOST_ROOT+'/deployment-state.json')).backup_snapshot));
|
||||
JS
|
||||
)
|
||||
printf '%s\n' "$rollback_snapshot" > "$check/evidence/requested-snapshot-id.txt"
|
||||
printf 'current-progress\n' > "$check/host/runtime/world/phase8-progress.txt"
|
||||
printf 'current-progress\n' > "$check/host/runtime/mod-state/phase8-progress.txt"
|
||||
printf 'only-after-snapshot\n' > "$check/host/runtime/phase8-after-only.txt"
|
||||
ls -A "$check/host" > "$check/evidence/root-before-plan.txt"
|
||||
before=$(docker inspect minecraft-lab-phase7-minecraft-1 --format '{{.Id}} {{.State.StartedAt}}')
|
||||
./mcpack rollback --config "$check/config.yaml" --remote-node "$node_binary" > "$check/evidence/plan.txt"
|
||||
./mcpack rollback-pack 0.0.4 --config "$check/config.yaml" --remote-node "$node_binary" > "$check/evidence/pack-plan.txt"
|
||||
ls -A "$check/host" > "$check/evidence/root-after-plan.txt"
|
||||
[[ "$before" == "$(docker inspect minecraft-lab-phase7-minecraft-1 --format '{{.Id}} {{.State.StartedAt}}')" ]]
|
||||
node -e 'const fs=require("fs"),assert=require("assert/strict");assert.equal(fs.readFileSync(process.argv[1],"utf8"),fs.readFileSync(process.argv[2],"utf8"))' "$check/evidence/root-before-plan.txt" "$check/evidence/root-after-plan.txt"
|
||||
./mcpack rollback-pack 0.0.4 --confirm-compatible --config "$check/config.yaml" --remote-node "$node_binary" > "$check/evidence/pack-rollback.log" 2>&1
|
||||
HOST_ROOT="$check/host" node --input-type=module <<'JS' > "$check/evidence/pack-assertions.txt"
|
||||
import fs from 'node:fs';import assert from 'node:assert/strict';import {execFileSync} from 'node:child_process';
|
||||
const root=process.env.HOST_ROOT,state=JSON.parse(fs.readFileSync(root+'/rollback-state.json'));
|
||||
assert.equal(state.phase,'complete');assert.equal(state.mode,'pack');assert(state.backup_snapshot);
|
||||
assert.equal(fs.readFileSync(root+'/runtime/world/phase8-progress.txt','utf8'),'current-progress\n');
|
||||
assert.equal(fs.readFileSync(root+'/runtime/mod-state/phase8-progress.txt','utf8'),'current-progress\n');
|
||||
assert(fs.existsSync(root+'/runtime/phase8-after-only.txt'));
|
||||
const container=JSON.parse(execFileSync('docker',['inspect','minecraft-lab-phase7-minecraft-1']))[0];
|
||||
assert.equal(container.State.Health.Status,'healthy');assert.equal(container.NetworkSettings.Ports['25565/tcp'][0].HostIp,'0.0.0.0');
|
||||
console.log('Pack-only rollback: retained 0.0.4, current progress preserved, backup verified, LAN bind and health retained.');
|
||||
JS
|
||||
./mcpack rollback --backup "$rollback_snapshot" --accept-progress-loss --config "$check/config.yaml" --remote-node "$node_binary" > "$check/evidence/snapshot-rollback.log" 2>&1
|
||||
HOST_ROOT="$check/host" node --input-type=module <<'JS' > "$check/evidence/snapshot-assertions.txt"
|
||||
import fs from 'node:fs';import assert from 'node:assert/strict';import {execFileSync} from 'node:child_process';import {verifySnapshot} from './platform/backups.mjs';
|
||||
const root=process.env.HOST_ROOT,state=JSON.parse(fs.readFileSync(root+'/rollback-state.json'));
|
||||
assert.equal(state.phase,'complete');assert.equal(state.mode,'snapshot');assert.equal(state.runtime_replaced,true);
|
||||
assert.equal(fs.readFileSync(root+'/runtime/world/phase8-progress.txt','utf8'),'snapshot-progress\n');
|
||||
assert.equal(fs.readFileSync(root+'/runtime/mod-state/phase8-progress.txt','utf8'),'snapshot-progress\n');
|
||||
assert(!fs.existsSync(root+'/runtime/phase8-after-only.txt'));
|
||||
assert.equal(fs.readFileSync(state.retired_runtime+'/world/phase8-progress.txt','utf8'),'current-progress\n');
|
||||
assert(fs.existsSync(state.retired_runtime+'/phase8-after-only.txt'));
|
||||
assert.equal(verifySnapshot(state.backup_snapshot).source_release.name,'minecraft-lab-neoforge-spike-0.0.4');
|
||||
assert.equal(fs.readFileSync(root+'/.env','utf8').includes('MC_BIND_ADDRESS=0.0.0.0'),true);
|
||||
const container=JSON.parse(execFileSync('docker',['inspect','minecraft-lab-phase7-minecraft-1']))[0];
|
||||
assert.equal(container.State.Health.Status,'healthy');assert.equal(container.NetworkSettings.Ports['25565/tcp'][0].HostIp,'0.0.0.0');
|
||||
assert(!fs.existsSync(root+'/.mcpack-runtime.lock'));
|
||||
console.log('Snapshot rollback: all runtime restored, subsequent progress removed only from active runtime, retired progress and current backup retained; source release, host settings, LAN bind and health verified.');
|
||||
JS
|
||||
node scripts/query-minecraft.mjs 127.0.0.1 25566 > "$check/evidence/restored-status.json"
|
||||
MC_ROOT="$check/host" MC_RELEASE_DIR="$check/host/releases/minecraft-lab-neoforge-spike-0.0.4" scripts/server.sh down
|
||||
scripts/spike-server.sh ps > "$check/evidence/primary-server-status.txt"
|
||||
printf 'Phase 8 real SSH/Docker rollback passed. Evidence: %s\n' "$check/evidence"
|
||||
Reference in New Issue
Block a user