dsoxlab 0.2.2__tar.gz → 0.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/workflows/appliance.yml +48 -6
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/CHANGELOG.fr.md +89 -4
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/CHANGELOG.md +84 -3
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/PKG-INFO +44 -2
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/README.fr.md +45 -2
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/README.md +43 -1
- dsoxlab-0.2.4/docs/appliance.fr.md +288 -0
- dsoxlab-0.2.4/docs/appliance.md +277 -0
- dsoxlab-0.2.4/docs/assets/appliance-connexion.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/catalog-author.fr.md +63 -1
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/catalog-author.md +62 -1
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/commands.fr.md +11 -2
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/commands.md +10 -2
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/contract-v1.fr.md +2 -1
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/contract-v1.md +2 -1
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/files.fr.md +5 -3
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/files.md +4 -3
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/learner.fr.md +53 -8
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/learner.md +48 -7
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/trainer.fr.md +16 -3
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/trainer.md +16 -3
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/README.md +6 -2
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/pyproject.toml +1 -1
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/uv.lock +1 -1
- dsoxlab-0.2.2/docs/appliance.fr.md +0 -169
- dsoxlab-0.2.2/docs/appliance.md +0 -155
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.bestpractices.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/CODEOWNERS +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/FUNDING.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/dependabot.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/workflows/ci.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/workflows/plumber.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/workflows/release.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.github/workflows/scorecard.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.gitignore +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.plumber.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.poutine.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/.pre-commit-config.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/CODE_OF_CONDUCT.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/CODE_OF_CONDUCT.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/CONTRIBUTING.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/CONTRIBUTING.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/LICENSE +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/NOTICE +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/RELEASING.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/RELEASING.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/SECURITY.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/SECURITY.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/README.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/README.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/appliance-bureau.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/appliance-lab-vm.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/dsoxlab-icon-dark.svg +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/dsoxlab-icon-mono.svg +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/dsoxlab-icon.svg +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/dsoxlab-lockup-dark.svg +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/dsoxlab-lockup-light.svg +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/dsoxlab-lockup-mono.svg +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-icon-1024.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-icon-256.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-icon-512.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-icon-dark-1024.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-icon-dark-512.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-lockup-dark-1024.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-lockup-dark-2048.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-lockup-light-1024.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-lockup-light-2048.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-social-preview-dark.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/assets/brand/png/dsoxlab-social-preview.png +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/brand.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/brand.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/demo.gif +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/demo.tape +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/exit-codes.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/exit-codes.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/infra-only.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/infra-only.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/machine-output.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/docs/machine-output.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/champ-inconnu.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/complet.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/position-negative.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/position-non-numerique.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/racine-chaine.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/racine-liste.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/racine-nulle.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/section-liste.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/tronque.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/context_json/vide.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/capstone-exam-score.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/schema-version-courante.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/schema-version-future.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/schema-version-mauvais-type.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/shell-fixtures-nested.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/shell-minimal.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/shell-services-init.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/shell-services.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/vm-multi-target.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/lab_yaml/vm-snapshot-requis.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/meta_yml/full-infra.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/meta_yml/schema-version-courante.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/meta_yml/schema-version-future.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/avec-bastion.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/bastion-sans-ip.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/hosts-liste.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/ip-numerique.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/outputs-aplatis.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/outputs-encapsules.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/sans-hosts.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/value-non-objet.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/corpus/terraform_outputs/vide.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/dict/yaml_contract.dict +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/fuzz_context_json.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/fuzz_lab_yaml.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/fuzz_meta_yaml.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/fuzz/fuzz_terraform_outputs.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/dsoxlab-appliance.pkr.hcl +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/faire-ova.sh +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/http/preseed.cfg +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/scripts/10-base.sh +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/scripts/20-outils.sh +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/scripts/30-premier-demarrage.sh +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/scripts/40-reseau-portable.sh +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/packer/scripts/90-nettoyage.sh +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/schemas/lab.schema.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/schemas/meta.schema.json +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/scripts/check-release.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/scripts/generer-doc.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/scripts/generer-png-marque.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/scripts/parcours-distribution.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/_amorcage.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/_barres.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/_commun.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/_socle.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/_validation.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/auteur.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/catalogues.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/contexte.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/demarrage.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/destruction.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/diagnostic.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/etat.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/indices.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/infrastructure.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/instructeur.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/parcours.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/cli/progression.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/config.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/discovery/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/discovery/repo.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/discovery/scanner.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/exit_codes.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/i18n/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/i18n/strings/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/i18n/strings/en.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/i18n/strings/fr.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/ansible.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/credentials.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/inventory.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/libvirt.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/pont.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/snapshot/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/snapshot/kvm.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/infra/terraform.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/interrupt.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/locking.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/logging_setup.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/_contract.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/course.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/hint.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/lab.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/repo.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/runtime.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/models/schema_version.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/py.typed +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/reporting/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/reporting/console.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/reporting/machine.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/runtimes/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/runtimes/base.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/runtimes/manager.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/runtimes/services.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/runtimes/shell.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/runtimes/vm.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/catalog.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/demo.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/doctor.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/guide_service.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/host_diagnosis.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/issue_service.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/lab_service.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/lab_state.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/progress_service.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/scaffold.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/support.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/services/update_check.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/sessions/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/sessions/store.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/catalogues.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/cloud-init/README.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/cloud-init/almalinux.yaml.tmpl +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/cloud-init/debian.yaml.tmpl +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/cloud-init/ubuntu.yaml.tmpl +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/README.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/README.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/README.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/README.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/hints.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/tests/conftest.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/challenge/tests/test_functional.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/lab.fr.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/lab.yaml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/scenario.fr.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/labs/demo/premiers-pas/scenario.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/meta.fr.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/demo/meta.yml +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/README.md +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/incus/main.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/incus/outputs.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/incus/variables.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/incus/versions.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/kvm/main.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/kvm/outputs.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/kvm/variables.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/kvm/versions.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/outscale/main.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/outscale/outputs.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/outscale/variables.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/templates/terraform/outscale/versions.tf +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/utils/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/utils/fichiers.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/utils/shell.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/validators/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/validators/content.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/validators/contract.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/validators/metadata.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/src/dsoxlab/validators/structure.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/__init__.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/conftest.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_ansible_availability.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_catalog.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_check_release.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_ci_valide_les_templates.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_cles_i18n_existantes.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_cli_smoke.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_cloud_init_degrade.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_cloud_init_incus_agent.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_cloud_init_templates.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_codes_de_sortie.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_commande_absente.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_completion.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_conteneurs_engendres.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_contrat_honore.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_convention_de_nommage.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_demo.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_description_alignee.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_doc_auteur_couvre_les_controles.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_doctor.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_doctor_explique.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_doctor_fix.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_doctor_installation.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_doctor_prerequis_vm.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_doctor_strict.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_documentation_synchrone.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_etat_libvirt.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_executable_absent.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_fixtures_declarees.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_guide_service.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_host_ready_timeout.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_i18n_coverage.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_i18n_validators.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_incus_pool.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_install_et_contexte.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_instructor_bootstrap.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_interruption.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_issue_service.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_journal_en_anglais.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_journalisation.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_json_output.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_json_schemas.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_kvm_disques_apparmor.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_lab_state.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_moteur_injoignable.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_nom_de_pont.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_note_sans_mesure.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_outputs_terraform.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_pager.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_parcours_distribution.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_progress_service.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_provision_ciblee.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_provision_et_json_services.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_repertoire_de_travail_annonce.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_scaffold.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_schema_version.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_schemas_sur_documents.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_services.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_session_spec.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_shell_fixtures.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_snapshot_kvm.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_sondes_des_tests_docker.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_sondes_virsh.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_stack_infra.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_start_sequence.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_support.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_support_en_anglais.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_update_check.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_validator_voit_tout.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_validators_content.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_verrou_depot.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_versions_supportees.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests/test_yaml_contract.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests_e2e/conftest.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests_e2e/pytest.ini +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests_e2e/test_boite_noire.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests_e2e/test_installation.py +0 -0
- {dsoxlab-0.2.2 → dsoxlab-0.2.4}/tests_e2e/test_parcours.py +0 -0
|
@@ -9,16 +9,23 @@
|
|
|
9
9
|
# 2. un build d'image de vingt minutes ne doit ni retarder une publication PyPI,
|
|
10
10
|
# ni pouvoir la faire échouer.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
12
|
+
# Il se déclenche sur **toute** version publiée, correctifs compris. La règle
|
|
13
|
+
# précédente — les seuls tags mineurs — économisait de la bande passante et
|
|
14
|
+
# coûtait plus cher que ça : elle laissait la doc annoncer une appliance que la
|
|
15
|
+
# dernière release ne portait pas, et obligeait le lecteur à chercher laquelle
|
|
16
|
+
# des releases précédentes en avait une. « La dernière release porte l'image »
|
|
17
|
+
# est la seule phrase qu'on n'a pas à nuancer.
|
|
18
|
+
#
|
|
19
|
+
# Ce que ça ne coûte pas : de l'espace qui s'accumule. Seuls les deux derniers
|
|
20
|
+
# jeux d'images sont conservés (voir l'étape de rétention), et l'image
|
|
21
|
+
# n'épinglant aucune version de dsoxlab, une ancienne n'offre rien d'autre que
|
|
22
|
+
# son poids.
|
|
16
23
|
|
|
17
24
|
name: Appliance
|
|
18
25
|
|
|
19
26
|
on:
|
|
20
27
|
push:
|
|
21
|
-
tags: ["v[0-9]+.[0-9]+.0"]
|
|
28
|
+
tags: ["v[0-9]+.[0-9]+.[0-9]+"]
|
|
22
29
|
workflow_dispatch:
|
|
23
30
|
inputs:
|
|
24
31
|
tag:
|
|
@@ -97,6 +104,24 @@ jobs:
|
|
|
97
104
|
echo "sum=$sum" >> "$GITHUB_OUTPUT"
|
|
98
105
|
echo "ISO : $name"
|
|
99
106
|
|
|
107
|
+
- name: Prepare the build directory on /mnt
|
|
108
|
+
# `/mnt` has the space (~70 GB against ~14 on `/`), but it belongs to
|
|
109
|
+
# root: the runner cannot create anything there. The first real run of
|
|
110
|
+
# this workflow died on exactly that, four hundredths of a second in —
|
|
111
|
+
# a defect no local build could show, since the directory exists and is
|
|
112
|
+
# writable on a developer's machine.
|
|
113
|
+
#
|
|
114
|
+
# `out/` is deliberately NOT created: Packer refuses to start when its
|
|
115
|
+
# output directory already exists ("It must not exist"), which is how
|
|
116
|
+
# it guarantees it never writes over a previous build. Creating it here
|
|
117
|
+
# traded one failure for another, one step later — measured on the
|
|
118
|
+
# second real run.
|
|
119
|
+
run: |
|
|
120
|
+
set -euo pipefail
|
|
121
|
+
sudo mkdir -p "${BUILD_DIR}/tmp"
|
|
122
|
+
sudo chown -R "$(id -u):$(id -g)" "${BUILD_DIR}"
|
|
123
|
+
df -h "${BUILD_DIR}"
|
|
124
|
+
|
|
100
125
|
- name: packer init && validate
|
|
101
126
|
working-directory: packer
|
|
102
127
|
env:
|
|
@@ -104,7 +129,6 @@ jobs:
|
|
|
104
129
|
ISO_SUM: ${{ steps.iso.outputs.sum }}
|
|
105
130
|
run: |
|
|
106
131
|
set -euo pipefail
|
|
107
|
-
mkdir -p "${BUILD_DIR}/out" "${BUILD_DIR}/tmp"
|
|
108
132
|
packer init .
|
|
109
133
|
packer validate \
|
|
110
134
|
-var "image_version=${GITHUB_REF_NAME#v}" \
|
|
@@ -206,6 +230,24 @@ jobs:
|
|
|
206
230
|
REPO: ${{ github.repository }}
|
|
207
231
|
run: |
|
|
208
232
|
set -euo pipefail
|
|
233
|
+
|
|
234
|
+
# Les deux workflows partent du même tag : celui-ci construit pendant
|
|
235
|
+
# vingt minutes, `release.yml` publie en deux. La Release existe donc
|
|
236
|
+
# en pratique bien avant qu'on arrive ici — mais « en pratique » n'est
|
|
237
|
+
# pas une garantie, et un upload sur une Release absente échouerait
|
|
238
|
+
# sur un message qui ne dirait pas pourquoi. On attend, et on le dit.
|
|
239
|
+
restants=30 # 30 × 20 s = dix minutes
|
|
240
|
+
until gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; do
|
|
241
|
+
restants=$((restants - 1))
|
|
242
|
+
if [ "$restants" -le 0 ]; then
|
|
243
|
+
echo "::error::La Release $TAG n'existe toujours pas après dix minutes."
|
|
244
|
+
echo "::error::Regardez release.yml : s'il a échoué, les images n'ont rien où s'attacher."
|
|
245
|
+
exit 1
|
|
246
|
+
fi
|
|
247
|
+
echo "En attente de la Release $TAG…"
|
|
248
|
+
sleep 20
|
|
249
|
+
done
|
|
250
|
+
|
|
209
251
|
gh release upload "$TAG" --repo "$REPO" --clobber \
|
|
210
252
|
"${BUILD_DIR}"/out/*.ova \
|
|
211
253
|
"${BUILD_DIR}"/out/*.qcow2 \
|
|
@@ -9,6 +9,90 @@ et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/).
|
|
|
9
9
|
|
|
10
10
|
## [Non publié]
|
|
11
11
|
|
|
12
|
+
## [0.2.4] - 2026-09-26
|
|
13
|
+
|
|
14
|
+
### Corrigé
|
|
15
|
+
|
|
16
|
+
- **Le build de l'appliance a avancé d'une étape, et s'est arrêté sur la
|
|
17
|
+
précédente.** `/mnt` étant enfin accessible en écriture, c'est Packer qui a
|
|
18
|
+
refusé de démarrer : *Output directory '/mnt/appliance/out' already exists.
|
|
19
|
+
It must not exist.* Ce refus est une qualité — c'est ainsi que Packer
|
|
20
|
+
garantit qu'il n'écrase jamais un build précédent — et l'étape de
|
|
21
|
+
préparation créait précisément ce répertoire. Elle ne crée plus que le
|
|
22
|
+
parent et le répertoire temporaire, et laisse `out/` à Packer. Deux échecs
|
|
23
|
+
de suite au même endroit disent quelque chose qu'il vaut la peine de
|
|
24
|
+
retenir : un workflow qui n'a jamais tourné est un workflow qui ne marche
|
|
25
|
+
pas, et le seul moyen de le savoir est de le jouer.
|
|
26
|
+
|
|
27
|
+
## [0.2.3] - 2026-09-26
|
|
28
|
+
|
|
29
|
+
### Corrigé
|
|
30
|
+
|
|
31
|
+
- **Le workflow de l'appliance n'avait jamais tourné, et il est mort au bout de
|
|
32
|
+
quatre centièmes de seconde.** `mkdir: cannot create directory
|
|
33
|
+
'/mnt/appliance': Permission denied` — sur un runner GitHub, `/mnt`
|
|
34
|
+
appartient à root, et c'est là qu'est la place (environ 70 Go contre 14 sur
|
|
35
|
+
`/`). Aucun build local ne pouvait le montrer : sur une machine de
|
|
36
|
+
développement, ce répertoire existe et s'écrit. Une étape dédiée le crée
|
|
37
|
+
désormais en `sudo` et le remet au runner.
|
|
38
|
+
|
|
39
|
+
- **L'image est publiée à chaque release, et plus seulement aux mineures.**
|
|
40
|
+
L'ancienne règle économisait de la bande passante et coûtait plus qu'elle
|
|
41
|
+
n'économisait : la documentation annonçait une appliance que la dernière
|
|
42
|
+
release ne portait pas, et le lecteur devait deviner laquelle des
|
|
43
|
+
précédentes l'avait. « La dernière release porte l'image » est la seule
|
|
44
|
+
phrase qui n'appelle aucune nuance, et rien ne s'accumule puisque l'étape de
|
|
45
|
+
rétention garde les deux derniers jeux. Les deux workflows partant désormais
|
|
46
|
+
du même tag, l'upload attend que la Release existe au lieu de le supposer —
|
|
47
|
+
et dit quel workflow regarder si elle n'arrive jamais.
|
|
48
|
+
|
|
49
|
+
### Modifié
|
|
50
|
+
|
|
51
|
+
- **La documentation est un parcours, plus une pile de pages.** Relue de bout
|
|
52
|
+
en bout contre le code, elle portait des ruptures qu'aucune page seule ne
|
|
53
|
+
pouvait révéler :
|
|
54
|
+
|
|
55
|
+
`learner.fr.md` promettait `run` juste après le clonage d'un catalogue, alors
|
|
56
|
+
que **66 des 86 labs du catalogue Linux** sont des labs `vm` : ce `run` sort
|
|
57
|
+
en 2, le `provision` qu'il suggère sort en 1 faute de clé SSH, et ni
|
|
58
|
+
`instructor bootstrap`, ni `start`, ni le mot Terraform n'apparaissaient sur
|
|
59
|
+
la page. Elle nomme maintenant ce qu'un lab `vm` demande à une machine, et
|
|
60
|
+
met `start` en premier — la commande qui joue tout l'ordre en annonçant
|
|
61
|
+
chaque étape avec la commande qui la rejoue seule.
|
|
62
|
+
|
|
63
|
+
`catalog-author.fr.md` listait les fichiers d'un lab sans dire ce qu'on y
|
|
64
|
+
met. Le barème que `validate-structure` impose (`### … (20 pts)` face à un
|
|
65
|
+
en-tête `N tâches, M points`, et un point par test), le format de
|
|
66
|
+
`hints.yaml`, et l'emplacement de `conftest.py` — pytest s'exécute depuis la
|
|
67
|
+
racine du catalogue — n'étaient documentés nulle part.
|
|
68
|
+
|
|
69
|
+
Le README n'atteignait ni l'index, ni `exit-codes.fr.md`,
|
|
70
|
+
`machine-output.fr.md` et `infra-only.fr.md` : trois pages de référence
|
|
71
|
+
inaccessibles depuis la porte d'entrée.
|
|
72
|
+
|
|
73
|
+
La clé SSH était décrite comme quelque chose que le catalogue livre. Il ne la
|
|
74
|
+
livre pas : les catalogues publiés ignorent tout le répertoire `ssh/`, et
|
|
75
|
+
`provision` refuse de démarrer sans la moitié privée. Elle se génère **par
|
|
76
|
+
clone**, avec `instructor bootstrap`, apprenants compris.
|
|
77
|
+
|
|
78
|
+
`contract-v1.fr.md` se contredisait à neuf lignes d'intervalle sur le
|
|
79
|
+
caractère obligatoire de `repo.category`.
|
|
80
|
+
|
|
81
|
+
- **`docs/appliance.fr.md` est un pas-à-pas**, de l'installation de VirtualBox
|
|
82
|
+
au premier lab, avec la vérification d'empreinte, la mémoire à donner à la
|
|
83
|
+
machine selon celle de l'hôte, ce que montre le premier démarrage en trois
|
|
84
|
+
temps, et un tableau de dépannage. Les deux README ouvrent sur les deux
|
|
85
|
+
façons d'entrer, chacune avec son parcours en quatre étapes.
|
|
86
|
+
|
|
87
|
+
### Ajouté
|
|
88
|
+
|
|
89
|
+
- **Rendre à César** : l'appliance est l'idée de [@cedric-ribier], et elle
|
|
90
|
+
existe parce qu'il en avait déjà construit une de bout en bout, documentée
|
|
91
|
+
dans [#91](https://github.com/stephrobert/dsoxlab/issues/91). Celle qui est
|
|
92
|
+
livrée ici s'en inspire directement.
|
|
93
|
+
|
|
94
|
+
[@cedric-ribier]: https://github.com/cedric-ribier
|
|
95
|
+
|
|
12
96
|
## [0.2.2] - 2026-09-26
|
|
13
97
|
|
|
14
98
|
### Ajouté
|
|
@@ -28,9 +112,10 @@ et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/).
|
|
|
28
112
|
|
|
29
113
|
L'image **n'épingle rien**. Le premier démarrage installe le dernier dsoxlab, et
|
|
30
114
|
les hyperviseurs seulement si l'hôte expose la virtualisation imbriquée, vérifiée
|
|
31
|
-
en direct et jamais supposée.
|
|
32
|
-
|
|
33
|
-
ne
|
|
115
|
+
en direct et jamais supposée. Elle est reconstruite à **chaque version
|
|
116
|
+
publiée**, correctifs compris : la dernière release porte l'image, et c'est la
|
|
117
|
+
seule phrase qui n'appelle aucune nuance. Rien ne s'accumule pour autant —
|
|
118
|
+
seuls les deux derniers jeux sont conservés.
|
|
34
119
|
|
|
35
120
|
Mesuré, non estimé : **461 Mio** pour le qcow2 et **446 Mio** pour l'OVA,
|
|
36
121
|
construits en 4 min 50 s, contre un budget que le workflow impose à 800 Mio. Une
|
|
@@ -41,7 +126,7 @@ et le projet suit le [versionnage sémantique](https://semver.org/lang/fr/).
|
|
|
41
126
|
bonne sous Linux, plutôt que de les vendre à égalité.
|
|
42
127
|
|
|
43
128
|
- **Seuls les deux derniers jeux d'images sont conservés sur les Releases.**
|
|
44
|
-
Environ 900 Mo par version
|
|
129
|
+
Environ 900 Mo par version, pour toujours, pour des images qui
|
|
45
130
|
n'épinglent aucune version de dsoxlab et installent la dernière au premier
|
|
46
131
|
démarrage : une ancienne n'offre aucune reproductibilité, seulement son
|
|
47
132
|
poids. Deux plutôt qu'une, pour qu'une image cassée ait un recours. Les
|
|
@@ -9,6 +9,86 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.2.4] - 2026-09-26
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **The appliance build got one step further, and stopped on the step before.**
|
|
17
|
+
With `/mnt` finally writable, Packer refused to start: *Output directory
|
|
18
|
+
'/mnt/appliance/out' already exists. It must not exist.* That refusal is a
|
|
19
|
+
feature — it is how Packer guarantees it never writes over a previous
|
|
20
|
+
build — and the preparation step was creating that very directory. It now
|
|
21
|
+
creates only the parent and the temporary directory, and leaves `out/` to
|
|
22
|
+
Packer. Two failures in a row at the same place say something worth keeping:
|
|
23
|
+
a workflow that has never run is a workflow that does not work, and the only
|
|
24
|
+
way to know is to run it.
|
|
25
|
+
|
|
26
|
+
## [0.2.3] - 2026-09-26
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **The appliance workflow had never run, and died four hundredths of a second
|
|
31
|
+
in.** `mkdir: cannot create directory '/mnt/appliance': Permission denied` —
|
|
32
|
+
on a GitHub runner `/mnt` belongs to root, and that is where the disk space
|
|
33
|
+
is (~70 GB against ~14 on `/`). No local build could show it, since the
|
|
34
|
+
directory exists and is writable on a developer's machine. A dedicated step
|
|
35
|
+
now creates it with `sudo` and hands it to the runner.
|
|
36
|
+
|
|
37
|
+
- **The image is published on every release, not only on minor ones.** The old
|
|
38
|
+
rule saved bandwidth and cost more than it saved: the documentation announced
|
|
39
|
+
an appliance the latest release did not carry, and the reader had to work out
|
|
40
|
+
which earlier release did. "The latest release carries the image" is the only
|
|
41
|
+
sentence that needs no caveat, and nothing accumulates since the retention
|
|
42
|
+
step keeps the last two sets. The two workflows now start from the same tag,
|
|
43
|
+
so the upload waits for the Release to exist instead of assuming it — and
|
|
44
|
+
says which workflow to look at if it never does.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- **The documentation is a path now, not a pile of pages.** Read end to end
|
|
49
|
+
against the code, it had breaks that no single page could reveal:
|
|
50
|
+
|
|
51
|
+
`learner.md` promised `run` right after cloning a catalog, while **66 of the
|
|
52
|
+
Linux catalog's 86 labs** are `vm` labs: that `run` exits 2, the `provision`
|
|
53
|
+
it suggests exits 1 for want of an SSH key, and neither `instructor
|
|
54
|
+
bootstrap`, nor `start`, nor the word Terraform appeared anywhere on the
|
|
55
|
+
page. It now names what a `vm` lab asks of a machine, and puts `start` first
|
|
56
|
+
— the command that plays the whole order and announces each step with the
|
|
57
|
+
command that replays it alone.
|
|
58
|
+
|
|
59
|
+
`catalog-author.md` listed a lab's files without saying what goes in them.
|
|
60
|
+
The scale that `validate-structure` enforces (`### … (20 pts)` against a
|
|
61
|
+
`N tasks, M points` header, and one point per test), the format of
|
|
62
|
+
`hints.yaml`, and where `conftest.py` lives — pytest runs from the catalog
|
|
63
|
+
root — were documented nowhere.
|
|
64
|
+
|
|
65
|
+
The README reached neither the index nor `exit-codes.md`,
|
|
66
|
+
`machine-output.md` and `infra-only.md`: three reference pages unreachable
|
|
67
|
+
from the front door.
|
|
68
|
+
|
|
69
|
+
The SSH key was described as something a catalog ships. It is not: published
|
|
70
|
+
catalogs ignore the whole `ssh/` directory, and `provision` refuses to start
|
|
71
|
+
without the private half. It is generated **per clone**, by `instructor
|
|
72
|
+
bootstrap`, learners included.
|
|
73
|
+
|
|
74
|
+
`contract-v1.md` contradicted itself nine lines apart on whether
|
|
75
|
+
`repo.category` is required.
|
|
76
|
+
|
|
77
|
+
- **`docs/appliance.md` is a step-by-step**, from installing VirtualBox to the
|
|
78
|
+
first lab, with the digest check, the memory to give the machine depending on
|
|
79
|
+
the host's, what the first boot looks like in three acts, and a
|
|
80
|
+
troubleshooting table. Both READMEs open on the two ways in, each with its
|
|
81
|
+
own four-step path.
|
|
82
|
+
|
|
83
|
+
### Added
|
|
84
|
+
|
|
85
|
+
- **Credit where it is due**: the appliance is [@cedric-ribier]'s idea, and it
|
|
86
|
+
exists because he had already built one end to end and documented it in
|
|
87
|
+
[#91](https://github.com/stephrobert/dsoxlab/issues/91). The one shipped here
|
|
88
|
+
is directly inspired by his.
|
|
89
|
+
|
|
90
|
+
[@cedric-ribier]: https://github.com/cedric-ribier
|
|
91
|
+
|
|
12
92
|
## [0.2.2] - 2026-09-26
|
|
13
93
|
|
|
14
94
|
### Added
|
|
@@ -27,8 +107,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
27
107
|
|
|
28
108
|
The image **pins nothing**. The first boot installs the latest dsoxlab, and the
|
|
29
109
|
hypervisors only if the host exposes nested virtualization — checked live, never
|
|
30
|
-
assumed.
|
|
31
|
-
|
|
110
|
+
assumed. It is rebuilt on **every published version**, patches included: the
|
|
111
|
+
latest release carries the image, which is the only sentence that needs no
|
|
112
|
+
caveat. Nothing accumulates — only the last two sets are kept.
|
|
32
113
|
|
|
33
114
|
Measured, not estimated: **461 MiB** for the qcow2 and **446 MiB** for the OVA,
|
|
34
115
|
built in 4 min 50 s, against a budget the workflow enforces at 800 MiB. A
|
|
@@ -39,7 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
39
120
|
selling them as equals.
|
|
40
121
|
|
|
41
122
|
- **Only the last two sets of images are kept on the Releases.** Roughly 900 MB
|
|
42
|
-
per
|
|
123
|
+
per version, forever, for images that pin no dsoxlab version and
|
|
43
124
|
install the latest at first boot: an old one offers no reproducibility, only
|
|
44
125
|
weight. Two rather than one, so a broken image has a fallback. The Releases,
|
|
45
126
|
their changelog and the Python distributions are untouched.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: dsoxlab
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Turn declarative exercises into reproducible, runnable and verifiable lab environments
|
|
5
5
|
Project-URL: Homepage, https://blog.stephane-robert.info/
|
|
6
6
|
Project-URL: Documentation, https://github.com/stephrobert/dsoxlab/blob/main/docs/README.md
|
|
@@ -118,9 +118,42 @@ and no Docker: it runs anywhere dsoxlab runs.
|
|
|
118
118
|
|
|
119
119
|
---
|
|
120
120
|
|
|
121
|
+
## Or: the appliance, in four steps
|
|
122
|
+
|
|
123
|
+
For Windows and macOS, where `uv tool install` is not an option. No knowledge
|
|
124
|
+
of virtualization required.
|
|
125
|
+
|
|
126
|
+
1. **Install VirtualBox** from <https://www.virtualbox.org/wiki/Downloads>. The
|
|
127
|
+
*Extension Pack* it offers is not needed.
|
|
128
|
+
2. **Download the `.ova`** from the latest
|
|
129
|
+
[release](https://github.com/stephrobert/dsoxlab/releases) that carries one,
|
|
130
|
+
and check its digest against the `SHA256SUMS` published next to it.
|
|
131
|
+
3. **Import and start**: in VirtualBox, *File → Import Appliance*, pick the
|
|
132
|
+
`.ova`, *Finish*, then *Start*. The first boot installs dsoxlab, the
|
|
133
|
+
hypervisors and the desktop, then **reboots on its own**: count five to
|
|
134
|
+
fifteen minutes, with nothing to type.
|
|
135
|
+
4. **Log in** with `student` / `dsoxlab` — the machine requires you to change
|
|
136
|
+
that password, which is public — then, in the desktop's terminal:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
dsoxlab demo && cd ~/.local/share/dsoxlab/demo
|
|
140
|
+
dsoxlab course premiers-pas
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`vm` labs need one more step, **nested virtualization**, which is enabled on
|
|
144
|
+
your computer and not inside the machine: *Settings → System → Processor →
|
|
145
|
+
Enable Nested VT-x/AMD-V*, appliance powered off. `dsoxlab doctor` says so when
|
|
146
|
+
it is missing.
|
|
147
|
+
|
|
148
|
+
Every step in detail, the actual requirements and a troubleshooting table are
|
|
149
|
+
on **[the appliance page](docs/appliance.md)**.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
121
153
|
## Documentation
|
|
122
154
|
|
|
123
|
-
|
|
155
|
+
Every page names its audience in its first lines, and
|
|
156
|
+
[the index](docs/README.md) lists them all.
|
|
124
157
|
|
|
125
158
|
| I want to… | Read |
|
|
126
159
|
| --- | --- |
|
|
@@ -128,6 +161,8 @@ Three readers, three doors. Every page names its audience in its first lines.
|
|
|
128
161
|
| Play labs on Windows or macOS, without installing anything | **[The appliance](docs/appliance.md)**, a ready-to-play VM |
|
|
129
162
|
| Write my own catalog of labs | **[For the catalog author](docs/catalog-author.md)**, then [the v1 contract](docs/contract-v1.md) field by field |
|
|
130
163
|
| Run the machines the labs need | **[For the trainer](docs/trainer.md)** |
|
|
164
|
+
| Get throwaway VMs, with no exercise to write | [Infrastructure without labs](docs/infra-only.md) |
|
|
165
|
+
| Call dsoxlab from a script or a CI, and branch on the result | [Exit codes](docs/exit-codes.md), then [the machine output](docs/machine-output.md) for `--json` |
|
|
131
166
|
| Know where dsoxlab writes on my disk | [Where dsoxlab writes](docs/files.md) |
|
|
132
167
|
| See every command | [Command reference](docs/commands.md), generated from the CLI |
|
|
133
168
|
|
|
@@ -217,6 +252,13 @@ persistent, and four releases come from his reports:
|
|
|
217
252
|
ready-to-use appliance, discussed in
|
|
218
253
|
[#91](https://github.com/stephrobert/dsoxlab/issues/91).
|
|
219
254
|
|
|
255
|
+
**And the appliance itself is his idea.** He did not ask for it: he had already
|
|
256
|
+
**built one end to end**, then documented it in
|
|
257
|
+
[#91](https://github.com/stephrobert/dsoxlab/issues/91). The one dsoxlab ships
|
|
258
|
+
today is directly inspired by his — the idea and the approach both. It is the
|
|
259
|
+
contribution a changelog shows least and the product owes most: without it,
|
|
260
|
+
there would be nothing to offer anyone working on Windows or macOS.
|
|
261
|
+
|
|
220
262
|
**[@Gedd18](https://github.com/Gedd18)** found that the lab catalog's
|
|
221
263
|
`conftest.py` failed to load whenever no infrastructure provider was resolved,
|
|
222
264
|
which silently blocked **every `shell` lab** — the very first ones a learner
|
|
@@ -80,10 +80,43 @@ conteneur, ni Docker : il tourne partout où dsoxlab tourne.
|
|
|
80
80
|
|
|
81
81
|
---
|
|
82
82
|
|
|
83
|
+
## Ou : l'appliance, en quatre étapes
|
|
84
|
+
|
|
85
|
+
Pour Windows et macOS, où `uv tool install` n'est pas une option. Aucune
|
|
86
|
+
connaissance de la virtualisation n'est nécessaire.
|
|
87
|
+
|
|
88
|
+
1. **Installez VirtualBox** depuis
|
|
89
|
+
<https://www.virtualbox.org/wiki/Downloads>. L'*Extension Pack* proposé
|
|
90
|
+
n'est pas nécessaire.
|
|
91
|
+
2. **Téléchargez le fichier `.ova`** de la dernière
|
|
92
|
+
[release](https://github.com/stephrobert/dsoxlab/releases) qui en porte un,
|
|
93
|
+
et vérifiez son empreinte avec le `SHA256SUMS` publié à côté.
|
|
94
|
+
3. **Importez et démarrez** : dans VirtualBox, *Fichier → Importer un appareil
|
|
95
|
+
virtuel*, choisissez le `.ova`, *Terminer*, puis *Démarrer*. Le premier
|
|
96
|
+
démarrage installe dsoxlab, les hyperviseurs et le bureau, puis **redémarre
|
|
97
|
+
tout seul** : comptez cinq à quinze minutes, sans rien taper.
|
|
98
|
+
4. **Connectez-vous** avec `student` / `dsoxlab` — la machine exige de changer
|
|
99
|
+
ce mot de passe, qui est public — puis, dans le terminal du bureau :
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
dsoxlab demo && cd ~/.local/share/dsoxlab/demo
|
|
103
|
+
dsoxlab course premiers-pas
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Les labs `vm` demandent une étape de plus, la **virtualisation imbriquée**, qui
|
|
107
|
+
s'active sur votre ordinateur et non dans la machine : *Configuration → Système
|
|
108
|
+
→ Processeur → Activer VT-x/AMD-V imbriqué*, appliance éteinte. `dsoxlab
|
|
109
|
+
doctor` le dit s'il manque.
|
|
110
|
+
|
|
111
|
+
Le détail de chaque étape, les prérequis chiffrés et un tableau de dépannage
|
|
112
|
+
sont dans **[la page de l'appliance](docs/appliance.fr.md)**.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
83
116
|
## Documentation
|
|
84
117
|
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
Chaque page nomme son public dès ses premières lignes, et
|
|
119
|
+
[l'index](docs/README.fr.md) les répertorie toutes.
|
|
87
120
|
|
|
88
121
|
| Je veux… | Lire |
|
|
89
122
|
| --- | --- |
|
|
@@ -91,6 +124,8 @@ lignes.
|
|
|
91
124
|
| Jouer des labs sous Windows ou macOS, sans rien installer | **[L'appliance](docs/appliance.fr.md)**, une VM prête à jouer |
|
|
92
125
|
| Écrire mon propre catalogue de labs | **[Pour l'auteur de catalogue](docs/catalog-author.fr.md)**, puis [le contrat v1](docs/contract-v1.fr.md) champ par champ |
|
|
93
126
|
| Monter les machines dont les labs ont besoin | **[Pour le formateur](docs/trainer.fr.md)** |
|
|
127
|
+
| Obtenir des VM jetables, sans aucun exercice à écrire | [L'infrastructure sans labs](docs/infra-only.fr.md) |
|
|
128
|
+
| Appeler dsoxlab depuis un script ou une CI, et décider sur le résultat | [Les codes de sortie](docs/exit-codes.fr.md), puis [la sortie machine](docs/machine-output.fr.md) pour `--json` |
|
|
94
129
|
| Savoir où dsoxlab écrit sur mon disque | [Où dsoxlab écrit](docs/files.fr.md) |
|
|
95
130
|
| Voir toutes les commandes | [Référence des commandes](docs/commands.fr.md), produite par la CLI |
|
|
96
131
|
|
|
@@ -186,6 +221,14 @@ et quatre versions viennent de ses remontées :
|
|
|
186
221
|
une image prête à l'emploi, discuté dans
|
|
187
222
|
[#91](https://github.com/stephrobert/dsoxlab/issues/91).
|
|
188
223
|
|
|
224
|
+
**Et l'appliance elle-même est son idée.** Il ne l'a pas demandée : il l'avait
|
|
225
|
+
déjà **construite de bout en bout**, puis documentée dans
|
|
226
|
+
[#91](https://github.com/stephrobert/dsoxlab/issues/91). Celle que dsoxlab
|
|
227
|
+
publie aujourd'hui s'inspire directement de la sienne — l'idée comme la
|
|
228
|
+
démarche. C'est la contribution la moins visible dans un journal des
|
|
229
|
+
modifications et la plus structurante pour le produit : sans elle, il n'y
|
|
230
|
+
aurait rien à proposer à qui travaille sous Windows ou macOS.
|
|
231
|
+
|
|
189
232
|
**[@Gedd18](https://github.com/Gedd18)** a trouvé que le `conftest.py` du
|
|
190
233
|
catalogue de labs ne se chargeait plus dès qu'aucun provider d'infrastructure
|
|
191
234
|
n'était résolu, ce qui bloquait en silence **tous les labs `shell`**, c'est-à-dire
|
|
@@ -81,9 +81,42 @@ and no Docker: it runs anywhere dsoxlab runs.
|
|
|
81
81
|
|
|
82
82
|
---
|
|
83
83
|
|
|
84
|
+
## Or: the appliance, in four steps
|
|
85
|
+
|
|
86
|
+
For Windows and macOS, where `uv tool install` is not an option. No knowledge
|
|
87
|
+
of virtualization required.
|
|
88
|
+
|
|
89
|
+
1. **Install VirtualBox** from <https://www.virtualbox.org/wiki/Downloads>. The
|
|
90
|
+
*Extension Pack* it offers is not needed.
|
|
91
|
+
2. **Download the `.ova`** from the latest
|
|
92
|
+
[release](https://github.com/stephrobert/dsoxlab/releases) that carries one,
|
|
93
|
+
and check its digest against the `SHA256SUMS` published next to it.
|
|
94
|
+
3. **Import and start**: in VirtualBox, *File → Import Appliance*, pick the
|
|
95
|
+
`.ova`, *Finish*, then *Start*. The first boot installs dsoxlab, the
|
|
96
|
+
hypervisors and the desktop, then **reboots on its own**: count five to
|
|
97
|
+
fifteen minutes, with nothing to type.
|
|
98
|
+
4. **Log in** with `student` / `dsoxlab` — the machine requires you to change
|
|
99
|
+
that password, which is public — then, in the desktop's terminal:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
dsoxlab demo && cd ~/.local/share/dsoxlab/demo
|
|
103
|
+
dsoxlab course premiers-pas
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`vm` labs need one more step, **nested virtualization**, which is enabled on
|
|
107
|
+
your computer and not inside the machine: *Settings → System → Processor →
|
|
108
|
+
Enable Nested VT-x/AMD-V*, appliance powered off. `dsoxlab doctor` says so when
|
|
109
|
+
it is missing.
|
|
110
|
+
|
|
111
|
+
Every step in detail, the actual requirements and a troubleshooting table are
|
|
112
|
+
on **[the appliance page](docs/appliance.md)**.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
84
116
|
## Documentation
|
|
85
117
|
|
|
86
|
-
|
|
118
|
+
Every page names its audience in its first lines, and
|
|
119
|
+
[the index](docs/README.md) lists them all.
|
|
87
120
|
|
|
88
121
|
| I want to… | Read |
|
|
89
122
|
| --- | --- |
|
|
@@ -91,6 +124,8 @@ Three readers, three doors. Every page names its audience in its first lines.
|
|
|
91
124
|
| Play labs on Windows or macOS, without installing anything | **[The appliance](docs/appliance.md)**, a ready-to-play VM |
|
|
92
125
|
| Write my own catalog of labs | **[For the catalog author](docs/catalog-author.md)**, then [the v1 contract](docs/contract-v1.md) field by field |
|
|
93
126
|
| Run the machines the labs need | **[For the trainer](docs/trainer.md)** |
|
|
127
|
+
| Get throwaway VMs, with no exercise to write | [Infrastructure without labs](docs/infra-only.md) |
|
|
128
|
+
| Call dsoxlab from a script or a CI, and branch on the result | [Exit codes](docs/exit-codes.md), then [the machine output](docs/machine-output.md) for `--json` |
|
|
94
129
|
| Know where dsoxlab writes on my disk | [Where dsoxlab writes](docs/files.md) |
|
|
95
130
|
| See every command | [Command reference](docs/commands.md), generated from the CLI |
|
|
96
131
|
|
|
@@ -180,6 +215,13 @@ persistent, and four releases come from his reports:
|
|
|
180
215
|
ready-to-use appliance, discussed in
|
|
181
216
|
[#91](https://github.com/stephrobert/dsoxlab/issues/91).
|
|
182
217
|
|
|
218
|
+
**And the appliance itself is his idea.** He did not ask for it: he had already
|
|
219
|
+
**built one end to end**, then documented it in
|
|
220
|
+
[#91](https://github.com/stephrobert/dsoxlab/issues/91). The one dsoxlab ships
|
|
221
|
+
today is directly inspired by his — the idea and the approach both. It is the
|
|
222
|
+
contribution a changelog shows least and the product owes most: without it,
|
|
223
|
+
there would be nothing to offer anyone working on Windows or macOS.
|
|
224
|
+
|
|
183
225
|
**[@Gedd18](https://github.com/Gedd18)** found that the lab catalog's
|
|
184
226
|
`conftest.py` failed to load whenever no infrastructure provider was resolved,
|
|
185
227
|
which silently blocked **every `shell` lab** — the very first ones a learner
|