dsoxlab keeps its state in two places, and nowhere else: in the catalogue you are playing, for progress, and under your home directory, for the log, the caches and the Terraform state. This reference page lists every file, every environment variable and every exit code of version 0.2.5, with the gesture each one calls for. It is written for anyone who wants to save their progress, find a log after a failure, or call dsoxlab from a script. Those locations are held in step with the code by a test of the project: they do not drift silently.
What you will learn
- Locate the progress database and the context, which live in the catalogue.
- Find the log, the caches and the Terraform state under your home directory.
- Set the language, the provider or the waiting delay through an environment variable.
- Interpret every exit code, and tell a "no" from a "cannot".
- Use the
--jsonoutput without depending on a translated label.
In the catalogue you are playing
Progress belongs to the catalogue, not to the machine. Two catalogues side by side keep separate histories, copying a catalogue's directory copies your history with it, and deleting it deletes its own. That is what makes a backup trivial: a single file to copy.
| Path | Content | Written by |
|---|---|---|
<catalogue>/.dsoxlab.db | SQLite database: the scores (results) and the hints taken (hint_requests) | check, submit, hint |
<catalogue>/.dsoxlab-context.json | Active section, level, language, lab, target and provider, plus the reading position in the course | use, run, course |
<catalogue>/ssh/id_ed25519 and .pub | The SSH key pair deployed on the machines of vm labs | instructor bootstrap |
The first two belong in the catalogue's .gitignore, and the published
catalogues do so. The key pair is never committed either: the private half
must not be, and the public one is useless without it, hence the rule of one
pair per clone, generated on every machine that provisions.
Under your home directory
Everything else follows the XDG conventions and moves with the three
matching variables. <catalog-id> is the repo.id of the catalogue's
meta.yml, which is why two clones of the same catalogue share a single
Terraform state and a single lock.
| Path | Content | Moved by |
|---|---|---|
~/.local/state/dsoxlab/dsoxlab.log | Full log of every command, whatever the verbosity | XDG_STATE_HOME |
~/.local/state/dsoxlab/<catalog-id>/terraform/<provider>/ | Terraform working directory and state, one per provider | XDG_STATE_HOME |
~/.local/state/dsoxlab/<catalog-id>/cloud-init/ | cloud-init templates copied out of the tool for provisioning | XDG_STATE_HOME |
~/.local/state/dsoxlab/<catalog-id>/dsoxlab.lock | Write lock of this catalogue | XDG_STATE_HOME |
~/.local/state/dsoxlab/<catalog-id>/labs/ | Fingerprints of the working directory, taken by run, to tell a ready lab from one in progress | XDG_STATE_HOME |
~/.local/state/dsoxlab/catalogue-actif | Identifier of the active catalogue | XDG_STATE_HOME |
~/.cache/dsoxlab/<catalog-id>/inventory.json | Generated Ansible inventory | XDG_CACHE_HOME |
~/.cache/dsoxlab/<catalog-id>/ssh_config | Generated OpenSSH configuration for the lab hosts | XDG_CACHE_HOME |
~/.cache/dsoxlab/version-check.json | Last version seen on PyPI, and when | XDG_CACHE_HOME |
~/.local/share/dsoxlab/demo/ | Demonstration catalogue installed by dsoxlab demo | XDG_DATA_HOME |
~/.local/share/dsoxlab/catalogs/ | Catalogues installed by catalog add, one subdirectory per identifier | XDG_DATA_HOME |
~/.ssh/config.d/<catalog-id>.conf | SSH fragment for the lab hosts, so that ssh, scp and your IDE reach them by name | none |
Two of those files are caches, and losing them only costs a regeneration:
inventory.json and ssh_config are rebuilt by the next command that needs
them. Anything that would point at the generated ssh_config, an Include or
an IDE profile, must therefore tolerate its disappearance. The fragment under
~/.ssh/config.d/ is the stable one, provided ~/.ssh/config carries an
Include of that directory before any Host block: dsoxlab does not write
that line for you, and warns at every provision while it is missing.
The Terraform state is deliberately outside the catalogue: a state file
placed in a lab repository ends up committed, and a committed state lies.
Shell completion writes outside both families, once: ~/.zfunc/_dsoxlab
plus a line in ~/.zshrc, or ~/.bash_completion.d/dsoxlab plus a line in
~/.bashrc.
What does not exist
Three paths have been documented in the past and are listed here so that
nobody looks for them again. There is no ~/.config/dsoxlab/config.yaml,
and no user configuration file at all: what can be set goes through the
contract of the meta.yml, the active context of dsoxlab use, or an
environment variable. There is no ~/.local/share/dsoxlab/progress.db: scores
live in <catalogue>/.dsoxlab.db. And XDG_CONFIG_HOME is read nowhere:
the three XDG variables cited above are the only ones dsoxlab honours.
Environment variables
An environment variable lasts for one call, or for one shell session, and takes precedence over the catalogue's context file. It is the right tool for a one-off try, a command in a script, or a delay to lengthen on a slow machine.
| Variable | Effect |
|---|---|
LAB_HOME | Root of the catalogue to play, instead of automatic detection |
DSOXLAB_LANG | Display language, en or fr, wins over the context file |
DSOXLAB_PROVIDER | Infrastructure provider, wins over dsoxlab use --provider |
DSOXLAB_TARGET | Default target of a vm lab, when the session sets none |
DSOXLAB_PAGER | Pager for course and challenge, then PAGER, default less -R |
DSOXLAB_LOG | DSOXLAB_LOG=debug is the same as -vv |
DSOXLAB_HOST_READY_TIMEOUT | Seconds to wait for a freshly provisioned host, default 180 |
DSOXLAB_NO_UPDATE_CHECK | Set to 1, silences the daily notice of a new version |
DSOXLAB_OUTSCALE_PROFILE, DSOXLAB_AWS_PROFILE | Credentials profile of those providers |
Two more are set by dsoxlab for the tests of a lab to read, and are not
meant to be set by hand: DSOXLAB_TARGET_HOST, the host the tests must
inspect, which is how a multi-distribution lab validates the chosen target, and
DSOXLAB_LAB_SESSION, the lab identifier inside the session opened by
run.
The exit codes
An exit code is the hardest contract the tool exposes: a JSON document can gain a field, a translated sentence can change a word, but a code, once a script reads it, cannot move without breaking that caller silently. They all live in the same place in the code, in an enumeration, and two tests keep the table honest: no value is used twice, and every code must appear in the documentation.
| Code | What it means | The gesture it calls for |
|---|---|---|
0 | The command did what was asked | Nothing |
1 | The command ran, and the answer is no: unknown lab identifier, failing test, host that does not answer, no active context | Read the message; the answer is about your work, not your installation |
2 | The command could not run: infrastructure not provisioned, provider not packaged, declared fixture missing, required restore point unobtainable | Prepare something; this is not a mistake in your work |
3 | Terraform is not installed, so provision and destroy have no way to act | Install it |
4 | Terraform answered, and it failed | Read its output; dsoxlab names the causes it recognises, such as a full or missing storage pool |
5 | A provision left orphan machines, defined on the hypervisor but absent from the state, or found some before starting | Run the virsh undefine line the message prints |
6 | A destroy could not remove those orphans | Remove them by hand, then run destroy again |
7 | Another dsoxlab command already holds the lock of this catalogue | Retry; it is the only code where retrying is right, and the message names the process holding it |
8 | A provision returned without every targeted host answering | dsoxlab status says which one and why; often more time or more vCPU |
9 | doctor --strict: a required check failed, and that is established | Repair what the table names |
10 | doctor --strict: a required check could not be measured | Measure again; nothing is concluded, so nothing is validated |
127 | An expected executable is not in the PATH | Install it; 127 is the code the shell itself returns here |
130 | A Ctrl-C | The message gives the gesture to resume |
Three distinctions are deliberate, and they are what justifies this table.
7 is the only code to retry on, because its cause is temporary by nature;
every other one describes a state that will not change on its own. 9 and
10 are separate because the gestures differ, repair against measure again,
and when both coexist, 9 wins: a certainty outweighs an ignorance. 1 and
2 split "no" from "cannot": a check that fails exits 1, the tool has
worked; a run whose fixture is missing exits 2, nothing was measured.
doctor without --strict exits 0 whatever it finds, deliberately: for a
human, a diagnosis is not a failure, and the verdict lives in the ok
field of --json. It is --strict, not --json, that turns the
diagnosis into 9 or 10.
The machine output, in three rules
Everything dsoxlab prints is made for eyes, tables whose width follows the
terminal, colours, progress bars, and it is made to move. --json renders a
document instead, and three rules govern it. Standard output carries the
document and nothing else: the context banner, the tips and the update notice
go to standard error. Every document carries a schema field, its first,
whose current value is 1. And a verdict is read from a key and a stable
token, key, state, kind, status, cause, never from a translated
label placed next to it for display.
One consequence deserves to be stated on its own: --json changes the
shape of the output, never the verdict nor the exit code. A check
on a failing lab exits 1 with or without it, and prints its document first, so
that a caller receiving a non-zero code can read what went wrong. Read the exit
code first, the document second.
dsoxlab list-labs --json | jq '.count'dsoxlab doctor --json --strict; echo "code: $?"dsoxlab check premiers-pas --json | jq '.check.ok'doctor --json --fix is refused, and says so on standard error: the
remediation commands write to standard output, and the document would
become unreadable. Read the diagnosis first, act second.
Key points
- Progress lives in
<catalogue>/.dsoxlab.db, per catalogue: one file to copy to save it. - The full log is always in
~/.local/state/dsoxlab/dsoxlab.log, and the Terraform state under~/.local/state/dsoxlab/<catalog-id>/. - There is no user configuration file: contract, active context or environment variable.
- A
DSOXLAB_*variable takes precedence over the context file, for one call. - 7 is retried, 9 is repaired, 10 is measured again; 1 is a "no", 2 a "cannot".
--jsonchanges the shape, never the verdict nor the code; read the code first.
Next steps
- Bringing up the infrastructure of vm labs: codes 5, 6 and 8 seen from the trainer's side, with the per-catalogue lock and the stable SSH fragment.