» Ansible Local Provisioner

Provisioner name: ansible_local

The Vagrant Ansible Local provisioner allows you to provision the guest using Ansible playbooks by executing ansible-playbook directly on the guest machine.

Warning:If you are not familiar with Ansible and Vagrant already, we recommend starting with the shell provisioner. However, if you are comfortable with Vagrant already, Vagrant is a great way to learn Ansible.

» Setup Requirements

The main advantage of the Ansible Local provisioner in comparison to the Ansible (remote) provisioner is that it does not require any additional software on your Vagrant host.

On the other hand, Ansible must obviously be installed on your guest machine(s).

Note: By default, Vagrant will try to automatically install Ansible if it is not yet present on the guest machine (see the install option below for more details).

» Usage

This page only documents the specific parts of the ansible_local provisioner. General Ansible concepts like Playbook or Inventory are shortly explained in the introduction to Ansible and Vagrant.

The Ansible Local provisioner requires that all the Ansible Playbook files are available on the guest machine, at the location referred by the provisioning_path option. Usually these files are initially present on the host machine (as part of your Vagrant project), and it is quite easy to share them with a Vagrant Synced Folder.

» Simplest Configuration

To run Ansible from your Vagrant guest, the basic Vagrantfile configuration looks like:

  1. Vagrant.configure("2") do |config|
  2. # Run Ansible from the Vagrant VM
  3. config.vm.provision "ansible_local" do |ansible|
  4. ansible.playbook = "playbook.yml"
  5. end
  6. end

Requirements:

  • The playbook.yml file is stored in your Vagrant's project home directory.

  • The default shared directory is enabled (./vagrant).

» Options

This section lists the specific options for the Ansible Local provisioner. In addition to the options listed below, this provisioner supports the common options for both Ansible provisioners.

  • install (boolean) - Try to automatically install Ansible on the guest system.

This option is enabled by default.

Vagrant will try to install (or upgrade) Ansible when one of these conditions are met:

  • Ansible is not installed (or cannot be found).
  • The version option is set to "latest".
  • The current Ansible version does not correspond to the version option.

Attention:There is no guarantee that this automated installation will replace a custom Ansible setup, that might be already present on the Vagrant box.

  • install_mode (:default, :pip, or :pip_args_only) - Select the way to automatically install Ansible on the guest system.

    • :default: Ansible is installed from the operating system package manager. This mode doesn't support version selection. For many platforms (e.g Debian, FreeBSD, OpenSUSE) the official package repository is used, except for the following Linux distributions:
      • On Ubuntu-like systems, the latest Ansible release is installed from the ppa:ansible/ansible repository. The compatibility is maintained only for active long-term support (LTS) versions.
      • On RedHat-like systems, the latest Ansible release is installed from the EPEL repository.
    • :pip: Ansible is installed from PyPI with pip package installer. With this mode, Vagrant will systematically try to install the latest pip version. With the :pip mode you can optionally install a specific Ansible release by setting the version option.

Example:

  1. config.vm.provision "ansible_local" do |ansible|
  2. ansible.playbook = "playbook.yml"
  3. ansible.install_mode = "pip"
  4. ansible.version = "2.2.1.0"
  5. end

With this configuration, Vagrant will install pip and then execute the command

  1. sudo pip install --upgrade ansible==2.2.1.0

As-is pip is installed if needed via a default command which looks like

  1. ```shell
  2. curl https://bootstrap.pypa.io/get-pip.py | sudo python
  3. ```

This can be problematic in certain scenarios, for example, when behind a proxy. It is possible to override this default command by providing an explicit command to run as part of the config using pip_install_cmd. For example:

  1. ```ruby
  2. config.vm.provision "ansible_local" do |ansible|
  3. ansible.playbook = "playbook.yml"
  4. ansible.install_mode = "pip"
  5. ansible.pip_install_cmd = "https_proxy=http://your.proxy.server:port curl -s https://bootstrap.pypa.io/get-pip.py | sudo https_proxy=http://your.proxy.server:port python"
  6. ansible.version = "2.2.1.0"
  7. end
  8. ```

In this case case pip will be installed via the command:

  1. ```shell
  2. https_proxy=http://your.proxy.server:port curl -s https://bootstrap.pypa.io/get-pip.py | sudo https_proxy=http://your.proxy.server:port python
  3. ```

If pip_install_cmd is not provided in the config, then pip is installed via the default command.- :pip_args_only: This mode is very similar to the :pip mode, with the difference that in this case no pip arguments will be automatically set by Vagrant.

  1. Example:
  2. ```ruby
  3. config.vm.provision "ansible_local" do |ansible|
  4. ansible.playbook = "playbook.yml"
  5. ansible.install_mode = "pip_args_only"
  6. ansible.pip_args = "-r /vagrant/requirements.txt"
  7. end
  8. ```
  9. With this configuration, Vagrant will install `pip` and then execute the command
  10. ```shell
  11. sudo pip install -r /vagrant/requirements.txt
  12. ```

The default value of install_mode is :default, and any invalid value for this option will silently fall back to the default value.

  • pip_args (string) - When Ansible is installed via pip, this option allows the definition of additional pip arguments to be passed along on the command line (for example, —index-url).

By default, this option is not set.

Example:

  1. config.vm.provision "ansible_local" do |ansible|
  2. ansible.playbook = "playbook.yml"
  3. ansible.install_mode = :pip
  4. ansible.pip_args = "--index-url https://pypi.internal"
  5. end

With this configuration, Vagrant will install pip and then execute the command

  1. sudo pip install --index-url https://pypi.internal --upgrade ansible
  • provisioning_path (string) - An absolute path on the guest machine where the Ansible files are stored. The ansible-galaxy and ansible-playbook commands are executed from this directory. This is the location to place an ansible.cfg file, in case you need it.

The default value is /vagrant.

  • tmp_path (string) - An absolute path on the guest machine where temporary files are stored by the Ansible Local provisioner.

The default value is /tmp/vagrant-ansible

» Tips and Tricks

» Install Galaxy Roles in a path owned by root

Disclaimer: This tip is not a recommendation to install galaxy roles out of the vagrant user space, especially if you rely on ssh agent forwarding to fetch the roles.

Be careful that ansible-galaxy command is executed by default as vagrant user. Setting galaxyroles_path to a folder like /etc/ansible/roles will fail, and ansible-galaxy will extract the role a second time in /home/vagrant/.ansible/roles/. Then if your playbook uses become to run as root, it will fail with a "role was not found"_ error.

To work around that, you can use ansible.galaxy_command to prepend the command with sudo, as illustrated in the example below:

  1. Vagrant.configure(2) do |config|
  2. config.vm.box = "centos/7"
  3. config.vm.provision "ansible_local" do |ansible|
  4. ansible.become = true
  5. ansible.playbook = "playbook.yml"
  6. ansible.galaxy_role_file = "requirements.yml"
  7. ansible.galaxy_roles_path = "/etc/ansible/roles"
  8. ansible.galaxy_command = "sudo ansible-galaxy install --role-file=%{role_file} --roles-path=%{roles_path} --force"
  9. end
  10. end

» Ansible Parallel Execution from a Guest

With the following configuration pattern, you can install and execute Ansible only on a single guest machine (the "controller") to provision all your machines.

  1. Vagrant.configure("2") do |config|
  2. config.vm.box = "ubuntu/trusty64"
  3. config.vm.define "node1" do |machine|
  4. machine.vm.network "private_network", ip: "172.17.177.21"
  5. end
  6. config.vm.define "node2" do |machine|
  7. machine.vm.network "private_network", ip: "172.17.177.22"
  8. end
  9. config.vm.define 'controller' do |machine|
  10. machine.vm.network "private_network", ip: "172.17.177.11"
  11. machine.vm.provision :ansible_local do |ansible|
  12. ansible.playbook = "example.yml"
  13. ansible.verbose = true
  14. ansible.install = true
  15. ansible.limit = "all" # or only "nodes" group, etc.
  16. ansible.inventory_path = "inventory"
  17. end
  18. end
  19. end

You need to create a static inventory file that corresponds to your Vagrantfile machine definitions:

  1. controller ansible_connection=local
  2. node1 ansible_ssh_host=172.17.177.21 ansible_ssh_private_key_file=/vagrant/.vagrant/machines/node1/virtualbox/private_key
  3. node2 ansible_ssh_host=172.17.177.22 ansible_ssh_private_key_file=/vagrant/.vagrant/machines/node2/virtualbox/private_key
  4. [nodes]
  5. node[1:2]

And finally, you also have to create an ansible.cfg file to fully disable SSH host key checking. More SSH configurations can be added to the ssh_args parameter (e.g. agent forwarding, etc.)

  1. [defaults]
  2. host_key_checking = no
  3. [ssh_connection]
  4. ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes