Files
pxe-server/docs/SITE-CUSTOMIZATION.md
cproudlock 04db6d6605 Generic build for other GE sites: no WJ data, one shopfloor type, Windows USB builder
Everything West Jefferson specific moved out to a separate repo
(pxe-site-wj): NTLARS/UDC/heat-treat backups keyed by WJ machine numbers,
CMM and Wax/Trace bay lists, WJ OpenText profiles, site-config.json, the
WJ preinstall list, and the WJ shopfloor PC types (Collections,
NoCollections, Common, Keyence, CMM, Genspect, HeatTreat, Wax/Trace,
Display, PartMarker) with GE-Enforce, machine numbers and the desktop
layout. The part-marker bench tools moved to their own repo. Dead
scripts removed: build-proxmox-iso, deploy-bios, sync_hardware_models,
mirror-from-gold, pull-bios, startnet-template.cmd.

Shopfloor is one generic type, gea-shopfloor-standard, with today's
timing:
- PPKG at first logon (unattend Order 10, unchanged).
- Install-AppList.ps1 runs C:\PreInstall\preinstall.json during setup.
- A new SYSTEM task, GE Shopfloor Post-PPKG, runs postppkg.json once
  after the post-PPKG reboot. It also clears AutoLogonCount after the
  ShopFloor handover (the Users-level monitor can be denied that HKLM
  write) and removes the Intune Sync task when done.
- Both lists ship empty. A site adds entries and installers.
- WinPE choice 3 goes straight to the PPKG menu. Staging, fetch and heal
  carry only the generic payload. The webapp's shopfloor sub-menu editor
  is gone, and the imaging tiles name the new stages.
- The playbook deploys the empty lists only if missing. It now deploys
  the PowerShell 7 MSI the shopfloor unattend installs, which it never
  did before.

Blancco site settings move into the webapp (Updates > Blancco releases):
business location, licensing Wi-Fi SSID and password. They are rendered
into the served preferences.xml and applied to every staged release, and
are seeded from site-vars (site_name, blancco_wifi_ssid,
blancco_wifi_password) only while none exist. The repo XML carries no
site values; the plaintext Wi-Fi password is gone from it.

New site_name and site_timezone settings: report and evidence-pack site
name, server clock and webapp time zone. No more West Jefferson defaults
in webapp/config.py or the dashboard title. Sync-BPRT.ps1 gets the
server address filled in at download instead of WJ's GE address.

USB on Windows:
- scripts/Build-PxeUsb.ps1 runs the same checks as build-usb.sh. It
  writes one FAT32 CIDATA partition (ISO files plus patched grub.cfg plus
  payload) with diskpart and reads every file back by SHA-256.
- Tested with Windows PowerShell 5.1 in the win11 VM, and the layout
  installs and first-boots in the pxetest VM.
- scripts/stage-usb-share.sh stages the build folder on a share.
- site-content/ is optional for both builders.

KB docs/kb/How_To_Deploy_PXE_Server_New_Site.html: new-site deployment,
Windows only, with a site-vars.yml guide.

Checks: webapp tests pass (5 suites); the unattend lint and playbook
syntax checks pass; every .ps1 parses; there are no WJ hosts, IPs, names
or PC types in playbook/, webapp/, scripts/ or autoinstall/.
2026-10-16 20:37:22 -04:00

280 lines
14 KiB
Markdown

# 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/<sitename>.yaml` template back to the repo.
## Values to change
### Network
The imaging NIC (isolated imaging LAN, static 172.16.9.1, the only NIC that
serves DHCP/TFTP/HTTP boot/SMB) is pinned by MAC. The GE corporate side (DHCP
client; SSH and the webapp on 9009 only) is optional. Both MACs in
`playbook/site-vars.yml` (copy `playbook/site-vars.example.yml`) may be left
empty:
- `pxe_nic_mac` empty: the first boot picks the imaging NIC itself
(`pxe-pick-nic --auto`). It takes the one wired port with a link, and only
if `pxe-nic-check` calls it isolated, then pins it; the choice is in
`/etc/pxe-server/nic-pick.conf` and is never re-guessed at boot. So during
the install plug in ONLY the imaging switch. When it cannot tell (no link,
two links, or that port sees GE) it changes nothing and the console says
to run `sudo pxe-pick-nic`: pull the imaging cable and plug it back in,
and the port that blinked is the imaging one. Run it again after swapping
a dead USB NIC, then re-run the playbook.
- `corp_nic_mac` empty: every other wired port (`en*`, `eth*`) is a DHCP
client, so the GE cable can go into any of them, at install or later.
dnsmasq is pinned to the imaging NIC (`interface=`) and serves only the
imaging subnet, and those ports ignore DHCP offers from 172.16.9.1. UFW
allows SSH and 9009 by source, not by interface.
- `corp_nic_mac` set: that port alone is the GE NIC, named `corp0` (as on
the WJ server).
The first-boot playbook pins the result in netplan (names `pxe0` / `corp0`,
overridable), dnsmasq, UFW and Samba.
| Value | Default | Where it lives |
|-------------------|----------------------|--------------------------------------------------------------------------------|
| PXE server IP | 172.16.9.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 | 172.16.9.0/24 | Same as above, plus `playbook/pxe_server_setup.yml` (UFW rules) |
| DHCP range | 172.16.9.10-100 | `playbook/site-vars.yml` (`pxe_dhcp_start`, `pxe_dhcp_end`) |
| NIC MACs / names | (picked at install) / pxe0, corp0 | `playbook/site-vars.yml` (`pxe_nic_mac`, `corp_nic_mac`, `pxe_nic_name`, `corp_nic_name`) |
| Hostname | pxeserver | `autoinstall/user-data` (identity.hostname) |
### Access from the GE corporate network
SSH (password auth, the shared `pxe` password) and the webapp on 9009 (no
login, runs as root) are reachable on the corp NIC. By default from ALL of
GE, as before, so a re-run never locks anyone out; the play prints a loud
warning on every run while that is so. Set these in `playbook/site-vars.yml`:
| Var | Default | Effect |
|--------------------------|---------|--------|
| `corp_admin_cidrs` | `[]` | List of admin subnets/hosts, e.g. `["10.134.48.0/24", "3.12.34.56/32"]`. When non-empty, UFW allows 22 and 9009 from these only (on `corp_nic_name` when `corp_nic_mac` is set, else on any interface) and drops the any-source rules. The play refuses (nothing changed) if an entry is invalid or your own SSH session is not inside one of them. The imaging NIC keeps its rules. |
| `corp_ssh_password_auth` | `true` | `false` adds `/etc/ssh/sshd_config.d/10-pxe-corp-auth.conf`: `PasswordAuthentication no`, re-allowed by a `Match Address` block for `pxe_subnet` and localhost. Keys only from GE. The play refuses while `pxe` has no `~/.ssh/authorized_keys`, and removes the drop-in again if `sshd -t` rejects it. |
| `allow_disruptive` | `false` | Re-runs while imaging is active (SMB sessions on 445, or DHCP leases granted in the last `pxe_busy_window_min` = 30 min) do not bounce the NICs or restart dnsmasq/Apache/Samba; a needed network change stops the play. `-e allow_disruptive=true` overrides. |
Recommended for a production box: `corp_admin_cidrs` set to the admin
desks' subnet, then (after `ssh-copy-id`) `corp_ssh_password_auth: false`.
### Re-running the playbook over SSH (from the GE side)
The network step refuses before changing anything when the NIC that
`pxe_nic_mac` names holds the default route, a DHCP lease, or the route to
your SSH client (swapped MACs or cables). When it does apply, it arms a
120 s auto-revert timer (`pxe-netplan-revert-*`), checks the names, the
imaging address and that the corp NIC (or, without one pinned, every other
port that had an address) gets its IPv4 back within 30 s, and
restores the previous netplan config AND NIC names on any failure. Backups:
`/var/backups/netplan-<timestamp>/`.
### 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.
### Engineering Layer (gea-engineer)
Handled by the repo; nothing to work out per site except the payload.
- `playbook/engineering/Install-EngineeringLayer.ps1` is deployed by the
playbook to `gea-engineer/Deploy/Applications/extra_engineering/`.
- `FlatUnattendW10-engineer.xml` runs it twice:
- specialize Order 37 (`-StageOnly`) copies the payload and the script to
`C:\PreInstall\engineering` while `C:\Deploy` exists;
- first logon Order 11 installs from that copy. The bulk-enrollment
`DeleteDeployDir` task removes `C:\Deploy` on the next boot, so a PC
that reboots before the employee signs in would otherwise install
nothing and show no icon.
- After the install it makes sure the "Configure my Engineering Layer"
icon is on the Public desktop (until the PC is configured), and registers
Active Setup so a later user gets the icon if someone else already used
it. The employee clicks it once, on the GE network: it maps V: and runs
`install_local_new.cmd` from GE's share, which removes the icon.
- Log on the PC: `C:\Logs\Engineering\install-engineering-layer.log`.
The site supplies the payload beside the script, in
`gea-engineer/Deploy/Applications/extra_engineering/`:
`engineering_layer/Engineering_Install_v3.1.exe` and `prereqs/`
(.NET 3.5 sxs cabs, VC++ redists), about 650 MB.
### 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`. 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:
- `\\172.16.9.1\image-upload` as the destination
- `C:\ProgramData\GEAerospace\MediaCreator\Cache\` as the source
Update both for a different site (`-Server`, `-CachePath`; `-WebPort` if the
webapp is not on 9009). The script checks every file on the server through
the webapp before the Image Import page will accept the upload.
## Recommended forward state
A site config file should drive substitution at build time. Proposed schema:
```yaml
# config/sites/<sitename>.yaml
site:
name: westjeff
pxe_server_ip: 172.16.9.1
pxe_subnet: 172.16.9.0/24
dhcp_range_start: 172.16.9.10
dhcp_range_end: 172.16.9.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/<sitename>.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.