You have joined Northwind Logistics as the engineer responsible for virtualisation. The person who built the platform left in June. You have been handed three nodes, a Ceph cluster, a backup server, a handover note, and a production workload that has been running on all of it for two years.
Nobody has told you anything is wrong with it. As far as the business is concerned this estate works: guests are up, backups are green, and the last incident anyone connects to it was months ago.
Your job is to find out whether that is true, and to say so in a form somebody can act on.
Format
- Part A — 18 auto-scored questions, in the set above this text. Machine-marked, 25% of the total. Most of them cannot be answered without having read the estate output properly.
- Part B — the risk register you write yourself. 45% of the total. The marking key is in this page, under a heading that says not to read it yet.
- Part C — 6 scenarios with rubrics, in the frontmatter of this assessment and summarised near the end. 30% of the total.
- Open-book, 3 hours. You may look up anything. You have no shell on the estate; the captures below are what you have.
- Pass: 75% overall, plus all four mandatory findings. The pass bar is justified where the pass criteria are set out.
The handover note
The previous engineer left this in the datacenter notes field. It is reproduced exactly.
Northwind virtualisation - handover
Cluster: nwl-prod, pve-01/02/03, Proxmox VE 9.2.4
Storage: Ceph (pool ceph-vm), plus local-lvm on each node
Backup: PBS 4.2.5, vm 150 on pve-02, job runs 22:00 nightly
HA: 5 guests, see ha-manager
Notes for whoever picks this up:
- Sizing is N+1. 506 GiB allocated across 3 x 256 GiB nodes, so two
nodes can carry everything.
- I gave pve-01 two corosync votes so the cluster stays quorate when
we take a node out for patching. Works well.
- noout is set. Left it on after the March maintenance because the
rebuild was going to be painful. Take it off when we have more
disk.
- vm 105 (ERP db) is not in the PBS job - it is too big and the
window was too tight. There is a snapshot cron on pve-01 instead.
- Restore has not been tested. It is on the list.
- Firewall rules are written but not enabled. Someone should check
them before turning it on.
- pve-03 is on pvetest, I was chasing a NIC issue in April.
- Do not reboot pve-01 during month-end.
The estate as you received it
Cluster and quorum
$ pvecm statusCluster information
-------------------
Name: nwl-prod
Config Version: 7
Transport: knet
Secure auth: on
Quorum information
------------------
Date: Wed Aug 12 09:41:03 2026
Quorum provider: corosync_votequorum
Nodes: 3
Node ID: 0x00000001
Ring ID: 1.3f2
Quorate: Yes
Votequorum information
----------------------
Expected votes: 4
Highest expected: 4
Total votes: 4
Quorum: 3
Flags: Quorate
Membership information
----------------------
Nodeid Votes Name
0x00000001 2 192.0.2.11 (local)
0x00000002 1 192.0.2.12
0x00000003 1 192.0.2.13Illustrative output
/etc/pve/corosync.conf:
logging {
debug: off
to_syslog: yes
}
nodelist {
node {
name: pve-01
nodeid: 1
quorum_votes: 2
ring0_addr: 192.0.2.11
}
node {
name: pve-02
nodeid: 2
quorum_votes: 1
ring0_addr: 192.0.2.12
}
node {
name: pve-03
nodeid: 3
quorum_votes: 1
ring0_addr: 192.0.2.13
}
}
quorum {
provider: corosync_votequorum
}
totem {
cluster_name: nwl-prod
config_version: 7
interface {
linknumber: 0
}
ip_version: ipv4-6
link_mode: passive
secauth: on
version: 2
}
Networking
/etc/network/interfaces on pve-01, identical in structure on the
other two nodes:
auto lo
iface lo inet loopback
iface enp1s0f0 inet manual
iface enp1s0f1 inet manual
# 25 GbE, cabled to the leaf switches, never configured
iface ens2f0 inet manual
iface ens2f1 inet manual
auto bond0
iface bond0 inet manual
bond-slaves enp1s0f0 enp1s0f1
bond-mode 802.3ad
bond-xmit-hash-policy layer3+4
mtu 9000
auto vmbr0
iface vmbr0 inet static
address 192.0.2.11/24
gateway 192.0.2.1
bridge-ports bond0
bridge-vlan-aware yes
bridge-vids 2-4094
mtu 9000
Relevant lines from /etc/pve/ceph.conf:
[global]
auth_client_required = cephx
auth_cluster_required = cephx
auth_service_required = cephx
cluster_network = 192.0.2.0/24
fsid = 4b1f8d2a-9c60-4f13-8a77-2ee5cbb01f4d
mon_allow_pool_delete = true
ms_bind_ipv4 = true
osd_pool_default_min_size = 1
osd_pool_default_size = 2
public_network = 192.0.2.0/24
Ceph
$ ceph -s cluster:
id: 4b1f8d2a-9c60-4f13-8a77-2ee5cbb01f4d
health: HEALTH_WARN
noout flag(s) set
1 daemons have recently crashed
services:
mon: 3 daemons, quorum pve-01,pve-02,pve-03 (age 5w)
mgr: pve-01(active, since 5w)
osd: 12 osds: 12 up (since 5w), 12 in (since 14M)
flags noout
data:
pools: 2 pools, 129 pgs
objects: 4.31M objects, 16 TiB
usage: 33 TiB used, 13 TiB / 46 TiB avail
pgs: 129 active+clean
io:
client: 18 MiB/s rd, 42 MiB/s wr, 1.90k op/s rd, 2.11k op/s wrIllustrative output
$ ceph osd pool ls detailpool 1 '.mgr' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins
pg_num 1 pgp_num 1 autoscale_mode on last_change 41 flags hashpspool
stripe_width 0 pg_num_max 32 pg_num_min 1 application mgr
pool 2 'ceph-vm' replicated size 2 min_size 1 crush_rule 1 object_hash rjenkins
pg_num 128 pgp_num 128 autoscale_mode warn last_change 1832 lfor 0/0/318
flags hashpspool,selfmanaged_snaps stripe_width 0 application rbdIllustrative output
$ ceph osd crush rule dump by-osd{
"rule_id": 1,
"rule_name": "by-osd",
"type": 1,
"steps": [
{ "op": "take", "item": -1, "item_name": "default" },
{ "op": "chooseleaf_firstn", "num": 0, "type": "osd" },
{ "op": "emit" }
]
}Illustrative output
$ ceph df--- RAW STORAGE ---
CLASS SIZE AVAIL USED RAW USED %RAW USED
ssd 46 TiB 13 TiB 33 TiB 33 TiB 71.74
TOTAL 46 TiB 13 TiB 33 TiB 33 TiB 71.74
--- POOLS ---
POOL ID PGS STORED OBJECTS USED %USED MAX AVAIL
.mgr 1 1 449 KiB 2 1.3 MiB 0.00 6.1 TiB
ceph-vm 2 128 16 TiB 4.31M 33 TiB 73.09 6.1 TiBIllustrative output
$ ceph osd treeID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 45.94434 root default
-3 15.31478 host pve-01
0 ssd 3.82870 osd.0 up 1.00000 1.00000
1 ssd 3.82870 osd.1 up 1.00000 1.00000
2 ssd 3.82870 osd.2 up 1.00000 1.00000
3 ssd 3.82870 osd.3 up 1.00000 1.00000
-5 15.31478 host pve-02
4 ssd 3.82870 osd.4 up 1.00000 1.00000
5 ssd 3.82870 osd.5 up 1.00000 1.00000
6 ssd 3.82870 osd.6 up 1.00000 1.00000
7 ssd 3.82870 osd.7 up 1.00000 1.00000
-7 15.31478 host pve-03
8 ssd 3.82870 osd.8 up 1.00000 1.00000
9 ssd 3.82870 osd.9 up 1.00000 1.00000
10 ssd 3.82870 osd.10 up 1.00000 1.00000
11 ssd 3.82870 osd.11 up 1.00000 1.00000Illustrative output
Storage as Proxmox sees it
$ pvesm statusName Type Status Total Used Available %
ceph-vm rbd active 24065771520 17557821440 6507950080 72.96%
local dir active 100597760 18874368 81723392 18.76%
local-lvm lvmthin active 1782579200 929038336 853540864 52.12%
nas-iso nfs active 2147483648 1932735283 214748365 90.00%
pbs-nwl pbs active 41943040000 38210371584 3732668416 91.10%
zbackup dir active 46137344000 31138512896 14998831104 67.49%Illustrative output
Relevant stanzas from /etc/pve/storage.cfg:
rbd: ceph-vm
content images,rootdir
krbd 0
pool ceph-vm
lvmthin: local-lvm
thinpool data
vgname pve
content rootdir,images
pbs: pbs-nwl
datastore nwl-store
server 192.0.2.150
content backup
encryption-key a1:b2:c3:REDACTED
fingerprint 3f:REDACTED
username backup@pbs!pve
dir: zbackup
path /zbackup/dump
content backup,iso
nodes pve-02
prune-backups keep-last=2
Guests
$ qm config 105agent: 0
boot: order=scsi0
cores: 16
cpu: host
memory: 131072
name: nwl-erp-db
net0: virtio=BC:24:11:3A:0E:71,bridge=vmbr0,tag=40
numa: 1
onboot: 1
ostype: l26
parent: auto-2026-03-19
scsi0: ceph-vm:vm-105-disk-0,discard=on,iothread=1,size=1200G
scsihw: virtio-scsi-single
sockets: 2Illustrative output
$ qm listsnapshot 105`-> auto-2025-06-02 2025-06-02 02:00:11 no-description
`-> auto-2025-06-03 2025-06-03 02:00:09 no-description
[ ... 37 further snapshots ... ]
`-> auto-2026-03-18 2026-03-18 02:00:14 no-description
`-> auto-2026-03-19 2026-03-19 02:00:12 no-description
`-> current You are here!Illustrative output
/etc/cron.d/nwl-erp-snapshot on pve-01:
0 2 * * * root /usr/sbin/qm snapshot 105 auto-$(date +\%F) >/dev/null 2>&1
$ qm config 110 ; echo '---' ; qm config 120boot: order=scsi0
cores: 4
cpu: x86-64-v2-AES
memory: 16384
name: nwl-fileserver
net0: virtio=BC:24:11:7D:12:9A,bridge=vmbr0,tag=20
onboot: 1
ostype: l26
scsi0: local-lvm:vm-110-disk-0,discard=on,size=800G
scsihw: virtio-scsi-single
---
boot: order=scsi0;ide2
cores: 8
cpu: x86-64-v2-AES
hostpci0: 0000:65:00.0,pcie=1
ide2: local:iso/win2022-eval.iso,media=cdrom
machine: q35
memory: 32768
name: nwl-terminal
net0: virtio=BC:24:11:44:C1:03,bridge=vmbr0,tag=30
onboot: 1
ostype: win11
scsi0: ceph-vm:vm-120-disk-0,discard=on,size=400G
scsihw: virtio-scsi-singleIllustrative output
The capacity sheet from the handover note, reproduced as written:
| Node | Memory | Guest memory allocated | Guests |
|---|---|---|---|
| pve-01 | 256 GiB | 198 GiB | vm 101, vm 110, three others |
| pve-02 | 256 GiB | 187 GiB | vm 102, vm 105, vm 150 |
| pve-03 | 256 GiB | 121 GiB | vm 120, two others |
| Total | 768 GiB | 506 GiB |
High availability
$ ha-manager statusquorum OK
master pve-01 (active, Wed Aug 12 09:41:00 2026)
lrm pve-01 (active, Wed Aug 12 09:41:02 2026)
lrm pve-02 (active, Wed Aug 12 09:41:04 2026)
lrm pve-03 (active, Wed Aug 12 09:41:01 2026)
service vm:101 (pve-01, started)
service vm:102 (pve-02, started)
service vm:105 (pve-02, started)
service vm:110 (pve-01, started)
service vm:120 (pve-03, started)Illustrative output
$ lsmod | grep -E 'softdog|wdt' ; systemctl is-active watchdog-muxsoftdog 16384 1
activeIllustrative output
The journal shows no watchdog reset on any node since the cluster was built. Fencing has never been exercised, planned or unplanned.
Backup
$ pvesh get /cluster/backupjob-id: backup-8a41e0c2-9f31
schedule: 22:00
storage: pbs-nwl
mode: snapshot
notes: nightly
exclude: 105
enabled: 1
last-run: 2026-08-11 22:00:03 status OK duration 41m18sIllustrative output
$ proxmox-backup-manager datastore list ; proxmox-backup-manager verify-job list ; proxmox-backup-manager garbage-collection status nwl-storeName Path Comment
nwl-store /mnt/datastore/nwl-store primary datastore
(no verify jobs configured)
Datastore: nwl-store
Last GC run: 2025-11-14 03:00:02
Schedule: (none)
Removed bytes: 0
Pending bytes: 2.71 TiBIllustrative output
$ proxmox-backup-client snapshot list --repository backup@pbs!pve@192.0.2.150:nwl-storesnapshot size verify state
vm/101/2026-08-11T22:00:07Z 412.8 GiB none
vm/101/2026-08-10T22:00:05Z 412.5 GiB none
vm/101/2026-08-09T22:00:11Z 412.1 GiB none
prune options for this datastore: keep-last=3Illustrative output
vm 150 is the PBS instance. It runs on pve-02, and qm config 150
shows its datastore disk as scsi1: ceph-vm:vm-150-disk-1,size=4000G.
The PBS encryption key is the one referenced in storage.cfg and
exists in /etc/pve/priv/storage/pbs-nwl.enc. There is no sync job, no
second PBS instance, and no tape.
Local storage and ZFS
$ zpool status pool: rpool
state: ONLINE
status: One or more devices has experienced an unrecoverable error.
action: Determine if the device needs to be replaced.
scan: none requested
config:
NAME STATE READ WRITE CKSUM
rpool ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-INTEL_SSDSC2KB480G8_PHYF1234 ONLINE 3 0 0
ata-INTEL_SSDSC2KB480G8_PHYF5678 ONLINE 0 0 0
errors: No known data errors
pool: zbackup
state: ONLINE
scan: scrub repaired 0B in 09:12:44 with 0 errors on Sun Feb 9 2025
config:
NAME STATE READ WRITE CKSUM
zbackup ONLINE 0 0 0
raidz2-0 ONLINE 0 0 0
[ 8 x 8 TB SATA, trimmed ]
logs
nvme-Consumer_NVMe_2TB_S4X9 ONLINE 0 0 0
errors: No known data errorsIllustrative output
/etc/cron.d/zfsutils-linux on all three nodes:
# Scrub the second Sunday of every month.
# 24 0 8-14 * * root [ $(date +\%w) -eq 0 ] && [ -x /usr/lib/zfs-linux/scrub ] && /usr/lib/zfs-linux/scrub
# Commented 2025-04-11, scrub latency during business hours. Reschedule to weekend nights.
/etc/zfs/zed.d/zed.rc has ZED_EMAIL_ADDR commented out, as shipped.
Identity, firewall and notifications
$ pveum acl list ; pveum user token list monitoring@pvepath type ugid roleid propagate
/ user ansible@pve Administrator 1
/ user monitoring@pve Administrator 1
/ user ebrandi@pam Administrator 1
tokenid expire privsep comment
checkmk 0 0 checkmk agent, added 2025-04-08Illustrative output
/etc/pve/firewall/cluster.fw:
[OPTIONS]
enable: 0
policy_in: DROP
policy_out: ACCEPT
[IPSET management]
192.0.2.0/24
[RULES]
IN SSH(ACCEPT) -source 0.0.0.0/0 -log nolog
IN ACCEPT -source +management -p tcp -dport 8006 -log nolog
IN ACCEPT -source +management -p tcp -dport 5900:5999 -log nolog
/etc/pve/nodes/pve-03/host.fw contains enable: 1. The equivalent
file on pve-01 and pve-02 contains enable: 0.
Administrator workstations were renumbered from 192.0.2.0/24 to
198.51.100.0/24 during the March migration. The node, storage and
corosync addresses stayed where they were.
/etc/pve/notifications.cfg:
matcher: default-matcher
comment Route all notifications to mail-to-root
mode all
target mail-to-root
root@pam has no email address configured. /var/spool/mail/root on
pve-01 is 1.4 GiB and has never been read.
SDN and package versions
/etc/pve/sdn/zones.cfg:
evpn: prod
controller evpnctl
vrf-vxlan 10040
exitnodes pve-01
ipam pve
mtu 8950
pvesh get /cluster/sdn reports the configuration as pending; the
running configuration on the nodes was last generated in February.
Package versions differ across the cluster:
| Node | Kernel | Repository |
|---|---|---|
| pve-01 | 6.14.11-4-pve | pve-no-subscription |
| pve-02 | 6.14.11-4-pve | pve-no-subscription |
| pve-03 | 6.17.2-1-pve | pve-no-subscription, pvetest |
pve-01 and pve-02 are Xeon Gold 6338. pve-03 is a Xeon Gold 6542Y, bought a year later as a capacity addition.
What you must produce
Six deliverables. They are marked together, and an answer that produces findings without severities, or remediation without validation, is incomplete rather than partially correct.
- Findings. A risk register. One row per finding: where it is, what it is, and what it can do. Findings that only exist in combination get their own row, and name the components they need.
- Evidence. For each finding, the specific artefact or the
read-only command that establishes it. “The pool looks wrong” is
not evidence.
ceph osd pool ls detailnext toceph osd crush rule dumpis. - Severity. A rating per finding, from the scale below, with one sentence of reasoning. The reasoning is what is marked; the label on its own is not.
- Remediation. What you change, and in what order. The order is marked, and it is marked hardest. A plan that starts with the most interesting defect has chosen wrong.
- Validation. For each remediation, the command whose output demonstrates it worked. Not “the pool was updated” — the pool detail line, the resolved vote count, the restored guest booting.
- Production recommendation. May this estate keep carrying the workload? Under what conditions? What is the blocking set, and what is merely backlog?
The severity scale
Use this scale, and use all of it.
| Severity | Meaning |
|---|---|
| Critical | Can cause data loss, credential disclosure, or an estate-wide outage. Blocks the next production change. |
| High | Can cause an outage of a subset of workload, a silent loss of protection, or a serious loss of assurance. Fix before the next maintenance window closes. |
| Medium | Degrades reliability, capacity or diagnosis. Scheduled work with an owner. |
| Low | Hygiene and maintainability. Backlog. |
| None | Looks like a finding and is not. Record it as examined so nobody re-raises it. |
Marking key: the risk register
Thirty-two entries, in two tables. The thirty below are the substantive findings; the two after them are judgement calls a complete register still has to make.
Score two points for each finding you produced independently, and one further point where your severity is within one band of the key and your reasoning holds.
| # | Where | Finding | Severity |
|---|---|---|---|
| F1 | corosync.conf | quorum_votes: 2 on pve-01 gives 4 expected votes and a quorum of 3, so the loss of pve-01 leaves the survivors inquorate and their HA watchdogs reset them | Critical |
| F2 | ceph osd pool ls detail | ceph-vm at size 2 min_size 1: one failure removes all redundancy, and writes continue onto a single replica with nothing to reconcile against | Critical |
| F3 | ceph osd crush rule dump | The by-osd rule chooses leaves by OSD, so both replicas of a PG can land on one host and a host failure can make PGs inactive | Critical |
| F4 | ceph df + topology | 16 TiB stored needs 32 TiB raw for two copies; eight surviving OSDs supply 30.6 TiB and full_ratio permits 29.1 TiB, so a node loss cannot be repaired inside the cluster | Critical |
| F5 | ceph.conf + interfaces + corosync.conf | Corosync ring0, the Ceph public network, the Ceph cluster network and all guest traffic share one 2x10 GbE bond, with no second corosync link | Critical |
| F6 | qm config 150 + storage.cfg | The PBS datastore is a disk of a guest of this cluster, in the pool it is protecting: the backup shares the failure it exists to survive | Critical |
| F7 | PBS | No verify job exists and no restore has ever been performed, so nothing has established that any snapshot is readable or usable | Critical |
| F8 | backup job + cron | vm 105, the ERP database, is excluded from the backup job; its only protection is a snapshot cron on pve-01 that has failed silently since the guest relocated on 2026-03-19 | Critical |
| F9 | storage.cfg + /etc/pve/priv | The PBS encryption key exists only on the cluster the backups exist to replace, with no escrow | Critical |
| F10 | pveum | monitoring@pve!checkmk: Administrator on /, privsep 0, no expiry, secret stored on a guest of this cluster | Critical |
| F11 | capacity sheet | Reserved memory for ARC, OSDs and the host is not modelled, so no single node failure can be absorbed - the smallest node alone exceeds the combined headroom of the other two | Critical |
| F12 | HA + F1 + F5 | The estate-outage machine: weighted votes, a shared corosync wire and an untested software watchdog turn any single node failure into three nodes rebooting | Critical (composite: F1, F5, F16) |
| F13 | ceph -s | noout set since March, converting a capacity crisis into an unbounded window at one replica, with no alarm attached to it | High |
| F14 | qm config 110 + ha-manager | vm 110 is HA-managed with its disk on local-lvm, so HA recovery onto another node cannot start it | High |
| F15 | qm config 120 + ha-manager | vm 120 is HA-managed with a bare hostpci0 address and a cdrom from node-local local, so HA recovery cannot start it either | High |
| F16 | /etc/default/pve-ha-manager | Fencing is the software watchdog and has never been exercised on this estate, planned or unplanned | High |
| F17 | qm config 105 + node inventory | cpu: host against a differently generationed pve-03 means the ERP database cannot be live-migrated, so the estate has no evacuation path for its most important guest | High |
| F18 | pve-03 packages | pvetest enabled on one node of three, running a kernel and toolstack ahead of its peers | High |
| F19 | cluster.fw | The management IPSET holds the pre-March node network while administrators are on 198.51.100.0/24, so the first enable: 1 removes web access from every workstation at once | High |
| F20 | cluster.fw | IN SSH(ACCEPT) -source 0.0.0.0/0 - the one rule that survives the lockout is the one that should not exist | High |
| F21 | PBS | Retention is keep-last=3 against a stated 30-day requirement | High |
| F22 | PBS | Garbage collection last ran 2025-11-14, no schedule, 2.71 TiB pending and the datastore at 91% | High |
| F23 | notifications.cfg | Every notification targets mail-to-root, root@pam has no address, and 1.4 GiB of unread mail sits in a local spool - so no alert has reached a human since the estate was built | High |
| F24 | qm listsnapshot 105 | 41 snapshots on the ERP disk, held in the same pool, consuming capacity in a cluster at 71% and lengthening the chain on the live image | High |
| F25 | zpool status | scan: none requested on rpool, the monthly scrub commented out in April 2025 and never rescheduled | High |
| F26 | zpool status + zed.rc | Three read errors on an rpool mirror member with ZED notification unconfigured, so a degrading boot disk is invisible | High |
| F27 | backup job | vm 101 and vm 102 are backed up with agent: 0, so the images are crash-consistent only | Medium |
| F28 | zpool status | The zbackup SLOG is a consumer NVMe with no power-loss protection, and the pool has not been scrubbed since February 2025 | Medium |
| F29 | sdn/zones.cfg | The EVPN zone has a single exit node, and the configuration has been pending since February so the next apply pushes changes nobody has reviewed | Medium |
| F30 | ceph -s | One ceph-mgr with no standby; and 128 PGs with the autoscaler in warn, giving roughly 21 PGs per OSD | Medium |
And two items that must appear in the register with the right verdict:
| # | Where | Item | Severity |
|---|---|---|---|
| F31 | ceph -s | 1 daemons have recently crashed, from March, investigated and closed but never archived | Low — harmless in itself, and it is holding the cluster at HEALTH_WARN so the next crash arrives into a warning nobody reads |
| F32 | pvesm status, repositories | local dir storage on every node holding ISOs and templates; pve-no-subscription on pve-01 and pve-02 | None — the first is the standard layout and no running guest depends on it for a disk; the second is a procurement decision already made. pvetest on pve-03 is the actual defect and it is F18 |
The interactions
Findings in isolation understate this estate. Six combinations matter more than their parts, and the register is expected to name them.
The estate-outage machine (F1 + F5 + F16). Take pve-01 away and the survivors hold 2 votes of 4, become inquorate, and are reset by their own watchdogs sixty seconds later. Take either other node away and the survivors stay quorate, Ceph marks the dead OSDs out after ten minutes, and the resulting backfill saturates the bond corosync is sharing until the token times out - at which point the watchdogs fire anyway. Two different first steps, one outcome. Any single one of these three findings is a design comment; together they mean this cluster has no survivable single-node failure at all.
The pool that cannot survive what it claims (F2 + F3 + F4 + F13).
size 2 means one failure removes redundancy. The by-osd rule means
size 2 does not even guarantee two hosts. min_size 1 means
production keeps writing onto whatever single copy remains. The
capacity arithmetic means the repair cannot complete. And noout means
it will not be attempted, so the estate sits at one replica
indefinitely with a warning that has been on the screen since March.
Fixing any one of these alone leaves the pool unsafe; the register has
to say which one goes first and why, and the answer is min_size 2
because it is the only one that costs nothing.
High availability that cannot recover (F14 + F15 + F17 + F16).
Five guests are HA-managed. One cannot start elsewhere because its
disk is node-local; one cannot start elsewhere because of a raw PCI
address and a node-local cdrom; one cannot be evacuated because of
cpu: host against a mismatched node. The watchdog that would fence a
failed node has never been tested. What the estate has is not high
availability, it is a mechanism that will attempt recovery, fail, mark
services in error, and leave the operator debugging the HA stack during
the incident instead of restoring service.
The unrestorable estate (F6 + F7 + F8 + F9 + F21 + F22). The backup server is a guest of the cluster. Its datastore is a disk in the pool it protects. Nothing verifies the chunks, nothing has ever restored one, retention holds three days against a thirty-day requirement, garbage collection has not run since November so the datastore fills, the key that decrypts it lives on the cluster, and the one guest the business cannot lose is not in the job at all. Six independent mechanisms, each of which alone would be a finding, and in series they mean the loss of the Ceph pool is the loss of the company’s data. This is the interaction that decides the production recommendation.
Failure without a signal (F23 + F13 + F25 + F26 + F31). Alerts go
to a mailbox nobody has ever opened. noout and a stale crash keep the
Ceph health line at HEALTH_WARN permanently, so a new warning arrives
into a state that already looks wrong. The ZFS scrub that would find
latent corruption was commented out sixteen months ago, and ZED cannot
tell anyone about the read errors it is already seeing. Every one of
these is a signal converted into silence, and they are arranged so that
the first genuine notification anybody receives about this estate will
be a person telephoning.
One credential, everything (F10 + F6 + F9 + F19 + F20). An Administrator token with no expiry and no privilege separation, whose secret sits in a file on a guest of the cluster. That token can delete every guest, the backup job, the backup server guest, and the datastore disk. The encryption key is on the same cluster. The firewall that might have limited where the token can be used from has never been enabled, and when it is, the rule that survives is unrestricted SSH. There is no second copy anywhere and no pull-mode remote. One credential, one step, nothing left.
Working the arithmetic
Two findings in this estate are arithmetic rather than judgement, and the register is expected to show the working rather than assert the conclusion.
ceph df
ceph osd df tree
ceph osd pool ls detailCeph, after losing one node. 16 TiB stored, size 2, so 32 TiB of
raw capacity is required to hold two copies. Twelve OSDs supply 46 TiB;
eight survivors supply 30.6 TiB. The requirement exceeds the survivors
before full_ratio is even considered, and full_ratio at 0.95 caps
usable raw at 29.1 TiB. The rebuild therefore cannot complete: it fills
the cluster and blocks client I/O across every guest, which is a worse
outcome than the node failure that started it.
Raising size to 3 needs 48 TiB of raw capacity against the 46 TiB
that exists, and that is before headroom for a failure. The honest
figure for the budget request is not “more disk” - it is roughly 24 TiB
of additional raw capacity to run size 3 with a node’s worth of
headroom, which on these OSDs is six more drives.
Memory, after losing one node. Each node has 256 GiB. Subtract the
ARC cap of 16 GiB, four OSDs at the default 4 GiB osd_memory_target
for roughly 16 GiB more, and the host, monitor, manager and PVE
services for several more - call it 40 GiB. That leaves about 216 GiB
per node for guests, against allocations of 198, 187 and 121 GiB.
Every node fits today. No node failure fits. pve-01 has 18 GiB of headroom and pve-02 has 29 GiB; between them they cannot take the 121 GiB that pve-03 is carrying, let alone the 198 GiB that pve-01 is. The handover note’s “506 fits in 512” is arithmetic performed on memory the guests were never going to get.
Scenarios
Six scenarios, with full rubrics in this assessment’s frontmatter. Items marked REQUIRED are pass or fail on their own.
| # | Scenario | The element most often missed |
|---|---|---|
| 1 | The cluster and quorum layer | Working the loss of each node separately instead of assuming a three-node cluster is symmetric |
| 2 | The Ceph layer | Reading the pool line and the CRUSH rule together, and doing the post-failure capacity arithmetic explicitly |
| 3 | The 02:14 incident | Not leaving a temporary quorum override in place afterwards - which is how the estate acquired its current defect |
| 4 | Proving the backups | Copy before prune, verify before trusting, restore before claiming |
| 5 | Identity, access and network policy | Evaluating the firewall rule set against the addresses administrators actually use, before applying it |
| 6 | The production recommendation | A blocking set small enough to be credible, plus interim controls that survive month-end without a large change |
Pass criteria
- 75% overall: Part A auto-scored at 25%, the risk register at 45%, the scenarios at 30%.
- All four mandatory findings present in Part B, each with a
defensible severity:
- F1, the weighted corosync vote that makes pve-01 a single point of failure for the whole cluster.
- F2 with F3, the replication and placement pairing, which must be identified as one finding about the pool rather than two unrelated settings.
- F8, the ERP database excluded from backup with a snapshot cron that has failed silently since March.
- F6, the backup datastore living inside the failure domain it exists to survive.
- At least three of the six interactions named, because a register of isolated items misrepresents this estate even when every item in it is correct.
- At least two findings rated Low or None with reasoning. An audit that cannot say what is not urgent has not made a judgement.
- Four of six scenarios passed against their rubrics, with no REQUIRED element missed in any scenario answer.
Why the bar is 75 and not 70
The rest of this course passes coursework at 70. This assessment is set higher deliberately, for three reasons.
The first is the marking scheme. Part B awards marks for findings a
careless reader still stumbles into. size 2 on a production pool is
not hard to see. Neither is a backup job that excludes the database, or
an Administrator token for a monitoring system. A candidate who skims
the captures, reports the eight most visible items and writes nothing
about severity, sequencing or interaction can assemble something close
to 70% out of the obvious half of the register. The bar has to sit
above that, or the result certifies the wrong thing.
The second is that the interactions carry the estate. Every one of the six is composed of findings that are individually survivable and jointly are not. An engineer who lists thirty items and never connects three of them has produced a document that will be triaged into a backlog and worked in the wrong order - which is materially worse than a shorter register that names the outage machine first.
The third is what the credential claims. This estate holds a company’s operational data on two replicas that can share a host, backed up to itself, alerting to a mailbox nobody opens. The question this assessment answers is not “does this person know Proxmox” - it is “would I let this person sign off the platform”. That is a higher bar in real life and it should be a higher bar here.
The mandatory findings exist for the same reason. A candidate could reach 75% on breadth while missing that the database has had no recoverable copy since March, and breadth does not compensate for that, so the scoring does not let it.