"""Scripted solutions: what a candidate would type on the task's host, as a script. `./ksim audit` runs a task's script as `candidate` in an interactive shell on its host (so the host's aliases apply) after grading the task untouched, and grades it again: full marks prove the task can be solved as its text describes, on a cluster of its own. %{param}, {WS} and {CP}.. are substituted as in the task. A task without a script is only audited for a clean seed. SOLVE: task id -> bash """ SOLVE = { # ---- 1-37: the first banks (questions.py, bank_extra.py); 13 is further down 1: r""" cat <> /spool/raw.txt; sleep 2; done"] volumeMounts: [{name: spool, mountPath: /spool}] - name: adapter image: busybox:1.36 command: [sh, -c, "tail -f /spool/raw.txt"] volumeMounts: [{name: spool, mountPath: /spool}] EOF kubectl -n %{ns} wait --for=condition=Ready pod/%{pod} --timeout=180s sleep 6 """, 2: r""" cat </dev/null 2>&1; do echo waiting; sleep 2; done"] containers: [{name: app, image: "nginx:1.27"}] EOF kubectl -n %{ns} create deploy backend --image=nginx:1.27 kubectl -n %{ns} rollout status deploy/backend --timeout=180s kubectl -n %{ns} wait --for=condition=Ready pod/%{pod} --timeout=180s """, 3: r""" cat </dev/null helm -n %{ns} install %{rel} {WS}/q6/chart --set replicaCount=2 >/dev/null helm -n %{ns} upgrade %{rel} {WS}/q6/chart --set replicaCount=4 >/dev/null helm -n %{ns} rollback %{rel} 1 >/dev/null helm -n %{ns} history %{rel} -o json | jq 'map(.revision) | max' > {WS}/q6/revision.txt """, 7: r""" kubectl -n %{ns} patch deploy %{dep} --type=json -p '[ {"op": "add", "path": "/spec/template/spec/containers/0/startupProbe", "value": {"httpGet": {"path": "/", "port": 80}, "periodSeconds": 5, "failureThreshold": 12}}, {"op": "add", "path": "/spec/template/spec/containers/0/readinessProbe", "value": {"httpGet": {"path": "/", "port": 80}, "periodSeconds": 5, "failureThreshold": 1}}, {"op": "add", "path": "/spec/template/spec/containers/0/livenessProbe", "value": {"tcpSocket": {"port": 80}, "periodSeconds": 10, "initialDelaySeconds": 15}}]' kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s """, 8: r""" for i in $(seq 1 40); do R=$(kubectl -n %{ns} get pod %{pod} -o jsonpath='{.status.containerStatuses[0].state.waiting.reason}'); case "$R" in *ImagePull*) break;; esac; sleep 3; done echo "$R" > {WS}/q8/reason.txt kubectl -n %{ns} set image pod/%{pod} worker=busybox:1.36 for i in $(seq 1 60); do [ "$(kubectl -n %{ns} get pod %{pod} -o jsonpath='{.status.phase}')" = Running ] && [ "$(kubectl -n %{ns} get pod %{pod} -o jsonpath='{.status.containerStatuses[0].ready}')" = true ] && break; sleep 3; done """, 9: r""" cat <> /data/boot.log; sleep 86400"] volumeMounts: [{name: data, mountPath: /data}, {name: scratch, mountPath: /scratch}] EOF kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s kubectl -n %{ns} delete pod -l app=%{dep} kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s sleep 5 """, 18: r""" kubectl -n %{ns} get deploy %{app}-stable -o json | jq 'del(.status, .metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp, .metadata.generation, .metadata.annotations, .metadata.managedFields) | .metadata.name = "%{app}-canary" | .spec.replicas = 1 | .spec.selector.matchLabels.track = "canary" | .spec.template.metadata.labels.track = "canary" | .spec.template.spec.containers[0].image = "nginx:1.27"' | kubectl apply -f - kubectl -n %{ns} scale deploy %{app}-stable --replicas=4 kubectl -n %{ns} rollout status deploy %{app}-canary --timeout=240s kubectl -n %{ns} rollout status deploy %{app}-stable --timeout=240s sleep 5 """, 19: r""" kubectl -n %{ns} patch deploy %{dep} -p '{"spec":{"minReadySeconds":10,"revisionHistoryLimit":3,"strategy":{"type":"RollingUpdate","rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}' kubectl -n %{ns} set image deploy %{dep} nginx=nginx:1.27 kubectl -n %{ns} rollout status deploy %{dep} --timeout=300s """, 20: r""" mkdir -p {WS}/q20/overlays/prod cat > {WS}/q20/overlays/prod/kustomization.yaml < {WS}/q21/defaults-1.3.0.yaml printf 'replicaCount: 2\nservice:\n type: NodePort\n' > {WS}/q21/%{rel}-values.yaml helm -n %{ns} install %{rel} {WS}/q21/charts/webapp-1.3.0.tgz -f {WS}/q21/%{rel}-values.yaml >/dev/null helm -n %{ns} upgrade %{old} {WS}/q21/charts/webapp-1.3.0.tgz --reset-then-reuse-values >/dev/null kubectl -n %{ns} rollout status deploy %{old}-webapp --timeout=240s kubectl -n %{ns} rollout status deploy %{rel}-webapp --timeout=240s """, 22: r""" cd {WS}/q22 printf '%s\n' extensions/v1beta1 batch/v1beta1 policy/v1beta1 autoscaling/v2beta2 > removed.txt cat > fixed.yaml </dev/null | wc -l)" -ge 3 ] && break; sleep 5; done sleep 20 kubectl top pod -n %{ns} --sort-by=cpu --no-headers | head -1 | awk '{print $1}' > {WS}/q23/cpu.txt kubectl top pod -n %{ns} --sort-by=memory --no-headers | head -1 | awk '{print $1}' > {WS}/q23/memory.txt echo 'kubectl top node' > {WS}/q23/nodes.sh echo 'kubectl top pod -A --sort-by=memory' > {WS}/q23/pods.sh """, 24: r""" for i in $(seq 1 40); do kubectl -n %{ns} logs %{pod} -c ingest --previous 2>/dev/null | grep -q FATAL && break; sleep 3; done kubectl -n %{ns} logs %{pod} -c ingest --previous > {WS}/q24/crash.log grep -o '/etc/ingest/[^ ]*\.yaml' {WS}/q24/crash.log | head -1 > {WS}/q24/missing.txt kubectl -n %{ns} logs %{pod} -c helper --tail=3 --timestamps > {WS}/q24/helper.log """, 25: r""" kubectl -n %{ns} get deploy %{dep} -o json | jq '(.spec.template.spec.containers[0].env[] | select(.name == "LOG_LEVEL") | .valueFrom.configMapKeyRef.key) = "log_level" | del(.spec.template.spec.containers[0].command)' | kubectl apply -f - kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s kubectl -n %{ns} exec deploy/%{dep} -- printenv LOG_LEVEL > {WS}/q25/log-level.txt """, 26: r""" for i in $(seq 1 40); do R=$(kubectl -n %{ns} get pod -l app=%{dep} -o jsonpath='{.items[0].status.containerStatuses[0].lastState.terminated.reason}' 2>/dev/null); [ -n "$R" ] && break; sleep 3; done echo $R > {WS}/q26/reason.txt kubectl -n %{ns} set resources deploy %{dep} -c resize --limits=memory=256Mi kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s sleep 35 """, 27: r""" kubectl get crd -o name | grep -i backup | cut -d/ -f2 > {WS}/q27/crd.txt kubectl get backups.data.example.com -A --no-headers 2>/dev/null | wc -l > {WS}/q27/count.txt cat < {WS}/q29/level.txt kubectl -n %{ns} patch deploy %{dep} --type=json -p '[ {"op": "add", "path": "/spec/template/spec/securityContext", "value": {"runAsNonRoot": true, "runAsUser": %{uid}, "seccompProfile": {"type": "RuntimeDefault"}}}, {"op": "add", "path": "/spec/template/spec/containers/0/securityContext", "value": {"allowPrivilegeEscalation": false, "capabilities": {"drop": ["ALL"]}}}]' kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s """, 30: r""" kubectl -n %{ns} create quota compute-quota --hard=requests.cpu=1,requests.memory=1Gi,limits.cpu=2,limits.memory=2Gi,pods=6 cat < {WS}/q31/qos.txt """, 32: r""" kubectl -n %{ns} create cm %{cm} --from-file=app.properties={WS}/q32/app.properties --from-literal=TIER=backend cat < {WS}/q33/old-password.txt kubectl -n %{ns} create secret generic %{sec} --from-literal=username=%{user} --from-literal=password=%{pw} cat < {WS}/q34/token.txt kubectl -n %{ns} create deploy %{dep} --image=nginx:1.27 --dry-run=client -o json | jq '.spec.template.spec.serviceAccountName = "%{sa}"' | kubectl apply -f - kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s """, 35: r""" cat < {WS}/q36/endpoints.txt """, 37: r""" kubectl -n %{ns} create secret tls %{dom}-tls --cert={WS}/q37/tls.crt --key={WS}/q37/tls.key kubectl -n %{ns} create ingress %{dom} --class=nginx --rule="%{dom}.example.com/api*=api:8080,tls=%{dom}-tls" --rule="%{dom}.example.com/*=web:80,tls=%{dom}-tls" """, # ---- 38-57: the fixed set A (bank_sim_a.py); 41 is further down 38: r""" kubectl -n danube run ferry --image=httpd:2-alpine --labels=tier=edge --dry-run=client -o json | jq '.spec.containers[0].name = "ferry-web"' | kubectl apply -f - kubectl -n danube wait --for=condition=Ready pod/ferry --timeout=180s mkdir -p {WS}/q38 echo "kubectl -n danube get pod ferry -o jsonpath='{.status.phase}'" > {WS}/q38/ferry-status.sh """, 39: r""" kubectl -n rhine create cronjob tide-report --image=busybox:1.36 --schedule='*/30 * * * *' --dry-run=client -o json -- sh -c 'echo "tide report $(date +%H:%M)"' | jq '.spec.suspend = true' | kubectl apply -f - kubectl -n rhine create job tide-report-manual --from=cronjob/tide-report kubectl -n rhine wait --for=condition=complete job/tide-report-manual --timeout=180s mkdir -p {WS}/q39 kubectl -n rhine logs job/tide-report-manual > {WS}/q39/manual-run.log """, 40: r""" cat <<'EOF' | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: {name: harbor-web, namespace: volga, labels: {app: harbor-web}} spec: replicas: 2 selector: {matchLabels: {app: harbor-web}} template: metadata: {labels: {app: harbor-web}} spec: volumes: [{name: html, emptyDir: {}}] initContainers: - name: page-gen image: busybox:1.36 env: [{name: POD_NAME, valueFrom: {fieldRef: {fieldPath: metadata.name}}}] command: [sh, -c, 'echo "harbor online: $POD_NAME" > /work/index.html'] volumeMounts: [{name: html, mountPath: /work}] containers: - name: nginx image: nginx:1.27 volumeMounts: [{name: html, mountPath: /usr/share/nginx/html}] EOF kubectl -n volga expose deploy harbor-web --port=80 kubectl -n volga rollout status deploy harbor-web --timeout=240s sleep 5 """, 42: r""" kubectl -n yukon get deploy dispatch-api -o jsonpath='{.spec.template.spec.containers[0].image}' > {WS}/q42/broken-image.txt kubectl -n yukon rollout undo deploy dispatch-api kubectl -n yukon rollout status deploy dispatch-api --timeout=240s kubectl -n yukon get deploy dispatch-api -o jsonpath='{.metadata.annotations.deployment\.kubernetes\.io/revision}' > {WS}/q42/revision.txt """, 43: r""" helm -n mekong list --failed -q > {WS}/q43/failed.txt helm -n mekong uninstall buoy-north >/dev/null helm -n mekong upgrade buoy-west {WS}/q43/charts/buoy-0.2.0.tgz --reuse-values --set replicaCount=3 >/dev/null helm -n mekong rollback buoy-east 1 >/dev/null kubectl -n mekong rollout status deploy buoy-west --timeout=240s kubectl -n mekong rollout status deploy buoy-east --timeout=240s """, 44: r""" C=$(kubectl create --dry-run=client -f {WS}/q44/gauge-pod.yaml -o json | jq -c '.spec.containers[0] | .securityContext = {allowPrivilegeEscalation: false, privileged: false}') kubectl -n ganges create deploy gauge-sensor --image=busybox:1.36 --replicas=3 --dry-run=client -o json | jq --argjson c "$C" '.spec.template.spec.containers = [$c]' > {WS}/q44/gauge-deployment.yaml kubectl apply -f {WS}/q44/gauge-deployment.yaml kubectl -n ganges delete pod gauge-sensor --grace-period=1 kubectl -n ganges rollout status deploy gauge-sensor --timeout=240s """, 45: r""" cd {WS}/q45/overlays/staging cat > kustomization.yaml < patch.yaml </dev/null | sed -n 's/^SHIM_TOKEN=//p'); [ -n "$T" ] && break; sleep 3; done echo "$T" > {WS}/q47/token.txt """, 48: r""" for i in $(seq 1 60); do best=$(for n in seine amur; do kubectl -n $n get pod -o json | jq -r --arg n $n '.items[] | "\(.status.containerStatuses[0].restartCount // 0) \($n)/\(.metadata.name)"'; done | sort -rn | head -1) [ "${best%% *}" -ge 2 ] 2>/dev/null && kubectl -n seine get events --field-selector type=Warning --no-headers 2>/dev/null | grep -q . && break sleep 3 done P=${best#* } echo "$P" > {WS}/q48/most-restarts.txt kubectl -n ${P%%/*} get pod ${P#*/} -o jsonpath='{.status.containerStatuses[0].lastState.terminated.exitCode}' > {WS}/q48/exit-code.txt echo 'kubectl -n seine get events --field-selector type=Warning --sort-by=.lastTimestamp' > {WS}/q48/warnings.sh """, 49: r""" kubectl -n nile create role configmap-reader --verb=get,list,watch --resource=configmaps kubectl -n nile create rolebinding ledger-sync-configmaps --role=configmap-reader --serviceaccount=nile:ledger-sync for i in $(seq 1 40); do kubectl -n nile logs deploy/ledger-sync --tail=1 2>/dev/null | grep -q 'can list configmaps' && break; sleep 3; done kubectl -n nile logs deploy/ledger-sync --tail=1 > {WS}/q49/log.txt """, 50: r""" kubectl -n indus create secret generic gatekeeper-tls-settings --from-file=tls-settings.conf={WS}/q50/tls-settings.conf --dry-run=client -o json | jq '.immutable = true' | kubectl apply -f - kubectl -n indus patch deploy gatekeeper --type=json -p '[ {"op": "add", "path": "/spec/template/spec/volumes", "value": [{"name": "tls", "secret": {"secretName": "gatekeeper-tls-settings"}}]}, {"op": "add", "path": "/spec/template/spec/containers/0/volumeMounts", "value": [{"name": "tls", "mountPath": "/etc/nginx/conf.d/tls-settings.conf", "subPath": "tls-settings.conf"}]}]' kubectl -n indus rollout status deploy gatekeeper --timeout=240s """, 51: r""" cat > {WS}/q51/default.conf <<'EOF' server { listen 80; location /status { return 200 "harbor v2 ok"; } location / { return 200 "harbor v1"; } } EOF kubectl -n niger create cm harbor-nginx --from-file=default.conf={WS}/q51/default.conf --dry-run=client -o yaml | kubectl apply -f - kubectl -n niger rollout restart deploy harbor-proxy kubectl -n niger rollout status deploy harbor-proxy --timeout=240s for i in 1 2 3 4 5; do kubectl -n niger run tmp --rm -i --restart=Never --image=nginx:1.27 -- curl -s http://harbor-proxy.niger.svc.cluster.local/status > {WS}/q51/status.txt /dev/null grep -q 'harbor v2 ok' {WS}/q51/status.txt && break; kubectl -n niger delete pod tmp --ignore-not-found >/dev/null 2>&1; sleep 3 done """, 52: r""" cat < /data/a.txt; sleep 86400"] volumeMounts: [{name: data, mountPath: /data}] - name: writer-b image: busybox:1.36 securityContext: {runAsUser: 2000} command: [sh, -c, "echo b > /data/b.txt; sleep 86400"] volumeMounts: [{name: data, mountPath: /data}] EOF kubectl -n murray wait --for=condition=Ready pod/ledger-pair --timeout=180s sleep 3 """, 53: r""" echo LimitRange/douro-limits > {WS}/q53/rejected-by.txt kubectl -n douro set resources deploy batch-runner -c runner --limits=memory=256Mi --requests=memory=128Mi kubectl -n douro rollout status deploy batch-runner --timeout=240s """, 54: r""" kubectl -n oder expose pod buoy-api --name=buoy-svc --port=8080 --target-port=80 sleep 3 for i in 1 2 3 4 5; do kubectl -n oder run tmp --rm -i --restart=Never --image=nginx:1.27 -- curl -s http://buoy-svc:8080 > {WS}/q54/response.html /dev/null grep -qi 'Welcome to nginx' {WS}/q54/response.html && break; kubectl -n oder delete pod tmp --ignore-not-found >/dev/null 2>&1; sleep 3 done kubectl -n oder delete pod tmp --ignore-not-found >/dev/null 2>&1 kubectl -n oder logs buoy-api > {WS}/q54/buoy.log """, 55: r""" cat < {WS}/q56/fqdn.txt for i in 1 2 3 4 5; do IP=$(kubectl -n ebro run tmp --rm -i --restart=Never --image=busybox:1.36 -- nslookup $F /dev/null | awk '/^Name:/ {n=1} n && /^Address/ {print $NF; exit}') [ -n "$IP" ] && break; kubectl -n ebro delete pod tmp --ignore-not-found >/dev/null 2>&1; sleep 3 done echo "$IP" > {WS}/q56/ip.txt """, 57: r""" kubectl -n dnieper patch ingress portal --type=json -p '[ {"op": "replace", "path": "/spec/rules/0/http/paths/0/pathType", "value": "Prefix"}, {"op": "replace", "path": "/spec/rules/0/http/paths/0/backend/service/port/number", "value": 8080}, {"op": "replace", "path": "/spec/rules/0/http/paths/1/backend/service/name", "value": "portal-ui"}]' """, # ---- 58-64: bank_more.py; 60 is further down 58: r""" cd {WS}/q58 sed -i 's#^apiVersion: extensions/v1beta1#apiVersion: apps/v1#' deployment.yaml yq -i '.spec.selector.matchLabels.app = "%{app}"' deployment.yaml kubectl apply -f deployment.yaml kubectl apply -f flag.yaml --dry-run=server 2> warning.txt >/dev/null sed -i 's#rollout.example.com/v1beta1#rollout.example.com/v1#' flag.yaml kubectl apply -f flag.yaml kubectl api-resources --no-headers | awk '{k=$NF; if (k=="CronJob" || k=="HorizontalPodAutoscaler" || k=="EndpointSlice" || k=="PriorityClass") print k, $(NF-2)}' > served.txt kubectl -n %{ns} rollout status deploy %{app} --timeout=240s """, 59: r""" cd {WS}/q59 echo cc > shortname.txt kubectl get cc -A --no-headers | awk '$NF == "Degraded" {print $1 "/" $2}' > degraded.txt MAX=$(kubectl get crd cacheclusters.cache.example.com -o jsonpath='{.spec.versions[0].schema.openAPIV3Schema.properties.spec.properties.replicas.maximum}') cat > cache.yaml < kustomization.yaml < {WS}/q62/reason.txt kubectl -n %{ns} patch deploy %{dep} --type=json -p '[ {"op": "replace", "path": "/spec/template/spec/containers/0/livenessProbe/httpGet/port", "value": %{port}}, {"op": "replace", "path": "/spec/template/spec/containers/0/readinessProbe/httpGet/path", "value": "/%{ready}"}]' kubectl -n %{ns} rollout status deploy %{dep} --timeout=240s """, 63: r""" echo "kubectl -n %{ns} get pods -o custom-columns=POD:.metadata.name,NODE:.spec.nodeName,IMAGE:.spec.containers[0].image" > {WS}/q63/inventory.sh kubectl -n %{ns} get pods -l tier=%{tier} --field-selector='status.phase!=Running' -o name | cut -d/ -f2 > {WS}/q63/not-running.txt kubectl -n %{ns} get pods -o jsonpath='{range .items[*]}{.spec.nodeName}{"\n"}{end}' | grep . | sort | uniq -c | sort -rn | awk 'NR==1 {print $2}' > {WS}/q63/busiest.txt """, 64: r""" for i in $(seq 1 30); do B=$(kubectl -n %{ns} logs -l app=%{app} --prefix --tail=-1 2>/dev/null | grep ERROR | head -1 | sed 's#^\[pod/\([^/]*\)/.*#\1#') [ -n "$B" ] && break; sleep 3 done echo "$B" > {WS}/q64/bad-pod.txt kubectl -n %{ns} logs "$B" | grep ERROR > {WS}/q64/errors.log kubectl -n %{ns} logs %{app}-0 -c migrate | awk '/schema version/ {print $3}' > {WS}/q64/schema.txt echo "kubectl -n %{ns} logs -l app=%{app} --prefix --tail=2" > {WS}/q64/tail.sh """, 13: r""" cd {WS}/q13/image podman build -q -t localhost/%{img}:v1 . >/dev/null sed -i 's/^ENV GREETING=hello/ENV GREETING=%{greet}\nENV APP_VERSION=v2/' Dockerfile podman build -q -t localhost/%{img}:v2 . >/dev/null podman save --format oci-archive -o {WS}/q13/%{img}-v2.tar localhost/%{img}:v2 >/dev/null 2>&1 podman run --rm localhost/%{img}:v2 > {WS}/q13/run.txt """, 41: r""" cd {WS}/q41/image docker build -q --build-arg APP_VERSION=2.1 -t localhost/beacon-relay:2.1 -t localhost/beacon-relay:latest . >/dev/null sudo podman run -d --name beacon-relay localhost/beacon-relay:2.1 >/dev/null sleep 2; podman logs beacon-relay > {WS}/q41/relay.log """, 60: r""" cd {WS}/q60/image printf 'FROM docker.io/library/busybox:1.36\nLABEL team=%{team}\nCOPY report.sh /app/report.sh\nRUN chmod 0755 /app/report.sh\nUSER 10001\nENTRYPOINT ["/app/report.sh"]\nCMD ["%{arg}"]\n' > Dockerfile podman build -q -t localhost/%{img}:1.1 . >/dev/null podman run --rm localhost/%{img}:1.1 > {WS}/q60/default.txt podman run --rm localhost/%{img}:1.1 %{arg2} > {WS}/q60/%{arg2}.txt podman rmi localhost/%{img}:1.0 >/dev/null """, # ---- 65-76: Services and Networking (bank_net.py). A policy needs a moment to reach the node, and # ---- the audit grades the instant the script ends - hence the sleeps a person would not need. 65: r""" cat < {WS}/q71/target.txt """, 72: r""" kubectl -n %{ns} describe pod -l app=%{app} | grep -i 'readiness probe failed' | head -1 echo 404 > {WS}/q72/code.txt kubectl -n %{ns} patch deploy %{app} --type=json -p '[{"op": "replace", "path": "/spec/template/spec/containers/0/readinessProbe/httpGet/path", "value": "/"}]' kubectl -n %{ns} rollout status deploy %{app} --timeout=180s """, 73: r""" IP=$(kubectl -n %{ns}-old get pod legacy -o jsonpath='{.status.podIP}') cat < {WS}/q74/response.txt """, 75: r""" kubectl -n %{ns} create ingress %{dom} --class=nginx --rule="shop.%{dom}.test/*=shop:80" --rule="blog.%{dom}.test/*=blog:8080" --default-backend=fallback:80 """, 76: r""" kubectl -n %{ns} create ingress %{dom}-routes --class=nginx --rule="%{dom}.example.com/healthz=status:8080" --rule="%{dom}.example.com/app*=app:80" --annotation nginx.ingress.kubernetes.io/rewrite-target=/ """, # ---- 77-84: Application Design and Build (bank_design.py) 77: r""" cd {WS}/q77/image printf 'FROM busybox:1.36\nWORKDIR /app\nCOPY run.sh /app/run.sh\nRUN chmod +x /app/run.sh\nENTRYPOINT ["/app/run.sh"]\n' > Dockerfile podman build -q -t localhost/%{img}:1.0 . >/dev/null podman tag localhost/%{img}:1.0 localhost/%{img}:stable podman run --rm localhost/%{img}:1.0 > {WS}/q77/out.txt """, 78: r""" podman image inspect localhost/%{img}:%{tag} --format 'user={{.Config.User}} workdir={{.Config.WorkingDir}} tier={{index .Config.Labels "tier"}}' > {WS}/q78/facts.txt echo "port=$(podman image inspect localhost/%{img}:%{tag} --format '{{range $p, $v := .Config.ExposedPorts}}{{$p}}{{end}}' | cut -d/ -f1)" >> {WS}/q78/facts.txt podman run --rm -e MODE=debug localhost/%{img}:%{tag} check > {WS}/q78/run.txt """, 79: r""" cat <> /data/started; exec httpd -f -p 80 -h /data"] volumeMounts: [{name: data, mountPath: /data}] volumeClaimTemplates: - metadata: {name: data} spec: accessModes: [ReadWriteOnce] storageClassName: standard resources: {requests: {storage: 50Mi}} EOF kubectl -n %{ns} rollout status sts %{app} --timeout=240s kubectl -n %{ns} delete pod %{app}-0 sleep 3 kubectl -n %{ns} rollout status sts %{app} --timeout=240s kubectl -n %{ns} wait --for=condition=Ready pod/%{app}-0 --timeout=120s """, 80: r""" cat <<'EOF' | kubectl apply -f - apiVersion: batch/v1 kind: Job metadata: {name: %{job}, namespace: %{ns}} spec: backoffLimit: 4 activeDeadlineSeconds: 120 ttlSecondsAfterFinished: 600 template: spec: restartPolicy: OnFailure volumes: [{name: work, emptyDir: {}}] containers: - name: import image: busybox:1.36 command: ["sh", "-c", "if [ -f /work/tried ]; then echo imported; else touch /work/tried; echo failing once; exit 1; fi"] volumeMounts: [{name: work, mountPath: /work}] EOF kubectl -n %{ns} wait --for=condition=Complete job/%{job} --timeout=120s """, 81: r""" cat <<'EOF' | kubectl apply -f - apiVersion: v1 kind: Pod metadata: {name: %{pod}, namespace: %{ns}} spec: volumes: - name: conf configMap: {name: ambassador-conf} containers: - name: app image: busybox:1.36 command: ["sh", "-c", "while true; do wget -T 2 -qO- http://localhost:8080/ > /tmp/last 2>&1; sleep 5; done"] - name: ambassador image: nginx:1.27 volumeMounts: [{name: conf, mountPath: /etc/nginx/conf.d}] EOF kubectl -n %{ns} wait --for=condition=Ready pod/%{pod} --timeout=180s sleep 8 """, 82: r""" kubectl -n %{ns} get pod %{pod} -o json | jq 'del(.status, .metadata.uid, .metadata.resourceVersion, .metadata.creationTimestamp) | .spec.initContainers |= reverse | .spec.containers[0].volumeMounts += [{"name": "work", "mountPath": "/work"}]' > /tmp/pod.json kubectl replace --force -f /tmp/pod.json kubectl -n %{ns} wait --for=condition=Ready pod/%{pod} --timeout=180s """, 83: r""" kubectl -n %{ns} delete pvc %{pvc} cat < {WS}/q85/image.txt kubectl -n %{ns} set image deploy/%{app}-stable web="$(cat {WS}/q85/image.txt)" kubectl -n %{ns} rollout status deploy/%{app}-stable --timeout=240s kubectl -n %{ns} delete deploy %{app}-canary sleep 20 """, 86: r""" kubectl -n %{ns} patch deploy %{dep} --type=json -p '[{"op": "replace", "path": "/spec/strategy", "value": {"type": "Recreate"}}]' kubectl -n %{ns} set image deploy/%{dep} nginx=nginx:1.27 kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s echo Recreate > {WS}/q86/strategy.txt """, 87: r""" kubectl -n %{ns} rollout pause deploy/%{dep} kubectl -n %{ns} set image deploy/%{dep} nginx=nginx:1.27 kubectl -n %{ns} set env deploy/%{dep} LOG_LEVEL=debug kubectl -n %{ns} set resources deploy/%{dep} --requests=cpu=50m,memory=64Mi kubectl -n %{ns} rollout resume deploy/%{dep} kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s sleep 10 """, 88: r""" for i in 1 2 3 4; do kubectl -n %{ns} rollout history deploy/%{dep} --revision=$i | grep -q 'busybox:%{tag}' && echo $i; done > {WS}/q88/revision.txt kubectl -n %{ns} rollout undo deploy/%{dep} --to-revision=$(cat {WS}/q88/revision.txt) kubectl -n %{ns} annotate deploy %{dep} kubernetes.io/change-cause="rollback to busybox:%{tag}" --overwrite kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s sleep 35 """, 89: r""" kubectl -n %{ns} rollout restart deploy/%{app} kubectl -n %{ns} rollout status deploy/%{app} --timeout=240s kubectl -n %{ns} annotate deploy %{app} kubernetes.io/change-cause="secret rotation" --overwrite sleep 35 kubectl -n %{ns} logs deploy/%{app} | head -1 > {WS}/q89/started.txt """, 90: r""" cd {WS}/q90 NS=$(helm list -A -o json | jq -r '.[] | select(.name == "%{rel}") | .namespace') echo $NS > namespace.txt helm list -A -o json | jq -r '.[] | select(.name == "%{rel}") | .chart' > chart.txt helm -n $NS get values %{rel} -o yaml > values.yaml helm -n $NS get manifest %{rel} > manifest.yaml """, 91: r""" helm repo add internal http://localhost:30080 >/dev/null helm repo update >/dev/null helm search repo internal/webapp --versions -o json | jq -r '.[].version' > {WS}/q91/versions.txt helm install %{rel} internal/webapp --version 1.2.0 -n %{ns} --create-namespace --set replicaCount=2 >/dev/null helm upgrade %{rel} internal/webapp -n %{ns} --reuse-values >/dev/null """, 92: r""" echo image.tag > {WS}/q92/key.txt helm -n %{ns} upgrade %{rel} {WS}/q92/chart --reuse-values --set image.tag=1.27 --wait --timeout 180s >/dev/null helm -n %{ns}-archive uninstall %{rel}-old >/dev/null sleep 10 """, 93: r""" cd {WS}/q93/app printf 'apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nnamespace: %{ns}\nresources:\n - deployment.yaml\nconfigMapGenerator:\n - name: %{app}-config\n envs:\n - settings.env\n' > kustomization.yaml kubectl apply -k . kubectl -n %{ns} rollout status deploy/%{app} --timeout=240s sed -i 's/^MODE=blue/MODE=green/' settings.env kubectl apply -k . kubectl -n %{ns} rollout status deploy/%{app} --timeout=240s sleep 35 """, # ---- 94-99: Application Observability and Maintenance (bank_obs.py) 94: r""" kubectl -n %{ns} patch deploy %{app} --type=json -p '[{"op": "add", "path": "/spec/template/spec/containers/0/readinessProbe", "value": {"httpGet": {"path": "/ready", "port": 80}, "periodSeconds": 3, "failureThreshold": 1}}]' kubectl -n %{ns} rollout status deploy/%{app} --timeout=240s sleep 35 POD=$(kubectl -n %{ns} get pod -l app=%{app} --field-selector status.phase=Running -o jsonpath='{.items[0].metadata.name}') kubectl -n %{ns} exec $POD -- rm /www/ready echo $POD > {WS}/q94/unready.txt sleep 10 """, 95: r""" kubectl -n %{ns} patch deploy %{dep} --type=json -p '[{"op": "add", "path": "/spec/template/spec/containers/0/startupProbe", "value": {"httpGet": {"path": "/", "port": 80}, "periodSeconds": 5, "failureThreshold": 18}}]' kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s """, 96: r""" echo FailedScheduling > {WS}/q96/reason.txt kubectl -n %{ns} get events --field-selector reason=FailedScheduling -o jsonpath='{.items[-1:].message}' > {WS}/q96/message.txt kubectl -n %{ns} set resources deploy/%{dep} --requests=cpu=50m,memory=640Mi --limits=memory=640Mi kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s """, 97: r""" kubectl -n %{ns} logs -l job-name=%{job} --tail=-1 | grep '^result' > {WS}/q97/results.txt kubectl -n %{ns} logs job/%{job}-load | grep '^FATAL' > {WS}/q97/fatal.txt kubectl -n %{ns} logs job/%{job}-load | head -1 > {WS}/q97/first.txt """, 98: r""" kubectl -n %{ns} logs deploy/%{dep} -c migrate > {WS}/q98/why.log 2>&1 kubectl -n %{ns} patch cm %{dep}-config -p '{"data": {"DB_HOST": "db.%{ns}.svc"}}' kubectl -n %{ns} rollout restart deploy/%{dep} kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s sleep 5 """, 99: r""" kubectl -n %{ns} debug %{pod} --image=busybox:1.36 --target=whoami --container=dbg -- sh -c 'tr "\0" "\n" < /proc/1/environ | grep WHOAMI_PORT_NUMBER; sleep 3600' >/dev/null 2>&1 for i in $(seq 1 20); do P=$(kubectl -n %{ns} logs %{pod} -c dbg 2>/dev/null | sed -n 's/^WHOAMI_PORT_NUMBER=//p'); [ -n "$P" ] && break; sleep 2; done echo $P > {WS}/q99/port.txt kubectl -n %{ns} patch svc %{pod} -p "{\"spec\": {\"ports\": [{\"port\": 80, \"targetPort\": $P}]}}" sleep 5 """, # ---- 100-105: Application Environment, Configuration and Security (bank_env.py) 100: r""" kubectl -n %{ns} create rolebinding %{dev}-view --clusterrole=view --user=%{dev} kubectl -n %{ns} create role pod-restarter --verb=delete --resource=pods kubectl -n %{ns} create rolebinding %{dev}-restart --role=pod-restarter --user=%{dev} kubectl -n %{ns} create rolebinding %{lead}-edit --clusterrole=edit --user=%{lead} for q in "get pods --subresource=log --as=%{dev}" "get secrets --as=%{dev}" "create rolebindings --as=%{lead}"; do kubectl -n %{ns} auth can-i $q; done > {WS}/q100/answers.txt 2>/dev/null """, 101: r""" echo requests.cpu > {WS}/q101/resource.txt kubectl -n %{ns} set resources deploy/%{dep} --requests=cpu=200m,memory=64Mi kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s sleep 5 """, 102: r""" cd {WS}/q102 kubectl -n %{ns} create configmap %{cm}-env --from-env-file=logging.env kubectl -n %{ns} create configmap %{cm}-files --from-file=application.properties=app.properties cat < {WS}/q103/id.txt kubectl -n %{ns} exec %{pod} -- touch /work/proof """, 104: r""" kubectl -n %{ns} create sa %{dep} kubectl -n %{ns} create role %{dep} --verb=get --resource=configmaps --resource-name=feature-flags kubectl -n %{ns} create rolebinding %{dep} --role=%{dep} --serviceaccount=%{ns}:%{dep} kubectl -n %{ns} set serviceaccount deploy/%{dep} %{dep} kubectl -n %{ns} rollout status deploy/%{dep} --timeout=240s sleep 12 """, 105: r""" cat <