Ansible is a popular dev-ops tools for us to execute ad-hoc commands immediately on large mounts of machines in parallel which accelerate our working speed.
It’s simple but powerful and compatible with different OS platforms. Even more, it has lots of pre-defined modules for us to use, which significantly make the dream of reusing Dev-Ops scripts come true.
However, when you’re goging to use this fantastic tool, how to debug when you’re executing the ansible play-book with flow of commands? It looks like a unstoppable flow.
So we need two things for debugging ansible playbook:
- Stoppable
- Print Debug Message
This article will also give some tiny intro about play-book. For more info, please review the official documents.
1. Stoppable
So, here we have a trick, using the fail module to stop the execution process.
Add next code snippet at wherever you want to stop.
1 | # more is here |
After that, you could see the message like below:1
2
3
4
5
6
7
8
9
10
11
12
13
14# more is here ...
TASK [pre-ansible : STOP ME] ******************************************************
fatal: [node-1-master]: FAILED! => {"changed": false, "failed": true, "msg": "This is the debugging stop"}
fatal: [node-2-slave-1]: FAILED! => {"changed": false, "failed": true, "msg": "This is the debugging stop"}
fatal: [lcoj-judger]: FAILED! => {"changed": false, "failed": true, "msg": "This is the debugging stop"}
NO MORE HOSTS LEFT *************************************************************
to retry, use: --limit @cluster.retry
PLAY RECAP *********************************************************************
lcoj-judger : ok=5 changed=1 unreachable=0 failed=1
node-1-master : ok=5 changed=1 unreachable=0 failed=1
node-2-slave-1 : ok=5 changed=1 unreachable=0 failed=1
2. Dry Run with --check
Next won’t execute the whole playbook, but will give a run through.1
ansible-playbook foo.yml --check
3. Print Debugging Message with Var
Of course you can print debug message with the fail
module. However, it has a born behavior: stop the process, which maybe unexpected.
Here we use the debug module to print statements during execution.
Next is an example of printing the eth1
address of each nodes in the inventory file.
1 | # more is here... |
Here is the output of such debug msg:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37TASK [pre-ansible : debug] *****************************************************
ok: [node-2-slave-1] => (item=node-1-master) => {
"item": "node-1-master",
"msg": "hosts mapping is: 192.168.33.10 node-1-master"
}
ok: [node-2-slave-1] => (item=node-2-slave-1) => {
"item": "node-2-slave-1",
"msg": "hosts mapping is: 192.168.33.11 node-2-slave-1"
}
ok: [node-2-slave-1] => (item=lcoj-judger) => {
"item": "lcoj-judger",
"msg": "hosts mapping is: 192.168.33.12 lcoj-judger"
}
ok: [node-1-master] => (item=node-1-master) => {
"item": "node-1-master",
"msg": "hosts mapping is: 192.168.33.10 node-1-master"
}
ok: [node-1-master] => (item=node-2-slave-1) => {
"item": "node-2-slave-1",
"msg": "hosts mapping is: 192.168.33.11 node-2-slave-1"
}
ok: [node-1-master] => (item=lcoj-judger) => {
"item": "lcoj-judger",
"msg": "hosts mapping is: 192.168.33.12 lcoj-judger"
}
ok: [lcoj-judger] => (item=node-1-master) => {
"item": "node-1-master",
"msg": "hosts mapping is: 192.168.33.10 node-1-master"
}
ok: [lcoj-judger] => (item=node-2-slave-1) => {
"item": "node-2-slave-1",
"msg": "hosts mapping is: 192.168.33.11 node-2-slave-1"
}
ok: [lcoj-judger] => (item=lcoj-judger) => {
"item": "lcoj-judger",
"msg": "hosts mapping is: 192.168.33.12 lcoj-judger"
}
In your play-book, please setup the gather_facts
to be true
. In this way, we can print the ipv4.adderss
of this host.
And the pre-ansible
is the role where the above code snippet lies in.
1 | - hosts: all |
Also, this debug
module with msg can print an object with all its field values. So if our msg
above changes to1
"hosts mapping is: {{ hostvars[item]['ansible_eth1'].ipv4 }} {{item}}"
it will print more message.
3.1. Register the response and then print using debug msg
1 | - hosts: all |
It will print msg like below:1
2
3ok: [localhost.domain] => {
"msg": "PRETTY_NAME=\"Ubuntu 16.04.1 LTS\""
}
4. Intro about Play-Book
In the section of Print Debugging Message with Var, we already saw one easy play
, here is another playbook with only one play. Please remember we do have ---
at the first line.
1 | --- |
4.1. Roles
With Roles, we can reuse the tasks commands. For example, next play, we will execute the play with roles pre-ansible
. Of course, we can execute more roles, just append the role directory name under roles
field.1
2
3
4
5- hosts: all
gather_facts: true
sudo: yes
roles:
- pre-ansible
Here is a glance of directory structure, we can see pre-ansible
directory in the roles
directory.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24[03:38 PM morganwu@promote noj-deploy]$ tree -L 2
.
├── ansible.cfg
├── cluster.yml
├── group_vars
│ └── all.yml
├── inventory.me
├── roles
│ ├── common
│ ├── docker
│ ├── etcd
│ ├── flannel
│ ├── kubernetes
│ ├── kubernetes-addons
│ ├── leetcode
│ ├── leetcode-backend
│ ├── master
│ ├── nginx
│ ├── node
│ ├── opencontrail
│ ├── opencontrail-provision
│ └── pre-ansible
├── setup.sh
└── setup_leetcode.sh
4.1.1. Use Condition when Choosing Roles
We even can use condition expression when choosing specific roles,1
2
3
4
5
6
7
8
9- hosts:
- etcd
- masters
- nodes
sudo: yes
roles:
- { role: flannel, when: networking == 'flannel' }
tags:
- network-service-install
This will only execute the roles of flannel
when the networking
varialbe is flannel
.
4.2. Tags
With Tags
, we can run specific play
and it makes our dev-ops work more flexible, in a non-linear style.
We will still using the example above. Here we have defined a tag pre-ansible
1
2
3
4
5
6
7- hosts: all
gather_facts: true
sudo: yes
roles:
- pre-ansible
tags:
- pre-ansible
When we execute playbook with --tags
, it will only execute this play and skip all other plays without this specific tag.1
[03:44 PM morganwu@promote noj-deploy]$ ansible-playbook -i inventory.me cluster.yml --tags=pre-ansible
4.2.1. Execute Multiple Tags
If you want to execute multiple tags once, just append with more tag name at the --tags
, eg.
1 | [03:44 PM morganwu@promote noj-deploy]$ ansible-playbook -i inventory.me cluster.yml --tags="pre-ansible,etcd,docker" |
This will execute the pre-ansible
, etcd
, docker
tags.
4.3. Var/String in a condition
Here is an example inventory_hostname
is a varaible, but “codential” and “node-1-master” are all strings.
The most important here is: the condition in the when, we use '
to wrap up.
1 | - include: frontend.yml |
Extra to learn: iptables related diagram:
From https://cesarti.files.wordpress.com/2012/02/iptables.gif
5. Execute SUDO commands, without NO_PASSWORD settings
Last but not the least, however sometimes very useful. Is for Ad-Hoc command in Ansible.
We all know it’s possible to execute ad-hoc ansible command for bunch of servers. But problems will come when you need to execute sudo command, the command from the server side will always be waiting for inputing the password to be continued.
We can use --sudo
/-b
to solve this. However, you have to make sure all the users in the nodes
server list has the same password
here. If you provide with the ansible_sudo_pass
password in inventory
file.1
host1 ansible_ssh_host=xxx.xxx.xxx.xxx ansible_ssh_port=22 ansible_ssh_user=user1 ansible_ssh_pass=password1 ansible_sudo_pass=password1
If we don’t have ansible_sudo_pass
, then we need to provide with the SUDO password
at the runtime.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30# This is the command, append using --sudo or we can use -b --become-user=<username>
[05:16 PM morganwu@morgan-yinnut my-deploy]$ ansible -i inventory.me nodes -m shell -a 'curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-xenial-td-agent2.sh | sh' --sudo
SUDO password:
node1 | SUCCESS | rc=0 >>
==============================
td-agent Installation Script
==============================
This script requires superuser access to install apt packages.
You will be prompted for your password by sudo.
OK
Ign:1 http://apt.newrelic.com/debian newrelic InRelease
Hit:2 http://apt.newrelic.com/debian newrelic Release
Hit:3 http://mirrors.linode.com/ubuntu xenial InRelease
Get:4 http://mirrors.linode.com/ubuntu xenial-updates InRelease [102 kB]
Get:5 http://mirrors.linode.com/ubuntu xenial-backports InRelease [102 kB]
Get:6 http://packages.treasuredata.com/2/ubuntu/xenial xenial InRelease [2,578 B]
Get:8 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Get:9 http://packages.treasuredata.com/2/ubuntu/xenial xenial/contrib amd64 Packages [399 B]
Get:10 http://packages.treasuredata.com/2/ubuntu/xenial xenial/contrib i386 Packages [399 B]
Ign:11 https://get.docker.com/ubuntu docker InRelease
Hit:12 https://get.docker.com/ubuntu docker Release
Fetched 310 kB in 0s (381 kB/s)
Reading package lists...
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
td-agent
0 upgraded, 1 newly installed, 0 to remove and 137 not upgraded.
# More output comes here
6. Conclusion
Ansible is easy but powerful with lots of pre-defined modules.
- We can use
fail
module to stop execution process ann usedebug
module to print message with variables. Roles
are designed fortask
reuuse.Tags
are designed to execute the specificPlay
(s) in one playbook.- Use
--sudo
to execute sudo commands in ad-hoc style.