First we have to create an inventory and include the nodes we want to manage. The simplest method is to create an ini-file. Each line defines a node and is in the format:
[<nodegroup>]
<node_name> ansible_host=<ip_address>
e.g.:
[hosts]
node1 ansible_host=192.168.67.3
To organize our ansible files we use the following directory structure:
inventories : inventory files
playbooks : playbook files
roles : role folders
We use host groups to categorize the host types. We can then use the host group names to target the hosts in the group.
[controller]
ansible ansible_host=192.168.99.5
[router]
ro0 ansible_host=192.168.99.1
ro1 ansible_host=192.168.99.23
[switches]
sw0 ansible_host=192.168.99.10
sw1 ansible_host=192.168.99.21
sw2 ansible_host=192.168.99.22
[hosts]
ns1 ansible_host=192.168.99.24
ns2 ansible_host=192.168.99.25
h1 ansible_host=192.168.99.26
h2 ansible_host=192.168.99.27
controller
router
switches
hosts
Playbooks
Roles
We can use ad-commands to send instructions to a bunch of hosts, e.g. to check if they are reachable. We still have to use an inventory to refer to the nodes. In the following example we check if all hosts in the inventory are up and reachable:
A task is the smallest unit in ansible. It's running a single command and its definition is usually stored in a file. An ad-hoc command is also considered a task that is created on the fly. Tasks could be simple as:
- name: task name
copy:
src : /tmp/file1
dest : /tmp/file2
The bash equivalent would be:
bash$ cp /tmp/file1 /tmp/file2
A play is the next bigger unit. It consists of one or more tasks. It is defined in a playbook.
- name: example-play
host: localhost
tasks:
- name: task 1 (create directory dir2)
file:
name : /tmp/dir2
state: directory
- name: task 2 (cp file into dir2 and rename it to file2)
copy:
src : /tmp/file
dest : /tmp/dir2/file2
A playbook consists of one or more plays.
# Playbook 1
- name: play 1
hosts: host1
tasks:
- name: task 1
file:
name : /tmp/dir2
state: directory
- name: task 2
copy:
src : /tmp/file
dest : /tmp/dir2/file2
- name: play 2
hosts: host2
tasks:
- name: task 1
yum:
name: httpd
- name: task 2
yum:
name: php
A role is
# Playbook
- name: install apache
hosts:
- host1
- host2
roles:
- roles/httpd
- roles/php
A module is a command in ansible that is used in tasks. It's usually a python script that is run on the target and if written in an idempotent way it makes sure the result of that script execution is always the same. Usually the command expects some arguments to use, e.g. filepath, username, ...
task 1:
command: file
arguments:
name: /etc/motd
owner: root
...
command that runs on the target
arguments passed to the command
We have used modules in our examples before when we used tasks. We called the module we used as command. The following example is using the file module with the arguments name and state to indicate that we want the directory /tmp/dir2 present on the target host.
- name: task 1
file:
name : /tmp/dir2
state: directory
We are going to create a simple hello world module that runs on the target and returns the json string: { "hello" : "world" }.
# ./library/hello.py
from ansible.module_utils.basic import *
def main():
module = AnsibleModule(argument_spec={}) # declare the code to be a module
res = {"hello":"world"} # prepare the response as json
module.exit_json(changed=False, meta=res) # return the response
if __name__ == '__main__': # make the script run standalone
main()
We would use that module in a playbook like so:
---
# ./playbooks/playbook.yml
- name: playbooks.hello
hosts: localhost
tasks:
- name: playbook.hello.tasks.module.run
hello:
This is how a run would look like. We use the environment variable ANSIBLE_LIBRARY to include our module.