Combining Ansible and Fabric

Written by Yannik Messerli - 10 January 2015

Ansible is a python software to automate the configuration of systems, software deployements and other advanced stuff. Instead of writing dozen of shell commands and repeat them again and again for your different hosts, just write some “playbooks”. They are sort of set of ordered commands that Ansible can run against hosts you will give him.

Fabric is a python library to help running a set of operations locally and/or on one (or multiple) host(s). It is useful to compile, sync, or migrate data before/after deploying an app.

While both seem similar in their description, they serve really different purposes. Ansible is useful for configuring different servers that will host one or multiple applications. Fabric is used to install one particular app. One example is the case of Capistrano. This software deploy one application on one server using its own startegy. (It creates multiple folders for the different releases.) Fabric can mimic the same strategy using Fabistrano. However, prerequies like python, git, etc, need to be installed beforehand. If Ansible can help you here, there is one drawback though: they haven’t really been designed to play well together.

				env.hosts = ["localhost:2221", "localhost:2222", "localhost:2223"]
				env.user = "vagrant"
				env.password = "..."

Fabric hosts configuration

Indeed, both Fabric and Ansible need to know where they will work. Since one is designed to setup a fairly large number of servers, it requires a small file with minimal information about ssh connections. In the other hand, Fabric requires information for mostly one server, stored in an environment variable (see image 1 and 2). The challenge was then to combine both methods.

vagrant1	ansible_ssh_host=localhost 	ansible_ssh_port=2221	ansible_ssh_user=vagrant 	ansible_ssh_private_key_file=... 	ansible_ssh_pass=...
vagrant2	ansible_ssh_host=localhost	ansible_ssh_port=2222	ansible_ssh_user=vagrant 	ansible_ssh_private_key_file=... 	ansible_ssh_pass=...
vagrant3	ansible_ssh_host=localhost	ansible_ssh_port=2223	ansible_ssh_user=vagrant 	ansible_ssh_private_key_file=... 	ansible_ssh_pass=...

Ansible hosts file

Note: I’m using the term ‘provision’ in the same sense that Vagrant is using it, e.i. the process to install and configure a VM. I don’t think it is the best sense though…

A fix

An obvious solution would be to pass to the Fabric script ansible host configurations. But, I struggled to find the way to pass it, e.g. to pass ansible_ssh_port or ansible_ssh_private_key_file. Indeed - if I am not yet completly familiar with Ansible, it really looks there is a security mecanism that mutes these two variables. Doesn’t it?

A workaround is to setup Fabric to connect to the remote server(s) using a ssh key we would setup beforehand, during the provsionning process in Ansible playbook. The key will be stored in the provision folder and will be used with any host. Note that this is definetely not the most secure way to do this. ;-)

Create a key to access the remote server(s)

We will use ssh-keygen script to generate a key pair: a public and a private key. This utility is usually installed on most of the systems: it comes with OpenSSH. First, create a directory under your provision folder, such as ssh. Create a file id_rsa in it. Then, type:

ssh-keygen -t rsa

It will ask you where you wish to create the key pair. (You want to create alongside your playbook in the folder ssh, right?) It should look like this:

 Enter file in which to save the key (/home/yannik/.ssh/id_rsa): ./ssh/id_rsa

The next question is about the passphrase - a security mecanism that protect your key from thieves. However, it requires you to enter the passphrase each time you want to use the key, which is not ideal when using it in Ansible. For the purpose of this tutorial, I will leave it blank.

Enter passphrase (empty for no passphrase):

At the end, you will get a nice random picture and your public key will be located at ssh/

Prepare the host - the playbook

So, you have probably a long playbook that is installing crazy packages on your server. At some point you want to run a Fabric command. Then, you can include these tasks to your playbook at the relevant position:

- name: add public for you ansible user on the server
  authorized_key: user= { {ansible_user_id}} key=" { { lookup('file', 'ssh/') } }"
- name: change key permision to avoid any error from ssh
  local_action: command chmod 600 ssh/
- name: run your fab command and pass the key file to fabric's ssh system
  local_action: command fab your_command -H : -u  -i ssh/id_rsa

You can run multiple Fabric command in your playbook.

Final words

Ansible is really great and powerful. I also really love Fabric and its simple interface - Fabristrano is definetely an important component in my deployement startegy. That said, this integration guide is probably not the best. So, I will probably follow up on this if I can find a better solution. Any help is welcomed in the comments below.

Written by

Yannik Messerli