diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..7e5da8f --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,203 @@ +# PXE Server Architecture + +This document describes the moving parts of the PXE server, the boot chain a +client follows, and how data flows between the server, clients, and external +systems. + +## Hardware and host OS + +- Single physical host (or VM) with at minimum 4 GB RAM, 4 CPU cores, and one + network interface attached to the isolated PXE LAN. +- Disk: 232 GB minimum if you stay slim (Dell_11 only, no Latitude); 500 GB + recommended for a full mirror; 2 TB+ recommended for headroom across all + driver sets and OS image variants. +- OS: Ubuntu Server 24.04 LTS (Noble), installed unattended via the autoinstall + USB built by `scripts/build-usb.sh`. + +## Network layout + +- PXE server static IP: `10.9.100.1/24` on an isolated subnet. +- DHCP range served by dnsmasq: `10.9.100.10 - 10.9.100.100`, 12h leases. +- Default gateway and DNS handed out via DHCP point at the PXE server itself. +- The subnet has no route to the corporate LAN. Client traffic (Blancco BMC + cloud, Intune enrollment) goes out via WiFi after Windows boots; PXE-time + traffic stays on the isolated LAN. + +## Services on the PXE server + +| Service | Port | Role | +|---------------|-----------|------------------------------------------------------| +| dnsmasq | 67/udp | DHCP. Hands out IPs and the next-server (TFTP) info. | +| dnsmasq | 69/udp | TFTP. Serves `ipxe.efi` to firmware PXE clients. | +| Apache | 80/tcp | HTTP. Serves wimboot, boot.wim, Blancco binaries, Clonezilla, memtest, and proxies the webapp on /. | +| Apache | 4433/tcp | HTTP. Serves `Altiris/iPXE/GetPxeScript.aspx` (the iPXE menu script). | +| Samba | 445/tcp | SMB shares. WinPE mounts these to fetch image content during deployment. | +| Flask webapp | 9009/tcp | Browser UI for image import, unattend editing, log/report viewing. | + +`/etc/cron.d/dnsmasq-restart` restarts dnsmasq 15 seconds after every reboot to +work around a systemd-resolved race condition that can prevent dnsmasq from +binding to the PXE interface on cold boot. + +`/etc/cron.d/media-tag-refresh` touches `Media.tag` in every image's +`Deploy/Control/` directory daily and on reboot. Without this, the WinPE +deployment loader stops finding the image after 30 days. + +## Samba shares + +| Share | Filesystem path | Purpose | +|------------------|-----------------------------|--------------------------------------------------------------| +| winpeapps | /srv/samba/winpeapps | Per-image-type Deploy/ trees (gea-standard, gea-shopfloor, etc.) and the deduped `_shared/` content (Operating Systems, Out-of-box Drivers, Packages). | +| clonezilla | /srv/samba/clonezilla | Clonezilla disk backup images (uploaded by clients running Clonezilla Live). | +| blancco-reports | /srv/samba/blancco-reports | XML erasure reports, written automatically by Blancco Drive Eraser at the end of each wipe. | +| enrollment | /srv/samba/enrollment | Single share that WinPE mounts as Y: during imaging. See "Enrollment share layout" below. | +| image-upload | /home/pxe/image-upload | Staging area for new image content uploaded from a Windows PC running `Upload-Image.ps1`. | + +All shares are accessible to `pxe-upload` (password `pxe`) and the public-side +ones also allow guest access. The `blancco` user (password `blancco`) writes to +`blancco-reports` only. + +## Enrollment share layout + +The `enrollment` share is the catchall WinPE pulls from during imaging. New +fresh installs (built from this repo) deploy this layout: + +``` +/srv/samba/enrollment/ + README.md + ppkgs/ GCCH bulk-enrollment PPKGs (.ppkg) + scripts/ run-enrollment.ps1, wait-for-internet.ps1, migrate-to-wifi.ps1 + config/ site-config.json, FlatUnattendW10*.xml, per-site overrides + shopfloor-setup/ PC-type post-imaging scripts (CMM, Display, Standard, Lab, etc.) + pre-install/ WinPE-phase content + bios/ Dell BIOS update binaries + check-bios.cmd + models.txt + installers/ UDC, OpenText, etc. staged on client during preinstall + preinstall.json Preinstall manifest read by the WinPE preinstall stage + installers-post/ Post-OOBE app installers + cmm/ PC-DMIS patched MSIs + blancco/ Blancco custom images / configs (BDE715_GEAE_INTERNET.img.gz) + logs/ Client-uploaded logs and diagnostic bundles +``` + +Older servers (built before this repo's reorganization) use a flat layout +(everything at the share root). Both layouts work; the `startnet.cmd` baked +into each server's `boot.wim` matches its own layout. + +## Boot chain (client perspective) + +A client PXE-boots from the isolated LAN. UEFI Secure Boot is supported for +WinPE; the Blancco and Clonezilla utilities require Secure Boot disabled. + +``` +1. Client UEFI firmware sends DHCP DISCOVER on the isolated LAN. +2. dnsmasq replies with IP, next-server (PXE server IP), and bootfile=ipxe.efi. +3. Firmware fetches /srv/tftp/ipxe.efi via TFTP. +4. ipxe.efi (Broadcom-signed for Secure Boot) starts, gets DHCP, fetches the + iPXE menu script from http://:4433/Altiris/iPXE/GetPxeScript.aspx. +5. Client picks an option: + + a. Windows PE: + iPXE -> wimboot -> boot.wim + boot.wim runs startnet.cmd which mounts SMB shares (Y: enrollment, + Z: chosen winpeapps), kicks off FlatSetupLoader.exe -> PESetup.exe + to deploy the OS, then handles per-PC-type setup before reboot. + + b. Blancco Drive Eraser: + iPXE chains http:///blancco/grubx64.efi + GRUB loads vmlinuz-bde-linux + initramfs over TFTP (HTTP times out on + large files inside GRUB) + Blancco boot uses copytoram=y to load the rootfs into memory, mounts + the customized airootfs.sfs over HTTP, connects to BMC cloud over WiFi + for license validation, then runs the configured erasure profile. + Reports are written back to \\\blancco-reports. + + c. Clonezilla Live: + iPXE loads vmlinuz + initrd over HTTP, fetches filesystem.squashfs. + + d. Memtest86+: + iPXE loads memtest.efi. +``` + +## Windows imaging lifecycle (gea-* images) + +``` +1. Boot to WinPE via PXE. +2. startnet.cmd mounts Y: \\server\enrollment and presents an interactive + image type and PC type menu. +3. Optionally checks BIOS firmware version against a manifest; if outdated, + stages the new firmware to the disk and reboots so it flashes on POST. +4. PESetup.exe runs the chosen image (image type determines OS, drivers, + apps to deploy). +5. After WinPE finishes, the system reboots into Windows OOBE. +6. During OOBE, the staged PPKG runs (GCCH bulk-enrollment, joins AAD, sets + up Intune enrollment). +7. After OOBE, the per-PC-type Run-ShopfloorSetup.ps1 runs from C:\Enrollment. + It installs the apps for that PC type (eDNC, OpenText, UDC, Dashboard, + etc. depending on the type), configures the desktop, and triggers Intune + sync. +``` + +## Webapp + +`/opt/pxe-webapp/` runs as a systemd service, reverse-proxied by Apache on +port 80 (`/`) and accessible directly on port 9009. Built with Flask. Pages: + +- Dashboard: service status, disk usage, recent activity. +- Images: import wizard for new content (from `image-upload` SMB share into + per-image Deploy/ trees), per-image driver and hardware config editing. +- Unattend editor: in-place editing of FlatUnattendW10.xml for each image. +- Startnet editor: edit and re-inject `Windows/System32/startnet.cmd` inside + the deployed `boot.wim` via wimupdate. +- Enrollment: PPKG inventory and upload. +- Backups: Clonezilla backup management. +- Reports: Blancco erasure report viewer. +- Audit: action log. + +## Data flow summary + +``` +Build workstation (this repo) + | + | scripts/build-usb.sh /dev/sdX ubuntu-24.04.iso + v +USB installer (2 partitions: ISO + CIDATA) + | + | inserted into target server, boot from USB + v +Ubuntu auto-install + first-boot Ansible playbook + | + v +Configured PXE server (10.9.100.1) ----+ + | +Windows PCs running Upload-Image.ps1 --+--> Image content (SMB, webapp import) + | +PXE clients (UEFI -> iPXE -> WinPE) ---+--> Image deployment (SMB, HTTP) +PXE clients (UEFI -> iPXE -> Blancco) -+--> Drive erasure + report upload + | + +--> Clonezilla backups (SMB) +``` + +## Where things live + +- Ansible playbook: `playbook/pxe_server_setup.yml`. Single file, idempotent. +- WinPE startup script (template): `playbook/startnet.cmd` (canonical) and + `startnet-template.cmd` (mirror copy at repo root for editor convenience). + The playbook injects this into `Windows/System32/startnet.cmd` inside the + `boot.wim` it deploys to `/var/www/html/win11/sources/`. +- iPXE menu script source: embedded in the playbook (`Create GetPxeScript.aspx` + task); deployed to `/var/www/html/Altiris/iPXE/GetPxeScript.aspx`. +- Per-PC-type setup scripts: `playbook/shopfloor-setup/`. The playbook copies + the whole tree to the enrollment share so WinPE can fetch them. +- Blancco assets: `boot-tools/blancco/` in the repo, deployed to + `/var/www/html/blancco/` plus TFTP symlinks in `/srv/tftp/blancco/`. +- Site-specific values (IPs, SSIDs, BMC creds, hostnames): currently + hardcoded in multiple files; see SITE-CUSTOMIZATION.md for the migration + plan to consolidate these in `config/`. + +## See also + +- SETUP.md: build process and target server install +- SITE-CUSTOMIZATION.md: what to change when bringing up a new site +- TROUBLESHOOTING.md: known failure modes and fixes +- BLANCCO.md: erasure boot chain details, custom config.img, BMC licensing +- GEA-IMAGING.md: WinPE deployment internals, PPKGs, per-type setup +- OPERATIONS.md: day 2 procedures (PPKG bumps, BIOS updates, image upload) diff --git a/docs/SITE-CUSTOMIZATION.md b/docs/SITE-CUSTOMIZATION.md new file mode 100644 index 0000000..b795564 --- /dev/null +++ b/docs/SITE-CUSTOMIZATION.md @@ -0,0 +1,199 @@ +# Site Customization + +The PXE server in this repo was built for the GE Aerospace West Jefferson site. +To stand it up at another site, several values need to change. This document +lists every site-specific value, where it lives today, and the recommended +forward state. + +## Status + +The repo has not yet been parameterized. As of 2026-04-14 the site-specific +values below are hardcoded in multiple files. The `config/` directory at the +repo root is a placeholder for the future state where one YAML file drives +substitution at build time. Until that exists, customizing for a new site +means editing the source files directly. + +If you are bringing up the first non-WJ site, expect to do this manually and +contribute a `config/sites/.yaml` template back to the repo. + +## Values to change + +### Network + +| Value | Default | Where it lives | +|-------------------|----------------------|--------------------------------------------------------------------------------| +| PXE server IP | 10.9.100.1 | `playbook/pxe_server_setup.yml` (dnsmasq config, iPXE script, samba conf, webapp env), `playbook/startnet.cmd` (mount paths), `boot-tools/blancco/grub-blancco.cfg` (TFTP/HTTP URLs) | +| PXE subnet | 10.9.100.0/24 | Same as above, plus `playbook/pxe_server_setup.yml` (UFW rules) | +| DHCP range | 10.9.100.10-100 | `playbook/pxe_server_setup.yml` (dnsmasq config) | +| Hostname | pxeserver | `autoinstall/user-data` (identity.hostname) | + +### Identity and credentials + +| Value | Default | Where it lives | +|-----------------------------|---------------------------------------|---------------------------------------------------------| +| Linux user | pxe / pxe | `autoinstall/user-data` (identity.username, password hash) | +| Samba upload user | pxe-upload / pxe | `playbook/pxe_server_setup.yml` (Samba user creation) | +| Samba blancco user | blancco / blancco | `playbook/pxe_server_setup.yml` | +| Sudo password | pxe | autoinstall password hash; also referenced in scripts that ssh + sudo | + +### WiFi and BMC (Blancco licensing) + +The Blancco custom `config.img` carries WiFi credentials and BMC cloud +credentials in plaintext. These are GE-Aerospace specific. + +| Value | Default | Where it lives | +|---------------|----------------------|-------------------------------------------------------------------------| +| WiFi SSID | INTERNETACCESS | `boot-tools/blancco/config.img` (inside the cpio archive: preferences.xml) | +| WiFi password | Acc3ssGr@nted22 | Same | +| BMC endpoint | classic.eu-west-1.blancco.cloud:443 | Same; encrypted credentials inside config.img | + +To rebuild `config.img` for a different site, see BLANCCO.md ("Rebuilding +config.img"). + +### Image types + +The repo defines seven image types (see `playbook/pxe_server_setup.yml`, +`image_types`). Most sites likely only need a subset. The current set: +- gea-standard +- gea-engineer +- gea-shopfloor +- ge-standard +- ge-engineer +- ge-shopfloor-lockdown +- ge-shopfloor-mce + +Trim or extend this list and the matching `shopfloor_types` filter as needed. + +### PC types (shopfloor sub-types) + +`playbook/shopfloor-setup/` contains per-PC-type install logic. The current +types reflect WJ shopfloor needs: +- CMM (PC-DMIS) +- WaxAndTrace +- Keyence +- Genspect +- Display (Lobby and Dashboard variants) +- Standard (Timeclock and Machine variants) +- Lab + +A site without CMMs can drop the CMM type and its installers entirely. + +### GCCH bulk-enrollment PPKGs + +PPKG filenames are baked into `playbook/startnet.cmd` and +`startnet-template.cmd`. They are tied to the GE Aerospace tenant. Other +sites/tenants will have their own PPKGs with different filenames. + +| PPKG enrollment menu choice | Default filename | +|-----------------------------|---------------------------------------------------------------| +| 1 NoOffice | GCCH_Prod_SFLD_NoOffice_US_Exp_20260430_v4.10.ppkg | +| 2 StdOffice x86 | GCCH_Prod_SFLD_StdOffice-x86_US_Exp_20260430_v4.10.ppkg | +| 3 StdOffice x64 | GCCH_Prod_SFLD_StdOffice-x64_US_Exp_20260430_v4.10.ppkg | +| 4 ProPlusOffice x86 | GCCH_Prod_SFLD_ProPlusOffice-x86_US_Exp_20260430_v4.10.ppkg | +| 5 ProPlusOffice x64 | GCCH_Prod_SFLD_ProPlusOffice-x64_US_Exp_20260430_v4.10.ppkg | + +When you bump PPKG versions, update the filenames in startnet.cmd, drop the +new PPKGs in `enrollment/` on the workstation, and rebuild the USB. + +### Site-specific shopfloor config + +`playbook/shopfloor-setup/site-config.json` has site-specific values like +default machine number ranges, share paths for software, and more. Inspect +that file for site name strings, share UNC paths, and machine number ranges. + +### Branding + +The Flask webapp uses GE Aerospace branding: +- Logo: `webapp/static/ge-aerospace-logo.svg` +- Favicon: `webapp/static/favicon.ico` +- Page titles and templates reference "GE Aerospace" in `webapp/templates/*.html` +- iPXE menu title: "GE Aerospace PXE Boot Menu" in `playbook/pxe_server_setup.yml` + +### Drivers (Dell) + +Driver content is hardware-specific, not strictly site-specific, but the set +of driver families to bundle changes by what hardware the site deploys: +- `Dell_11/Pro` and `Dell_11/ProMax`: Dell Pro Micro PCs (most common shopfloor) +- `Dell_11/Optiplex`: traditional desktops +- `Dell_11/Precision`: workstations +- `Dell_11/Latitude`: laptops (large, often excluded if site has none) + +The `scripts/download-drivers.py` and `scripts/Download-Drivers.ps1` scripts +populate `drivers-staging/` from upstream sources. Edit these to target the +relevant hardware lists. + +### BIOS update manifest + +`playbook/shopfloor-setup/BIOS/models.txt` maps Dell model strings to the +BIOS .exe to flash. Update this whenever new hardware arrives or Dell +publishes a new firmware release for a model already in the fleet. + +### Intune DSC categories + +The post-enrollment Intune DSC delivery (per `intune-dsc.md` memory) pulls +per-category YAML from Azure Blob: +- main +- cmm +- displaypcs +- waxtrace + +Different sites/tenants will need their own categories and their own Azure +Blob storage account. + +### Image-upload paths on Windows + +`scripts/Upload-Image.ps1` defaults to: +- `\\10.9.100.1\image-upload` as the destination +- `C:\ProgramData\GEAerospace\MediaCreator\Cache\` as the source + +Update both for a different site. + +## Recommended forward state + +A site config file should drive substitution at build time. Proposed schema: + +```yaml +# config/sites/.yaml +site: + name: westjeff + pxe_server_ip: 10.9.100.1 + pxe_subnet: 10.9.100.0/24 + dhcp_range_start: 10.9.100.10 + dhcp_range_end: 10.9.100.100 + hostname: pxeserver + +credentials: + pxe_user: pxe + pxe_password: pxe + pxe_upload_password: pxe + blancco_password: blancco + +blancco: + wifi_ssid: INTERNETACCESS + wifi_password: Acc3ssGr@nted22 + bmc_endpoint: classic.eu-west-1.blancco.cloud:443 + +ppkg_versions: + current: v4.10 + expiry: 20260430 + +intune_dsc_categories: [main, cmm, displaypcs, waxtrace] + +image_types: [gea-standard, gea-engineer, gea-shopfloor] +shopfloor_types: [gea-shopfloor] +``` + +`scripts/build-usb.sh` and the playbook would consume this and substitute +into the templated config files. Implementing this is a separate piece of +work; until then, edit source files directly. + +## Secrets handling + +Some values above are sensitive (WiFi passwords, BMC credentials, Samba +passwords). Today these sit in plain text in the repo. For a multi-site +deployment, treat them as per-site secrets: +- Keep `config/sites/.secrets.yaml` out of git (gitignore). +- Distribute via secure channel (1Password, Vault, etc.) when standing up + a new site. +- The `eMxInfo.txt` precedent (see `feedback_emxinfo_secret.md`) is a good + template: never commit, document where the canonical copy lives. diff --git a/scripts/mirror-from-gold.sh b/scripts/mirror-from-gold.sh new file mode 100755 index 0000000..1f912ca --- /dev/null +++ b/scripts/mirror-from-gold.sh @@ -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 [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 [--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/ +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 "============================================"