Clonezilla back up / restore by machine number

Boot menu: "Clonezilla: back up this PC" and "restore this PC" ask for the
machine number and boot Clonezilla (64-bit with Debian shim, or 32-bit
i686 by cpuid) with ocs_repository=smb3://clonezilla:<pw>@server/clonezilla/,
ocs_prerun fetching clonezilla-scripts/pxe-cz.sh and ocs_live_run running
it. The script validates the machine number, saves
<machine>-<YYYY-MM-DD-HHMM> (server time), writes pxe-meta.txt, runs
ocs-chkimg, and restores only that machine's images with -k1 -r after a
typed YES. The old entry is "Clonezilla: manual".

Playbook: clonezilla Samba user for the [clonezilla] share only, password
from clonezilla_smb_password (validated, filled into the menu
placeholder), scripts installed to the web root.

Webapp: Clonezilla backups page lists image folders and zips grouped by
machine number with serial/model/version/check, serial mismatch flag,
delete, move to another machine, streamed tar download, disk space bar
and an explicit keep-last-N retention with preview. Tests and a VM test
plan added.
This commit is contained in:
cproudlock
2026-10-15 15:26:30 -04:00
parent dde1aacccb
commit 9d56a5369e
11 changed files with 1991 additions and 67 deletions

View File

@@ -0,0 +1,473 @@
#!/bin/bash
# PXE Clonezilla: back up or restore a PC by its machine number.
#
# The iPXE menu (GetPxeScript.aspx, "Clonezilla: back up / restore this
# PC") boots Clonezilla live with:
# ocs_prerun="wget ... -O /tmp/pxe-cz.sh http://<server>/clonezilla-scripts/pxe-cz.sh"
# ocs_repository="smb3://clonezilla:<password>@<server>/clonezilla/"
# ocs_live_run="bash /tmp/pxe-cz.sh"
# pxe_cz_mode=save|restore pxe_machine=<typed text> pxe_end=1
# Clonezilla runs the prerun (this download), mounts the repository on
# /home/partimag, then runs this script as root on the console.
#
# Images are named <machine>-<YYYY-MM-DD-HHMM> (server time, site zone),
# with pxe-meta.txt (machine, serial, model, disk, date, Clonezilla
# version, 32/64-bit, check result) next to Clonezilla's own files. The
# PXE webapp (Tools > Clonezilla backups) reads both.
#
# Runs under Clonezilla live's bash (3.3.3 amd64 and 3.2.0-5 i686, both
# Debian with coreutils, util-linux, dmidecode, wget). Plain ASCII only.
set -u
# PXE_CZ_* overrides exist only for testing this script off Clonezilla.
OCSROOT="${PXE_CZ_OCSROOT:-/home/partimag}"
CMDLINE_FILE="${PXE_CZ_CMDLINE:-/proc/cmdline}"
SYS_BLOCK="${PXE_CZ_SYS_BLOCK:-/sys/block}"
SITE_TZ="America/New_York"
SERVER="$(sed -n 's/.*ocs_prerun="[^"]*http:\/\/\([^/":]*\).*/\1/p' "$CMDLINE_FILE" 2>/dev/null)"
[ -n "$SERVER" ] || SERVER=172.16.9.1
CMDLINE=" $(cat "$CMDLINE_FILE" 2>/dev/null) "
# --- output helpers -------------------------------------------------------
line() { echo "======================================================================"; }
banner() {
echo
line
for l in "$@"; do echo " $l"; done
line
echo
}
# Ask what to do at the end. Success: power off after 60 s unless a key is
# pressed. Failure: wait, the operator has to read the message.
finish() {
local ok="$1" ans
sync
while true; do
echo
echo " [Enter] power off r = reboot s = shell (type exit to come back)"
if [ "$ok" = "yes" ]; then
echo -n " Powering off in 60 seconds... "
if ! read -r -t 60 ans; then ans=""; echo; fi
else
echo -n " Choice: "
read -r ans || ans=""
fi
case "$ans" in
r|R) umount "$OCSROOT" 2>/dev/null; sync; reboot; sleep 30 ;;
s|S) bash -i ;;
*) umount "$OCSROOT" 2>/dev/null; sync; poweroff; sleep 30 ;;
esac
done
}
fail() {
banner "FAILED: $1" "${@:2}"
finish no
exit 1
}
# --- machine number -------------------------------------------------------
# Letters, digits and dash, starting with a letter or digit, up to 32.
valid_machine() {
[[ "$1" =~ ^[A-Za-z0-9][A-Za-z0-9-]{0,31}$ ]]
}
# The text typed at the iPXE prompt sits between pxe_machine= and the
# pxe_end=1 sentinel, so a typed space shows up here and is rejected
# instead of being split into another kernel parameter.
machine_from_cmdline() {
local rest
case "$CMDLINE" in
*" pxe_machine="*" pxe_end=1 "*) ;;
*) echo ""; return ;;
esac
rest="${CMDLINE#* pxe_machine=}"
echo "${rest%% pxe_end=1 *}"
}
# Sets MACHINE (upper case). Not run in $(...): finish() reads the
# keyboard and must write to the console.
get_machine() {
local m
m="$(machine_from_cmdline)"
if [ -z "$m" ] || ! valid_machine "$m"; then
if [ -n "$m" ]; then
banner "The machine number typed at the boot menu is not valid:" \
" [$m]" "Use letters, digits and dash only (for example 6501 or WJ-6501)."
else
banner "No machine number was given at the boot menu."
fi
while true; do
echo -n " Machine number (letters, digits, dash; empty = stop): "
read -r m || m=""
[ -n "$m" ] || finish no
valid_machine "$m" && break
echo " [$m] is not a valid machine number: use letters, digits and dash only."
done
fi
MACHINE="$(echo "$m" | tr '[:lower:]' '[:upper:]')"
}
# --- time -----------------------------------------------------------------
# The PC's clock is often wrong (dead CMOS battery on old PCs, local time
# on Windows PCs), so take the time from the PXE server's HTTP Date header
# and set the live system clock from it. Falls back to the PC clock.
TIME_SOURCE="pc-clock"
sync_clock() {
local hdr epoch
hdr="$(wget -q -S --spider -T 10 -t 2 "http://$SERVER/clonezilla-scripts/pxe-cz.sh" 2>&1 \
| sed -n 's/^ *Date: *//p' | head -1)"
[ -n "$hdr" ] || return 0
epoch="$(date -u -d "$hdr" +%s 2>/dev/null)" || return 0
[ -n "$epoch" ] || return 0
date -u -s "@$epoch" >/dev/null 2>&1 && TIME_SOURCE="pxe-server"
}
site_date() {
if [ -e "/usr/share/zoneinfo/$SITE_TZ" ]; then
TZ="$SITE_TZ" date "$@"
else
date "$@"
fi
}
# --- hardware -------------------------------------------------------------
dmi() {
local v
v="$(dmidecode -s "$1" 2>/dev/null | grep -v '^#' | head -1 | tr -d '\r' | sed 's/^ *//; s/ *$//')"
echo "$v"
}
# Whole disks a backup can come from or a restore can go to: no CD, loop,
# RAM, zram, device-mapper, md, eMMC boot areas, or empty card readers.
list_disks() {
local d n size
for d in "$SYS_BLOCK"/*; do
n="${d##*/}"
case "$n" in
loop*|sr*|ram*|zram*|dm-*|md*|fd*|nbd*|*boot[0-9]|*rpmb) continue ;;
esac
size="$(cat "$d/size" 2>/dev/null)"
[ -n "$size" ] && [ "$size" -gt 0 ] 2>/dev/null || continue
echo "$n"
done
}
disk_bytes() { echo $(( $(cat "$SYS_BLOCK/$1/size" 2>/dev/null || echo 0) * 512 )); }
disk_model() {
local m
m="$(cat "$SYS_BLOCK/$1/device/model" 2>/dev/null | sed 's/^ *//; s/ *$//')"
[ -n "$m" ] || m="$(lsblk -dn -o MODEL "/dev/$1" 2>/dev/null | sed 's/^ *//; s/ *$//')"
[ -n "$m" ] || m="unknown model"
echo "$m"
}
disk_tran() { lsblk -dn -o TRAN "/dev/$1" 2>/dev/null | sed 's/ //g'; }
human() {
local b="$1"
awk -v b="$b" 'BEGIN { if (b >= 1e12) printf "%.1f TB", b/1e12; else printf "%.0f GB", b/1e9 }'
}
describe_disk() {
local n="$1" t
t="$(disk_tran "$n")"
echo "/dev/$n $(human "$(disk_bytes "$n")") $(disk_model "$n")${t:+ ($t)}"
}
# pick_disk "prompt" -> disk name on stdout. One disk: that one.
pick_disk() {
local prompt="$1" disks n i ans
mapfile -t disks < <(list_disks)
if [ "${#disks[@]}" -eq 0 ]; then
echo ""
return
fi
if [ "${#disks[@]}" -eq 1 ]; then
echo "${disks[0]}"
return
fi
while true; do
{
echo
echo " $prompt"
i=1
for n in "${disks[@]}"; do
echo " $i) $(describe_disk "$n")"
i=$((i + 1))
done
echo -n " Number (1-${#disks[@]}): "
} >&2
read -r ans || ans=""
if [[ "$ans" =~ ^[0-9]+$ ]] && [ "$ans" -ge 1 ] && [ "$ans" -le "${#disks[@]}" ]; then
echo "${disks[$((ans - 1))]}"
return
fi
echo " Type a number from the list." >&2
done
}
live_version() {
local v=""
if [ -e /etc/ocs/ocs-live.conf ]; then
# shellcheck disable=SC1091
v="$(. /etc/ocs/ocs-live.conf >/dev/null 2>&1; echo "${drbl_ocs_live_ver:-}")"
fi
[ -n "$v" ] || v="clonezilla $(dpkg-query -W -f='${Version}' clonezilla 2>/dev/null)"
echo "$v"
}
bits() {
case "$(uname -m)" in
x86_64|amd64) echo 64 ;;
*) echo 32 ;;
esac
}
# set_meta FILE KEY VALUE: replace or add one key=value line.
set_meta() {
local f="$1" k="$2" v="$3" tmp
v="$(echo "$v" | tr -d '\r\n')"
tmp="$(mktemp /tmp/pxe-meta.XXXXXX)"
[ -e "$f" ] && grep -v "^$k=" "$f" > "$tmp"
echo "$k=$v" >> "$tmp"
cat "$tmp" > "$f"
rm -f "$tmp"
}
get_meta() {
sed -n "s/^$2=//p" "$1" 2>/dev/null | head -1
}
repo_ready() {
mountpoint -q "$OCSROOT" 2>/dev/null || grep -qs " $OCSROOT cifs " /proc/mounts
}
# --- backup ---------------------------------------------------------------
do_save() {
local m="$1" disk stamp img n meta rc chk
disk="$(pick_disk "This PC has more than one disk. Which one do you want to back up?")"
[ -n "$disk" ] || fail "No disk found to back up." "Check the disk is connected and shows in the BIOS."
stamp="$(site_date +%Y-%m-%d-%H%M)"
img="$m-$stamp"
n=2
while [ -e "$OCSROOT/$img" ]; do
img="$m-$stamp-$n"
n=$((n + 1))
done
banner "BACKUP of machine $m" \
"Disk: $(describe_disk "$disk")" \
"Image: $img" \
"To: \\\\$SERVER\\clonezilla\\$img"
ocs-sr -q2 -batch -j2 -z9p -i 0 -sfsck -scs -senc -p command savedisk "$img" "$disk"
rc=$?
meta="$OCSROOT/$img/pxe-meta.txt"
if [ ! -d "$OCSROOT/$img" ]; then
fail "Clonezilla did not create the image $img (exit code $rc)." \
"See the messages above. Nothing was saved."
fi
: > "$meta"
set_meta "$meta" machine "$m"
set_meta "$meta" date "$(site_date '+%Y-%m-%d %H:%M %Z')"
set_meta "$meta" date_utc "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
set_meta "$meta" time_source "$TIME_SOURCE"
set_meta "$meta" serial "$(dmi system-serial-number)"
set_meta "$meta" manufacturer "$(dmi system-manufacturer)"
set_meta "$meta" model "$(dmi system-product-name)"
set_meta "$meta" disk "$disk"
set_meta "$meta" disk_model "$(disk_model "$disk")"
set_meta "$meta" disk_size_bytes "$(disk_bytes "$disk")"
set_meta "$meta" clonezilla "$(live_version)"
set_meta "$meta" bits "$(bits)"
if [ -d /sys/firmware/efi ]; then set_meta "$meta" firmware uefi; else set_meta "$meta" firmware bios; fi
if [ "$rc" -ne 0 ]; then
set_meta "$meta" save failed
set_meta "$meta" check not-run
fail "Clonezilla could not save machine $m (exit code $rc)." \
"The partial image $img is marked as failed on the share;" \
"delete it in the webapp (Tools > Clonezilla backups) and try again."
fi
set_meta "$meta" save ok
banner "Checking the saved image $img ..."
ocs-chkimg -b "$img"
chk=$?
set_meta "$meta" check_date "$(site_date '+%Y-%m-%d %H:%M %Z')"
if [ "$chk" -ne 0 ]; then
set_meta "$meta" check failed
fail "The image $img was saved but its CHECK FAILED (exit code $chk)." \
"Do not rely on it. Back this PC up again."
fi
set_meta "$meta" check ok
sync
banner "SUCCESS: machine $m backed up and checked." \
"Image: $img" \
"Serial: $(get_meta "$meta" serial) Model: $(get_meta "$meta" model)"
finish yes
}
# --- restore --------------------------------------------------------------
is_cz_image() {
local d="$1"
[ -d "$d" ] || return 1
[ -f "$d/disk" ] || [ -f "$d/parts" ] || return 1
local f
for f in "$d"/*; do
case "${f##*/}" in
*-ptcl-img*|*.dd-img*|*-img.*|clonezilla-img) return 0 ;;
esac
done
return 1
}
# Images of one machine, newest first: <machine>-YYYY-MM-DD-HHMM[-n] by
# name, plus any image whose pxe-meta.txt says machine=<machine>.
machine_images() {
local m="$1" d n mm
for d in "$OCSROOT"/*/; do
d="${d%/}"
n="${d##*/}"
is_cz_image "$d" || continue
mm="$(get_meta "$d/pxe-meta.txt" machine | tr '[:lower:]' '[:upper:]')"
if [ "$mm" = "$m" ]; then
echo "$n"
elif [ -z "$mm" ] && echo "$n" | tr '[:lower:]' '[:upper:]' | grep -qE "^$m-[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{4}(-[0-9]+)?$"; then
echo "$n"
fi
done | sort_newest
}
# Sort names by their date stamp (the last YYYY-MM-DD-HHMM[-n]), newest first.
sort_newest() {
local n key
while read -r n; do
key="$(echo "$n" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{4}(-[0-9]+)?$')"
echo "${key:-0000}|$n"
done | sort -r | cut -d'|' -f2-
}
image_disks() { tr -s ' \t' '\n' < "$OCSROOT/$1/disk" 2>/dev/null | grep -v '^$'; }
image_disk_bytes() {
local img="$1" src="$2" b sec
b="$(get_meta "$OCSROOT/$img/pxe-meta.txt" disk_size_bytes)"
if [[ "$b" =~ ^[0-9]+$ ]]; then echo "$b"; return; fi
# Clonezilla's sfdisk dump: "last-lba: N" (GPT) or the partitions' end.
sec="$(sed -n 's/^last-lba: *//p' "$OCSROOT/$img/$src-pt.sf" 2>/dev/null | head -1)"
if [[ "$sec" =~ ^[0-9]+$ ]]; then echo $(( (sec + 34) * 512 )); return; fi
echo 0
}
do_restore() {
local m="$1" imgs i n ans img src srcb tgt tgtb meta chkopt rc mo se ck
mapfile -t imgs < <(machine_images "$m")
if [ "${#imgs[@]}" -eq 0 ]; then
fail "No images for machine $m on \\\\$SERVER\\clonezilla." \
"Check the machine number, or look in the webapp (Tools > Clonezilla backups)."
fi
while true; do
echo
echo " Images of machine $m (newest first):"
i=1
for n in "${imgs[@]}"; do
meta="$OCSROOT/$n/pxe-meta.txt"
mo="$(get_meta "$meta" model)"; se="$(get_meta "$meta" serial)"; ck="$(get_meta "$meta" check)"
echo " $i) $n ${mo:-model ?} serial ${se:-?} check: ${ck:-?}"
i=$((i + 1))
done
echo -n " Image to restore (1-${#imgs[@]}, q = quit): "
read -r ans || ans=q
case "$ans" in q|Q) finish no ;; esac
if [[ "$ans" =~ ^[0-9]+$ ]] && [ "$ans" -ge 1 ] && [ "$ans" -le "${#imgs[@]}" ]; then
img="${imgs[$((ans - 1))]}"
break
fi
echo " Type a number from the list."
done
meta="$OCSROOT/$img/pxe-meta.txt"
if [ "$(get_meta "$meta" save)" = "failed" ]; then
fail "The image $img is marked as a FAILED backup and cannot be restored."
fi
mapfile -t src < <(image_disks "$img")
if [ "${#src[@]}" -ne 1 ]; then
fail "The image $img holds ${#src[@]} disks (${src[*]:-none})." \
"Restore it with Clonezilla: manual (boot menu)."
fi
srcb="$(image_disk_bytes "$img" "${src[0]}")"
tgt="$(pick_disk "Which disk do you want to restore $img to? (ALL DATA ON IT WILL BE ERASED)")"
[ -n "$tgt" ] || fail "No disk found to restore to."
tgtb="$(disk_bytes "$tgt")"
if [ "$srcb" -gt 0 ] && [ "$tgtb" -lt "$srcb" ]; then
fail "The target disk is SMALLER than the disk the image came from." \
"Image disk: $(human "$srcb")" "Target disk: $(describe_disk "$tgt")" \
"Use a disk at least as large, or Clonezilla: manual (expert mode, -icds)."
fi
banner "RESTORE machine $m" \
"Image: $img (saved $(get_meta "$meta" date))" \
"From: $(get_meta "$meta" model) serial $(get_meta "$meta" serial) disk $(human "$srcb")" \
"Target: $(describe_disk "$tgt")" \
"" \
"EVERYTHING on /dev/$tgt will be ERASED and replaced by this image." \
"This PC: $(dmi system-product-name) serial $(dmi system-serial-number)"
echo -n " Type YES (capitals) to erase /dev/$tgt and restore: "
read -r ans || ans=""
if [ "$ans" != "YES" ]; then
banner "Cancelled. Nothing was written."
finish no
fi
# A larger target: -k1 recreates the partition table proportionally
# (every partition scaled by target/source size) and -r grows each
# filesystem to its new partition, so the extra space is used. The
# default (-k0) copies the table as-is and leaves the rest unallocated.
# The image was checked after it was saved; check again only if that
# check did not pass.
chkopt=""
[ "$(get_meta "$meta" check)" = "ok" ] && chkopt="-scr"
ocs-sr -g auto -e1 auto -e2 -r -j2 -k1 $chkopt -batch -p command restoredisk "$img" "$tgt"
rc=$?
if [ "$rc" -ne 0 ]; then
fail "Clonezilla could not restore $img to /dev/$tgt (exit code $rc)." \
"The disk may be partly written: do not boot from it until a restore succeeds."
fi
sync
banner "SUCCESS: $img restored to /dev/$tgt." "At the next start, boot this PC from its disk (not the network)."
finish yes
}
# --- main -----------------------------------------------------------------
MODE="$(echo "$CMDLINE" | sed -n 's/.* pxe_cz_mode=\([a-z]*\) .*/\1/p')"
case "$MODE" in
save|restore) ;;
*) fail "Unknown mode [$MODE] on the kernel command line (pxe_cz_mode=save or restore)." ;;
esac
if ! repo_ready; then
fail "The backup share \\\\$SERVER\\clonezilla is not mounted on $OCSROOT." \
"Check the PXE server is up and the clonezilla Samba account works" \
"(playbook var clonezilla_smb_password), then boot this option again."
fi
sync_clock
MACHINE=""
get_machine
case "$MODE" in
save) do_save "$MACHINE" ;;
restore) do_restore "$MACHINE" ;;
esac

View File

@@ -10,8 +10,10 @@ item --gap -- ---- Drive Erase ----
item blancco Blancco Drive Eraser
item blancco_debug Blancco Drive Eraser (debug / SSH)
item --gap -- ---- Utilities ----
item clonezilla Clonezilla Live (Disk Imaging)
item clonezilla32 Clonezilla Live 32-bit (XP-era PCs, forced)
item cz_backup Clonezilla: back up this PC
item cz_restore Clonezilla: restore this PC
item clonezilla Clonezilla: manual (USB or other location)
item clonezilla32 Clonezilla: manual, 32-bit (XP-era PCs, forced)
item --gap -- Memory test: Dell PCs press F12 at power-on, Diagnostics
item --gap -- ----
item reboot Reboot
@@ -48,6 +50,47 @@ echo Windows PE boot FAILED (see the error above).
echo Check that the PXE server is up and the win11 boot files are staged.
prompt Press any key to return to menu... && goto menu || goto menu
# --- Clonezilla by machine number (back up / restore) ---------------------
# The image share is \\${server}\clonezilla (Samba account clonezilla,
# the playbook fills in its password). Clonezilla mounts it on
# /home/partimag (ocs_repository, SMB 3), downloads
# clonezilla-scripts/pxe-cz.sh (ocs_prerun) and runs it (ocs_live_run):
# it checks the machine number, saves <machine>-<YYYY-MM-DD-HHMM> or lists
# that machine's images to restore, and writes pxe-meta.txt.
:cz_backup
set cz_mode save
goto cz_machine
:cz_restore
set cz_mode restore
goto cz_machine
:cz_machine
# iPXE cannot check characters: pxe-cz.sh accepts letters, digits and dash
# and asks again there. Empty: ask again. Esc / Ctrl-C: back to the menu.
echo
echo -n Machine number: && read czmachine || goto menu
isset ${czmachine} || goto cz_machine
# Same CPU check as the manual entry below (cpuid --ext 29 = 64-bit).
cpuid --ext 29 && goto cz_auto64 || goto cz_auto32
:cz_auto64
set base http://${server}/clonezilla
kernel ${base}/vmlinuz boot=live username=user union=overlay config components noswap edd=on nomodeset nodmraid locales=en_US.UTF-8 keyboard-layouts=us ocs_prerun="wget -q -T 15 -t 5 -O /tmp/pxe-cz.sh http://${server}/clonezilla-scripts/pxe-cz.sh" ocs_repository="smb3://clonezilla:__CLONEZILLA_SMB_PASSWORD__@${server}/clonezilla/" echo_ocs_repository=no ocs_live_run="bash /tmp/pxe-cz.sh" ocs_live_extra_param="" ocs_live_batch=no net.ifnames=0 nosplash noprompt fetch=${base}/filesystem.squashfs pxe_cz_mode=${cz_mode} pxe_machine=${czmachine} pxe_end=1 || goto secureboot_warn
initrd ${base}/initrd.img || goto boot_failed
# Secure Boot ON: Debian's shim, as in :clonezilla64 below.
shim ${base}/shimx64.efi ||
boot || goto secureboot_warn
:cz_auto32
# 3.2.0-5 i686 over legacy BIOS only; UEFI goes to the 64-bit build.
iseq ${platform} efi && goto cz_auto64 ||
set base http://${server}/clonezilla-i686
kernel ${base}/vmlinuz boot=live username=user union=overlay config components noswap edd=on nomodeset nodmraid locales=en_US.UTF-8 keyboard-layouts=us ocs_prerun="wget -q -T 15 -t 5 -O /tmp/pxe-cz.sh http://${server}/clonezilla-scripts/pxe-cz.sh" ocs_repository="smb3://clonezilla:__CLONEZILLA_SMB_PASSWORD__@${server}/clonezilla/" echo_ocs_repository=no ocs_live_run="bash /tmp/pxe-cz.sh" ocs_live_extra_param="" ocs_live_batch=no net.ifnames=0 nosplash noprompt fetch=${base}/filesystem.squashfs pxe_cz_mode=${cz_mode} pxe_machine=${czmachine} pxe_end=1 || goto boot_failed
initrd ${base}/initrd.img || goto boot_failed
boot || goto boot_failed
# --- Clonezilla manual (interactive: USB, SSH, NFS or any share) ------------
:clonezilla
# 64-bit CPUs (cpuid extended bit 29 = long mode) get the current Clonezilla;
# older 32-bit-only CPUs (Pentium 4 without EM64T, Pentium M, early Atom:

View File

@@ -180,6 +180,14 @@
# suffix is not blancco_ksuffix.
blancco_kver: "7.0.0-34-generic"
blancco_ksuffix: "{{ blancco_kver.split('.')[0] }}{{ blancco_kver.split('.')[1] }}"
# Samba account for the [clonezilla] share only (Clonezilla back up /
# restore by machine number). The iPXE menu carries it in Clonezilla's
# ocs_repository URI (smb3://clonezilla:<password>@server/clonezilla/),
# so any imaging client can read it: it opens that one share and
# nothing else. Set a site value in site-vars.yml. Allowed characters:
# letters, digits . _ ~ - (it sits in a URI, a kernel command line and
# a mount option list), 8 to 64 of them.
clonezilla_smb_password: "clonezilla-backup"
image_types:
- gea-standard
- gea-engineer
@@ -250,6 +258,17 @@
Fix playbook/site-vars.yml and re-run.
quiet: yes
- name: "Clonezilla: check the clonezilla Samba password"
assert:
that:
- clonezilla_smb_password is string
- clonezilla_smb_password is match('^[A-Za-z0-9._~-]{8,64}$')
fail_msg: >-
clonezilla_smb_password must be 8-64 characters from A-Z a-z 0-9 . _ ~ -
(it goes into Clonezilla's smb3:// URI on the kernel command line).
Fix it in playbook/site-vars.yml and re-run.
quiet: yes
# --- Re-run safety (nothing below changes the box until these pass) ---
- name: "Re-run safety: is imaging in progress? (SMB sessions, recent DHCP leases)"
args:
@@ -754,13 +773,50 @@
# (iPXE shim command) so it runs with Secure Boot on. The Blancco
# Releases page edits this file (test entry), so keep exactly one
# "item blancco" line and the :blancco_efi kernel+initrd block.
# The Clonezilla back up / restore entries carry the clonezilla
# Samba password: the tracked file has the placeholder
# __CLONEZILLA_SMB_PASSWORD__, filled in here (content, so a re-run
# with the same password changes nothing).
copy:
src: "{{ usb_mount }}/ipxe/GetPxeScript.aspx"
content: "{{ lookup('file', usb_mount ~ '/ipxe/GetPxeScript.aspx', rstrip=False) | replace('__CLONEZILLA_SMB_PASSWORD__', clonezilla_smb_password) }}"
dest: "{{ web_root }}/Altiris/iPXE/GetPxeScript.aspx"
mode: '0644'
backup: yes
diff: false # the content carries clonezilla_smb_password
when: "'STAGED-TEST' not in menu_test_entry.stdout"
- name: "Menu: NOT replaced, so check the live menu's Clonezilla password"
# The Blancco test entry blocked the menu update above: a changed
# clonezilla_smb_password would leave the live menu with the old one
# (Clonezilla back up / restore then cannot mount the share).
shell: |
F="{{ web_root }}/Altiris/iPXE/GetPxeScript.aspx"
grep -q 'ocs_repository=' "$F" || { echo "no Clonezilla repository entries in the live menu"; exit 0; }
if grep -qF "smb3://clonezilla:${CZ_PW}@" "$F"; then echo "password matches"; else
echo "WARNING: the live menu's Clonezilla entries do not carry clonezilla_smb_password;"
echo "remove the Blancco test entry and re-run to update the menu."
fi
environment:
CZ_PW: "{{ clonezilla_smb_password }}"
register: menu_cz_pw
changed_when: false
no_log: true
when: "'STAGED-TEST' in menu_test_entry.stdout"
- name: "Menu: Clonezilla password check result"
debug:
msg: "{{ menu_cz_pw.stdout }}"
when: "'STAGED-TEST' in menu_test_entry.stdout"
- name: "Install the Clonezilla back up / restore scripts (fetched by Clonezilla live)"
# GetPxeScript.aspx: ocs_prerun downloads
# http://<server>/clonezilla-scripts/pxe-cz.sh, ocs_live_run runs it.
copy:
src: "{{ usb_mount }}/clonezilla-scripts/"
dest: "{{ web_root }}/clonezilla-scripts/"
mode: '0644'
directory_mode: '0755'
# Boot files (80) and the iPXE menu (4433) are served on the imaging IP
# only, never on the GE NIC. 9009 (webapp) stays on all addresses: admins
# reach it from the GE side (see pxe-server.conf below).
@@ -1118,7 +1174,9 @@
browseable = yes
read only = no
guest ok = no
valid users = pxe-upload
# clonezilla: the menu's back up / restore entries (this share
# only); pxe-upload: admins and manual Clonezilla runs.
valid users = pxe-upload clonezilla
force user = root
comment = Clonezilla backup images
@@ -1171,6 +1229,20 @@
executable: /bin/bash
changed_when: false
- name: "Create the clonezilla Samba user ([clonezilla] share only)"
# System user, no home, no login shell. Only [clonezilla] lists it in
# valid users. smbpasswd runs every time so a changed
# clonezilla_smb_password takes effect (the menu is updated with it).
shell: |
id clonezilla >/dev/null 2>&1 || useradd -r -M -d /nonexistent -s /usr/sbin/nologin clonezilla
printf '%s\n%s\n' "$CZ_PW" "$CZ_PW" | smbpasswd -a -s clonezilla >/dev/null
environment:
CZ_PW: "{{ clonezilla_smb_password }}"
args:
executable: /bin/bash
changed_when: false
no_log: true
- name: "Deploy nf_conntrack TCP timeout sysctl for PXE workload"
copy:
src: "{{ usb_mount }}/pxe-server-helpers/99-pxe-conntrack.conf"

View File

@@ -35,3 +35,10 @@ corp_nic_mac: "" # e.g. "20:88:10:af:0d:e5"
# Optional: kernel the Blancco UEFI entries boot (must be installed; see
# scripts/download-packages.sh BLANCCO_KVER).
# blancco_kver: "7.0.0-34-generic"
# Recommended: the password of the Samba account "clonezilla", which can
# open only the [clonezilla] share (Clonezilla back up / restore by machine
# number). The iPXE menu carries it, so treat it as an imaging-LAN secret,
# not a real one. 8-64 characters from A-Z a-z 0-9 . _ ~ - (default
# "clonezilla-backup").
# clonezilla_smb_password: "change-me-per-site"