0%

Blocks

Blocks allow for logical grouping of tasks and in play error handling.

1
2
3
4
5
6
7
8
9
10
11
- name: test blocks resuce and always
hosts: web2
tasks:
- name: first command
debug:
msg: "first message success"
- name: second command
command: /bin/false
- name: third command
debug:
msg: "this is third command"

There are three tasks in this playbook, but the second one is a wrong command, which will failed to be executed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
anna@ansible-controller:~/Desktop/ansible-code/inventory/block-resuce-always$ ansible-playbook -i hosts site.yml 

PLAY [test blocks resuce and always] ******************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************************
ok: [cube4200]

TASK [first command] **********************************************************************************************************************************************************************************************************************************
ok: [cube4200] => {
"msg": "first message sucess"
}

TASK [second command] *********************************************************************************************************************************************************************************************************************************
fatal: [cube4200]: FAILED! => {"changed": true, "cmd": ["/bin/false"], "delta": "0:00:00.011635", "end": "2020-06-21 21:31:18.222247", "msg": "non-zero return code", "rc": 1, "start": "2020-06-21 21:31:18.210612", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

PLAY RECAP ********************************************************************************************************************************************************************************************************************************************
cube4200 : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

Since the second faild, so the third one will be skipped. I don’t want this happen, So I use block to solove this.

Blocks error handling

Blocks also introduce the ability to handle errors in a way similar to exceptions in most programming languages. Blocks only deal with ‘failed’ status of a task. A bad task definition or an unreachable host are not ‘rescuable’ errors.

three key words: block rescure always are similar as try exception and final in python.
block section: will execute normally
rescue section: will execute only when block section has error
always section: will run no matter what the task status is.

I add block into playbook

1
2
3
4
5
6
7
8
9
10
11
12
13
- name: test blocks recue and always
hosts: web2
tasks:
- block:
- name: test block, this is first command
debug:
msg: "first message success"
- name: second command
command: /bin/false
rescue:
- name: third command, this is excuted only when block failed, otherwise will be skipped
debug:
msg: "some command in block failed, so this message be excuted"

after running

Read more »

power off using cron

I am going to power off one of my node using cron module.

1
2
3
4
5
6
7
8
9
10
11
12
- name: cron to poweroff
hosts: web2
become: yes

tasks:
- name: power off
cron:
name: "shutdown"
user: root
minute: "52"
hour: "16"
job: "sync; /sbin/shutdown"

after running playbook, the remote will be shutdown on 16:42 everyday.

Wake-on-LAN

Compare to shutdown, power on remote is a little bit hard. Ansible has a Wake-on-LAN module can do it, but remote needs has Wake-on-LAN option is enabled.
Wake-on-LAN (WOL) is an Ethernet networking standard that allows a server to be turned on by a network message.

If you don’t see this option in your BIOS or UEFI, check the computer or motherboard’s manual to see if it supports Wake-on-LAN.

To verify if remote supports Wake-on-LAN, use ethtool -s eth0 wol g

1
2
3
[anna@cube4200 ~]$ sudo ethtool enp3s0 |grep Wake
Supports Wake-on: pumbg
Wake-on: g

It shows remote node cube4200 supports Wake-on-LAN

Let’s write playbook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- name: power on
hosts: web2
gather_facts: no

tasks:
- name: Send a magic Wake-on-LAN packet to turn on individual systems via gateway
wakeonlan:
mac: '00:f0:d2:d0:a0:0e'
broadcast: 255.255.255.255
delegate_to: localhost
- wakeonlan:
mac: '00:f0:d2:d0:a0:0e'
port: 9
delegate_to: localhost

after running

1
2
3
4
5
6
7
8
9
10
11
12
anna@ansible-controller:/tmp$ ansible-playbook wakeonlan.yml 

PLAY [power on] ********************************************************************************************************

TASK [Send a magic Wake-on-LAN packet to 00:00:5E:00:53:66] ************************************************************
changed: [cube4200 -> localhost]

TASK [wakeonlan] *******************************************************************************************************
changed: [cube4200 -> localhost]

PLAY RECAP *************************************************************************************************************
cube4200 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

waitting few seconds, I can ssh to cube4200

1
2
anna@ansible-controller:/tmp$ ssh anna@cube4200
Last login: Thu Jun 18 00:56:29 2020 from 192.168.0.31

Notice: gather_facts: no must be configured. Because gather_facts default is yes, so when playbook is excuted, it will gather facts from remote, which is not power on yet, so ansible will output error message as following:

1
2
3
4
5
6
7
8
9
anna@ansible-controller:/tmp$ ansible-playbook wakeonlan.yml 

PLAY [power on] ********************************************************************************************************

TASK [Gathering Facts] *************************************************************************************************
fatal: [cube4200]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: System is going down.\n\nConnection closed by 192.168.0.30 port 22", "unreachable": true}

PLAY RECAP *************************************************************************************************************
cube4200 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0

uri is a net tool moudle, which interacts with HTTP and HTTPS web services and supports Digest, Basic and WSSE HTTP authentication mechanisms.

1
2
3
4
5
6
7
8
tasks:
- name: Check that a page returns a status 200
uri:
url: http://www.example.com
return_content: yes
register: this
- debug:
msg: "{{this}}"

look at the output

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/net-tools-modules$ ansible-playbook site1.yml 

PLAY [uri] ********************************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************************************************************************************************
ok: [cube4200]
ok: [ansible-node1]

TASK [Check that a page returns a status 200] *********************************************************************************************************************************************************************************************************
ok: [cube4200]
ok: [ansible-node1]

TASK [debug] ******************************************************************************************************************************************************************************************************************************************
ok: [ansible-node1] => {
"msg": {
"accept_ranges": "bytes",
"age": "478999",
"cache_control": "max-age=604800",
"changed": false,
"connection": "close",
"content": "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style type=\"text/css\">\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</h1>\n <p>This domain is for use in illustrative examples in documents. You may use this\n domain in literature without prior coordination or asking for permission.</p>\n <p><a href=\"https://www.iana.org/domains/example\">More information...</a></p>\n</div>\n</body>\n</html>\n",
"content_length": "1256",
"content_type": "text/html; charset=UTF-8",
"cookies": {},
"cookies_string": "",
"date": "Wed, 17 Jun 2020 02:39:51 GMT",
"elapsed": 0,
"etag": "\"3147526947\"",
"expires": "Wed, 24 Jun 2020 02:39:51 GMT",
"failed": false,
"last_modified": "Thu, 17 Oct 2019 07:18:26 GMT",
"msg": "OK (1256 bytes)",
"redirected": false,
"server": "ECS (sjc/4E44)",
"status": 200,
"url": "http://www.example.com",
"vary": "Accept-Encoding",
"x_cache": "HIT"
}
}
ok: [cube4200] => {
"msg": {
"accept_ranges": "bytes",
"age": "478426",
"cache_control": "max-age=604800",
"changed": false,
"connection": "close",
"content": "<!doctype html>\n<html>\n<head>\n <title>Example Domain</title>\n\n <meta charset=\"utf-8\" />\n <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <style type=\"text/css\">\n body {\n background-color: #f0f0f2;\n margin: 0;\n padding: 0;\n font-family: -apple-system, system-ui, BlinkMacSystemFont, \"Segoe UI\", \"Open Sans\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n \n }\n div {\n width: 600px;\n margin: 5em auto;\n padding: 2em;\n background-color: #fdfdff;\n border-radius: 0.5em;\n box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);\n }\n a:link, a:visited {\n color: #38488f;\n text-decoration: none;\n }\n @media (max-width: 700px) {\n div {\n margin: 0 auto;\n width: auto;\n }\n }\n </style> \n</head>\n\n<body>\n<div>\n <h1>Example Domain</h1>\n <p>This domain is for use in illustrative examples in documents. You may use this\n domain in literature without prior coordination or asking for permission.</p>\n <p><a href=\"https://www.iana.org/domains/example\">More information...</a></p>\n</div>\n</body>\n</html>\n",
"content_length": "1256",
"content_type": "text/html; charset=UTF-8",
"cookies": {},
"cookies_string": "",
"date": "Wed, 17 Jun 2020 02:39:50 GMT",
"elapsed": 0,
"etag": "\"3147526947\"",
"expires": "Wed, 24 Jun 2020 02:39:50 GMT",
"failed": false,
"last_modified": "Thu, 17 Oct 2019 07:18:26 GMT",
"msg": "OK (1256 bytes)",
"redirected": false,
"server": "ECS (sjc/4E76)",
"status": 200,
"url": "http://www.example.com",
"vary": "Accept-Encoding",
"x_cache": "HIT"
}
}

PLAY RECAP ********************************************************************************************************************************************************************************************************************************************
ansible-node1 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cube4200 : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Notice: if there is no return_content: yes, the output will only parts of above info.
the status is 200, which means it is normal.

file module has a fetch module, which is the same as copy but in reverse.

1
2
3
4
5
6
tasks:
- name: fetech
fetch:
src: /tmp/ansible-file-test.txt
dest: /tmp/
flat:

go to my local machine to see /tmp directory

1
2
3
4
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/files-modules/inventory$ ll /tmp/ansible-node1/tmp/ansible-file-test.txt 
-rw-rw-r-- 1 anna anna 10 Jun 16 18:18 /tmp/ansible-node1/tmp/ansible-file-test.txt
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/files-modules/inventory$ ll /tmp/cube4200/tmp/ansible-file-test.txt
-rw-rw-r-- 1 anna anna 0 Jun 16 18:18 /tmp/cube4200/tmp/ansible-file-test.txt

there are two hosts directories which are relate to my two hosts.

for the flat, it means ansible will not distinct the files from different hosts, the latest file will overwrite the old one.
for example

1
2
3
4
5
6
tasks:
- name: fetech
fetch:
src: /tmp/ansible-file-test.txt
dest: /tmp/
flat: yes

notice: the default of flat is no, I am turning on it here, it will let the new file overwrite old file

1
2
3
4
5
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/files-modules/inventory$ ll /tmp
total 76
drwxrwxrwt 18 root root 4096 Jun 16 18:28 ./
drwxr-xr-x 24 root root 4096 Jun 9 20:21 ../
-rw-rw-r-- 1 anna anna 0 Jun 16 18:28 ansible-file-test.txt

from above, I can see there is only one ansible-file-test.txt file which is from cube4200, and there is no file from ansible-node1.

Ansible lint: Ansible Lint is a commandline tool for linting playbooks. Use it to detect behaviors and practices that could potentially be improved.

Install

At first I try to Use pip install ansible-int, it failed.
then I try the apt install.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/set-fact module$ sudo apt install ansible-lint
[sudo] password for anna:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
golang-1.10-go golang-1.10-race-detector-runtime golang-1.10-src golang-race-detector-runtime golang-src ieee-data pkg-config python-certifi python-chardet python-jmespath python-kerberos python-libcloud python-lockfile python-netaddr
python-openssl python-requests python-selinux python-simplejson python-urllib3 python-xmltodict
Use 'sudo apt autoremove' to remove them.
The following NEW packages will be installed:
ansible-lint
0 upgraded, 1 newly installed, 0 to remove and 34 not upgraded.
Need to get 24.8 kB of archives.
After this operation, 146 kB of additional disk space will be used.
Get:1 http://us.archive.ubuntu.com/ubuntu bionic/universe amd64 ansible-lint all 3.4.20+git.20180203-1 [24.8 kB]
Fetched 24.8 kB in 0s (76.1 kB/s)
Selecting previously unselected package ansible-lint.
(Reading database ... 240199 files and directories currently installed.)
Preparing to unpack .../ansible-lint_3.4.20+git.20180203-1_all.deb ...
Unpacking ansible-lint (3.4.20+git.20180203-1) ...
Setting up ansible-lint (3.4.20+git.20180203-1) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/set-fact module$ ansible-lint --version
ansible-lint 3.4.20

It shows the lint version is 3.4.20

use lint to test yml file

1
2
3
4
5
6
7
8
9
10


anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/packaging_modules/inventory$ ansible-lint site.yml
[ANSIBLE0002] Trailing whitespace
site.yml:10
name:

[ANSIBLE0010] Package installs should not use latest
site.yml:16
Task/Handler: test apt module

then I go to line 10 to add ‘test package module’ after name, and save playbook.
after run ansible-lint

1
2
3
4
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/packaging_modules/inventory$ ansible-lint site.yml
[ANSIBLE0010] Package installs should not use latest
site.yml:16
Task/Handler: test apt module

It only shows the second code which needs improved.

after I commented out the state: latest, the output of ansible-lint site.yml shows nothing, which means nothing needs improve in this site.yml file.

what is set_fact

Set fact is a module which allows setting new variables. These variables are set on a host-by-host base just like facts discovered by the setup module.

In ansible, there are some default info of hosts in hostvars variable, such as “ansible_check_mode”, “group_names” etc, and also the “ansible_facts”, which is not default show up, only when gather_facts is set to “yes”, it will show the details of ansible_fact. Except these two kinds of info, I can also use set_fact module to create my own info pair.

1
2
3
4
5
6
7
8
- name: set fact
hosts: all
gather_facts: no

tasks:
- name: gather facts
debug:
var: hostvars[ansible_host] #ansible_host is variable name, which means cube4200 and ansible-node1 in this case

Let’s look at he output of this playbook,

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/set-fact module$ ansible-playbook site.yml 

PLAY [set fact] ************************************************************************

TASK [gather facts] ********************************************************************
ok: [cube4200] => {
"hostvars[ansible_host]": {
"ansible_check_mode": false,
"ansible_connection": "ssh",
"ansible_diff_mode": false,
"ansible_facts": {},
"ansible_forks": 5,
"ansible_inventory_sources": [
"/home/anna/Desktop/ansible-code/inventory/modules/set-fact module/hosts"
],
"ansible_playbook_python": "/usr/bin/python2",
"ansible_run_tags": [
"all"
],
"ansible_skip_tags": [],
"ansible_user": "anna",
"ansible_verbosity": 0,
"ansible_version": {
"full": "2.9.9",
"major": 2,
"minor": 9,
"revision": 9,
"string": "2.9.9"
},
"group_names": [
"web2"
],
"groups": {
"all": [
"cube4200",
"ansible-node1"
],
"ungrouped": [],
"web1": [
"ansible-node1"
],
"web2": [
"cube4200"
]
},
"inventory_dir": "/home/anna/Desktop/ansible-code/inventory/modules/set-fact module",
"inventory_file": "/home/anna/Desktop/ansible-code/inventory/modules/set-fact module/hosts",
"inventory_hostname": "cube4200",
"inventory_hostname_short": "cube4200",
"omit": "__omit_place_holder__a53469922527cea947bde7fea01f0f911fe92d8c",
"playbook_dir": "/home/anna/Desktop/ansible-code/inventory/modules/set-fact module"
}
}
ok: [ansible-node1] => {
"hostvars[ansible_host]": {
"ansible_check_mode": false,
"ansible_connection": "ssh",
"ansible_diff_mode": false,
"ansible_facts": {},
"ansible_forks": 5,
"ansible_inventory_sources": [
"/home/anna/Desktop/ansible-code/inventory/modules/set-fact module/hosts"
],
"ansible_playbook_python": "/usr/bin/python2",
"ansible_run_tags": [
"all"
],
"ansible_skip_tags": [],
"ansible_user": "pi",
"ansible_verbosity": 0,
"ansible_version": {
"full": "2.9.9",
"major": 2,
"minor": 9,
"revision": 9,
"string": "2.9.9"
},
"group_names": [
"web1"
],
"groups": {
"all": [
"cube4200",
"ansible-node1"
],
"ungrouped": [],
"web1": [
"ansible-node1"
],
"web2": [
"cube4200"
]
},
"inventory_dir": "/home/anna/Desktop/ansible-code/inventory/modules/set-fact module",
"inventory_file": "/home/anna/Desktop/ansible-code/inventory/modules/set-fact module/hosts",
"inventory_hostname": "ansible-node1",
"inventory_hostname_short": "ansible-node1",
"omit": "__omit_place_holder__a53469922527cea947bde7fea01f0f911fe92d8c",
"playbook_dir": "/home/anna/Desktop/ansible-code/inventory/modules/set-fact module"
}
}

PLAY RECAP *****************************************************************************
ansible-node1 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cube4200 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

eventhought gather_facts is “no”, ansible still show some basic info of every hosts.
If gather_facts is “yes”, except the default info, ansible will show ansible-facts info which included a lots of system info of every hosts.

Read more »

Ansible Vault is a feature of ansible that allows you to keep sensitive data such as passwords or keys in encrypted files, rather than as plaintext in playbooks or roles. These vault files can then be distributed or placed in source control.

encrypt a file using ansible-vault

I created a vars file to test ansible-vault command

1
2
3
port: 443
greeting: "greeting from vars file"
ansible_user: pi
Read more »

In this session, I am going to talk about command module.

1
2
3
tasks:
- name: test command module
command: cat /etc/hosts

the playbook is pretty simple, let’s look at output

1
2
3
4
5
6
7
8
9
10
11
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/command-modules$ ansible-playbook site.yml 

PLAY [test command module] ******************************************************

TASK [test command module] ******************************************************
changed: [ansible-node1]
changed: [cube4200]

PLAY RECAP **********************************************************************
ansible-node1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cube4200 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

It shows successfully exectute ansible tasks, but I didn’t see the context of /etc/hosts.

If I want to see the output, I am supposed to let output to be a variable, it looks like following:

1
2
3
4
5
6
7
tasks:
- name: test command module
command: cat /etc/hosts
register: output
- name: print the output of command
debug:
msg: "{{ output }}"

after adding register, I can see the /etc/hosts now.

Read more »

If I am going to download an python archived file from python.org, I need to use net tools and file module to achieve my goal.

Net tools module: get_url

playbook:

1
2
3
4
5
6
7
8
9
tasks:
- name: mkdir
file:
path: /tmp/python-download/ # use file module to create directory name /tmp/python-download
state: directory
- name: get url
get_url:
url: https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz # the download url
dest: /tmp/python-download/

output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/net-tools-modules$ ansible-playbook site.yml 

PLAY [test net tool get_url] ****************************************************

TASK [Gathering Facts] **********************************************************
ok: [ansible-node1]
ok: [cube4200]

TASK [mkdir] ********************************************************************
changed: [ansible-node1]
changed: [cube4200]

TASK [get url] ******************************************************************
changed: [ansible-node1]
changed: [cube4200]

PLAY RECAP **********************************************************************
ansible-node1 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cube4200 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

we can check if the python file has been downloaded.

1
2
3
4
5
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/net-tools-modules$ ansible all -m shell -a "ls /tmp/python-download"
ansible-node1 | CHANGED | rc=0 >>
Python-3.8.3.tgz
cube4200 | CHANGED | rc=0 >>
Python-3.8.3.tgz

It shows Python-3.8.3.tgz already downloaded.

file modules: unarchive

In order to unarchive Python-3.8.3.tgz, I need to use unarchive module

1
2
3
4
5
- name: unarchive compress file
unarchive:
src: /tmp/python-download/Python-3.8.3.tgz
dest: /etc/tmp
remote_src: yes #indicate the archived file is already on the remote system and not local to the Ansible controller.

Notice: remote_src default is no, which means ansible is going to find Python-3.8.3.tgz at my local machine, but actually this file already is in remote, so I need to switch to yes.

output is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/net-tools-modules$ ansible-playbook site.yml 

TASK [unarchive compress file] *****************************************************************************************************************************************************************************************************************
changed: [cube4200]
changed: [ansible-node1]

PLAY RECAP *************************************************************************************************************************************************************************************************************************************
ansible-node1 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
cube4200 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/net-tools-modules$ ansible all -m shell -a "ls /etc/tmp"
cube4200 | CHANGED | rc=0 >>
Python-3.8.3
ansible-node1 | CHANGED | rc=0 >>
Python-3.8.3

packaging module: yum

yum is CentOS Linux package management tool.

1
2
3
4
5
6
7
8
9
tasks:
- name: upgrade all packages
yum:
name: '*' # update all packages
state: latest
- name: install a package
yum:
name: git
state: latest

output is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/packaging_modules/inventory$ ansible-playbook site.yml 

PLAY [test packageing modules] **************************************************

TASK [upgrade all packages] *****************************************************
changed: [cube4200]

TASK [install a package] ********************************************************
changed: [cube4200]

PLAY RECAP **********************************************************************
cube4200 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[anna@cube4200 ~]$ which git
/usr/bin/git
[anna@cube4200 ~]$ git --version
git version 1.8.3.1

Notice: the update task took long time to update all packages.

packaging module: apt

apt is Ubuntu package management tool.

In this example, I am going to install git in two different linux, one use yum on CentOS, anther one use apt on Debian. So I need to add some condition to let ansible know which node should use yum or apt.
Before running site.yml I can use ansible web1 -m gather_facts |grep distribution to see the OS of nodes.

1
2
3
4
5
6
7
8
9
10
11
tasks:
- name: test yum module
yum:
name: git
state: latest
when: ansible_facts['distribution'] == "CentOS" # this is from gather_facts
- name: test apt module
apt:
name: git
state: latest
when: ansible_facts['distribution'] == "Debian"

During running, I can see ansible will judge which command (apt or yum) to use.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
anna@ansible-controller:~/Desktop/ansible-code/inventory/modules/packaging_modules/inventory$ ansible-playbook site.yml 

PLAY [test packageing modules] **************************************************

TASK [Gathering Facts] **********************************************************
ok: [ansible-node1]
ok: [cube4200]

TASK [test yum module] **********************************************************
skipping: [ansible-node1]
changed: [cube4200]

TASK [test apt module] **********************************************************
skipping: [cube4200]
ok: [ansible-node1]

PLAY RECAP **********************************************************************
ansible-node1 : ok=2 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
cube4200 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0

cube4200 uses CentOS, so when testing apt command, it is skipped; ansible_node1 uses Debian, which is skipped when testing yum.

packaging module: package

package module is more general and simplify the installing packages

1
2
3
4
5
tasks:
- name: test package module
package:
name: git
state: latest

Notice: sometime package will have different name in different OS, under this situation, package module will not work, I still need to use yum or apt with gather_facts conditon to install packages.