4
votes

Firstly, I've seen lots of similarly tagged posts but nothing that works.. I have an existing Ansible host that I successfully use to deploy software to other servers. I wanted to setup a test environment using Vagrant to run my existing playbook(s) without any changes.

I've installed Ansible and Vagrant on a different server and copied over the playbook, inventory and group/host vars files.

However, when I run vagrant up which invokes the playbook on the Vagrant host, using an Ansible (remote) provisioner, it gives the following message when running against hosts: localhost

PLAY [Set fact for later use] **************************************************
skipping: no hosts matched

The playbook (extract) looks like this:

- name: Set fact for later use
  hosts: localhost
  tasks:
    - name: set number of hosts for later use
      set_fact: num_hosts="{{ groups[tagname] | length }}" 

I've also tried:

- name: Set fact for later use
  hosts: 127.0.0.1
  connection: local
  tasks:
    - name: set number of hosts for later use
      set_fact: num_hosts="{{ groups[tagname] | length }}"

My static inventory (extract) looks like this:

'# Ungrouped hosts, specify before any group headers.
localhost ansible_connection=local

I've tried dynamic inventory and various combinations of localhost/127.0.0.1 in the playbook and the inventory file but the step is always skipped on the Vagrant host.

3

3 Answers

3
votes

Adding localhost to ansible.limit has solved my problem I launch provisioning only once per Vagrantfile execution, so I use

ansible.limit = "all,localhost"

In case when you launch Ansible provisioning for each VM you may use something like

ansible.limit = "#{machine.vm.hostname},localhost"

The limit key passed directly to Ansible, and Vagrant set it in any case. In case when limit not specified directly it will be set to current VM host name, so that Ansible will work only with VM which is being provisioned right now.

2
votes

I'm going to answer based of your first playbook example:

- name: Set fact for later use
  hosts: localhost
  tasks:
    - name: set number of hosts for later use
      set_fact: num_hosts="{{ groups[tagname] | length }}"

In this playbook extract, when you say hosts: localhost, you are not actually telling ansible to run the task on localhost (127.0.0.1). Instead, ansible is expecting 'localhost' to be a heading in a 'hosts' file which, by default, is found here: /etc/ansible/hosts.

To demonstrate this, take a look at the structure of the ansible playbook in Wallabag's Docker repo:

Wallabag's Ansible Setup

Notice how there is an ansible playbook (entrypoint.yml) and another hosts file. The hosts file reads:

[localhost]
localhost

This file, known as an Inventory, provides a list of hosts on which the playbook should be run. Now look at the first two lines of the entrypoints.yml playbook:

---
- hosts: localhost
...

When we say that the entry for hosts is 'localhost', we are not using localhost to mean 127.0.0.1, but we are simply referring to all of the hosts in the hosts file under the [localhost] heading.


Thus, if we wanted to keep the same functionality, but changed the hosts file to:

[bingo]
localhost

we would want to change the second line of entrypoint.yml to:

---
- hosts: bingo
...
0
votes

Basically, I know the playbook works because I run it all the time. I tried running it manually on the Vagrant host and it ran as expected. Then it was simply a case of replacing the Ansible provisioner with the Vagrant host_shell provisioner which is available via a plugin:

vagrant plugin install vagrant-host-shell

For completeness:

config.vm.provision :host_shell, inline: <<-SHELL
  cd ansible
  ansible-playbook -v -i inventory install.yml --extra-vars '{"db":"mysql"}'
  SHELL