One of the basics of using Ansible is choosing which hosts to operate against. I’m going to walk through the basics of choosing hosts in Ansible, then I’ll cover some advanced tips on using it with AWX or, better yet, Ascender.
Hosts vs. inventory
I’ll start by discussing inventories, which are really just big lists of all the hosts I could possibly operate against. Inventories also, generally, store additional variables for individual hosts or for groups of hosts.
When using Ansible on the command line, you will maintain these inventories in simple flat files either in INI or YAML format (it seems INI is the most common type seen).
[web] web1.gregsowell.com web2.gregsowell.com [db] db1.gregsowell.com db2.gregsowell.com
web: hosts: web1.gregsowell.com web2.gregsowell.com db: hosts: db1.gregsowell.com db2.gregsowell.com
Inventories in Ascender are stored directly in the database like so:
Ascender inventories can also be sourced from dynamic inventory scripts, which means Ascender will reach out to some external source like a network monitoring system or ServiceNow’s Configuration Management Database (CMDB), and pull in hosts dynamically so that the inventory will always be up-to-date.
Playbooks have a section called “hosts.” This required option is where you will specify which specific hosts inside of the inventory you want to operate against.
Take, for example, this playbook for updating packages in Rocky [https://github.com/gregsowell/ascender-rocky-lts/blob/main/rocky-update-mixed-lts.yml]. I’ll grab a little snippet from the beginning:
--- - name: Perform package update with LTS support hosts: lts_demo
The hosts section is comprised of a comma separated list of hosts, a comma separated list of groups, or a comma separated combination of both hosts and groups.
A good practice is to simply reference a group or groups when writing playbooks. If you target specific hosts, which is fine from time to time, when you want to change which host to operate against, you have to update your playbook before rerunning your automation. My goal is always to change as few things as possible, and to touch my playbooks only when necessary. If I reference a group, then as hosts get added and removed from the group, I never have to modify my playbook!
Now, let’s talk about the limit option. This is available both on CLI Ansible as well as via Ascender. Limit allows you to further select which hosts to operate against.
So inventory is a big list of all my hosts.
The hosts section narrows down which hosts to operate against.
The limit option then narrows down the hosts that were returned in the “hosts” section.
ansible all -m [module] -a "[module options]" --limit "host1"
The efficiency trinity
By combining three things, you can make running your playbooks pretty efficient: hosts: all, limiting, and a limit check in your playbooks.
In your playbook you can specify the hosts section to use the “all” group. All is an implicit group that is comprised of every host in an inventory. This means if I set the hosts section in my playbook to “all,” I’ll never have to adjust it again!
--- - name: Perform package update with LTS support hosts: all
This can be dangerous, though. Imagine I want to use automation to wipe and rebuild a server…if I run it against all hosts in my inventory, I’m going to have a VERY bad time. There are two important things to fix this. One is using the limit option and the other is something at the beginning of my playbook to be a fail-safe.
Protection in playbook
I’ll take my playbook from before and add to it:
--- - name: Perform package update with LTS support hosts: all gather_facts: false tasks: - name: quick check if all hosts was specified with no limit ansible.builtin.assert: that: ansible_play_hosts_all|length < groups.all|length fail_msg: '[ERROR] All hosts not allowed.' run_once: true
The highlighted task does something very special. It uses the assert module to check that a condition is true or not. In this specific case, what it does is count all of the hosts selected for this run, and compares that number to the number of hosts in the all group. If you are running against “all,” it will error out, but if you are limiting the number of hosts down to less than that, it will allow the playbook to continue on just fine. This means that I am protected against someone accidentally running this against “all!”
So how do I prevent my protection task from getting hit… by using the limit option, of course.
In Ascender, I could modify and save my job template to use the specific limit options I want, or I could use the prompt on launch option which will popup on run and allow me to easily enter my option!
Configure Ascender job template
Launch Ascender job template with prompt on launch
So I hope you find this to be a quick, convenient, and safe way to select hosts in your automations. If you have any questions, comments, or ideas on modification, please feel free to reach out to me… it’s so quiet over here and I need your feedback, LOL. Thanks, and happy automating!