In all the examples we have shared so far, we haven’t been using an inventory file; instead we are simply setting ‘hosts: localhost’. A question I get asked from time to time is “How can a playbook be run against multiple clusters without having to use outside scripting to loop it?” The solution is the task option “connection: local” along with an inventory file containing your cluster names. Let me show you an example.
For this to work best, it is important that you have your clusters short name (i.e. not the FQDN) in DNS so it can be used in an inventory file. For this example, I have two clusters named, ‘vsim’ and ‘cvo’. I created an inventory.yml file that has them as an entry.
inventory.yml
vsim
cvo
For the playbook, I set the login message on both of these clusters using the na_ontap_motd module.
playbook.yml
—
– hosts: all
gather_facts: false
name: Setup ONTAP
vars:
username: “admin”
state: present
password: netapp123
tasks:
– name: set motd
na_ontap_motd:
state: “{{ state }}”
vserver: “{{ inventory_hostname }}”
message: “I am the MOTD”
hostname: “{{ inventory_hostname }}”
username: “{{ username }}”
password: “{{ password }}”
https: true
validate_certs: false
connection: local
Here’s how it works:
- In line two you can see that I am not using localhost as the hosts. Instead I use the “all” catch indicating host names from the inventory file.
- Line three needs to be there with an entry of false. Without this Ansible will hang and fail as it won’t be able to do a unix host facts gather against the ONTAP systems.
- Lines thirteen and fifteen use the variable {{ inventory_hostname }}. This uses the entry from the inventory file that is currently being run.
Using the ‘shortname’ via DNS is important as most settings still require a vserver to be defined and that is usually the cluster ‘shortname’ when doing a cluster level configuration.
Finally, the last line (which is indented the same amount as the module line) is telling ansible to run this module locally.
Assuming both my playbook.yml and inventory.yml are in the same directory, I call the playbook with a simple one-line command
# ansible-playbook -i inventory.yml playbook.yml
PLAY [Setup ONTAP] ***************************************************************************************************************************************************************************************************************************
TASK [set motd] ******************************************************************************************************************************************************************************************************************************
changed: [cvo]
changed: [vsim]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
cvo : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
vsim : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can see how this will allow you to string together tasks that would be universal across all your clusters and run them from a single playbook using only Ansible for the looping.
For those who can’t use short name in DNS for whatever reason, you can assign variables at the inventory level. Here I could use the variable “{{ cluster }}”.
Inventory.yml
[all]
vsim.netapp.com cluster=”vsim”
cvo.netapp.com cluster=”cvo”
With this setup I can still use ‘hostname: “{{ inventory_hostname }}”’, but now I can use ‘vserver: “{{ cluster }}”’
If you have any questions or comments, or think you know a better way to do the same thing, please join me and others on our Pub Slack workspace in the #configurationmgmt channel. If you aren’t on Slack with us yet, get an invite at www.netapp.io/slack. As always you can find other posts about Ansible as well as our other OpenEco projects at www.netapp.io.
Thanks! Totally makes sense and so simple, but I hadn’t thought about trying this!
Wouldn’t it be possible to use Jinja2 Voodoo and get the vServer name like this?
vserver: ‘{{ inventory_hostname.split(“.”)[0] | lower }}’
That way you could use the FQDN and still have the short name for the vServer
This has been brought up and would indeed work. I was trying to keep it as simple as possible and Jinja scares some.