Pragmatism in the real world

Provisioning with Ansible within the Vagrant guest

I’ve been setting up a Vagrant VM for use with some client projects and picked Ansible to do this. Firstly, I played with the Ansible provisioner, but found it a little slow and then I realised that Ansible doesn’t run on Windows.

Rather than migrate what I’d done to Puppet, Evan recommended that I look into running Ansible on the guest instead and provided some hints. This turned out to be quite easy.

These are the steps when starting from the ubuntu/trusty64 base box.

Use the Shell provisioner

As we’re running Ansible on the guest, we use the shell provisioner, so my Vagrantfile contains:

config.vm.provision :shell,
  :keep_color => true,
  :inline => "export PYTHONUNBUFFERED=1 && export ANSIBLE_FORCE_COLOR=1 && cd /vagrant/provisioning && ./init.sh"

This simply tells Vagrant to run init.sh which is stored in the provisioning directory of my project.

I immediately noticed a warning when running vagrant up: “stdin: is not a tty error”. This is due to the way Ubuntu tries to echo a message to a shell that isn’t interactive. To get rid of this, we need to configure Vagrant’s ssh shell to be a non-login one in the Vagrantfile:

config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'"

init.sh

Our shell provisioner needs to do two things:

  1. Install Ansible
  2. Run our playbook

So, init.sh looks like this:

#!/usr/bin/env bash

if [ $(dpkg-query -W -f='${Status}' ansible 2>/dev/null | grep -c "ok installed") -eq 0 ];
then
    echo "Add APT repositories"
    export DEBIAN_FRONTEND=noninteractive
    apt-get install -qq software-properties-common &> /dev/null || exit 1
    apt-add-repository ppa:ansible/ansible &> /dev/null || exit 1

    apt-get update -qq

    echo "Installing Ansible"
    apt-get install -qq ansible &> /dev/null || exit 1
    echo "Ansible installed"
fi

cd /vagrant/provisioning
ansible-playbook setup.yml --connection=local

Obviously, we only want to install Ansible once, so we check the output of dpkg-query and only install if it’s not already installed. Installation is easy enough: we just use apt-get to add install what we need (quietly!) from the ansible ppa as per the docs.

Once Ansible is installed, we can run ansible-playbook with the --connnection-local switch to run out playbook, setup.yml in my case.

At this point, it’s all standard Ansible all the way for your provisioning. It’s just faster and works with Windows.

2 thoughts on “Provisioning with Ansible within the Vagrant guest

  1. Another way to sidestep the issue is to package your own box with Ansible already installed. Depending on the software to be installed, it may be faster to stand up the VM, install the basic and perhaps large sized packages, and then use 'vagrant package' to save that as your new base box. It can be much faster to get to a working state to let Ansible mostly configure the installed packages instead of downloading them at each 'up'. YMMV.

Comments are closed.