How to execute Ad-Hoc commands on remote node using ansible

How to execute Ad-Hoc commands on remote node using ansible

ansible_adhoc.jpg

Test Environment

Ansible Controller
Ansible Node

In this article we will how we can install ansible and manage a remote node by gathering information related to the remote node from the controller node. We will look at some the Ad-hoc modules which we can execute using the ansible tool.

If you are interested in watching the video, here is the youtube video on the same with the step by step procedure.

Procedure –

Step1: Install Ansible from RPM repository

Lets install ansible on the Ansible controller node

Install Ansible
[admin@ansicontrol ~]$ sudo dnf install ansible
...
Installed:
  ansible-2.9.18-1.fc32.noarch                libsodium-1.0.18-3.fc32.x86_64            python3-babel-2.8.0-3.fc32.noarch
  python3-bcrypt-3.1.7-4.fc32.x86_64          python3-cffi-1.14.0-1.fc32.x86_64         python3-chardet-3.0.4-15.fc32.noarch
  python3-cryptography-2.8-3.fc32.x86_64      python3-fluidity-sm-0.2.0-18.fc32.noarch  python3-idna-2.8-6.fc32.noarch
  python3-invoke-1.4.1-1.fc32.noarch          python3-jinja2-2.11.3-1.fc32.noarch       python3-jmespath-0.9.4-4.fc32.noarch
  python3-lexicon-1.0.0-10.fc32.noarch        python3-markupsafe-1.1.1-5.fc32.x86_64    python3-ntlm-auth-1.1.0-9.fc32.noarch
  python3-paramiko-2.7.1-2.fc32.noarch        python3-ply-3.11-7.fc32.noarch            python3-pyasn1-0.4.8-1.fc32.noarch
  python3-pycparser-2.19-2.fc32.noarch        python3-pynacl-1.3.0-6.fc32.x86_64        python3-pysocks-1.7.1-4.fc32.noarch
  python3-pytz-2020.5-1.fc32.noarch           python3-pyyaml-5.4.1-1.fc32.x86_64        python3-requests-2.22.0-8.fc32.noarch
  python3-requests_ntlm-1.1.0-10.fc32.noarch  python3-urllib3-1.25.7-3.fc32.noarch      python3-winrm-0.3.0-9.fc32.noarch
  python3-xmltodict-0.12.0-7.fc32.noarch      sshpass-1.06-9.fc32.x86_64

Complete!

Step2: Validate Ansible Installation

Verify the ansible installation by checking the version information

Validate Ansible version
[admin@ansicontrol ~]$ ansible --version
ansible 2.9.18
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/admin/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.8/site-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.8.2 (default, Feb 28 2020, 00:00:00) [GCC 10.0.1 20200216 (Red Hat 10.0.1-0.8)]

Step3: Create an Inventory file with the nodes to manage

Lets define the inventory file with the hostame or ip address of the remote which we would like to manage.

Create inventory file
[admin@ansicontrol ansible]$ cat /etc/ansible/hosts
...

[stack]

192.168.47.130

Step4: Generate SSH key pairs and copy to remote node

Generate ssh private and publice for user admin.

Generate SSH key-pair
[admin@ansicontrol ansible]$ ssh-keygen -t rsa -C admin
[admin@ansicontrol ansible]$ ls -ltr ~/.ssh/
total 12
-rw-r--r--. 1 admin admin  176 Mar 29 15:53 known_hosts
-rw-r--r--. 1 admin admin  559 Mar 29 15:56 id_rsa.pub
-rw-------. 1 admin admin 2590 Mar 29 15:56 id_rsa

Once the key pair are generated we can copy the public key to the remote node as shown below.

Copy the public key to the remote node
[admin@ansicontrol ansible]$ ssh-copy-id -i ~/.ssh/id_rsa.pub admin@192.168.47.130
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/admin/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
admin@192.168.47.130's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'admin@192.168.47.130'"
and check to make sure that only the key(s) you wanted were added.

Step5: Validate SSH connection

We can validate the remote ssh login using the user admin once the ssh public key has been copied to the remote host. You should be able to login without asking for the password.

Verify the remote ssh login
[admin@ansicontrol ansible]$ ssh admin@192.168.47.130
Web console: https://ansinode.stack.com:9090/ or https://192.168.47.130:9090/

Last login: Mon Mar 29 15:54:35 2021 from 192.168.47.129
[admin@ansinode ~]$ logout
Connection to 192.168.47.130 closed.

Now that we are able to remote ssh to our node using user admin. Lets try to run some Ad-hoc command using ansible. Ad-hoc commands can be used to manage thefiles, packages, users, groups, services and facts about the remote node. The default module for the ansible command-line utility is the ansible.builtin.command module.

Step6: Ping the remote node

As a first step, lets try to use the ping module to ping the remote and check what is the response we get from the remote node.

Ping remote node
[admin@ansicontrol ansible]$ ansible stack -m ping
192.168.47.130 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"

Step7: Check the kernel version and hostname of the remote host

In this step we will run the ad-hoc command ‘uname -a’ to get the hostname and kernal version details as shown below.

Check remote node hostname and kernel version
[admin@ansicontrol ansible]$ ansible stack -a "uname -a"
192.168.47.130 | CHANGED | rc=0 >>
Linux ansinode.stack.com 5.6.6-300.fc32.x86_64 #1 SMP Tue Apr 21 13:44:19 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

Step8: Check the free memory

Verify the free memory that is available on the remote node as shown below.

Check remote node free memory
[admin@ansicontrol ansible]$ ansible stack -a "free -m"
192.168.47.130 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:           1951         257        1220           1         472        1542
Swap:          2047           0        2047

Step9: Check the IP address

Verify the IP address of the remote node as shown below.

Check remote node IP address
[admin@ansicontrol ansible]$ ansible stack -a "ip addr"
192.168.47.130 | CHANGED | rc=0 >>
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:63:e4:47 brd ff:ff:ff:ff:ff:ff
    altname enp2s1
    inet 192.168.47.130/24 brd 192.168.47.255 scope global dynamic noprefixroute ens33
       valid_lft 1093sec preferred_lft 1093sec
    inet6 fe80::c8da:2d7b:8a00:668a/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

Until now we have looked at how we can use the default command module. If we want to use a different module we need to pass the -m module name. For using the shell module we need to pass the module name ‘ansible.builtin.shell’. Lets see some of the examples below.

Step10: Run the shell module to retrieve the hostname of the node

Please note we need to make sure on the shell quoting rules so the local shell retains the variables and passes it to Ansible. For example, using double rather than single quotes in the above example would evaluate the variable on the box you were on.

Check hostname using single quote and double quote to see the difference
[admin@ansicontrol ansible]$ ansible stack -m shell -a 'echo $HOSTNAME'
192.168.47.130 | CHANGED | rc=0 >>
ansinode.stack.com
[admin@ansicontrol ansible]$ ansible stack -m shell -a "echo $HOSTNAME"
192.168.47.130 | CHANGED | rc=0 >>
ansicontrol.stack.com

Step11: Copy files using the copy module

Here, lets create and txt file and use the copy module to copy the file from controller node to the remote node destination location.

Copy file using the copy module and verify in the remote node
[admin@ansicontrol ansible]$ cat /tmp/helloansible.txt
Hello Ansible
[admin@ansicontrol ansible]$ ls -ltr /tmp/helloansible.txt
-rw-rw-r--. 1 admin admin 14 Mar 29 16:37 /tmp/helloansible.txt

[admin@ansicontrol ansible]$ ansible stack -m copy -a 'src=/tmp/helloansible.txt dest=/tmp/helloansible.txt'
192.168.47.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "checksum": "97b63eb592e525b043cf4a8d50fa88ad5fd1f031",
    "dest": "/tmp/helloansible.txt",
    "gid": 1000,
    "group": "admin",
    "md5sum": "a26463d9ebdd339c8ece493267ae5ee5",
    "mode": "0664",
    "owner": "admin",
    "secontext": "unconfined_u:object_r:user_home_t:s0",
    "size": 14,
    "src": "/home/admin/.ansible/tmp/ansible-tmp-1617016144.584841-1823-233756633783429/source",
    "state": "file",
    "uid": 1000

[admin@ansinode ~]$ ls -ltr /tmp/helloansible.txt
-rw-rw-r--. 1 admin admin 14 Mar 29 16:39 /tmp/helloansible.txt

Step12: Changing file ownership and permissions using the file module and Managing files

We can also change the ownership and permissions of the files using the file module as shown below. First lets try to change the permissions on the file.

Change permission of the file on remote node
[admin@ansicontrol ansible]$ ansible stack -m file -a "dest=/tmp/helloansible.txt mode=600"
192.168.47.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "gid": 1000,
    "group": "admin",
    "mode": "0600",
    "owner": "admin",
    "path": "/tmp/helloansible.txt",
    "secontext": "unconfined_u:object_r:user_home_t:s0",
    "size": 14,
    "state": "file",
    "uid": 1000

[admin@ansinode ~]$ ls -ltr /tmp/helloansible.txt
-rw-------. 1 admin admin 14 Mar 29 16:39 /tmp/helloansible.txt

Now lets try to change ownership of the file to root:root and see what happens

Change ownership of the remote node file to root without privilage
[admin@ansicontrol ansible]$ ansible stack -m file -a "dest=/tmp/helloansible.txt owner=root group=root"
192.168.47.130 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "gid": 1000,
    "group": "admin",
    "mode": "0600",
    "msg": "chown failed: [Errno 1] Operation not permitted: b'/tmp/helloansible.txt'",
    "owner": "admin",
    "path": "/tmp/helloansible.txt",
    "secontext": "unconfined_u:object_r:user_home_t:s0",
    "size": 14,
    "state": "file",
    "uid": 1000
}

As you can see the user admin does not have the privilage to change the ownership of the file. Lets try to elevate the privilage to root user to change the ownership.

Change ownership of the remote node file to root with privilage escalation and validate the remote node file
[admin@ansicontrol ansible]$ ansible stack -m file -a "dest=/tmp/helloansible.txt owner=root group=root" --become --ask-become-pass
BECOME password:
192.168.47.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "gid": 0,
    "group": "root",
    "mode": "0600",
    "owner": "root",
    "path": "/tmp/helloansible.txt",
    "secontext": "unconfined_u:object_r:user_home_t:s0",
    "size": 14,
    "state": "file",
    "uid": 0
}

[admin@ansinode ~]$ ls -ltr /tmp/helloansible.txt
-rw-------. 1 root root 14 Mar 29 16:39 /tmp/helloansible.txt

We can also manage the directories on the remote node as shown below.

Create and remove directory from remote node using the file module and validate on the remote node
[admin@ansicontrol ansible]$ ansible stack -m file -a "dest=/tmp/stack state=directory"

[admin@ansinode ~]$ ls -ltr /tmp/stack/
total 0

[admin@ansicontrol ansible]$ ansible stack -m file -a "dest=/tmp/stack state=absent"

[admin@ansinode ~]$ ls -ltr /tmp/stack/
ls: cannot access '/tmp/stack/': No such file or directory

Step13: Managing the packages on the remote node using yum module

Here we can install, update, remove the packages on the remote machine using the yum module as shown.

Managing Packages on the remote node using the yum module
[admin@ansicontrol ansible]$ ansible stack -m yum -a 'name=sscg state=present' --become --ask-become-pass
BECOME password:
192.168.47.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "msg": "",
    "rc": 0,
    "results": [
        "Installed: sscg-2.6.2-1.fc32.x86_64"
    ]
}

[admin@ansicontrol ansible]$ ansible stack -m yum -a 'name=sscg state=latest' --become --ask-become-pass
BECOME password:
192.168.47.130 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "msg": "Nothing to do",
    "rc": 0,
    "results": []
}

[admin@ansicontrol ansible]$ ansible stack -m yum -a 'name=sscg state=absent' --become --ask-become-pass
BECOME password:
192.168.47.130 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": true,
    "msg": "",
    "rc": 0,
    "results": [
        "Removed: sscg-2.6.2-1.fc32.x86_64"
    ]
}

We can also manage users and groups using the ‘user’ module and services using the service module. Also one of the most important thing is about capturing the information about the remote node using the setup module as shown below.

Check remote node facts collected using the setup module
[admin@ansicontrol ansible]$ ansible stack -m setup
192.168.47.130 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.47.130"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::c8da:2d7b:8a00:668a"
        ],
        "ansible_apparmor": {
            "status": "disabled"
        },
...

Hope you enjoyed reading this article. Thank you..