Ansible for Packages and Repositories
On the RHCE exam you never type dnf install on a managed node: you write a play that targets the right group and lets a module do it. That gives you idempotence for free: a second run reports ok, not changed.
Installing packages. ansible.builtin.dnf (or the generic ansible.builtin.package) takes a list in name, which is one transaction and much faster than a loop:
yaml - name: Developer tools hosts: dev tasks: - ansible.builtin.dnf: name: [tmux, zsh, "@RPM Development Tools"] state: present latest = update, absent = remove
state: latest with name: "" updates everything. Group names start with @ and need quotes in YAML.
Repositories. ansible.builtin.yumrepository writes a file in /etc/yum.repos.d named after name (or file):
yaml - ansible.builtin.yumrepository: name: webasha-tools description: WebAsha internal tools baseurl: http://utility/repo/tools gpgcheck: true gpgkey: http://utility/repo/RPM-GPG-KEY-webasha enabled: true
description is required. For the GPG key itself there is ansible.builtin.rpmkey: key: <url or path state: present, which imports it into the RPM database so the first install does not stop on an unknown key.
Package facts. ansible.builtin.packagefacts fills ansiblefacts.packages, a dictionary of lists (one entry per installed version). Use it in conditions such as when: "'httpd' in ansiblefacts.packages" or in content: {{ ansiblefacts.packages['httpd'][0].version }}.
Collections first. Many later tasks need ansible.posix or community.general. Exams usually give a URL; put it in collections/requirements.yml and install into the project:
yaml collections: - name: http://utility/collections/ansible-posix-1.6.2.tar.gz type: url
ansible-galaxy collection install -r collections/requirements.yml -p collections
Checking your work. Run the playbook twice: the second run should show only ok. Then confirm from control without logging in, for example ansible dev -m command -a 'rpm -q tmux zsh' and ansible test,prod -m command -a 'rpm -q tmux', which must fail on the hosts that should not have it. A quick ansible-navigator run packages.yml -m stdout --check also shows what would change before you touch anything. Graders look at the end state on every host in the inventory, so a play that targets the wrong group is wrong even if the right group is also correct.
Pitfalls. Targeting all when the task said one group (the grader checks the other hosts too). Forgetting become (set it in ansible.cfg). Using command: dnf install, which is never idempotent and usually costs marks. Leaving a broken repo enabled: every later dnf task on that host then fails.