kubestronaut-sim runs each exam task on a host of its own - a kind (kubeadm) cluster in rootless podman, or a QEMU/KVM Ubuntu VM for the CKS tasks that need their own kernel (Falco, AppArmor) - and puts a browser desktop in front of them, the way killer.sh and sailor.sh do. - ksim, sim/: the engine (sessions, drills, study mode, grading, coverage, audit), host and VM lifecycle, the desktop - images/: exam host images (common, CKS variant with its tools, VM guest) - cka/ (131 tasks), ckad/ (105), cks/ (110): task banks, curricula with study notes, reference solutions and scripted solutions Every domain of every track has at least 17 pool tasks. `./ksim audit` proves a task three ways: it seeds cleanly on its own host, scores nothing before anyone has worked on it, and reaches full marks when its scripted solution is run on the host as `candidate`. All 346 tasks pass (CKA audited 2026-10-13, CKAD and CKS 2026-10-12). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JZPd3GGWyxTgAkL6a4gAJz
40 lines
1.8 KiB
Python
40 lines
1.8 KiB
Python
"""Building blocks shared by the CKAD task banks written for the per-task hosts (77 onwards): bash
|
|
for setups and checks. The generic ones - NET, PODS, PY - are sim/bank.py's.
|
|
|
|
The two rules of the CKS banks hold here as well: a task scores nothing before anyone has worked
|
|
on it, and what can be tested for real - a request, a file in a container, a container's
|
|
environment - is tested for real rather than read off the object.
|
|
"""
|
|
from sim.bank import C, CAN, NET, NS, PODS, PY, ns_pick, name_pick # noqa: F401 (the banks import these from here)
|
|
|
|
# Rollouts and the Pods they leave behind.
|
|
ROLL = r"""
|
|
# rolled NS DEPLOYMENT N [SECONDS]: the Deployment has N replicas, all of them updated and available
|
|
rolled() {
|
|
local i
|
|
for i in $(seq 1 $(( ${4:-60} / 3 ))); do
|
|
[ "$(j -n "$1" deploy "$2" '{.status.replicas}')" = "$3" ] && [ "$(j -n "$1" deploy "$2" '{.status.updatedReplicas}')" = "$3" ] \
|
|
&& [ "$(j -n "$1" deploy "$2" '{.status.availableReplicas}')" = "$3" ] && return 0
|
|
sleep 3
|
|
done; return 1
|
|
}
|
|
# newest NS SELECTOR: the name of the newest Running Pod the selector matches
|
|
newest() { $K -n "$1" get pod -l "$2" --field-selector status.phase=Running --sort-by=.metadata.creationTimestamp -o jsonpath='{.items[-1:].metadata.name}' 2>/dev/null; }
|
|
"""
|
|
|
|
# img IMAGE GO-TEMPLATE: a property of an image in the host's store ("" if there is no such image)
|
|
IMG = r"""
|
|
img() { podman image inspect "$1" --format "$2" 2>/dev/null | tr -d '\r'; }
|
|
"""
|
|
|
|
# same LIST-FILE EXPECTED-FILE: the candidate's list names exactly the expected items (order,
|
|
# blanks and a leading "kind/" ignored)
|
|
SAME = r"""
|
|
same() { [ -s "$1" ] && diff <(tr -d ' \r' < "$1" | sed 's#.*/##' | grep . | sort -u) <(sort -u "$2") >/dev/null; }
|
|
"""
|
|
|
|
# one FILE: the file's content with blanks and line ends removed - for a one-word answer
|
|
ONE = r"""
|
|
one() { tr -d ' \t\n\r' < "$1" 2>/dev/null; }
|
|
"""
|