Reference — How It Works#
Three pieces work together: your repo (the content and the automation), the Dynatrace Enablement app (in the learner's tenant — the UI, the checks, the token minting) and Orbital (the server that runs one container per learner). This page follows a training from import to the last check.
1. Import — the app reads your repo, not a website#
When a training is imported (Import Lab, or automatically for the dynatrace-wwse catalog), the app reads the raw Markdown from the GitHub repo — not the rendered GitHub Pages site:
| It reads | For |
|---|---|
mkdocs.yaml (nav:) |
The steps, in nav order. If every top-level nav entry is a section, one repo becomes several trainings. |
docs/<page>.md |
Each step's content and its interactive blocks (LAB_QUESTION, LAB_SOLUTION, STEP_SETUP, …). |
| Front-matter of the first page | Catalog card: description, tags, difficulty, duration. |
.assessment/<id>.json |
Scored assessments referenced by LAB_QUESTIONAIRE. |
.devcontainer/devcontainer.json — does it exist? |
Hands-on (a live environment) if it does, self-paced (docs + quizzes, no environment) if not. There is nothing to declare. |
GitHub Pages is still worth publishing — it is the readable, RUM-tracked site for people outside the app — but the app does not depend on it. A change reaches the app when it is on the repo's main branch and the training is imported again.
Interactive blocks are HTML comments
LAB_QUESTION, LAB_SOLUTION and the other blocks are HTML comments: invisible on GitHub and in MkDocs. They only become buttons, quizzes and solution panels inside the app.
2. Start — tokens first, then the container#
When a learner clicks Start on a hands-on training:
- The app mints tokens in the learner's tenant. It asks Orbital which tokens this training needs — read from the repo's
.devcontainer/yaml/dt-tokens.yaml, falling back to the framework default — and mints exactly those, scoped and valid for 4 hours. Nobody pastes a token. - Orbital starts a container from the framework image (
shinojosa/dt-enablement) under Sysbox, so Docker and a k3d cluster run inside it unprivileged. -
Orbital writes
.devcontainer/.envbefore anything runs:Variable Value DT_ENVIRONMENTthe learner's tenant URL DT_OPERATOR_TOKEN,DT_INGEST_TOKENminted tokens (the default dt-tokens.yaml)any other env_varevery extra token your dt-tokens.yamldeclares, plus itsaliasesDT_HOSTGROUPthe learner's session id, <user>-<yyyymmdd>— the key to per-learner isolationORBITAL_ENVIRONMENT=true,ORBITAL_JOB_IDlets your functions know they run on Orbital K3D_*,EXTERNAL_HOSTNAMEcluster ports and the host name apps are exposed on -
Orbital runs
.devcontainer/post-create.sh, then.devcontainer/post-start.sh— exactly as a Codespace would. This is where your cluster, Dynatrace and your apps get built. See 02 — Automate the Environment. - The learner gets the steps next to a terminal into that container, with every framework function and your
my_functions.shalready loaded.
3. Learn — every step is checked#
| Block | Where it runs | What it proves |
|---|---|---|
shell-verification |
in the learner's container (Orbital) | the cluster/app is in the state the step asked for |
dql-verification |
in the learner's tenant (the app runs the DQL) | the telemetry really reached Grail |
multiple-choice, LAB_QUESTIONAIRE |
in the app | the learner understood the concept |
STEP_SETUP |
in the container, silently, when the step opens | prepares the step (e.g. generates the DynaKube) |
LAB_SOLUTION |
in the container, on Run solution — or by automation | the step can be solved without a human |
Progress lives in the learner's Dynatrace user app-state, not in the container, and each start, answer, completed step and completed training is emitted as a bizevent (com.dynatrace.enablement.training.*) — that is how you see who got how far.
4. Resume — rebuilt from the solutions#
A container is disposable: it can be shut down to save cost, or lost — the progress survives. When the learner comes back, Orbital builds a fresh container (post-create.sh, post-start.sh) and then replays the LAB_SOLUTION commands of every completed step, in order, before handing it over. The learner lands where they left off.
Resume stops at the first completed step that changed the environment but has no solution (and no LAB_NO_SOLUTION marker). Solutions are forward-dependent, so skipping one would leave a state no author designed. Every step with a solution is a step the environment can be rebuilt past.
5. Night — the training tests itself#
The nightly pipeline, for every active repo in the dynatrace-wwse repos.yaml:
- runs
integration-test— builds the environment and runs.devcontainer/test/integration.sh; - and, for repos tagged
enablement-app, runstraining-test: it provisions a real session with minted tokens and walks the training section by section — everyLAB_QUESTIONmust parse,STEP_SETUPruns, theLAB_SOLUTIONcommands run (withLAB_WAIT=1), the solution'sverifycommands run, then every shell and DQL check of the section runs against the real tenant. Each section is PASS or FAIL.
A training whose solutions are complete is therefore tested end to end every night — when a Dynatrace release, an operator version or an app image breaks a step, you find out the next morning, not from a customer.
6. Deliver — self-service or workshop#
The same training, unchanged, is delivered two ways:
- Self-service — any learner in any tenant with the app opens it from the catalog.
- Workshop — a trainer creates a workshop: a roster (one email per line) or a join code, two gates (Open room unlocks chat and the board; Start unlocks environments and steps), a live board with each learner's progress, chat, raise-hand and direct messages, and the Workshop Pad (welcome notes, solutions, Q&A — exportable when the workshop ends). Learners join across tenants; the trainer team can have up to 5 trainers.
Codespaces vs. Orbital — same container, different host#
| Codespaces / Dev Containers | Orbital (the app) | |
|---|---|---|
| Image | shinojosa/dt-enablement |
same |
post-create.sh, post-start.sh |
run on create / start | run on every provision (and before a resume replay) |
| Dynatrace tokens | Codespaces secrets or .devcontainer/.env — you provide them |
minted by the app from dt-tokens.yaml |
Session id (DT_HOSTGROUP) |
derived from GITHUB_USER + date |
set by Orbital per learner |
| Terminal | VS Code | the app's terminal tab |
| Lesson UI | MkDocs on port 8000 / GitHub Pages | the app |
A training that works in a Codespace works on Orbital — that is the point of building on the framework.