Expert · Ansible fundamentals · topic 48 of 57 · 35 min
Everyday modules and handlers
Explanation
The modules you will use every week
| Module | Use it to | Key options |
|---|---|---|
| ansible.builtin.dnf | Install, update or remove packages | name, state: present / latest / absent |
| ansible.builtin.service (or systemd_service) | Start, stop, enable services | name, state: started / stopped / restarted, enabled |
| ansible.builtin.copy | Copy a file or write fixed content | src or content, dest, owner, group, mode |
| ansible.builtin.template | Write a file from a Jinja2 template | src (a .j2 file), dest, mode |
| ansible.builtin.file | Directories, links, permissions, delete | path, state: directory / link / absent / touch, mode |
| ansible.builtin.user / group | Accounts | name, uid, groups, append, password, state |
| ansible.builtin.lineinfile | Make sure one line is in a file | path, regexp, line, state |
| ansible.posix.firewalld | Firewall services and ports | service or port, permanent, immediate, state |
| ansible.builtin.debug | Print a message or variable | msg, var |
FQCN (fully qualified collection name) means collection.name.module, such as ansible.builtin.copy. Short names like copy usually still work, but FQCNs avoid confusion when two collections have a module with the same short name, and linting tools expect them.
- name: Create the app directory
ansible.builtin.file:
path: /opt/notes
state: directory
owner: notes
mode: "0750"
- name: Allow only key logins
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config.d/01-hardening.conf
regexp: '^PasswordAuthentication'
line: PasswordAuthentication no
create: true
mode: "0600"
- name: Create user ravi in wheel
ansible.builtin.user:
name: ravi
groups: wheel
append: true
state: presentHandlers: restart only when needed
After changing a config file you usually restart the service. But you do not want to restart it on every run, only when the file actually changed. A handler is a task in a separate handlers section. A normal task can notify it; the handler runs once, at the end of the play, and only if at least one notifying task reported changed.
- name: Configure Apache
hosts: webservers
become: true
tasks:
- name: Set the server admin email
ansible.builtin.lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^ServerAdmin'
line: ServerAdmin webmaster@example.com
notify: Restart Apache
- name: Apache is running
ansible.builtin.service:
name: httpd
state: started
enabled: true
handlers:
- name: Restart Apache
ansible.builtin.service:
name: httpd
state: restarted- If several tasks notify the same handler, it still runs only once.
- Handlers run at the end of the play, in the order they are written in handlers, not the order notified.
- If a later task fails on a host, pending handlers do not run there (unless you use --force-handlers or force_handlers: true).
- ansible.builtin.meta: flush_handlers runs pending handlers right away, in the middle of the play.
Collections you will need
ansible-core ships only ansible.builtin. Modules such as ansible.posix.firewalld, ansible.posix.selinux or community.general.timezone come from collections. Install them with ansible-galaxy collection install ansible.posix (from Ansible Galaxy or your company's automation hub), or use an execution environment that already contains them. The next module covers collections in depth.
Common mistakes
- mode: 644 without quotes or a leading 0. YAML reads 644 as the decimal number 644, which is not the permissions you meant. Write mode: "0644".
- Restarting a service as a normal task every time. Use a handler.
- A notify name with a typo: the play fails with "The requested handler ... was not found".
- lineinfile without regexp, so a changed value adds a second line instead of replacing the old one.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Everyday modules and handlers · 1/6
A few modules do most of the work: dnf, service, copy, template, file, user, lineinfile and firewalld.
Prefer a video by a teacher? Find free videos on “ansible handlers notify modules copy template lineinfile tutorial” on YouTube ↗
In real life: Rolling out a config change to a university's web farm
A university in Delhi runs its admission portal on six web servers. When the admissions office changed its contact email, the team updated one line in a playbook. On the run, only the lineinfile task reported changed, so the handler restarted Apache exactly once per server, at the end. Servers that already had the new line were not restarted at all.
RUNNING HANDLER [Restart Apache] ***********************************************
changed: [web01.du.example.edu]
changed: [web02.du.example.edu]
...
PLAY RECAP *********************************************************************
web01.du.example.edu : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0Practice (0/4 done)
When does a handler run?
Which line has the bug? 1: - name: Config file 2: ansible.builtin.copy: 3: src: app.conf 4: dest: /etc/app.conf 5: mode: 644
Model handlers. Each task result is a dict with name, changed (bool) and notify (a list of handler names, maybe empty). Write handlers_to_run(results, handler_order) that returns the handlers that will run: those notified by at least one CHANGED task, each once, in the order of handler_order (the order they are written in the handlers section).
Write motd.yml for all hosts: create the group "ops" and user "ops1" in it, write /etc/motd with copy (content includes the host name), make sure /opt/ops exists (owner ops1, mode 0750), set "ClientAliveInterval 300" in an sshd drop-in with lineinfile, and reload sshd through a handler only when that line changes.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Inventory and ansible.cfgAnsible fundamentals · same module
- Ansible playbooksDevOps: Git, Docker, Kubernetes and CI/CD · Configuration management with Ansible, and YAML
- Roles, collections and ansible-galaxyAnsible in depth
- Jinja2 templatesAnsible in depth
- Roles, templates, Galaxy and VaultDevOps: Git, Docker, Kubernetes and CI/CD · Configuration management with Ansible, and YAML
- Ansible: inventory and ad-hoc commandsDevOps: Git, Docker, Kubernetes and CI/CD · Configuration management with Ansible, and YAML
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
Which module makes sure a directory exists?
Answer: ansible.builtin.file with state: directory
file manages paths, including directories.
Three tasks notify the same handler and all change. How many times does it run?
Answer: 1
Once, at the end of the play.
Which collection provides the firewalld module?
Answer: ansible.posix
ansible.posix.firewalld.
In lineinfile, what does regexp do?
Answer: Finds the existing line to replace, so you do not get duplicates
Matching lines are replaced by line.
Which module writes a file from a Jinja2 .j2 file with variables filled in?
Answer: template
template renders Jinja2.
Two tasks notify "Reload nginx" and both report changed. How many times does the handler run on that host?Related
Answer: Once, at the end of the play
Handlers are deduplicated and run once, after the tasks of the play.
From Ansible playbooks
In a role, where does the template module look for src files by default?Related
Answer: templates/
templates/ for template, files/ for copy.
What is ansible_managed used for?Related
Answer: A header saying the file is managed by Ansible
It warns people not to edit by hand.
From Jinja2 templates
What is a collection in Ansible?Related
Answer: A package of modules, roles and plugins under a namespace, like community.general
Collections are how modules are packaged and shared, for example through Galaxy.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- This is the last topic of “Ansible fundamentals”. The module exam comes next.
- Module 9 exam: Ansible fundamentals · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Ansible in depth. 57 topics left in the course before the final exam.