refactor: retire simulator sets A and B; C and D are the fixed sets
Removes tracks/cka/bank_sim_a.py and bank_sim_b.py (34 tasks, ids 201-217 and 301-317). The previous commit holds their last versions, with every fix from the audit applied and both sets verified end to end - restore with `git show HEAD~1:tracks/cka/bank_sim_a.py` if one is ever wanted back. The baseline keeps repairing what those sets could leave on a cluster that ran them (the maintenance taint, cordons, Q317's controller flag, Q314's static pod) - only its comments changed. `breaks` keys that existed solely to keep pool tasks apart from set A/B tasks are gone. History keeps its raw entries; weak-spots is regenerated without the retired tasks. A mistyped drill argument now gets a usage message instead of a traceback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
55ab18f814
commit
228e4f790b
20
README.md
20
README.md
@ -4,9 +4,9 @@ Entry point is `./exam` (renamed from `cka-sim` so it can't collide with the dir
|
||||
|
||||
Hands-on exam tasks graded **per check** against a real cluster, an exam clock, a browser
|
||||
front end modelled on the real PSI exam, attempt history, and drills that rotate through the
|
||||
domains before you sit a full exam. Tracks: **CKA** (136 tasks: a random pool of 43 normal +
|
||||
24 hard, plus four fixed simulator sets A–D of 17–18 tasks each), CKAD and CKS (scaffolded — same
|
||||
format, add questions when you get there).
|
||||
domains before you sit a full exam. Tracks: **CKA** (102 tasks: a random pool of 43 normal +
|
||||
24 hard, plus two fixed simulator sets, C and D, of 18 and 17 tasks), CKAD and CKS (scaffolded —
|
||||
same format, add questions when you get there).
|
||||
|
||||
## How a session is built
|
||||
|
||||
@ -68,7 +68,7 @@ The same state is available from the terminal if you prefer:
|
||||
./exam drill # next least-drilled domain, 5 tasks (add --hard)
|
||||
./exam drill weak | drill 2 17 20 | drill TSHOOT NET | drill setd
|
||||
./exam start [--hard] # full exam (gated until all domains drilled; --force)
|
||||
./exam sim a|b|c|d # a fixed 17/18-task simulator set, exam rules, 120 min
|
||||
./exam sim c|d # a fixed 18/17-task simulator set, exam rules, 120 min
|
||||
./exam study [DOMAIN|weak|N..] # no clock, solutions visible, nothing recorded
|
||||
./exam list | show N | timer | status # during
|
||||
./exam end # submit
|
||||
@ -133,12 +133,12 @@ Before every session a baseline pass repairs anything a previous, unfinished ses
|
||||
The kindnet CNI here **enforces** NetworkPolicy (it embeds a policy engine), so a wrong policy
|
||||
really drops traffic; no ingress or Gateway controller runs, so those are graded on the objects.
|
||||
|
||||
**Simulator sets** (`./exam sim a|b|c|d`, never drawn into random sessions): A and B are
|
||||
killer.sh-grade investigate-and-write-to-file sets, C is modelled on an 18-question commercial
|
||||
mock sitting, and D is killer.sh-style — control-plane inventory, event forensics with crictl,
|
||||
a broken kubelet unit, kubelet certificates, manual scheduling with the scheduler stopped, Helm
|
||||
housekeeping with a stuck release, and an enforced AND-vs-OR NetworkPolicy. All are original
|
||||
scenarios, not copies of any commercial simulator.
|
||||
**Simulator sets** (`./exam sim c|d`, never drawn into random sessions): C is modelled on an
|
||||
18-question commercial mock sitting, and D is killer.sh-style — control-plane inventory, event
|
||||
forensics with crictl, a broken kubelet unit, kubelet certificates, manual scheduling with the
|
||||
scheduler stopped, Helm housekeeping with a stuck release, and an enforced AND-vs-OR
|
||||
NetworkPolicy. Both are original scenarios, not copies of any commercial simulator. (Sets A and B
|
||||
were retired in favour of these two; their last versions are in git history.)
|
||||
|
||||
## Adding tasks or a new track
|
||||
|
||||
|
||||
40
exam
40
exam
@ -212,8 +212,8 @@ def q_by_id(n: int) -> dict[str, Any]:
|
||||
for q in QUESTIONS:
|
||||
if q["id"] == n:
|
||||
return q
|
||||
# ids are not contiguous (1-43 base, 101-124 hard, 201-217 / 301-317 / 401-418 / 501-517 sim
|
||||
# sets), so print the real ranges rather than "1-<count>", which named ids that do not exist.
|
||||
# ids are not contiguous (1-43 base, 101-124 hard, 401-418 / 501-517 sim sets), so print the
|
||||
# real ranges rather than "1-<count>", which named ids that do not exist.
|
||||
ids = sorted(q["id"] for q in QUESTIONS)
|
||||
ranges, start, prev = [], ids[0], ids[0]
|
||||
for i in ids[1:] + [None]:
|
||||
@ -375,7 +375,7 @@ def drilled_domains():
|
||||
|
||||
def breaks_of(q):
|
||||
"""A task's "breaks" as a set. It is a string or a list: Q118 damages the scheduler AND the
|
||||
controller-manager, and declaring only one let it share a session with Q38/Q317."""
|
||||
controller-manager, and declaring only one let it share a session with Q38."""
|
||||
b = q.get("breaks")
|
||||
return set() if not b else ({b} if isinstance(b, str) else set(b))
|
||||
|
||||
@ -653,11 +653,10 @@ f=/etc/kubernetes/manifests/kube-scheduler.yaml
|
||||
sed -i "s|^\( *\)- kube-schedulerr$|\1- kube-scheduler|" $f 2>/dev/null
|
||||
' </dev/null
|
||||
|
||||
# controller-manager: undo Q38's injected flag, Q118's broken image tag and Q317's sabotage - both
|
||||
# its current form (the CSR signing controller switched off in --controllers) and the older one
|
||||
# (--cluster-signing-cert-file pointed at a missing file). That older form crash-looped the WHOLE
|
||||
# controller-manager, because a controller that fails to start is fatal there, so every later
|
||||
# session silently lost deployments, jobs, endpoints and PV phases, not just CSR signing.
|
||||
# controller-manager: undo Q38's injected flag and Q118's broken image tag. The last two lines
|
||||
# undo the retired set B's Q317 (the CSR signing controller switched off in --controllers, or in
|
||||
# its older form --cluster-signing-cert-file pointed at a missing file, which crash-looped the WHOLE
|
||||
# controller-manager); a cluster that ever ran that set may still carry either.
|
||||
nx "$CP" '
|
||||
f=/etc/kubernetes/manifests/kube-controller-manager.yaml
|
||||
sed -i "/--leader-elect-lease-duration=1s/d" $f 2>/dev/null
|
||||
@ -711,9 +710,10 @@ for n in "$W1" "$W2" "$W3"; do
|
||||
' </dev/null
|
||||
done
|
||||
|
||||
# static pods the bank drops on nodes: Q05's static-web and Q314's edge-cache on W3 (edge-cache
|
||||
# sat in ContainerCreating for days, its hostPath deliberately missing), Q103's relocated copies,
|
||||
# Q509's ops-beacon on the control plane. Each setup recreates what its own session needs.
|
||||
# static pods the bank drops on nodes: Q05's static-web on W3, Q103's relocated copies, Q509's
|
||||
# ops-beacon on the control plane - and edge-cache, left on W3 by the retired set B (it sat in
|
||||
# ContainerCreating for days, its hostPath deliberately missing). Each setup recreates what its
|
||||
# own session needs.
|
||||
nx "$W3" 'rm -f /etc/kubernetes/manifests/static-web*.yaml /etc/kubernetes/manifests/edge-cache.yaml /etc/kubernetes/static/*.yaml' </dev/null
|
||||
nx "$CP" 'rm -f /etc/kubernetes/manifests/ops-beacon*.yaml' </dev/null
|
||||
|
||||
@ -729,8 +729,8 @@ if $K get sc standard >/dev/null 2>&1; then
|
||||
fi
|
||||
|
||||
# w1-taint: clear every randomized demo taint key the bank can apply. Q25 draws from
|
||||
# dedicated/team/workload, Q107 from pool/lane, and Q307 pins maintenance=inprogress - miss one
|
||||
# and that node silently stops accepting pods for every later session.
|
||||
# dedicated/team/workload and Q107 from pool/lane; `maintenance` was the retired set B's and may
|
||||
# still be on a cluster that ran it. Miss one and that node silently stops accepting pods.
|
||||
# One key per call: `kubectl taint node N a- b-` aborts on the first key that is not present and
|
||||
# removes NOTHING, so the single taint that is actually set survives the "cleanup" and W1 keeps
|
||||
# rejecting pods in every later session - the exact failure this block exists to prevent.
|
||||
@ -750,9 +750,8 @@ if $K -n kube-system get deploy metrics-server >/dev/null 2>&1 \
|
||||
-p '[{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]' >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# w1-block/w2-drain/w3-drain: Q307 cordons W1 and Q117 cordons W2, and Q208/Q309 have the
|
||||
# candidate drain W2/W3. A cordon left behind fails any later task that counts pods per node
|
||||
# (Q26/Q211 DaemonSet coverage, Q212's one-pod-per-node spread).
|
||||
# cordons: Q117 cordons W2, and a drain task left half-done leaves a node cordoned. A cordon left
|
||||
# behind fails any later task that needs every worker (Q26's DaemonSet coverage, Q107's spread).
|
||||
for n in "$W1" "$W2" "$W3"; do $K uncordon "$n" >/dev/null 2>&1 || true; done
|
||||
|
||||
# Deliberately NOT restored, and why:
|
||||
@ -763,10 +762,6 @@ for n in "$W1" "$W2" "$W3"; do $K uncordon "$n" >/dev/null 2>&1 || true; done
|
||||
# to tell "mid-attempt" from "correctly completed" without guessing, and guessing wrong here
|
||||
# rewrites etcd's data-dir or re-issues certs on a healthy cluster. Re-run ./setup.sh (or
|
||||
# ./teardown.sh && ./setup.sh) if one of those leaves the control plane wedged.
|
||||
#
|
||||
# proxy-rules (Q302) needs nothing: its setup only creates a namespace and deletes a pod and
|
||||
# service. The "breaks" key is there for no_conflicts() bookkeeping, not because it damages
|
||||
# shared state.
|
||||
"""
|
||||
|
||||
def restore_baseline(log: Callable[..., Any] = _log_msg):
|
||||
@ -904,8 +899,11 @@ def cmd_drill(args):
|
||||
ids += [q["id"] for q in set_questions(a.lower().replace("set", ""))]
|
||||
elif a.upper() in DOMAINS:
|
||||
ids += [q["id"] for q in QUESTIONS if q["domain"] == a.upper()]
|
||||
else:
|
||||
elif a.isdigit():
|
||||
ids.append(q_by_id(int(a))["id"])
|
||||
else:
|
||||
die(f"'{a}' is not a task id, a domain ({', '.join(DOMAINS)}) or a set "
|
||||
f"({', '.join('set' + k for k in SETS) or 'none'}).")
|
||||
ids = sorted(set(ids))
|
||||
qs, solo = split_solo([q for q in QUESTIONS if q["id"] in ids])
|
||||
if solo:
|
||||
|
||||
@ -282,8 +282,8 @@ $K -n %{ns} delete deploy %{dep} --ignore-not-found >/dev/null
|
||||
},
|
||||
{
|
||||
"id": 26, "domain": "WORK", "title": "DaemonSet on every node",
|
||||
# needs every node schedulable: Q25/Q107 taint W1 and must keep the taint, Q307 blocks it
|
||||
"breaks": ["w1-taint", "w1-block"],
|
||||
# needs every node schedulable: Q25/Q107 taint W1 and must keep the taint
|
||||
"breaks": ["w1-taint"],
|
||||
"params": lambda r: {"ns": ns_pick(r, "agents"), "ds": name_pick(r, "node-agent")},
|
||||
"task": """
|
||||
Create a DaemonSet `%{ds}` in namespace `%{ns}` (image `busybox:1.36`, command `sleep 3600`)
|
||||
|
||||
@ -670,7 +670,7 @@ echo "$pv" > "$WS/.q116-pv"
|
||||
},
|
||||
# ============================================================== TSHOOT ====
|
||||
{
|
||||
"id": 117, "domain": "TSHOOT", "breaks": ["w2-kubelet", "w2-drain"], "difficulty": "hard", "title": "Worker node: three things wrong", "disruptive": True,
|
||||
"id": 117, "domain": "TSHOOT", "breaks": "w2-kubelet", "difficulty": "hard", "title": "Worker node: three things wrong", "disruptive": True,
|
||||
"params": lambda r: {"ctx": "k8s-c1-H"},
|
||||
"task": CTX + """
|
||||
Node `{W2}` is unusable. Make it fully usable again: `Ready`, schedulable, kubelet running and
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
"""Simulator Set D - 17 tasks, fixed set, killer.sh-style.
|
||||
|
||||
Original scenarios, not copies of any commercial simulator. They exercise the techniques the
|
||||
killer.sh CKA environment is known for that sets A-C do not already cover: saying how every
|
||||
killer.sh CKA environment is known for that the rest of the bank did not cover: saying how every
|
||||
control-plane piece is run, cluster facts to an exact file, readiness gated on a Service,
|
||||
`--sort-by` scripts, event forensics around kube-proxy with crictl, API-resource and RBAC census,
|
||||
a kubelet whose systemd unit points at the wrong binary, Secrets mounted read-only and renamed into
|
||||
|
||||
@ -6,7 +6,7 @@ mkns() {
|
||||
# Wait for the namespace's `default` ServiceAccount before returning. The controller creates it
|
||||
# asynchronously, and a Pod applied in the gap is rejected outright:
|
||||
# error looking up service account <ns>/default: serviceaccount "default" not found
|
||||
# Setups that create a namespace and immediately apply Pods lose that race under load (Q204),
|
||||
# Setups that create a namespace and immediately apply Pods lose that race under load,
|
||||
# which fails the seed and costs the candidate a whole task. It belongs here, not in each task.
|
||||
for _ in $(seq 1 30); do $K -n "$1" get sa default >/dev/null 2>&1 && return 0; sleep 1; done
|
||||
}
|
||||
|
||||
@ -23,8 +23,9 @@ TRACK = {
|
||||
# tasks per domain drawn into a session (weights follow the exam blueprint)
|
||||
"quota": {"ARCH": 5, "WORK": 4, "NET": 4, "STOR": 2, "TSHOOT": 5}, # 20 tasks
|
||||
"quota_hard": {"ARCH": 6, "WORK": 5, "NET": 5, "STOR": 3, "TSHOOT": 6}, # 25 tasks, hard ones preferred
|
||||
# fixed simulator sets (./exam sim a|b|c|d) - excluded from random sampling
|
||||
"sets": {"a": "Simulator Set A", "b": "Simulator Set B", "c": "Simulator Set C", "d": "Simulator Set D (killer.sh-style)"},
|
||||
# fixed simulator sets (./exam sim c|d) - excluded from random sampling. Sets A and B were
|
||||
# retired on 2026-09-22; their last (fixed, verified) versions are in git history.
|
||||
"sets": {"c": "Simulator Set C", "d": "Simulator Set D (killer.sh-style)"},
|
||||
"domains": {
|
||||
"ARCH": "Cluster Architecture, Installation & Configuration (25%)",
|
||||
"WORK": "Workloads & Scheduling (15%)",
|
||||
@ -631,10 +632,10 @@ $K -n default delete pod sched-probe --wait=false >/dev/null 2>&1
|
||||
]
|
||||
|
||||
# ---- aggregate the banks: 1-20 here, 21-43 in bank_extra, 101-124 (hard) in bank_hard,
|
||||
# ---- 201-217 / 301-317 / 401-418 / 501-517 in the four fixed simulator sets
|
||||
from tracks.cka import bank_extra, bank_hard, bank_sim_a, bank_sim_b, bank_sim_c, bank_sim_d
|
||||
# ---- 401-418 / 501-517 in the two fixed simulator sets
|
||||
from tracks.cka import bank_extra, bank_hard, bank_sim_c, bank_sim_d
|
||||
QUESTIONS = (QUESTIONS + bank_extra.QUESTIONS + bank_hard.QUESTIONS
|
||||
+ bank_sim_a.QUESTIONS + bank_sim_b.QUESTIONS + bank_sim_c.QUESTIONS + bank_sim_d.QUESTIONS)
|
||||
+ bank_sim_c.QUESTIONS + bank_sim_d.QUESTIONS)
|
||||
QUESTIONS.sort(key=lambda q: q["id"])
|
||||
_ids = [q["id"] for q in QUESTIONS]
|
||||
assert len(_ids) == len(set(_ids)), "duplicate question ids"
|
||||
|
||||
@ -100,27 +100,6 @@ _Generated by exam from 10 attempt(s); regenerated on every `end`._
|
||||
- ✗ Service ledger-21 port 9000 in the same namespace
|
||||
- ✗ ns.txt has the namespace
|
||||
|
||||
### Q202 · ARCH · Helm chart with CRDs, then a custom resource (1/1 failed, last 3/8 pts, last failed 2026-09-19T12:27)
|
||||
- ✗ watchAllNamespaces=true reached the pod env
|
||||
- ✗ Ledger main-ledger has currency USD and retentionDays 30
|
||||
|
||||
### Q204 · WORK · Which Pods get evicted first (1/1 failed, last 0/8 pts, last failed 2026-09-19T12:27)
|
||||
- ✗ evicted-first.txt lists exactly the BestEffort pods
|
||||
- ✗ api-qos.txt says Burstable
|
||||
- ✗ guaranteed.txt names orion-ledger
|
||||
|
||||
### Q217 · TSHOOT · Inspect a container with crictl (1/1 failed, last 0/10 pts, last failed 2026-09-19T12:27)
|
||||
- ✗ Pod tiger-probe Running with both labels
|
||||
- ✗ container.txt holds a real container ID for that Pod
|
||||
- ✗ container.txt records the runtimeType
|
||||
- ✗ container.log holds the httpd startup output
|
||||
|
||||
### Q313 · NET · Two hosts, TLS, and a default backend (1/1 failed, last 0/11 pts, last failed 2026-09-19T12:27)
|
||||
- ✗ Secret classic-tls is a TLS secret with CN classic.r700.io
|
||||
- ✗ both host rules route to the right Services on /
|
||||
- ✗ TLS covers both hosts with classic-tls
|
||||
- ✗ defaultBackend points at web-classic:80, class is nginx
|
||||
|
||||
## Attempt matrix
|
||||
|
||||
| Q | Domain | Title | D1 | E2 | D3 | D4 | D5 | D6 | D7 | D8 | D9 | D10 |
|
||||
@ -192,40 +171,6 @@ _Generated by exam from 10 attempt(s); regenerated on every `end`._
|
||||
| 122 | ARCH | Renew control-plane certificates | · | · | · | · | · | · | · | · | · | · |
|
||||
| 123 | TSHOOT | Nothing works: kube-apiserver itself is down | · | · | · | · | · | · | · | · | · | · |
|
||||
| 124 | ARCH | Prepare a node join without shell access to the control plane | · | · | · | · | · | · | · | · | · | · |
|
||||
| 201 | ARCH | kubeconfig forensics | · | · | · | · | · | · | · | · | · | · |
|
||||
| 202 | ARCH | Helm chart with CRDs, then a custom resource | · | · | · | · | · | · | · | · | · | 3/8 |
|
||||
| 203 | WORK | Find the controller, then scale it | · | · | · | · | · | · | · | · | · | · |
|
||||
| 204 | WORK | Which Pods get evicted first | · | · | · | · | · | · | · | · | · | 0/8 |
|
||||
| 205 | ARCH | Kustomize: drop a ConfigMap, add an HPA, override in prod | · | · | · | · | · | · | · | · | · | · |
|
||||
| 206 | STOR | PV, PVC and a Deployment that mounts it | · | · | · | · | · | · | · | · | · | · |
|
||||
| 207 | TSHOOT | Resource usage scripts | · | · | · | · | · | · | · | · | · | · |
|
||||
| 208 | ARCH | Drain a node for maintenance | · | · | · | · | · | · | · | · | · | · |
|
||||
| 209 | ARCH | Query the API from inside a Pod | · | · | · | · | · | · | · | · | · | · |
|
||||
| 210 | ARCH | ServiceAccount limited to two resources | · | · | · | · | · | · | · | · | · | · |
|
||||
| 211 | WORK | DaemonSet on every node | · | · | · | · | · | · | · | · | · | · |
|
||||
| 212 | WORK | One Pod per node, on purpose | · | · | · | · | · | · | · | · | · | · |
|
||||
| 213 | NET | Convert an Ingress to Gateway API, then split on a header | · | · | · | · | · | · | · | · | · | · |
|
||||
| 214 | ARCH | Certificate expiry, two ways | · | · | · | · | · | · | · | · | · | · |
|
||||
| 215 | NET | Egress policy with paired destinations | · | · | · | · | · | · | · | · | · | · |
|
||||
| 216 | NET | CoreDNS: back up, extend, verify | · | · | · | · | · | · | · | · | · | · |
|
||||
| 217 | TSHOOT | Inspect a container with crictl | · | · | · | · | · | · | · | · | · | 0/10 |
|
||||
| 301 | ARCH | etcd configuration facts | · | · | · | · | · | · | · | · | · | ✓ |
|
||||
| 302 | NET | Service rules on the node | · | · | · | · | · | · | · | · | · | · |
|
||||
| 303 | NET | A second Service CIDR | · | · | · | · | · | · | · | · | · | · |
|
||||
| 304 | ARCH | Bound tokens versus legacy tokens | · | · | · | · | · | · | · | · | · | · |
|
||||
| 305 | WORK | Schedule without the scheduler | · | · | · | · | · | · | · | · | · | · |
|
||||
| 306 | STOR | Grow a volume in place | · | · | · | · | · | · | · | · | · | · |
|
||||
| 307 | TSHOOT | Node accepts nothing new | · | · | · | · | · | · | · | · | · | · |
|
||||
| 308 | ARCH | API resource reference card | · | · | · | · | · | · | · | · | · | · |
|
||||
| 309 | WORK | A PodDisruptionBudget that blocks maintenance | · | · | · | · | · | · | · | · | · | · |
|
||||
| 310 | NET | Route to something outside the cluster | · | · | · | · | · | · | · | · | · | · |
|
||||
| 311 | ARCH | Image inventory across the cluster | · | · | · | · | · | · | · | · | · | · |
|
||||
| 312 | WORK | A Job that fails, then one that doesn't | · | · | · | · | · | · | · | · | · | · |
|
||||
| 313 | NET | Two hosts, TLS, and a default backend | · | · | · | · | · | · | · | · | · | 0/11 |
|
||||
| 314 | TSHOOT | A static pod that never starts | · | · | · | · | · | · | · | · | · | · |
|
||||
| 315 | STOR | Keep the data when the claim goes | · | · | · | · | · | · | · | · | · | · |
|
||||
| 316 | ARCH | Plan a control-plane upgrade | · | · | · | · | · | · | · | · | · | · |
|
||||
| 317 | TSHOOT | Certificates stop being issued | · | · | · | · | · | · | · | · | · | · |
|
||||
| 401 | STOR | Provision geo-fence persistent storage | · | · | · | · | · | · | · | · | · | · |
|
||||
| 402 | ARCH | Render a chart, then install it | · | · | · | · | · | · | · | · | · | · |
|
||||
| 403 | TSHOOT | Fix the driver onboarding app | · | · | · | · | · | · | · | · | · | · |
|
||||
@ -244,5 +189,22 @@ _Generated by exam from 10 attempt(s); regenerated on every `end`._
|
||||
| 416 | NET | NetworkPolicy for the safety monitor | · | · | · | · | · | · | · | · | · | · |
|
||||
| 417 | ARCH | Enforce TLS 1.3 on the booking portal | · | · | · | · | · | · | · | · | · | · |
|
||||
| 418 | TSHOOT | Investigate vehicle tracker health | · | · | · | · | · | · | · | · | · | · |
|
||||
| 501 | ARCH | How the control plane is run | · | · | · | · | · | · | · | · | · | · |
|
||||
| 502 | TSHOOT | Cluster facts to an exact file | · | · | · | · | · | · | · | · | · | · |
|
||||
| 503 | NET | Ready only when its dependency answers | · | · | · | · | · | · | · | · | · | · |
|
||||
| 504 | WORK | Sorting done by kubectl | · | · | · | · | · | · | · | · | · | · |
|
||||
| 505 | TSHOOT | Event forensics around kube-proxy | · | · | · | · | · | · | · | · | · | · |
|
||||
| 506 | ARCH | API resources and a Role census | · | · | · | · | · | · | · | · | · | · |
|
||||
| 507 | TSHOOT | Kubelet unit points at nothing | · | · | · | · | · | · | · | · | · | · |
|
||||
| 508 | WORK | Secrets as a read-only volume and renamed env vars | · | · | · | · | · | · | · | · | · | · |
|
||||
| 509 | ARCH | Static Pod on the control plane behind a Service | · | · | · | · | · | · | · | · | · | · |
|
||||
| 510 | ARCH | The kubelet's two certificates | · | · | · | · | · | · | · | · | · | · |
|
||||
| 511 | WORK | A Pod for the control plane only | · | · | · | · | · | · | · | · | · | · |
|
||||
| 512 | TSHOOT | Stop the scheduler, schedule by hand | · | · | · | · | · | · | · | · | · | · |
|
||||
| 513 | ARCH | Helm release housekeeping | · | · | · | · | · | · | · | · | · | · |
|
||||
| 514 | STOR | Per-replica storage for a StatefulSet | · | · | · | · | · | · | · | · | · | · |
|
||||
| 515 | NET | Namespace AND pod selector, enforced | · | · | · | · | · | · | · | · | · | · |
|
||||
| 516 | NET | Resolves everything except the cluster | · | · | · | · | · | · | · | · | · | · |
|
||||
| 517 | STOR | A claim that can never bind | · | · | · | · | · | · | · | · | · | · |
|
||||
|
||||
_E = full exam, D = drill, · = not in that session, n/m = partial credit._
|
||||
|
||||
@ -347,8 +347,8 @@
|
||||
const eligible = S.bank.filter(q => hard || q.difficulty !== 'hard'), seenN = eligible.filter(q => (S.seen || []).includes(q.id)).length;
|
||||
$('#allDesc').textContent = `${seenN}/${eligible.length} tasks attempted. 5 unseen tasks per session, round-robin across domains${hard ? ', hard first' : ''}; then whatever you failed.`;
|
||||
$('#nextDesc').textContent = `${S.track.domains[nxt]} — 5 tasks, ${hard ? 5 : 6} min each. Drills rotate through all domains before the exam.`;
|
||||
// one button per fixed set the track defines (Set C and later were unreachable from here when
|
||||
// the buttons were hard-coded to A and B)
|
||||
// one button per fixed set the track defines - never hard-code the letters: newer sets used to
|
||||
// be unreachable from here
|
||||
$('#simOpts').innerHTML = Object.entries(S.sets || {}).map(([k, info]) =>
|
||||
`<button class="opt" data-sim="${k}"><b>${esc(info.name)}</b><span>${info.count} fixed tasks, ${S.track.minutes} min, exam rules, no feedback until you submit.</span></button>`).join('');
|
||||
$('#simOpts').querySelectorAll('[data-sim]').forEach(el => el.onclick = () => startSim(el.dataset.sim));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user