-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild-agentbox-iso.sh
More file actions
executable file
·181 lines (167 loc) · 8.45 KB
/
Copy pathbuild-agentbox-iso.sh
File metadata and controls
executable file
·181 lines (167 loc) · 8.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#!/usr/bin/env bash
# build-agentbox-iso.sh — assemble a per-OS agentbox ISO from THIS repo tree.
#
# Replaces the hand-assembled "bring the files here + xorriso" step the per-OS READMEs
# used to spell out (win10 step 0, win2000/win98 "Build the agentbox ISO"). Given an OS,
# it stages the repo-tracked agent payload — rvmc_agent.py (the right fork), rvmc-input.au3,
# the OS installer (install-agentbox.cmd/.bat) and, where the fork has one, rvmc-agent-task.xml
# (+ win98's rvmc-run.reg / rvmc-start.bat) — writes a VERSION stamp that records exactly which
# agent got baked, and burns it with the SAME tool the READMEs used (xorriso -as mkisofs).
#
# The large non-git binaries (the Python installer, AutoIt, offline wheels, the portable
# Python25/ tree, the vendored simplejson/ package) are NOT in the repo. Point --stage at a
# directory holding them and they are folded onto the ISO; without it the script still builds
# a repo-only ISO (useful for wiring/inspection) but warns that it will not INSTALL as-is.
#
# ./build-agentbox-iso.sh win10 --stage ~/vmctl/state/win10-build
# ./build-agentbox-iso.sh win2000 -s ~/vmctl/state/win2000-build -o /tmp/agentbox-win2000.iso
#
# The ISO is drive-letter-agnostic: every installer scans D:.. for rvmc_agent.py. After it is
# built, add the CD to the OS's build VM per that OS's README and run the installer in-guest.
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
PROG="$(basename "$0")"
usage() {
cat >&2 <<EOF
usage: $PROG <os> [--stage <dir>] [--out <iso>] [--keep]
<os> one of: win10 win11 win7 win7-fresh win2000 win98
--stage, -s directory holding the non-git binaries for this OS (optional)
--out, -o output ISO path (default: ~/vmctl/state/isos/agentbox-<os>.iso;
win7-fresh defaults to agentbox.iso — see its case)
--keep, -k keep the temp staging dir (debug)
EOF
exit 2
}
OS=""; STAGE_BIN=""; OUT=""; KEEP=0
while [ $# -gt 0 ]; do
case "$1" in
-s|--stage) STAGE_BIN="${2:?--stage needs a dir}"; shift 2 ;;
-o|--out) OUT="${2:?--out needs a path}"; shift 2 ;;
-k|--keep) KEEP=1; shift ;;
-h|--help) usage ;;
-*) echo "$PROG: unknown option $1" >&2; usage ;;
*) if [ -z "$OS" ]; then OS="$1"; else echo "$PROG: unexpected arg $1" >&2; usage; fi; shift ;;
esac
done
[ -n "$OS" ] || usage
# ---- per-OS payload -------------------------------------------------------------------------
# AGENT_SRC which rvmc_agent.py to bake (root py3.4 main, or the py2 fork for 2000/98)
# LABEL ISO volume id (matches the per-OS README)
# REPO_FILES repo-tracked files copied to the ISO ROOT verbatim (installer, au3, task xml, ...)
# EXT_BINS non-git payload names expected under --stage (files or dirs); warn if absent
# OUT_DEFAULT lets a fork override the default output name (win7-fresh must be agentbox.iso, the
# name its build XML references); the others fall through to agentbox-<os>.iso below.
REPO_FILES=(); EXT_BINS=(); OUT_DEFAULT=""
case "$OS" in
win10)
AGENT_SRC="$HERE/rvmc_agent.py"; LABEL="AGENTBOX10"
REPO_FILES=("$HERE/rvmc-input.au3" "$HERE/win10/install-agentbox.cmd" "$HERE/win10/rvmc-agent-task.xml")
EXT_BINS=("python-3.12-amd64.exe")
;;
win7-fresh)
# The conservation-grade win7 golden (catalog id win7-fresh). CRITICAL: this agentbox ISO is
# PAYLOAD-ONLY — it deliberately carries NO install-agentbox.cmd. win7-fresh's installer rides
# a SEPARATE unattend ISO (autounattend.xml + install-agentbox.cmd, poll-armed), and the
# autounattend runs install-agentbox.cmd from EVERY CD that has one — so a copy here would
# CLOBBER the unattend CD's --poll Run key (the exact fleet failure mode found in the first
# rebake). Output is agentbox.iso (the name win7-fresh-build.xml references), NOT agentbox-<os>.
AGENT_SRC="$HERE/rvmc_agent.py"; LABEL="AGENTBOX7"
REPO_FILES=("$HERE/rvmc-input.au3")
EXT_BINS=("python-34.msi" "autoit-setup.exe" "wheels")
OUT_DEFAULT="$HOME/vmctl/state/isos/agentbox.iso"
;;
win11)
AGENT_SRC="$HERE/rvmc_agent.py"; LABEL="AGENTBOX11"
REPO_FILES=("$HERE/rvmc-input.au3" "$HERE/win11/install-agentbox.cmd" "$HERE/win11/rvmc-agent-task.xml")
EXT_BINS=("python-3.12-amd64.exe")
;;
win81)
AGENT_SRC="$HERE/rvmc_agent.py"; LABEL="AGENTBOX81"
REPO_FILES=("$HERE/rvmc-input.au3" "$HERE/win81/install-agentbox.cmd" "$HERE/win81/rvmc-agent-task.xml")
# KB2999226-x64.msu is REQUIRED on stock 8.1: without the Universal CRT update, the Python
# 3.12 installer fails 0x80070643. install-agentbox.cmd installs it first.
EXT_BINS=("python-3.12-amd64.exe" "KB2999226-x64.msu")
;;
win7)
AGENT_SRC="$HERE/rvmc_agent.py"; LABEL="AGENTBOX7"
REPO_FILES=("$HERE/rvmc-input.au3" "$HERE/win7/install-agentbox.cmd")
EXT_BINS=("python-34.msi" "autoit-setup.exe" "wheels")
;;
win2000)
AGENT_SRC="$HERE/win2000/rvmc_agent.py"; LABEL="AGENTBOX"
REPO_FILES=("$HERE/rvmc-input.au3" "$HERE/win2000/install-agentbox.cmd")
EXT_BINS=("python-27.msi" "autoit-setup.exe")
;;
win98)
AGENT_SRC="$HERE/win98/rvmc_agent.py"; LABEL="AGENTBOX98"
REPO_FILES=("$HERE/rvmc-input.au3" "$HERE/win98/install-agentbox.bat" \
"$HERE/win98/rvmc-run.reg" "$HERE/win98/rvmc-start.bat")
EXT_BINS=("Python25" "simplejson")
;;
*)
echo "$PROG: unknown OS '$OS' (want win10|win11|win7|win7-fresh|win2000|win98)" >&2; exit 2 ;;
esac
: "${OUT_DEFAULT:=$HOME/vmctl/state/isos/agentbox-${OS}.iso}"
: "${OUT:=$OUT_DEFAULT}"
# Safety net for the separate-unattend-ISO forks (win7-fresh): the autounattend executes
# install-agentbox.cmd from EVERY CD, so this payload-only agentbox ISO must NOT carry one.
case "$OS" in
win7-fresh)
for f in "${REPO_FILES[@]}"; do
case "$f" in
*/install-agentbox.cmd|*/install-agentbox.bat)
echo "$PROG: refusing to bake $OS: install-agentbox.* on a payload-only agentbox ISO would clobber the unattend CD's poll-armed Run key" >&2
exit 1 ;;
esac
done
;;
esac
[ -f "$AGENT_SRC" ] || { echo "$PROG: agent source missing: $AGENT_SRC" >&2; exit 1; }
# ---- pin the baked agent version --------------------------------------------------------------
AGENT_VERSION="$(sed -n 's/^AGENT_VERSION = "\([^"]*\)".*/\1/p' "$AGENT_SRC" | head -1)"
RVMC_PROTOCOL="$(sed -n 's/^RVMC_PROTOCOL = \([0-9][0-9]*\).*/\1/p' "$AGENT_SRC" | head -1)"
[ -n "$AGENT_VERSION" ] || { echo "$PROG: could not read AGENT_VERSION from $AGENT_SRC" >&2; exit 1; }
GIT_SHA="$(git -C "$HERE" rev-parse --short HEAD 2>/dev/null || echo unknown)"
BUILT_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# ---- stage ------------------------------------------------------------------------------------
STAGE="$(mktemp -d "${TMPDIR:-/tmp}/agentbox-${OS}.XXXXXX")"
cleanup() { [ "$KEEP" -eq 1 ] || rm -rf "$STAGE"; }
trap cleanup EXIT
# the agent always lands at the ISO root as rvmc_agent.py (the name every installer greps for)
cp -f "$AGENT_SRC" "$STAGE/rvmc_agent.py"
for f in "${REPO_FILES[@]}"; do
[ -f "$f" ] || { echo "$PROG: repo file missing: $f" >&2; exit 1; }
cp -f "$f" "$STAGE/"
done
# fold in the non-git binaries from --stage (files or whole dirs); warn on anything missing
missing=0
for b in "${EXT_BINS[@]}"; do
if [ -n "$STAGE_BIN" ] && [ -e "$STAGE_BIN/$b" ]; then
cp -a "$STAGE_BIN/$b" "$STAGE/"
else
echo "$PROG: WARNING: binary payload '$b' not staged (looked in '${STAGE_BIN:-<none>}')" >&2
missing=1
fi
done
[ "$missing" -eq 0 ] || echo "$PROG: WARNING: ISO is repo-only; add the missing payload above before it can INSTALL." >&2
# ---- VERSION stamp (a built golden records which agent it baked) -------------------------------
cat > "$STAGE/VERSION" <<EOF
# rvmc agentbox — baked by $PROG
os=$OS
agent_version=$AGENT_VERSION
rvmc_protocol=${RVMC_PROTOCOL:-unknown}
agent_source=$(python3 - "$HERE" "$AGENT_SRC" <<'PY' 2>/dev/null || basename "$AGENT_SRC"
import os,sys; print(os.path.relpath(sys.argv[2], sys.argv[1]))
PY
)
label=$LABEL
built_from_commit=$GIT_SHA
built_at=$BUILT_AT
EOF
# ---- burn -------------------------------------------------------------------------------------
mkdir -p "$(dirname "$OUT")"
rm -f "$OUT"
# `.` maps the staging dir's CONTENTS to the ISO root, preserving subdirs (Python25/, simplejson/)
# as directories — the flatten trap the win98 README warns about when dirs are passed positionally.
( cd "$STAGE" && xorriso -as mkisofs -J -R -V "$LABEL" -o "$OUT" . )
echo "built $OUT (label $LABEL, agent $AGENT_VERSION, protocol ${RVMC_PROTOCOL:-?}, commit $GIT_SHA)"