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
45 lines
2.7 KiB
Bash
45 lines
2.7 KiB
Bash
#!/bin/bash
|
|
# ksim-vm run boot the exam host of this container. Its disk is /env/disk.qcow2, a thin copy of
|
|
# the base disk made on the first start; /course is the task's /opt/course.
|
|
# ksim-vm build make the base disk: boot the Ubuntu cloud image once with guest/provision.sh as
|
|
# its first-boot script, and keep the result.
|
|
#
|
|
# /base .state/vm of the simulator: the Ubuntu cloud image and the base disks (read-only for run)
|
|
# /env the host's own directory (.state/envs/<host>): disk and console log
|
|
# /keys the simulator's ssh key pair (read-only)
|
|
set -euo pipefail
|
|
KVM=(-enable-kvm -cpu host -machine q35 -display none -monitor none -device virtio-rng-pci)
|
|
|
|
case "${1:-run}" in
|
|
run)
|
|
base=/base/${KSIM_BASE:?}
|
|
[ -f /env/disk.qcow2 ] || qemu-img create -q -f qcow2 -F qcow2 -b "$base" /env/disk.qcow2
|
|
# what the machine needs to know about itself, handed over as a second shared directory:
|
|
# its name, and the key the simulator and the desktop log in with (guest/firstboot.sh reads both)
|
|
mkdir -p /run/ksim && echo "${KSIM_HOSTNAME:?}" > /run/ksim/hostname && cp /keys/id_ed25519.pub /run/ksim/authorized_keys
|
|
exec qemu-system-x86_64 "${KVM[@]}" -smp "${KSIM_VM_CPUS:-2}" -m "${KSIM_VM_MB:-2048}" -serial file:/env/console.log \
|
|
-drive file=/env/disk.qcow2,if=virtio,cache=unsafe,discard=unmap \
|
|
-netdev user,id=n0,hostfwd=tcp::22-:22,hostfwd=tcp::6443-:6443 -device virtio-net-pci,netdev=n0 \
|
|
-virtfs local,path=/course,mount_tag=course,security_model=passthrough,id=course \
|
|
-virtfs local,path=/run/ksim,mount_tag=ksim,security_model=none,readonly=on,id=ksim
|
|
;;
|
|
build)
|
|
out=/base/${KSIM_BASE:?}; work=/base/.build.qcow2; log=/base/build.log
|
|
rm -f "$work" /base/.seed.iso "$out.new"; : > "$log"
|
|
qemu-img create -q -f qcow2 -F qcow2 -b /base/noble.img "$work" 20G
|
|
printf 'instance-id: ksim-build\nlocal-hostname: ksim-build\n' > /tmp/meta-data
|
|
cloud-localds /base/.seed.iso /build/provision.sh /tmp/meta-data
|
|
# the guest powers itself off when provision.sh is through; -no-reboot turns that into QEMU exiting
|
|
timeout "${KSIM_BUILD_TIMEOUT:-2400}" qemu-system-x86_64 "${KVM[@]}" -smp 4 -m 4096 -serial "file:$log" -no-reboot \
|
|
-drive file="$work",if=virtio,cache=unsafe -drive file=/base/.seed.iso,if=virtio,format=raw \
|
|
-netdev user,id=n0 -device virtio-net-pci,netdev=n0 \
|
|
-virtfs local,path=/build,mount_tag=build,security_model=none,readonly=on,id=build || true
|
|
if ! grep -q KSIM-PROVISION-OK "$log"; then
|
|
echo "provisioning did not finish - the end of the VM's console:" >&2; tail -n 40 "$log" >&2; rm -f "$work" /base/.seed.iso; exit 1
|
|
fi
|
|
qemu-img convert -O qcow2 "$work" "$out.new" && mv "$out.new" "$out"
|
|
rm -f "$work" /base/.seed.iso
|
|
;;
|
|
*) echo "usage: ksim-vm run|build" >&2; exit 2 ;;
|
|
esac
|