Creating Labs

Scripting System

Learn how to write setup, check, solve, and cleanup scripts for POV Demo labs.

Script Types

Tasks support setup, check, and solve scripts. The executor runs each script type in parallel across the VMs that have a matching script.

TypeWhen It RunsPurpose
setupWhen a task is set up (the first task is set up as the session becomes ready)Configure the VM, install tools, create initial state
checkWhen the learner clicks "Check"Validate the learner's work; exit 0 = pass, non-zero = fail
solveWhen the learner clicks "Solve"Apply the solution
Lab-level scripts in lab_scripts/ use setup-{vm} and cleanup-{vm}. Setup runs during provisioning. Cleanup is run during teardown only for labs with AWS resources, and a cleanup failure does not stop teardown.

Naming Convention

With virtual machines, scripts are discovered only with the matching {operation}-{vm-name} filename. With no VMs, task scripts are named setup, check, and solve; lab setup may be lab_scripts/setup.

Script filenameVM name in config.yml
setup-ubuntu-1ubuntu-1
check-nomad-server-1nomad-server-1
solve-kubernetes-control-1kubernetes-control-1

Setup Scripts

Setup scripts configure the environment before the learner begins. Non-check scripts run with bash -e; source a profile explicitly if the script needs profile-defined configuration.

# Non-check scripts are executed with bash -e
set -e

# Install required tools
apt-get update -q
apt-get install -y -q curl wget jq

# Create initial directory structure
mkdir -p /home/user/workspace
chown user:user /home/user/workspace

# Pre-populate a config file the learner will modify
cat > /home/user/workspace/config.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data: {}
EOF

# Add setup commands to bash history so learner can reference them
history -s "kubectl apply -f config.yaml"
  • Non-check scripts run with bash -e, so their shebang is ignored. Source the required profile explicitly when a script needs it.
  • Use set -e so the script fails fast on errors
  • Prefer idempotent scripts so reruns are safe.
  • Use history -s "command" to pre-populate terminal history (NOT set -o history)

Check Scripts

Check scripts validate the learner's work. Exit status controls the result: zero succeeds and non-zero fails. The executor sources /opt/tekanaid/scripts/check_template.sh when present and supplies fallback helpers.

#!/bin/bash
source /opt/tekanaid/scripts/check_template.sh

# Check that kubectl is configured correctly
check_command "kubectl cluster-info" "kubectl cluster-info should appear in shell history"

# Check that the deployment exists
check_command "kubectl get deployment my-app -n default" \
  "kubectl get deployment should appear in shell history"

# Check specific content in a file
check_file_content "/home/user/workspace/config.yaml" \
  "name: my-config" \
  "ConfigMap name should be 'my-config'"

echo "All checks passed!"

Solve Scripts

Recommendation: Include set -e for readable, portable scripts. The executor already invokes non-check scripts with bash -e; local validation does not require it on a specific line.
# Non-check scripts are executed with bash -e
set -e

# Apply the solution
kubectl apply -f /home/user/workspace/solution.yaml

# Verify the solution worked
kubectl wait --for=condition=available deployment/my-app --timeout=60s
  • Prefer an idempotent solution so rerunning it is safe.
  • Use history -s "command" to show the solution commands in terminal history (NOT set -o history)

Helper Functions

The executor sources /opt/tekanaid/scripts/check_template.sh before each check script. Source that path explicitly only when running the script outside the executor.

FunctionSignatureDescription
check_commandcheck_command "pattern" "message"Checks the root shell history for pattern; fails with message when absent.
check_file_contentcheck_file_content "file" "pattern" "message"Fails if pattern is not found in file.
failfail "message"Immediately fails the check with message.
ensure_history_flushedensure_history_flushedFlushes shell history before a history check.

AI Gateway

An AI gateway is configured only when the session has a gateway key and the service has AI_GATEWAY_URL. When configured, the VM profile exports these client-compatible variables.

VariableValue
OPENAI_API_BASEGateway base URL with /v1
OPENAI_API_KEYSession gateway key
ANTHROPIC_BASE_URLGateway base URL
ANTHROPIC_API_KEYSession gateway key
LLM_API_BASEGateway base URL
LLM_API_KEYSession gateway key