Add ARCHITECTURE.md, SITE-CUSTOMIZATION.md, mirror-from-gold.sh

Two new docs cover what the system is (boot chain, services, shares,
enrollment layout, data flow) and what to change per site (every
hardcoded value, where it lives, secrets handling).

scripts/mirror-from-gold.sh replicates content from an existing PXE
server (Operating Systems, drivers, packages, custom installers, BIOS,
PCDMIS, Blancco custom image, site-config) onto a freshly-installed PXE
server. Translates the legacy flat enrollment layout on the source into
the reorganized taxonomy (ppkgs/, pre-install/installers/, installers-
post/cmm/, blancco/, config/) on the destination. Tolerates rsync
exit 23 (permission-denied subdirs like the OpenText W10shortcuts dir
that is pxe-upload-group-only on legacy servers).
This commit is contained in:
cproudlock
2026-04-14 17:56:46 -04:00
parent d6776f7c7f
commit adef507084
3 changed files with 586 additions and 0 deletions

184
scripts/mirror-from-gold.sh Executable file
View File

@@ -0,0 +1,184 @@
#!/bin/bash
#
# mirror-from-gold.sh - Replicate content from an existing PXE server (GOLD)
# onto a freshly-installed PXE server.
#
# Run this ON THE NEW PXE SERVER, pointing at the GOLD server's IP.
# It pulls Operating Systems, drivers, packages, custom installers, and
# Blancco assets that are NOT bundled on the USB installer.
#
# Source paths on GOLD use the legacy flat enrollment layout. Destination
# paths on the new server use the reorganized layout (ppkgs/, scripts/,
# config/, pre-install/, installers-post/, blancco/, etc).
#
# Usage:
# sudo ./mirror-from-gold.sh <GOLD_IP> [options]
#
# Options:
# --skip-drivers Do not mirror Dell driver tree (saves ~178G).
# --skip-dell10 Do not mirror Dell_10 drivers (saves ~179G).
# --skip-latitude Do not mirror Latitude drivers (saves ~48G).
# --skip-os Do not mirror Operating Systems (saves ~22G).
# --dry-run Show what would transfer without doing it.
#
# Prereqs:
# - GOLD's pxe user accepts the SSH key this script generates.
# - GOLD's filesystem is world-readable for the paths involved
# (it is, by default).
# Note: not using `set -e`. rsync legitimately exits non-zero (e.g. 23
# "some files/attrs were not transferred") when source dirs have files
# the rsync user cannot read (the OpenText W10shortcuts dir on GOLD is
# pxe-upload-group-only). We log and continue instead of aborting.
set -uo pipefail
GOLD="${1:-}"
shift || true
if [ -z "$GOLD" ]; then
echo "Usage: $0 <GOLD_IP> [--skip-drivers|--skip-dell10|--skip-latitude|--skip-os|--dry-run]"
exit 1
fi
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: must run as root (sudo)."
exit 1
fi
SKIP_DRIVERS=0
SKIP_DELL10=0
SKIP_LATITUDE=0
SKIP_OS=0
DRY_RUN=""
while [ $# -gt 0 ]; do
case "$1" in
--skip-drivers) SKIP_DRIVERS=1 ;;
--skip-dell10) SKIP_DELL10=1 ;;
--skip-latitude) SKIP_LATITUDE=1 ;;
--skip-os) SKIP_OS=1 ;;
--dry-run) DRY_RUN="--dry-run" ;;
*) echo "Unknown option: $1"; exit 1 ;;
esac
shift
done
KEY=/root/.ssh/pxe-mirror-key
if [ ! -f "$KEY" ]; then
echo "[setup] Generating mirror SSH key at $KEY"
mkdir -p /root/.ssh && chmod 700 /root/.ssh
ssh-keygen -t ed25519 -N '' -f "$KEY" -q
echo
echo "Copy the following public key into pxe@$GOLD's ~/.ssh/authorized_keys"
echo "(easiest: ssh pxe@$GOLD 'mkdir -p ~/.ssh && chmod 700 ~/.ssh' and then"
echo " scp '$KEY.pub' pxe@$GOLD:~/.ssh/authorized_keys, then chmod 600 there)"
echo
cat "$KEY.pub"
echo
read -rp "Press enter once the key is installed on GOLD..."
fi
RSH="ssh -i $KEY -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
# Quick connectivity check
echo "[check] Testing key-based SSH to pxe@$GOLD..."
$RSH "pxe@$GOLD" "whoami" >/dev/null || {
echo "ERROR: SSH to pxe@$GOLD failed. Install $KEY.pub on GOLD first."
exit 1
}
echo " OK"
mirror() {
local label="$1"
local src="$2"
local dest="$3"
shift 3
echo
echo "==== $label ===="
echo " src: pxe@$GOLD:$src"
echo " dest: $dest"
mkdir -p "$dest"
rsync -aHl --info=progress2 --no-inc-recursive $DRY_RUN "$@" \
-e "$RSH" \
"pxe@$GOLD:$src" "$dest" || \
echo " WARNING: rsync exited rc=$? (likely a permissions issue on source); continuing"
}
# ---------- Shared imaging content (winpeapps/_shared) ----------
DRIVER_EXCLUDES=()
[ "$SKIP_DELL10" = "1" ] && DRIVER_EXCLUDES+=(--exclude='Dell_10')
[ "$SKIP_LATITUDE" = "1" ] && DRIVER_EXCLUDES+=(--exclude='Latitude')
if [ "$SKIP_OS" = "0" ]; then
mirror "Operating Systems (gea-Operating Systems)" \
"/srv/samba/winpeapps/_shared/gea-Operating Systems/" \
"/srv/samba/winpeapps/_shared/gea-Operating Systems/"
fi
mirror "Packages (gea-Packages)" \
"/srv/samba/winpeapps/_shared/gea-Packages/" \
"/srv/samba/winpeapps/_shared/gea-Packages/"
mirror "Sources (gea-Sources)" \
"/srv/samba/winpeapps/_shared/gea-Sources/" \
"/srv/samba/winpeapps/_shared/gea-Sources/"
if [ "$SKIP_DRIVERS" = "0" ]; then
mirror "Out-of-box Drivers" \
"/srv/samba/winpeapps/_shared/Out-of-box Drivers/" \
"/srv/samba/winpeapps/_shared/Out-of-box Drivers/" \
"${DRIVER_EXCLUDES[@]}"
fi
# ---------- Per-image-type Deploy/ trees (mostly symlinks to _shared) ----------
for img in gea-standard gea-engineer gea-shopfloor; do
mirror "Image dir: $img" \
"/srv/samba/winpeapps/$img/" \
"/srv/samba/winpeapps/$img/" \
--exclude=backup --exclude=logs --exclude='New folder' --exclude=ProMax
done
# ---------- Enrollment-share content with path translation (flat -> taxonomy) ----------
# Preinstall installers (adobe, opentext, drivers, display, vcredist, UDC, Oracle, etc.)
mirror "Pre-install installers" \
"/srv/samba/enrollment/preinstall/installers/" \
"/srv/samba/enrollment/pre-install/installers/" \
--exclude='*.old'
# CMM installers (PCDMIS) - flat dir on GOLD becomes installers-post/cmm/
mirror "CMM installers (PCDMIS)" \
"/srv/samba/enrollment/cmm-installers/" \
"/srv/samba/enrollment/installers-post/cmm/"
# Blancco custom image - flat file on GOLD becomes blancco/<file>
echo
echo "==== Blancco custom image ===="
mkdir -p /srv/samba/enrollment/blancco
rsync -aHl --info=progress2 $DRY_RUN \
-e "$RSH" \
"pxe@$GOLD:/srv/samba/enrollment/BDE715_GEAE_INTERNET.img.gz" \
"/srv/samba/enrollment/blancco/"
# Site-specific config file
echo
echo "==== Site config (site-config.json) ===="
echo " Verifying GOLD's copy is more recent than playbook default..."
rsync -avhl $DRY_RUN -e "$RSH" \
"pxe@$GOLD:/srv/samba/enrollment/site-config.json" \
"/srv/samba/enrollment/config/site-config.json" 2>/dev/null || \
echo " (no site-config.json at flat path on GOLD - skipping)"
# Permissions: anything we just created should be readable by the share
chown -R root:root /srv/samba/enrollment /srv/samba/winpeapps
find /srv/samba/enrollment /srv/samba/winpeapps -type d -exec chmod 0755 {} \; 2>/dev/null || true
find /srv/samba/enrollment /srv/samba/winpeapps -type f -exec chmod 0644 {} \; 2>/dev/null || true
find /srv/samba/enrollment/ppkgs -name '*.ppkg' -exec chmod 0755 {} \; 2>/dev/null || true
echo
echo "============================================"
echo "Mirror complete. Verify with:"
echo " du -sh /srv/samba/winpeapps/_shared/*"
echo " du -sh /srv/samba/enrollment/*"
echo " df -h /srv"
echo "============================================"