title: Vagrant: running Ansible provisioning after all VMs booted, Ansible cannot connect to all hosts
body: <p>I'm trying to figure out how to use Ansible with Vagrant the proper way. By default, it seems Vagrant is isolating Ansible execution per box and executes playbooks after each box partially as it applies to that single box in the loop. I find this VERY counterproductive and I have tried tricking Vagrant into executing a playbook across all of the hosts AFTER all of them booted, but it seems Ansible, when started from Vagrant never sees more than a single box at a time.</p>
  
  <p>Edit: these are the version I am working with:</p>
  
  <p>Vagrant: 2.2.6
  Ansible: 2.5.1
  Virtualbox: 6.1</p>
  
  <p>The playbook (with the hosts.ini) by itsef executes without issues when I run it stand-alone with the ansible-playbook executable after the hosts come up, so the problem is with my Vagrant file. I just cannot figure it out.</p>
  
  <p>This is the Vagrantfile:</p>
  
  <pre class="lang-rb prettyprint-override"><code># -*- mode: ruby -*-
  # vi: set ft=ruby :
  
  IMAGE_NAME = "ubuntu/bionic64"
  
  Vagrant.configure("2") do |config|
      config.ssh.insert_key = false
      config.vm.box = IMAGE_NAME
  
      # Virtualbox configuration
      config.vm.provider "virtualbox" do |v|
          v.memory = 4096
          v.cpus = 2
          #v.linked_clone = true
      end
  
      # master and node definition
      boxes = [
          { :name =&gt; "k8s-master", :ip =&gt; "192.168.50.10" },
          { :name =&gt; "k8s-node-1", :ip =&gt; "192.168.50.11" }
      ]
  
      boxes.each do |opts|
          config.vm.define opts[:name] do |config|
              config.vm.hostname = opts[:name]
              config.vm.network :private_network, ip: opts[:ip]
  
              if opts[:name] == "k8s-node-1"
                  config.vm.provision "ansible_local" do |ansible|
                      ansible.compatibility_mode = "2.0"
                      ansible.limit = "all"
                      ansible.config_file = "ansible.cfg"
                      ansible.become = true
                      ansible.playbook = "playbook.yml"
                      ansible.groups = {
                          "masters" =&gt; ["k8s-master"],
                          "nodes" =&gt; ["k8s-node-1"]
                      }
                  end
              end
          end
      end
  end
  </code></pre>
  
  <p>ansible.cfg</p>
  
  <pre><code>[defaults]
  connection = smart
  timeout = 60
  deprecation_warnings = False
  host_key_checking = False
  inventory = hosts.ini
  
  [ssh_connection]
  ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes
  </code></pre>
  
  <p>hosts.ini</p>
  
  <pre><code>[masters]
  k8s-master ansible_host=192.168.50.10 ansible_user=vagrant
  
  [nodes]
  k8s-node-1 ansible_host=192.168.50.11 ansible_user=vagrant
  
  [all:vars]
  ansible_python_interpreter=/usr/bin/python3
  ansible_ssh_user=vagrant
  ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key
  </code></pre>
  
  <p>playbook.yml</p>
  
  <pre><code>- hosts: all
    become: yes
    tasks:
      - name: Update apt cache.
        apt: update_cache=yes cache_valid_time=3600
        when: ansible_os_family == 'Debian'
  
      - name: Ensure swap is disabled.
        mount:
          name: swap
          fstype: swap
          state: absent
  
      - name: Disable swap.
        command: swapoff -a
        when: ansible_swaptotal_mb &gt; 0
  
      - name: create the 'mobile' user
        user: name=mobile append=yes state=present createhome=yes shell=/bin/bash
  
      - name: allow 'mobile' to have passwordless sudo
        lineinfile:
          dest: /etc/sudoers
          line: 'mobile ALL=(ALL) NOPASSWD: ALL'
          validate: 'visudo -cf %s'
  
      - name: set up authorized keys for the mobile user
        authorized_key:
          user: mobile
          key: "{{ lookup('pipe','cat ssh_keys/*.pub') }}"
          state: present
          exclusive: yes
  
  - hosts: all
    become: yes
    tasks:
     - name: install Docker
       apt:
         name: docker.io
         state: present
         update_cache: true
  
     - name: install APT Transport HTTPS
       apt:
         name: apt-transport-https
         state: present
  
     - name: add Kubernetes apt-key
       apt_key:
         url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
         state: present
  
     - name: add Kubernetes' APT repository
       apt_repository:
        repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
        state: present
        filename: 'kubernetes'
  
     - name: install kubelet
       apt:
         name: kubelet=1.17.0-00
         state: present
         update_cache: true
  
     - name: install kubeadm
       apt:
         name: kubeadm=1.17.0-00
         state: present
  
  - hosts: masters
    become: yes
    tasks:
     - name: install kubectl
       apt:
         name: kubectl=1.17.0-00
         state: present
         force: yes
  
  - hosts: k8s-master
    become: yes
    tasks:
      - name: check docker status
        systemd:
          state: started
          name: docker
  
      - name: initialize the cluster
        shell: kubeadm init --apiserver-advertise-address 192.168.50.10 --pod-network-cidr=10.244.0.0/16 &gt;&gt; cluster_initialized.txt
        args:
          chdir: $HOME
          creates: cluster_initialized.txt
  
      - name: create .kube directory
        become: yes
        become_user: mobile
        file:
          path: $HOME/.kube
          state: directory
          mode: 0755
  
      - name: copy admin.conf to user's kube config
        copy:
          src: /etc/kubernetes/admin.conf
          dest: /home/mobile/.kube/config
          remote_src: yes
          owner: mobile
  
      - name: install Pod network
        become: yes
        become_user: mobile
        shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml &gt;&gt; pod_network_setup.txt
        args:
          chdir: $HOME
          creates: pod_network_setup.txt
  
  - hosts: k8s-master
    become: yes
    gather_facts: false
    tasks:
      - name: get join command
        shell: kubeadm token create --print-join-command 2&gt;/dev/null
        register: join_command_raw
  
      - name: set join command
        set_fact:
          join_command: "{{ join_command_raw.stdout_lines[0] }}"
  
  - hosts: nodes
    become: yes
    tasks:
      - name: check docker status
        systemd:
          state: started
          name: docker
  
      - name: join cluster
        shell: "{{ hostvars['k8s-master'].join_command }} &gt;&gt; node_joined.txt"
        args:
          chdir: $HOME
          creates: node_joined.txt
  </code></pre>
  
  <p>The moment the playbook tries to execute against k8s-master, it fails like this:</p>
  
  <pre><code>fatal: [k8s-master]: UNREACHABLE! =&gt; {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname k8s-master: Temporary failure in name resolution", "unreachable": true}
  </code></pre>
  
  <p>The host is up. SSH works.</p>
  
  <p>Who can help me sort this out?</p>
  
  <p>Thanks!</p>