Initial commit
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
# KubeKosh Configuration Schema Reference
|
||||
|
||||
KubeKosh uses two primary JSON files to define its curriculum, learning paths, and exam configurations:
|
||||
1. **Bundles (`scenarios/bundles.json`)**: Defines the high-level study bundles (e.g., CKA, CKAD, CKS), active highlights, durations for exams, and lists of included scenarios.
|
||||
2. **Scenarios (`scenarios/scenarios.json`)**: Defines individual exercises, hands-on tasks, multiple-choice questions (MCQs), environment preparations, and automated validation scripts.
|
||||
|
||||
---
|
||||
|
||||
## 1. Bundles Schema (`scenarios/bundles.json`)
|
||||
|
||||
Bundles are defined as a JSON array of objects. Each bundle organizes a learning track or mock exam.
|
||||
|
||||
### Schema Fields
|
||||
* **`id`** *(string, required)*: A unique, kebab-case identifier for the bundle (e.g., `k8s-basics`).
|
||||
* **`name`** *(string, required)*: The human-readable name of the bundle shown in navigation (e.g., `Kubernetes Basics`).
|
||||
* **`icon`** *(string, required)*: An emoji or glyph representing the bundle (e.g., `🌱`).
|
||||
* **`tagline`** *(string, required)*: A short summary of the bundle's objectives.
|
||||
* **`color`** *(string, required)*: Hex color code representing the bundle's UI identity/accent color (e.g., `#3fb950`).
|
||||
* **`colorDim`** *(string, required)*: Translucent RGBA color matching the accent color at low opacity, used for UI row highlighting (e.g., `rgba(63,185,80,0.12)`).
|
||||
* **`exam_minutes`** *(number, required)*: The time limit allocated for the mock exam in minutes (e.g., `60`).
|
||||
* **`scenario_ids`** *(array of strings, required)*: List of scenario IDs belonging to this bundle in the order they should appear.
|
||||
|
||||
### Example Bundle
|
||||
```json
|
||||
{
|
||||
"id": "k8s-basics",
|
||||
"name": "Kubernetes Basics",
|
||||
"icon": "🌱",
|
||||
"tagline": "Core concepts for beginners",
|
||||
"color": "#3fb950",
|
||||
"colorDim": "rgba(63,185,80,0.12)",
|
||||
"exam_minutes": 60,
|
||||
"scenario_ids": [
|
||||
"pod-basics-mcq",
|
||||
"kubectl-essentials-mcq",
|
||||
"namespaces-basics",
|
||||
"deploy-nginx"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Scenarios Schema (`scenarios/scenarios.json`)
|
||||
|
||||
Scenarios are defined as a JSON array of objects. A scenario can be either a hands-on console challenge (`"task"`) or a multiple-choice question (`"mcq"`).
|
||||
|
||||
### Common Fields (All Types)
|
||||
```jsonc
|
||||
{
|
||||
"id": "unique-kebab-case-id", // string — unique scenario identifier
|
||||
"title": "Human-readable Title", // string — shown in sidebar list
|
||||
"category": "Workloads", // string — groups scenarios in sidebar accordion
|
||||
"difficulty": "Easy", // "Easy" | "Medium" | "Hard"
|
||||
"type": "task", // "task" | "mcq"
|
||||
"weight": 7, // number — points value (used for final grade scoring)
|
||||
"description": "## Markdown...", // string — problem statement supporting GitHub-flavored Markdown
|
||||
"hints": [...], // array — see Hints schema below
|
||||
"setup_commands": [...], // array<object> — commands run on environment preparation
|
||||
"teardown_commands": [...], // array<object> — optional — cleanup commands run after scenario completes
|
||||
"default_namespace": "default" // string — optional — default active namespace for the terminal
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Hints Schema
|
||||
Each hint is rendered as a collapsible card inside the Hints tab of the UI:
|
||||
```jsonc
|
||||
{
|
||||
"title": "Short title for the hint card",
|
||||
"body": "Explanation text (plain text, no markdown format).",
|
||||
"command": "kubectl run nginx --image=nginx" // optional — renders a copyable code block
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Setup & Teardown Commands
|
||||
* **`setup_commands`**: Executed sequentially on the Kubernetes cluster when the user starts a scenario or clicks **"Prepare Environment"**. Useful for pre-deploying resources or injecting bugs.
|
||||
* **`teardown_commands`**: Optional cleanup commands run when moving away from or resetting a scenario.
|
||||
* Commands must be **objects** with a `command` key:
|
||||
```jsonc
|
||||
"setup_commands": [
|
||||
{ "command": "kubectl create namespace debug" },
|
||||
{ "command": "kubectl create deployment broken-app --image=nginx:1.25 -n debug" }
|
||||
]
|
||||
```
|
||||
* *Note:* Non-zero exit codes are tolerated (e.g., "namespace already exists" errors won't halt the pipeline). All commands execute as `root`.
|
||||
|
||||
---
|
||||
|
||||
### Type: `"task"` — Hands-On Scenario
|
||||
Requires the user to run shell commands in the interactive terminal. The system runs an automated validation sequence to check the cluster state.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"type": "task",
|
||||
"validation": {
|
||||
"description": "Check that deployment has been correctly configured",
|
||||
"commands": [
|
||||
{
|
||||
"description": "Checks the running pods count",
|
||||
"command": "kubectl get deploy nginx -o jsonpath='{.status.readyReplicas}'",
|
||||
"expected_output": "3",
|
||||
"match": "exact" // "exact" | "contains" | "regex"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Match Modes
|
||||
| Mode | Behaviour |
|
||||
| :--- | :--- |
|
||||
| `exact` | Trimmed stdout must exactly equal `expected_output`. |
|
||||
| `contains` | stdout must contain `expected_output` as a substring. |
|
||||
| `not_contains` | stdout must **not** contain `expected_output` as a substring. |
|
||||
| `regex` | stdout must match the regular expression in `expected_output`. |
|
||||
|
||||
---
|
||||
|
||||
### Type: `"mcq"` — Multiple Choice Question
|
||||
Renders a questionnaire block. No terminal is shown. The user answers by selecting an option.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"type": "mcq",
|
||||
"options": [
|
||||
{ "id": "a", "text": "Option A explanation" },
|
||||
{ "id": "b", "text": "Option B explanation" },
|
||||
{ "id": "c", "text": "Option C explanation" },
|
||||
{ "id": "d", "text": "Option D explanation" }
|
||||
],
|
||||
"correct_option": "c", // must match one of the option IDs
|
||||
"explanation": "Detailed explanation of why C is the correct answer." // shown after submitting
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Full Examples
|
||||
|
||||
### Full Example — Hands-On Task Scenario
|
||||
```json
|
||||
{
|
||||
"id": "scale-deployment",
|
||||
"title": "Scale a Deployment",
|
||||
"category": "Workloads",
|
||||
"difficulty": "Easy",
|
||||
"type": "task",
|
||||
"weight": 4,
|
||||
"description": "## Scale the Deployment\n\nA deployment named `myapp` exists in the `default` namespace.\n\n**Scale it to 5 replicas.**",
|
||||
"hints": [
|
||||
{
|
||||
"title": "Using kubectl scale",
|
||||
"body": "The scale subcommand lets you change the replica count imperatively.",
|
||||
"command": "kubectl scale deployment myapp --replicas=5"
|
||||
}
|
||||
],
|
||||
"setup_commands": [
|
||||
{ "command": "kubectl create deployment myapp --image=nginx:1.25 --replicas=1" }
|
||||
],
|
||||
"teardown_commands": [
|
||||
{ "command": "kubectl delete deployment myapp --ignore-not-found" }
|
||||
],
|
||||
"default_namespace": "default",
|
||||
"validation": {
|
||||
"description": "Checks that myapp has 5 ready replicas.",
|
||||
"commands": [
|
||||
{
|
||||
"description": "myapp has 5 ready replicas",
|
||||
"command": "kubectl get deployment myapp -o jsonpath='{.status.readyReplicas}'",
|
||||
"expected_output": "5",
|
||||
"match": "exact"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Full Example — MCQ Scenario
|
||||
```json
|
||||
{
|
||||
"id": "service-types-mcq",
|
||||
"title": "Kubernetes Service Types",
|
||||
"category": "Networking",
|
||||
"difficulty": "Easy",
|
||||
"type": "mcq",
|
||||
"weight": 3,
|
||||
"description": "## Kubernetes Service Types\n\nWhich `kubectl` command creates a ClusterIP service named `my-svc` exposing port 80 for a deployment named `my-app`?",
|
||||
"options": [
|
||||
{ "id": "a", "text": "kubectl expose deployment my-app --name=my-svc --port=80 --type=ClusterIP" },
|
||||
{ "id": "b", "text": "kubectl create service my-svc --port=80" },
|
||||
{ "id": "c", "text": "kubectl apply service my-app --port=80" },
|
||||
{ "id": "d", "text": "kubectl expose pod my-app --name=my-svc --port=80 --type=NodePort" }
|
||||
],
|
||||
"correct_option": "a",
|
||||
"explanation": "`kubectl expose deployment` is the correct imperative command. It creates a Service targeting the deployment's pods. `--type=ClusterIP` is the default but explicit here for clarity.",
|
||||
"hints": [
|
||||
{
|
||||
"title": "kubectl expose syntax",
|
||||
"body": "Use kubectl expose to create a Service from an existing resource. Specify the resource type, name, port, and service type.",
|
||||
"command": "kubectl expose deployment my-app --name=my-svc --port=80 --type=ClusterIP"
|
||||
}
|
||||
],
|
||||
"setup_commands": [],
|
||||
"teardown_commands": [],
|
||||
"default_namespace": "default"
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user