Simple Ansible paybook without Python installed in target machines

Somak Das
4 min readJul 8, 2017

In my previous post related to Setting up and executing basic Ansible playbook, we have seen what Ansible is, learnt how to setup Ansible and seen how to write a basic playbook and execute it.

In this post we will be looking into how to build our playbook when there is no python installed on the target machines. By default Ansible modules require python to be present in the target machines, since they are all written in python.

So 1st of all lets understand why this may be required and then we will proceed to the different ways to achieve that. There are mainly two case where this might be required:

  • The first case is installing python-simplejson on older (Python 2.4 and before) hosts that need it as a dependency to run modules, since nearly all core modules require it.
  • Another is speaking to any devices such as routers that do not have any Python installed. In any other case, using the shell or command module is much more appropriate.

So how do we achieve this in Ansible?

By using the raw module. It executes a low-down and dirty SSH command. To know more about the raw module in Ansible please visit here.

Note: If using raw from a playbook, you may need to disable fact gathering using gather_facts: no if you’re using raw to bootstrap python onto the machine.* If you want to execute a command securely and predictably, it may be better to use the command or shell modules instead.* the environment keyword does not work with raw normally, it requires a shell which means it only works if executable is set or using the module with privilege escalation (become).

Now lets write the same playbook as we did in the previous post in step-4 for creating a new user in the remote machine and enable ssh connection for the new user using the raw module. We are not going to use the raw module to simple bootstrap python dependencies, rather we will see how to write the playbook so that it doesn't depend on python in the remote machines. So lets check out the playbook.

Note: For the below Ansible playbook I have assumed that we have a ansible_user and ansible_ssh_pass to run the playbook to the remote machines. Sample host file will be as follows: 192.0.2.50(your remote machine IP address or host name) ansible_user=<someuser> ansible_ssh_pass=<your_password>

Playbook1:

---
- hosts: all

gather_facts: False
become: True
vars:
user: user1
passw: Password1$
tasks:- name: Check if user exists
register: user1_exists
raw: getent passwd {{user}}
ignore_errors: true
- name: delete user1 user
raw: userdel {{user}} -r
when: user1_exists|success
- name: add user user1
raw: useradd -m {{user}}
- name: add user password
raw: usermod --password $(echo {{passw}} | openssl passwd -1 -stdin) {{user}}
- name: make dir .ssh in crvp home
raw: mkdir ../{{user}}/.ssh
- name: change ownership to crvp user
raw: chown {{user}}:{{user}} ../{{user}}/.ssh
- name: give required permission to .ssh
raw: chmod 777 ../{{user}}/.ssh/
- name: create authorized_keys
raw: touch ../{{user}}/.ssh/authorized_keys
- name: change ownership to crvp user
raw: chown {{user}}:{{user}} ../{{user}}/.ssh/authorized_keys
- name: give required permission to authorized_keys
raw: chmod 666 ../{{user}}/.ssh/authorized_keys

The above playbook is pretty self explanatory. 1st thing to notice is the gather_facts which is set to false, since we are using ansible raw module.

In the variable section we have declared the user name and the password for the user which we are going to create in our remote machines.

In the task list, the 1st and the 2nd task is using a conditional and Jinja2 expressions. We have used condition and ignore_errors in the 1st task to make sure it gets executed even if there is an error response and the 2nd task will get executed depending on the response we get from task 1.To more about conditionals in Ansible please check here.

In the next script I have finally copied the ssh key from our Ansible host machine into authorized_keys in the remote machine, so that we can SSH into those remote machines using the new user and the new key.

Note: At the time when I was wrote these scripts, the become_user was not working due to a bug. Thus I had to break my script into two scripts and do the file copy operation in the 2nd scripts as the newly created user. May be its fixed now I will check once and update.

Playbook2:

— -
- hosts: all
gather_facts: Falsevars:
user: user1
passw: Password1$
tasks:- name: local scp — copy key file into authorized_keys
local_action: “command scp ../.ssh/user1_user.pub {{ansible_user}}@{{inventory_hostname}}:../{{user}}/.ssh/authorized_keys”
- name: give required permission to .ssh for user
raw: chmod 0700 ../{{user}}/.ssh/
become: true
- name: give required permission to authorized_keys for user
raw: chmod 0600 ../{{user}}/.ssh/authorized_keys
become: true

In this playbook as we mentioned we are copying the public key for ssh into the authorized_keys of the newly created user. For file copy I have used local_action module, which helps us to run any command in the ansible host itself rather than in the remote machines. Inside the local_action we have used scp command which is used to copy file over SSH so here it copies the ../.ssh/user1_user.pub file to ../user1/.ssh/authorized_keys.

To know more about local_action check here.

So after running these two scripts in any number of remote machines (mentioned in the host file), we should be able to ssh onto those remote machines with the new user that we have created.

Hope this post would be helpful for those who wants to write playbook without python dependency in the remote machines.

--

--

Somak Das

Cloud architect | Polyglot Programmer | Digital Entrepreneur | Affiliate marketer | www.instagram.com/digital_somak