Eliminate USB requirement for WinPE PXE boot, add image upload script
- Add startnet.cmd: FlatSetupLoader.exe + Boot.tag/Media.tag eliminates physical USB requirement for WinPE PXE deployment - Add Upload-Image.ps1: PowerShell script to robocopy MCL cached images to PXE server via SMB (Deploy, Tools, Sources) - Add gea-shopfloor-mce image type across playbook, webapp, startnet - Change webapp import to move (not copy) for upload sources to save disk - Add Samba symlink following config for shared image directories - Add Media.tag creation task in playbook for drive detection - Update prepare-boot-tools.sh with Blancco config/initramfs patching - Add grub-efi-amd64-bin to download-packages.sh Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -105,7 +105,10 @@ if [ -n "$BLANCCO_ISO" ] && [ -f "$BLANCCO_ISO" ]; then
|
||||
cp "$TMPDIR/arch/x86_64/airootfs.sfs" "$OUT_DIR/blancco/arch/x86_64/"
|
||||
echo " Extracted Blancco boot files."
|
||||
|
||||
# Patch config.img to auto-save reports to PXE server Samba share
|
||||
# --- Patch config.img (size-preserving) ---
|
||||
# config.img is a CPIO archive containing preferences.xml (padded to 32768 bytes).
|
||||
# The CPIO itself must remain exactly 194560 bytes (380 x 512-byte blocks).
|
||||
# We use Python for byte-level replacement to preserve exact sizes.
|
||||
if [ -f "$OUT_DIR/blancco/config.img" ]; then
|
||||
echo " Patching config.img for network report storage..."
|
||||
CFGTMP=$(mktemp -d)
|
||||
@@ -113,19 +116,149 @@ if [ -n "$BLANCCO_ISO" ] && [ -f "$BLANCCO_ISO" ]; then
|
||||
cpio -id < "$OUT_DIR/blancco/config.img" 2>/dev/null
|
||||
|
||||
if [ -f "$CFGTMP/preferences.xml" ]; then
|
||||
# Set network share to PXE server's blancco-reports Samba share
|
||||
sed -i 's|<hostname></hostname>|<hostname>10.9.100.1</hostname>|' "$CFGTMP/preferences.xml"
|
||||
sed -i 's|<path></path>|<path>blancco-reports</path>|' "$CFGTMP/preferences.xml"
|
||||
# Enable auto-backup of reports to the network share
|
||||
sed -i 's|<auto_backup>false</auto_backup>|<auto_backup>true</auto_backup>|' "$CFGTMP/preferences.xml"
|
||||
ORIG_SIZE=$(stat -c%s "$CFGTMP/preferences.xml")
|
||||
|
||||
# Repack config.img
|
||||
ls -1 | cpio -o -H newc > "$OUT_DIR/blancco/config.img" 2>/dev/null
|
||||
echo " Reports will auto-save to \\\\10.9.100.1\\blancco-reports"
|
||||
python3 << 'PYEOF'
|
||||
import sys
|
||||
|
||||
with open("preferences.xml", "rb") as f:
|
||||
data = f.read()
|
||||
|
||||
orig_size = len(data)
|
||||
|
||||
# Set SMB share credentials and path
|
||||
data = data.replace(
|
||||
b'<username encrypted="false"></username>',
|
||||
b'<username encrypted="false">blancco</username>'
|
||||
)
|
||||
data = data.replace(
|
||||
b'<password encrypted="false"></password>',
|
||||
b'<password encrypted="false">blancco</password>'
|
||||
)
|
||||
data = data.replace(
|
||||
b'<hostname></hostname>',
|
||||
b'<hostname>10.9.100.1</hostname>'
|
||||
)
|
||||
data = data.replace(
|
||||
b'<path></path>',
|
||||
b'<path>blancco-reports</path>'
|
||||
)
|
||||
|
||||
# Enable auto-backup
|
||||
data = data.replace(
|
||||
b'<auto_backup>false</auto_backup>',
|
||||
b'<auto_backup>true</auto_backup>'
|
||||
)
|
||||
|
||||
# Enable bootable report
|
||||
data = data.replace(
|
||||
b'<bootable_report>\n <enabled>false</enabled>\n </bootable_report>',
|
||||
b'<bootable_report>\n <enabled>true</enabled>\n </bootable_report>'
|
||||
)
|
||||
|
||||
# Maintain exact file size by trimming trailing padding/whitespace
|
||||
diff = len(data) - orig_size
|
||||
if diff > 0:
|
||||
# The file has trailing whitespace/padding before the final XML closing tags
|
||||
# Trim from the padding area (spaces before closing comment or end of file)
|
||||
end_pos = data.rfind(b'<!-- ')
|
||||
if end_pos > 0:
|
||||
comment_end = data.find(b' -->', end_pos)
|
||||
if comment_end > 0:
|
||||
data = data[:comment_end - diff] + data[comment_end:]
|
||||
if len(data) > orig_size:
|
||||
# Fallback: trim trailing whitespace
|
||||
data = data.rstrip()
|
||||
data = data + b'\n' * (orig_size - len(data))
|
||||
elif diff < 0:
|
||||
# Pad with spaces to maintain size
|
||||
data = data[:-1] + b' ' * (-diff) + data[-1:]
|
||||
|
||||
if len(data) != orig_size:
|
||||
print(f" WARNING: Size mismatch ({len(data)} vs {orig_size}), padding to match")
|
||||
if len(data) > orig_size:
|
||||
data = data[:orig_size]
|
||||
else:
|
||||
data = data + b'\x00' * (orig_size - len(data))
|
||||
|
||||
with open("preferences.xml", "wb") as f:
|
||||
f.write(data)
|
||||
|
||||
print(f" preferences.xml: {orig_size} bytes (preserved)")
|
||||
PYEOF
|
||||
|
||||
# Repack CPIO with exact 512-byte block alignment (194560 bytes)
|
||||
ls -1 "$CFGTMP" | (cd "$CFGTMP" && cpio -o -H newc 2>/dev/null) | \
|
||||
dd bs=512 conv=sync 2>/dev/null > "$OUT_DIR/blancco/config.img"
|
||||
echo " Reports: SMB blancco@10.9.100.1/blancco-reports, bootable report enabled"
|
||||
fi
|
||||
cd "$SCRIPT_DIR"
|
||||
rm -rf "$CFGTMP"
|
||||
fi
|
||||
|
||||
# --- Patch initramfs to keep network interfaces up after copytoram ---
|
||||
# Blancco uses copytoram=y which triggers archiso_pxe_common latehook to
|
||||
# flush all network interfaces. Binary-patch the check from "y" to "N" so
|
||||
# the condition never matches. IMPORTANT: full extract/repack BREAKS booting.
|
||||
echo " Patching initramfs to preserve network after copytoram..."
|
||||
python3 << PYEOF
|
||||
import lzma, sys, os
|
||||
|
||||
initramfs = "$OUT_DIR/blancco/initramfs-bde-linux.img"
|
||||
|
||||
with open(initramfs, "rb") as f:
|
||||
compressed = f.read()
|
||||
|
||||
# Decompress XZ stream
|
||||
try:
|
||||
raw = lzma.decompress(compressed)
|
||||
except lzma.LZMAError:
|
||||
print(" WARNING: Could not decompress initramfs (not XZ?), skipping patch")
|
||||
sys.exit(0)
|
||||
|
||||
# Binary patch: change the copytoram check from "y" to "N"
|
||||
old = b'"y" ]; then\n for curif in /sys/class/net'
|
||||
new = b'"N" ]; then\n for curif in /sys/class/net'
|
||||
|
||||
if old not in raw:
|
||||
# Try alternate pattern with different whitespace
|
||||
old = b'"\${copytoram}" = "y"'
|
||||
new = b'"\${copytoram}" = "N"'
|
||||
|
||||
if old in raw:
|
||||
raw = raw.replace(old, new, 1)
|
||||
# Recompress with same XZ settings as archiso
|
||||
recompressed = lzma.compress(raw, format=lzma.FORMAT_XZ,
|
||||
check=lzma.CHECK_CRC32,
|
||||
preset=6)
|
||||
with open(initramfs, "wb") as f:
|
||||
f.write(recompressed)
|
||||
print(" initramfs patched: copytoram network flush disabled")
|
||||
else:
|
||||
print(" WARNING: copytoram pattern not found in initramfs, skipping patch")
|
||||
PYEOF
|
||||
|
||||
# --- Build GRUB EFI binary for Blancco chainload ---
|
||||
# Broadcom iPXE can't pass initrd to Linux kernels in UEFI mode.
|
||||
# Solution: iPXE chains to grubx64.efi, which loads kernel+initrd via TFTP.
|
||||
GRUB_CFG="$SCRIPT_DIR/boot-tools/blancco/grub-blancco.cfg"
|
||||
if [ -f "$GRUB_CFG" ]; then
|
||||
if command -v grub-mkstandalone &>/dev/null; then
|
||||
echo " Building grubx64.efi (GRUB chainload for Blancco)..."
|
||||
grub-mkstandalone \
|
||||
--format=x86_64-efi \
|
||||
--output="$OUT_DIR/blancco/grubx64.efi" \
|
||||
--modules="linux normal echo net efinet tftp chain sleep" \
|
||||
"boot/grub/grub.cfg=$GRUB_CFG" 2>/dev/null
|
||||
echo " Built grubx64.efi ($(du -h "$OUT_DIR/blancco/grubx64.efi" | cut -f1))"
|
||||
else
|
||||
echo " WARNING: grub-mkstandalone not found. Install grub-efi-amd64-bin:"
|
||||
echo " sudo apt install grub-efi-amd64-bin grub-common"
|
||||
echo " Then re-run this script to build grubx64.efi"
|
||||
fi
|
||||
else
|
||||
echo " WARNING: grub-blancco.cfg not found at $GRUB_CFG"
|
||||
fi
|
||||
else
|
||||
echo " Could not extract boot files from ISO."
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user