One of the simplest ways Ansible can be used is by using ad-hoc commands. These can be used when you want to issue some commands on a server or a bunch of servers. Ad-hoc commands are not stored for future uses but represent a fast way to interact with the desired servers.
- You can run ansible either ad-hoc or as a playbook
- Both methods have the same capabilities
- Ad-hoc commands are effectively one-liners
Use cases for Ad-hoc
- Operational commands
- Checking log contents
- Daemon control
- Process management
- Informational commands
- Check installed software
- Check system properties
- Gather system performance information (CPU, disk space, memory use)
- Research
- Work with unfamiliar modules on test systems
- Practice for playbook engineering
Ad-hoc vs Playbook
| Ad-hoc mode | Playbook mode |
|
|
Common modules
ping– Validate if server is up and recheable. No required parameters.setup– Gather ansible facts. No required parameters.yum– Use yum package manager. Parametersnameandstate.service– Control Daemons. Parametersnameandstate.user– Manipulate system users. Parametersname.copy– Copy files. Parameterssrc.file– Work with files. Parameterspath.git– Interact with git repositories. Parametersrepoanddest.
You can check if the hosts are accessible from the ansible server by issuing a ping command on all hosts.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[root@controlnode ansible]# cat inventory managedhost1 ansible_host=managedhost1.example.com [labservers] managedhost1.example.com managedhost2.example.com [root@controlnode ansible]# ansible -i inventory all -m ping managedhost2.example.com | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname managedhost2.example.com: Name or service not known\r\n", "unreachable": true } managedhost1 | SUCCESS => { "changed": false, "ping": "pong" } managedhost1.example.com | SUCCESS => { "changed": false, "ping": "pong" } |
You can issue the same command only on a specific group:
|
1 2 3 4 5 6 7 8 9 |
[root@controlnode ansible]# ansible -i inventory labservers -m ping managedhost1.example.com | SUCCESS => { "changed": false, "ping": "pong" } managedhost2.example.com | SUCCESS => { "changed": false, "ping": "pong" } |
You can issue the same command only on a specific host if needed.
|
1 2 3 4 5 |
[root@controlnode ansible]# ansible -i inventory all -m ping --limit managedhost1 managedhost1 | SUCCESS => { "changed": false, "ping": "pong" } |
The flag -a may be used without -m (module) to run shell command.
|
1 2 3 4 5 6 7 8 9 |
[root@controlnode ansible]# ansible all -i inventory -a "/usr/bin/echo hi" managedhost2.example.com | SUCCESS | rc=0 >> hi managedhost1 | SUCCESS | rc=0 >> hi managedhost1.example.com | SUCCESS | rc=0 >> hi |
To reboot all managed hosts:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[root@controlnode ansible]# ansible all -i inventory -a "/sbin/reboot" managedhost2.example.com | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: Shared connection to managedhost2.example.com closed.\r\n", "unreachable": true } managedhost1.example.com | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: Shared connection to managedhost1.example.com closed.\r\n", "unreachable": true } managedhost1 | UNREACHABLE! => { "changed": false, "msg": "Failed to connect to the host via ssh: Shared connection to managedhost1.example.com closed.\r\n", "unreachable": true } |
If you need to copy a file to multiple destinations rapidly, you can use the copy module in ansible which uses SCP. So the command and its output look like below:
|
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 |
[root@controlnode ansible]# touch /home/miro/ansible/testfile [root@controlnode ansible]# ansible -i inventory all -m copy -a "src=/home/miro/ansible/testfile dest=/tmp/testfile" managedhost2.example.com | SUCCESS => { "changed": true, "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "dest": "/tmp/testfile", "gid": 0, "group": "root", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "mode": "0644", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 0, "src": "/root/.ansible/tmp/ansible-tmp-1579610363.34-77937205353512/source", "state": "file", "uid": 0 } managedhost1.example.com | SUCCESS => { "changed": true, "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "dest": "/tmp/testfile", "gid": 0, "group": "root", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "mode": "0644", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 0, "src": "/root/.ansible/tmp/ansible-tmp-1579610363.35-210160212137566/source", "state": "file", "uid": 0 } managedhost1 | SUCCESS => { "changed": false, "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "path": "/tmp/testfile", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 0, "state": "file", "uid": 0 } |
In the next example, you will find out how to install a package via the yum module on two Centos hosts.
|
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 |
[root@controlnode ansible]# ansible -i inventory all -m yum -a 'name=tcpdump state=present' managedhost2.example.com | SUCCESS => { "changed": false, "msg": "", "rc": 0, "results": [ "14:tcpdump-4.5.1-3.el7.x86_64 providing tcpdump is already installed" ] } managedhost1 | SUCCESS => { "changed": false, "msg": "", "rc": 0, "results": [ "14:tcpdump-4.9.2-4.el7_7.1.x86_64 providing tcpdump is already installed" ] } managedhost1.example.com | SUCCESS => { "changed": false, "msg": "", "rc": 0, "results": [ "14:tcpdump-4.9.2-4.el7_7.1.x86_64 providing tcpdump is already installed" ] } |
If you are not logged as superuser you will have problem to use yum:
|
1 2 3 4 5 6 7 8 9 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -m yum -a "name=elinks state=latest" managedhost1 | FAILED! => { "changed": true, "msg": "You need to be root to perform this command.\n", "rc": 1, "results": [ "Loaded plugins: fastestmirror\n" ] } |
So you can use -b parameter to beacome a root on remote host:
|
1 2 3 4 5 6 7 8 9 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -b -m yum -a "name=elinks state=latest" managedhost1 | SUCCESS => { "changed": true, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: centos1.hti.pl\n * centosplus: mirroronet.pl\n * extras: mirroronet.pl\n * updates: mirroronet.pl\nResolving Dependencies\n--> Running transaction check\n---> Package elinks.x86_64 0:0.12-0.37.pre6.el7.0.1 will be installed\n--> Processing Dependency: libnss_compat_ossl.so.0()(64bit) for package: elinks-0.12-0.37.pre6.el7.0.1.x86_64\n--> Processing Dependency: libmozjs185.so.1.0()(64bit) for package: elinks-0.12-0.37.pre6.el7.0.1.x86_64\n--> Running transaction check\n---> Package js.x86_64 1:1.8.5-20.el7 will be installed\n---> Package nss_compat_ossl.x86_64 0:0.9.6-8.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository\n Size\n================================================================================\nInstalling:\n elinks x86_64 0.12-0.37.pre6.el7.0.1 base 882 k\nInstalling for dependencies:\n js x86_64 1:1.8.5-20.el7 base 2.3 M\n nss_compat_ossl x86_64 0.9.6-8.el7 base 37 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package (+2 Dependent packages)\n\nTotal download size: 3.2 M\nInstalled size: 9.6 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal 1.7 MB/s | 3.2 MB 00:01 \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : nss_compat_ossl-0.9.6-8.el7.x86_64 1/3 \n Installing : 1:js-1.8.5-20.el7.x86_64 2/3 \n Installing : elinks-0.12-0.37.pre6.el7.0.1.x86_64 3/3 \n Verifying : elinks-0.12-0.37.pre6.el7.0.1.x86_64 1/3 \n Verifying : 1:js-1.8.5-20.el7.x86_64 2/3 \n Verifying : nss_compat_ossl-0.9.6-8.el7.x86_64 3/3 \n\nInstalled:\n elinks.x86_64 0:0.12-0.37.pre6.el7.0.1 \n\nDependency Installed:\n js.x86_64 1:1.8.5-20.el7 nss_compat_ossl.x86_64 0:0.9.6-8.el7 \n\nComplete!\n" ] } |
But user miro must be added to sudoers file.
Creating a file on managed host in user directory:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -m file -a "path=/home/miro/newfile state=touch" managedhost1 | SUCCESS => { "changed": true, "dest": "/home/miro/newfile", "gid": 1000, "group": "miro", "mode": "0664", "owner": "miro", "secontext": "unconfined_u:object_r:user_home_t:s0", "size": 0, "state": "file", "uid": 1000 } |
The same in the root home directory:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -b -m file -a "path=/root/newfile state=touch" managedhost1 | SUCCESS => { "changed": true, "dest": "/root/newfile", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 0, "state": "file", "uid": 0 } |
Informations about the file:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -m file -a "path=/home/miro/newfile" managedhost1 | SUCCESS => { "changed": false, "gid": 1000, "group": "miro", "mode": "0664", "owner": "miro", "path": "/home/miro/newfile", "secontext": "unconfined_u:object_r:user_home_t:s0", "size": 0, "state": "file", "uid": 1000 } |
Changing properties of the file:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -m file -a "path=/home/miro/newfile mode=0400" managedhost1 | SUCCESS => { "changed": true, "gid": 1000, "group": "miro", "mode": "0400", "owner": "miro", "path": "/home/miro/newfile", "secontext": "unconfined_u:object_r:user_home_t:s0", "size": 0, "state": "file", "uid": 1000 } |
Changing ownership of file:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -m file -a "path=/home/miro/newfile owner=root" managedhost1 | FAILED! => { "changed": false, "gid": 1000, "group": "miro", "mode": "0400", "msg": "chown failed: [Errno 1] Operacja niedozwolona: '/home/miro/newfile'", "owner": "miro", "path": "/home/miro/newfile", "secontext": "unconfined_u:object_r:user_home_t:s0", "size": 0, "state": "file", "uid": 1000 } |
The ownership of file can be only changed by root. We must add -b parameter:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -b -m file -a "path=/home/miro/newfile owner=root" managedhost1 | SUCCESS => { "changed": true, "gid": 1000, "group": "miro", "mode": "0400", "owner": "root", "path": "/home/miro/newfile", "secontext": "unconfined_u:object_r:user_home_t:s0", "size": 0, "state": "file", "uid": 0 } |
Creating a user sam in the labservers group:
|
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 |
[miro@controlnode ansible]$ ansible labservers -i inventory -b -m user -a "name=sam" managedhost1.example.com | SUCCESS => { "changed": true, "comment": "", "createhome": true, "group": 4002, "home": "/home/sam", "name": "sam", "shell": "/bin/bash", "state": "present", "system": false, "uid": 4002 } yes managedhost2.example.com | SUCCESS => { "changed": true, "comment": "", "createhome": true, "group": 6004, "home": "/home/sam", "name": "sam", "shell": "/bin/bash", "state": "present", "system": false, "uid": 6004 } |
Adding user sam to the wheel group. Append parameter is needed due to we dont wan’t to wipe out group file:
|
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 |
[miro@controlnode ansible]$ ansible labservers -i inventory -b -m user -a "name=sam append=yes groups=wheel" managedhost1.example.com | SUCCESS => { "append": true, "changed": true, "comment": "", "group": 4002, "groups": "wheel", "home": "/home/sam", "move_home": false, "name": "sam", "shell": "/bin/bash", "state": "present", "uid": 4002 } managedhost2.example.com | SUCCESS => { "append": true, "changed": true, "comment": "", "group": 6004, "groups": "wheel", "home": "/home/sam", "move_home": false, "name": "sam", "shell": "/bin/bash", "state": "present", "uid": 6004 } |
Gathering facts about managed hosts:
|
1 |
[miro@controlnode ansible]$ ansible managedhost1 -i inventory -b -m setup |


