CIQ

Mastering Ansible Host Selection: Tips for AWX and Ascender

Mastering Ansible Host Selection: Tips for AWX and Ascender
Greg SowellOctober 5, 2023

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.

Video tutorial

https://www.youtube.com/watch?v=5rekBJrRlAI

Hosts vs. inventory

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).

INI Format

[web]
web1.gregsowell.com
web2.gregsowell.com

[db]
db1.gregsowell.com
db2.gregsowell.com

YAML Format

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.

Hosts

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!

Limit

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.

CLI Format


ansible all -m [module] -a "[module options]" --limit "host1"

Ascender format

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.

hosts: all

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!”

Limit

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

Conclusion

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!

Related posts

Ascender Config as Code with Network Backups to Git and Rollback

Ascender Config as Code with Network Backups to Git and Rollback

Aug 23, 2023

Ascender Automation

Ascender Custom Dynamic Inventory Scripts

Ascender Custom Dynamic Inventory Scripts

Nov 14, 2023

Ascender Automation

Ascender Migrates Host From CentOS 7 To Rocky 8

Ascender Migrates Host From CentOS 7 To Rocky 8

Oct 11, 2023

Ascender Automation

123
7
>>>