TT Lab
Get started
Learn Learning paths Courses

Ansible Fundamentals

Write Your First Playbook and Run It in Check Mode

Continue in TT Lab

Goal

You declare the desired state of a server with a playbook and learn to check the scope of impact in check mode before running it.

Why it matters

A shell script writes "what to do", but a playbook writes "what state it must be in when finished". Because of this difference, running the same playbook any number of times gives the same result. What creates that property is not the syntax but the module — the file module does nothing if the directory already exists, and if only the permissions differ, it fixes only the permissions. By contrast, command/shell does not know the current state, so it always reports that it changed something. That is why the principle "don't use the shell if a dedicated module exists" is a matter of correctness, not a style preference. Finally, --check --diff is the last safety device before you first touch a production server.

Steps

  1. Create /root/ans/play/site.yml. It has a single play with a name, and hosts is web. It must pass ansible-playbook -i /root/ans/inventory/hosts.ini --syntax-check.
  2. Add a task that uses the file module to create the directory /root/ans/artifacts/app with permission 0755, and run it.
  3. With the copy module, create /root/ans/artifacts/app/app.conf. Its content must include the two lines listen_port=8080 and env=lab, one line each. Do not hardcode the value of env; move it out into an app_env variable and set its default to lab (you will change this value in step 6).
  4. Make at least 3 tasks, and give every task a name.
  5. Put a config tag on the tasks that handle configuration, run with --tags config, and save the output to /root/ans/out/tags.txt.
  6. Run the playbook with --check --diff -e app_env=stage and save the output to /root/ans/out/check.txt. The diff in the output must show env=stage, but the actual /root/ans/artifacts/app/app.conf must still be env=lab. Never actually apply it in this step.
  7. Copy /opt/lab/fixtures/ansible/motd.seed to /root/ans/artifacts/motd, then use lineinfile to make it Welcome=labhub and Owner=platform-team. The Banner=unset line must be left as it is, and only one line starting with Welcome= may remain.
  8. Copy /opt/lab/fixtures/ansible/broken-play.yml to /root/ans/play/fixed.yml, fix the four errors, and run it. As a result, /root/ans/artifacts/fixed/report.txt must contain fixed by student, and the handler definition and notify must still be alive.

Notes

Create the playbook skeleton and pass the syntax check

Create /root/ans/play/site.yml. It has a single play with a name, and hosts is web. It must pass ansible-playbook -i /root/ans/inventory/hosts.ini --syntax-check.

The top level of a playbook is a list. Put name, hosts, and tasks in each play, and check with --syntax-check.

Create a directory with the file module

Add a task that uses the file module to create the directory /root/ans/artifacts/app with permission 0755, and run it.

Use the file module instead of a shell command. Check the state value and how mode is written (in quotes).

Place a config file with the copy module

With the copy module, create /root/ans/artifacts/app/app.conf. Its content must include the two lines listen_port=8080 and env=lab, one line each. Do not hardcode the value of env; move it out into an app_env variable and set its default to lab (you will change this value in step 6).

Instead of src, the copy module can also take the content directly with content. Write multiple lines as a YAML block scalar. Move the environment value out into a variable so that you can change it later.

Give every task a name

Make at least 3 tasks, and give every task a name.

There must be at least 3 tasks, and not even one task may lack a name.

Add tags and run only part of the playbook

Put a config tag on the tasks that handle configuration, run with --tags config, and save the output to /root/ans/out/tags.txt.

Put tags: [config] on the configuration-related tasks and run with --tags config. Be sure to leave at least one task without the tag — that is what makes the narrowing visible. One point that is easy to misunderstand: tasks filtered out by --tags are not shown as skipping. They disappear from the output entirely, and skipped= is also 0. This differs from tasks filtered out by when: — those stay in the set of tasks to run but get caught by the condition, so they leave a trace.

Preview in check mode

Run the playbook with --check --diff -e app_env=stage and save the output to /root/ans/out/check.txt. The diff in the output must show env=stage, but the actual /root/ans/artifacts/app/app.conf must still be env=lab. Never actually apply it in this step.

To --check --diff, add a different value with -e. The output shows what would change, but the actual file must stay as it is.

Change only a specific line of an existing file

Copy /opt/lab/fixtures/ansible/motd.seed to /root/ans/artifacts/motd, then use lineinfile to make it Welcome=labhub and Owner=platform-team. The Banner=unset line must be left as it is, and only one line starting with Welcome= may remain.

Copy the fixture to /root/ans/artifacts/motd, then fix it with lineinfile. You must find the existing line with regexp, or the number of lines will grow.

Fix the broken playbook

Copy /opt/lab/fixtures/ansible/broken-play.yml to /root/ans/play/fixed.yml, fix the four errors, and run it. As a result, /root/ans/artifacts/fixed/report.txt must contain fixed by student, and the handler definition and notify must still be alive.

Two module argument names, one state value, and one top-level key name are wrong. Look at which line the error message points to.