Skip to content
Français
Français
medium

93 free RHCE practice labs

2 min read

93 hands-on labs to practise for the Red Hat Certified Engineer (EX294), roughly 68 hours of work, each one graded on the state of your machine rather than on the commands you typed. They run on your own hardware with the `dsoxlab` command line, and cost nothing.

Automation with Ansible, on Red Hat Enterprise Linux machines. The RHCSA is its prerequisite, and the exam stays entirely hands-on.

  • 93labs
  • 68hours of practice
  • 86on real VMs

Levels 30 beginner 43 intermediate 20 advanced

Official exam objectives published by Red Hat

These are not exam questions. They are hands-on exercises on the skills the exam measures, graded on the state of your machine.

Ansible and the RHCE EX294

93 labs attestation still to produce

Add this catalogue dsoxlab catalog add https://github.com/stephrobert/ansible-training

Preparing the environment

  • Prepare Ansible managed nodes

    Converge the 5 managed node prerequisites (Python 3, SSH, NOPASSWD sudo, chrony, SELinux) with an idempotent bootstrap playbook.

    dsoxlab start bootstrap-prepare-managed-nodes

    25m beginner virtual machines Companion guide (French)

Discovering Ansible

  • Declarative vs imperative: why Ansible does not drift

    Compare a Bash script that drifts on every run with a playbook that converges, and prove idempotence with changed=0 on the second pass.

    dsoxlab start decouvrir-declaratif-vs-imperatif

    25m beginner virtual machines Companion guide (French)

  • Ansible installation: verify your control node

    Identify your install method, check the 8 binaries on PATH, the modules reachable via ansible-doc and the collections the repo relies on.

    dsoxlab start decouvrir-installation-ansible

    20m beginner shell Companion guide (French)

  • ansible.cfg: precedence and critical options

    Write a project ansible.cfg, check the active config with ansible-config dump, override an option by environment variable and enable a callback.

    dsoxlab start decouvrir-configuration-ansible

    30m beginner virtual machines Companion guide (French)

  • Ansible CLI: the 8 everyday commands

    Chain ad-hoc runs, ansible-doc, ansible-config, ansible-inventory, ansible-galaxy, ansible-vault and ansible-lint across the lab.

    dsoxlab start decouvrir-prise-en-main-cli

    20m beginner shell Companion guide (French)

First steps

  • First playbook: install nginx on the webservers

    Write a 5-task playbook (dnf, systemd, firewalld), read the PLAY RECAP, capture output with register and check idempotence on the second pass.

    dsoxlab start premiers-pas-premier-playbook

    30m beginner virtual machines Companion guide (French)

  • First steps with ansible-vault

    Encrypt a secrets file with ansible-vault, consume it through vars_files and protect output with no_log and a 0600 .vault_password.

    dsoxlab start premiers-pas-ansible-vault

    45m beginner virtual machines Companion guide (French)

Writing Ansible code

  • Plays and tasks: anatomy and execution order

    Structure a play with pre_tasks, tasks, post_tasks and handlers, then prove the real execution order with timestamped marker files.

    dsoxlab start ecrire-code-plays-et-tasks

    40m intermediate virtual machines Companion guide (French)

  • handlers: the restart-on-config-change pattern

    Notify several handlers, decouple them with listen, force meta: flush_handlers and pair validate so an invalid config is never applied.

    dsoxlab start ecrire-code-handlers

    35m intermediate virtual machines Companion guide (French)

  • tags: target or skip a subset of tasks

    Set tags, target with --tags and exclude with --skip-tags, inspect the plan via --list-tasks and use the special always and never tags.

    dsoxlab start ecrire-code-tags

    40m intermediate virtual machines Companion guide (French)

  • check mode and diff: dry-run and change preview

    Run a playbook with --check --diff, spot the modules that do not support check, force check_mode: false and diagnose a false changed positive.

    dsoxlab start ecrire-code-checkmode-diff

    45m intermediate virtual machines Companion guide (French)

  • Variables: declaration and scope

    Declare variables with vars and vars_files, override them with --extra-vars and diagnose an unexpected value caused by YAML typing.

    dsoxlab start ecrire-code-variables-base

    40m beginner virtual machines Companion guide (French)

  • Collection types: lists, dicts, nested structures

    Declare lists and lists of dicts in YAML, loop over them with loop_control: label, filter with when and reach nested fields.

    dsoxlab start ecrire-code-types-collections

    40m intermediate virtual machines Companion guide (French)

  • facts and magic vars: ansible_facts, hostvars

    Read system facts, use inventory_hostname, groups and hostvars, then cut the collection cost with gather_subset.

    dsoxlab start ecrire-code-facts-magic-vars

    40m intermediate virtual machines Companion guide (French)

  • Custom facts: facts.d and ansible_local

    Drop an INI custom fact then an executable script returning JSON into /etc/ansible/facts.d, and read them back through ansible_local.

    dsoxlab start ecrire-code-custom-facts

    40m intermediate virtual machines Companion guide (French)

  • Variable precedence: the 22 levels

    Stack the same variable at several levels to demonstrate which one wins, from role defaults up to --extra-vars.

    dsoxlab start ecrire-code-precedence-variables

    55m advanced virtual machines Companion guide (French)

  • register and set_fact: capture and create variables

    Capture module output with register, reuse it in when and loop, create a runtime fact and persist it with cacheable: true.

    dsoxlab start ecrire-code-register-set-fact

    40m intermediate virtual machines Companion guide (French)

  • Parallelism: forks, serial, throttle, strategy

    Tell forks from serial, run a rolling update with serial: 1, compare the linear and free strategies and rate-limit a single task with throttle.

    dsoxlab start ecrire-code-parallelisme-strategies

    50m advanced virtual machines Companion guide (French)

  • async and poll: long tasks without blocking SSH

    Detach a long task with async + poll: 0, collect its result via async_status, poll actively with until and diagnose an orphaned job.

    dsoxlab start ecrire-code-async-poll

    45m advanced virtual machines Companion guide (French)

  • Delegation: delegate_to, run_once, local_action

    Redirect a task to another host, run it only once in a multi-host play and target the control node with local_action.

    dsoxlab start ecrire-code-delegation

    45m advanced virtual machines Companion guide (French)

  • lookups: fetch external data at runtime

    Read a file, an environment variable or a command output on the control node, generate a password and tell lookup from query.

    dsoxlab start ecrire-code-lookups

    40m intermediate virtual machines Companion guide (French)

  • Jinja2: interpolation, logic and whitespace

    Interpolate variables, loop and branch inside a template, then kill stray blank lines with whitespace control.

    dsoxlab start ecrire-code-jinja2-base

    45m intermediate virtual machines Companion guide (French)

  • Essential Jinja2 filters: default, combine, selectattr

    Handle missing variables with default, work on lists, filter a list of dicts with selectattr and map, merge dicts with combine.

    dsoxlab start ecrire-code-filtres-jinja-essentiels

    45m intermediate virtual machines Companion guide (French)

  • when conditions: operators and Jinja tests

    Gate a task on a fact, combine several conditions, test whether a variable is defined and diagnose a when that matches wrongly.

    dsoxlab start ecrire-code-conditions-when

    40m intermediate virtual machines Companion guide (French)

  • loop: iterate over lists and dicts

    Loop over a list and a list of dicts, keep console output readable with loop_control: label, iterate a dict with dict2items.

    dsoxlab start ecrire-code-boucles-loop

    40m intermediate virtual machines Companion guide (French)

  • Legacy with_* loops: migrating to loop

    Recognise with_items, with_dict and with_subelements, migrate them to loop plus Jinja2 filters and automate it with ansible-lint --fix.

    dsoxlab start ecrire-code-boucles-with-deprecated

    45m intermediate virtual machines Companion guide (French)

  • block, rescue, always: try/catch/finally

    Group tasks in a block, catch the error with rescue to roll back, guarantee cleanup with always and read ansible_failed_task.

    dsoxlab start ecrire-code-block-rescue-always

    40m intermediate virtual machines Companion guide (French)

  • failed_when and changed_when: redefine success and change

    Neutralise changed on read-only commands, define changed_when from output and accept some return codes as success.

    dsoxlab start ecrire-code-failed-when-changed-when

    40m intermediate virtual machines Companion guide (French)

  • ignore_errors: legitimate use vs anti-pattern

    Measure the effect of ignore_errors on the PLAY RECAP, spot its few legitimate cases and prefer failed_when or block/rescue.

    dsoxlab start ecrire-code-ignore-errors

    40m intermediate virtual machines Companion guide (French)

  • any_errors_fatal: stop the play on the first error

    Enable any_errors_fatal on a multi-host play, compare it with the default and with max_fail_percentage, and combine it with serial.

    dsoxlab start ecrire-code-any-errors-fatal

    50m advanced virtual machines Companion guide (French)

  • Advanced Jinja2 filters: regex, b64, password_hash

    Extract with regex_search, encode to base64, hash a password with sha512, query JSON with json_query and handle IPs and CIDRs.

    dsoxlab start ecrire-code-filtres-jinja-avances

    50m advanced virtual machines Companion guide (French)

  • Jinja2 tests: is defined, is mapping, is sequence

    Test a variable's definition and type, match a regex with is match and is search, and combine those tests in when and in {% if %}.

    dsoxlab start ecrire-code-tests-jinja

    40m intermediate virtual machines Companion guide (French)

  • template module: validate, backup, whitespace

    Render a config from a Jinja2 template, reject invalid syntax with validate, back up the previous file and set mode, owner and group.

    dsoxlab start ecrire-code-module-template

    45m intermediate virtual machines Companion guide (French)

  • lineinfile vs template: which module when

    Arbitrate between lineinfile, blockinfile and template, combine base plus overrides and diagnose a lineinfile that stacks for lack of a regexp.

    dsoxlab start ecrire-code-lineinfile-vs-template

    40m intermediate virtual machines Companion guide (French)

  • import vs include: static or dynamic

    Choose between import_* parsed at start and include_* resolved at runtime, and observe how tags and when behave differently in each case.

    dsoxlab start ecrire-code-import-include

    45m advanced virtual machines Companion guide (French)

File modules

  • copy module: transfer files and inline content

    Transfer a file with src: or write inline content with content:, mastering mode, owner, backup and validate.

    dsoxlab start modules-fichiers-copy

    35m beginner virtual machines Companion guide (French)

  • file module: states, permissions and symlinks

    Manage the state of a file or directory (directory, absent, link, hard, touch), recursive permissions and symbolic links.

    dsoxlab start modules-fichiers-file

    30m beginner virtual machines Companion guide (French)

  • blockinfile module: idempotent multi-line block

    Insert and maintain a multi-line block in an existing file with custom markers, insertafter/insertbefore and idempotence.

    dsoxlab start modules-fichiers-blockinfile

    30m beginner virtual machines Companion guide (French)

  • lineinfile module: edit a line in an existing file

    Add, replace by regexp or remove a line in a config file, using backrefs and syntax validation before the write.

    dsoxlab start modules-fichiers-lineinfile

    25m beginner virtual machines Companion guide (French)

  • replace module: substitute a pattern in a file

    Substitute a regex pattern throughout a file, scope it with before/after, and preserve parts of it with capture groups.

    dsoxlab start modules-fichiers-replace

    35m intermediate virtual machines Companion guide (French)

  • fetch module: retrieve files from managed nodes

    Collect logs and configs from managed nodes to the control node, per-host tree or flat mode with inventory_hostname.

    dsoxlab start modules-fichiers-fetch

    35m beginner virtual machines Companion guide (French)

  • archive and unarchive modules: compress and extract

    Create a tar.gz archive on the managed node and extract local, remote or already-present tarballs idempotently with creates.

    dsoxlab start modules-fichiers-archive-unarchive

    30m beginner virtual machines Companion guide (French)

Package modules

  • package module: distro-agnostic installation

    Install and remove packages without depending on the distro package manager, weighing state: present against state: latest.

    dsoxlab start modules-paquets-package

    30m beginner virtual machines Companion guide (French)

  • dnf module: enablerepo, security, exclude, autoremove

    Enable a repo on the fly, patch CVEs only, exclude the kernel from a bulk upgrade and clean up orphaned dependencies.

    dsoxlab start modules-paquets-dnf-options

    45m advanced virtual machines Companion guide (French)

  • yum_repository module: declare an RPM repository

    Declare a yum/dnf repository with gpgcheck, import its GPG key via rpm_key, and disable a repo without removing it.

    dsoxlab start modules-paquets-yum-repository

    35m intermediate virtual machines Companion guide (French)

Service modules

  • systemd_service module: manage systemd services

    Start, enable, reload and mask services, drop a custom unit file with daemon_reload, and notify a service from a handler.

    dsoxlab start modules-services-systemd

    35m beginner virtual machines Companion guide (French)

  • cron module: schedule idempotent jobs

    Schedule idempotent cron jobs via a user crontab or /etc/cron.d, with environment variables and clean disabling.

    dsoxlab start modules-services-cron

    30m beginner virtual machines Companion guide (French)

User modules

  • user module: create, modify and remove accounts

    Create accounts with home, shell and secondary groups, hash a password, force a specific UID, and remove an account with its home.

    dsoxlab start modules-utilisateurs-user

    35m beginner virtual machines Companion guide (French)

  • group module: manage Linux groups

    Create groups with a forced GID, tell system groups from user groups, and order group creation before the users that reference it.

    dsoxlab start modules-utilisateurs-group

    30m beginner virtual machines Companion guide (French)

  • authorized_key module: user SSH keys

    Provision public SSH keys, force an exclusive list, restrict a key with key_options, and handle several users with subelements.

    dsoxlab start modules-utilisateurs-authorized-key

    35m beginner virtual machines Companion guide (French)

  • sudoers module: manage sudo rights safely

    Create rules under /etc/sudoers.d/ with automatic visudo validation, limit allowed commands, and handle nopassword on a group.

    dsoxlab start modules-utilisateurs-sudoers

    50m advanced virtual machines Companion guide (French)

RHEL modules

  • firewalld module: manage the RHEL firewall

    Allow predefined services and custom ports per zone, with the permanent + immediate trap and the firewall reload.

    dsoxlab start modules-rhel-firewalld

    30m beginner virtual machines Companion guide (French)

  • sysctl module: persisted kernel parameters

    Change kernel parameters (ip_forward, tcp_syncookies, swappiness) with immediate effect and persistence through /etc/sysctl.d/.

    dsoxlab start modules-rhel-sysctl

    40m intermediate virtual machines Companion guide (French)

  • selinux module: modes, booleans and contexts

    Switch SELinux to enforcing, flip a boolean persistently, and set a custom context with sefcontext followed by restorecon.

    dsoxlab start modules-rhel-selinux

    55m advanced virtual machines Companion guide (French)

  • mount module: manage fstab and mount points

    Handle the 5 mount states, mount a loop device, set noatime/nodev/nosuid options, and make a mount survive a reboot.

    dsoxlab start modules-rhel-mount

    45m intermediate virtual machines Companion guide (French)

  • parted module: create a disk partition

    Create aligned MBR or GPT partitions idempotently, set flags (lvm, boot, esp), and inspect the existing partition table.

    dsoxlab start modules-rhel-parted

    35m intermediate virtual machines Companion guide (French)

  • filesystem module: create a filesystem

    Format partitions as ext4 and xfs, pick the right fstype for the use case, and force a rebuild with force: true.

    dsoxlab start modules-rhel-filesystem

    35m intermediate virtual machines Companion guide (French)

  • LVM: chaining lvg, lvol, filesystem and mount

    Build a PV, VG and LV on a spare disk, format it, mount it through fstab, and grow it online with resizefs.

    dsoxlab start modules-rhel-lvm-storage

    50m advanced virtual machines Companion guide (French)

Network modules

  • get_url module: download a file over HTTP/HTTPS

    Download a file onto the managed node idempotently, check its integrity with a sha256 checksum, and authenticate the request.

    dsoxlab start modules-reseau-get-url

    35m beginner virtual machines Companion guide (French)

  • uri module: REST API calls

    Call a REST API with GET/POST and a JSON body, accept several status_code values, and loop a healthcheck with until/retries.

    dsoxlab start modules-reseau-uri

    50m advanced virtual machines Companion guide (French)

Diagnostic modules

  • stat module: inspect files and directories

    Check existence, type, size, mode and checksum of a file without modifying it, to drive conditional logic.

    dsoxlab start modules-diagnostic-stat

    30m beginner virtual machines Companion guide (French)

  • find module: multi-file search

    Search files by glob, regex, age, size and type, then chain loop and file for a targeted, idempotent cleanup.

    dsoxlab start modules-diagnostic-find

    30m beginner virtual machines Companion guide (French)

  • assert and fail modules: defensive validation

    Validate prerequisites at the start of a play, customize fail_msg and success_msg, and fail explicitly on an error branch.

    dsoxlab start modules-diagnostic-assert-fail

    40m intermediate virtual machines Companion guide (French)

  • wait_for and pause modules: synchronization

    Wait for a TCP port to open or close, for a file or a regex to appear, and add a timed or interactive pause.

    dsoxlab start modules-diagnostic-wait-for-pause

    35m intermediate virtual machines Companion guide (French)

Inventories

  • Write a static inventory from scratch: groups, children and group vars

    Author an Ansible static inventory by hand: declare host groups, a parent group with children, and group variables, then prove the resolved inventory with ansible-inventory and ansible -m ping.

    dsoxlab start inventaires-statiques

    40m beginner virtual machines Companion guide (French)

  • group_vars and host_vars: structured inventory variables

    Spread inventory variables across all, group and host levels, then check the resolved value with ansible-inventory --host.

    dsoxlab start inventaires-group-vars-host-vars

    30m beginner virtual machines Companion guide (French)

  • Host patterns: wildcards and the :, & and ! operators

    Target exactly the hosts you want with --limit and the union, intersection and exclusion operators, without touching the playbook.

    dsoxlab start inventaires-patterns-hotes

    35m intermediate virtual machines Companion guide (French)

  • Dynamic KVM inventory with community.libvirt

    Discover libvirt VMs automatically through the inventory plugin, build Jinja groups and keyed_groups, with no manual inventory.

    dsoxlab start inventaires-dynamique-kvm

    35m intermediate virtual machines Companion guide (French)

Roles

  • Create your first role with ansible-galaxy role init

    Scaffold a webserver role, fill in tasks, defaults, handlers and meta, then call it from a playbook with roles:.

    dsoxlab start roles-creer-premier-role

    45m beginner virtual machines Companion guide (French)

  • Role variables: defaults/ vs vars/ and precedence

    Split variables between defaults/ (overridable) and vars/ (internal), wire them into tasks and a Jinja2 template, then verify precedence.

    dsoxlab start roles-variables-defaults-vars

    35m intermediate virtual machines Companion guide (French)

  • Role handlers and meta: notify and galaxy_info

    Write several handlers (service and non-service), trigger them with notify, choose between restarted and reloaded, then complete meta/main.yml for Galaxy.

    dsoxlab start roles-handlers-meta

    40m intermediate virtual machines Companion guide (French)

  • argument_specs: validate a role's input variables

    Write meta/argument_specs.yml to type, constrain and document input variables, then watch an invalid input get rejected automatically.

    dsoxlab start roles-argument-specs

    50m intermediate virtual machines Companion guide (French)

  • Consume a role: roles:, import_role, include_role

    Call the same role three different ways and choose between static and dynamic, especially once a when: is involved.

    dsoxlab start roles-consommer-role

    50m intermediate virtual machines Companion guide (French)

  • Role dependencies via meta/main.yml

    Chain roles with dependencies:, pass them variables, control execution order and dodge the diamond trap with allow_duplicates.

    dsoxlab start roles-dependencies

    45m intermediate virtual machines Companion guide (French)

  • RHEL system roles: converge time synchronisation with timesync

    Consume a vendor role from linux-system-roles: drive chronyd on db1.lab through timesync variables, never writing chrony.conf by hand.

    dsoxlab start roles-system-roles

    1h advanced virtual machines Companion guide (French)

Galaxy and publishing

  • ansible-galaxy CLI: init, install, list, build, publish

    Init a role and a collection, install from Galaxy or Git, list what is present, build a tarball and publish it with an API token.

    dsoxlab start galaxy-ansible-galaxy-cli

    20m beginner shell Companion guide (French)

  • Install roles and collections from Galaxy or Git

    Write a requirements.yml mixing Galaxy roles, Git sources and collections, pin every version and vendor a role into the project for reproducible installs.

    dsoxlab start galaxy-installer-roles

    30m intermediate shell Companion guide (French)

Ansible Vault

  • Ansible Vault: encrypt your first secrets file

    Encrypt a YAML file with ansible-vault, view it, edit it, consume it from a playbook, then rekey and decrypt it.

    dsoxlab start vault-introduction

    35m beginner virtual machines Companion guide (French)

  • encrypt_string vs whole-file encryption

    Encrypt a single value with encrypt_string, mix it with plaintext variables via the !vault tag, and choose between inline and whole-file.

    dsoxlab start vault-chiffrer-fichier-variable

    45m intermediate virtual machines Companion guide (French)

  • Multiple vault-ids: isolate dev, staging and prod

    Encrypt each environment with a labelled vault-id, decrypt several vault-ids in a single run and lay out group_vars per environment.

    dsoxlab start vault-id-multiples

    45m intermediate virtual machines Companion guide (French)

  • Mixed playbooks: main.yml plus vault.yml per group

    Split public variables from secrets inside each group_vars, adopt the vault_* convention, and confirm Ansible merges both files transparently.

    dsoxlab start vault-playbooks-mixtes

    50m intermediate virtual machines Companion guide (French)

  • Vault inside a role: plaintext defaults, encrypted vars

    Expose public variables in defaults/main.yml pointing to vault_* values in an encrypted vars/main.yml, and override them from the playbook.

    dsoxlab start vault-dans-roles

    50m intermediate virtual machines Companion guide (French)

  • Fetch secrets from HashiCorp Vault or OpenBao

    Start a local Vault, store a secret in it, read it from Ansible with community.hashi_vault, and compare token, AppRole and JWT authentication.

    dsoxlab start vault-integration-hashicorp

    50m advanced shell Companion guide (French)

  • Fetch secrets from Passbolt

    Start a local Passbolt CE, authenticate with an OpenPGP key, read a secret from Ansible and compare the Passbolt model with HashiCorp Vault.

    dsoxlab start vault-integration-passbolt

    40m intermediate shell Companion guide (French)

Troubleshooting

  • Verbosity levels and callback plugins

    Pick the -v level that matches the symptom, enable profile_tasks and YAML output (callback_result_format), and see what a missing no_log leaks.

    dsoxlab start troubleshooting-verbosite

    40m intermediate virtual machines Companion guide (French)

  • Interactive debugger: debugger: on_failed

    Enable the debugger on failure, inspect task, task_vars and result in the REPL, patch arguments on the fly then replay the task with redo.

    dsoxlab start troubleshooting-debugger

    50m advanced virtual machines Companion guide (French)

  • Fix broken idempotence and tune performance

    Make a shell task idempotent with creates or changed_when, measure a baseline with profile_tasks, then enable pipelining, forks and ControlPersist.

    dsoxlab start troubleshooting-idempotence-perfs

    50m advanced virtual machines Companion guide (French)

Collections

  • Explore Ansible collections: FQCN and structure

    List and inspect installed collections, read a galaxy.yml, walk the plugins/roles/playbooks layout and track down a module by its FQCN.

    dsoxlab start collections-decouvrir

    50m advanced virtual machines Companion guide (French)

  • Automation content navigator: discover a module in a collection and use it

    Use ansible-navigator to find a module inside an installed collection, apply it to produce a verifiable kernel state on db1.lab, and validate an inventory with ansible-navigator inventory.

    dsoxlab start collections-navigator

    45m advanced virtual machines Companion guide (French)

  • requirements.yml: multi-source install with GPG signatures

    Declare four sources in a requirements.yml, pin every version, check integrity with collection verify and target several Galaxy servers.

    dsoxlab start collections-requirements

    45m intermediate virtual machines Companion guide (French)

Advanced practices

  • Version your playbooks with Git

    Initialize a Git repository for your playbooks, track and commit them, then push to a local bare remote: the exact EX294 gesture, with no forge to set up.

    dsoxlab start pratiques-versionner-git

    25m beginner shell Companion guide (French)

RHCE EX294 exam

  • RHCE EX294 mock exam: 19 tasks in 4 hours

    Work through 19 timed tasks covering inventories, variables, vault, files, packages, services, roles, error handling, rolling waves, delegation, tags, scheduled jobs, custom facts and content collections, each validated by pytest.

    dsoxlab start rhce-mock-ex294

    4h advanced virtual machines Companion guide (French)

  • Mock RHCE EX294 #2

    A second full timed EX294 mock: the same 19 categories as mock #1, but every concrete value differs (Apache/valkey stack, different users, LVM layout, ports, SELinux boolean, cron schedule, collection), so nothing can be copied from memory. Each task is proven by pytest.

    dsoxlab start rhce-mock-ex294-2

    4h advanced virtual machines Companion guide (French)

Back to all 352 labs How to run a lab