# How to manage Vagrant VM lifecycle with ansible?

**URL:** <https://forum.ansible.com/t/how-to-manage-vagrant-vm-lifecycle-with-ansible/44743>\
**Category:** Get Help\
**Tags:** molecule, ansible-core\
**Created:** [October 27, 2025, 8:22am UTC](https://forum.ansible.com/t/how-to-manage-vagrant-vm-lifecycle-with-ansible/44743 "2025-10-27T08:22:18Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![pushrbx](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/pushrbx/32/9718_2.png) [@pushrbx](https://forum.ansible.com/u/pushrbx)\
**Post date:** [October 27, 2025, 8:22am UTC](https://forum.ansible.com/t/how-to-manage-vagrant-vm-lifecycle-with-ansible/44743/1 "2025-10-27T08:22:18Z")

</div>

I’m trying to create a molecule scenario where through Vagrant a VM would be created, then the tests would be ran against that. I tried to ask LLMs but they get very confused with the pre-ansible-native vs ansible-native configuration and they are giving me non-sense, so I’m trying my luck here. I understand the ansible-native config of molecule that far that it’s my responsibility to create a `create.yml` playbook which would spin up a VM through Vagrant.  
I can’t find any collection which would be like:

```auto
tasks:
  - name: Create virtual machine
    vagrant:
      box: ....

```

rather I ended up with the solution to execute vagrant like this:

```auto
tasks:
  - name: Create virtual machine
    command:
      cmd: vagrant up
      # Vagrantfile is in the scenario's directory
      chdir: "{{ lookup('env', 'MOLECULE_SCENARIO_DIRECTORY') }}"

```

I think the downside of this approach is that I can’t really register the state “natively” whether the virtual machine is running and ready. Is there a more “native” method to do “molecule test start → ensure virtual machine created via vagrant → ensure virtual machine is running through vagrant” → run tests?

---

<div class="post-metadata">

**Author:** ![pushrbx](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/pushrbx/32/9718_2.png) [@pushrbx](https://forum.ansible.com/u/pushrbx)\
**Post date:** [November 13, 2025, 2:39pm UTC](https://forum.ansible.com/t/how-to-manage-vagrant-vm-lifecycle-with-ansible/44743/2 "2025-11-13T14:39:40Z")

</div>

I’ve solved it on my own. Below are the things I’ve done if anyone else needs it.  
The best answer I could find was a custom inventory plugin.

The inventory plugin which uses `vagrant global-state` command to find hosts:

> <https://gist.github.com/pushrbx/dd651e9ff677650b394bb4cc95b05636>

Place this inside `plugins/inventory` folder, and add an empty ` __init__.py` file next to it.  
I’ve used the following repo as a baseline for it: [vagrant-ansible-dynamic-inventory/vagrant\_inventory.py at master · chornberger-c2c/vagrant-ansible-dynamic-inventory · GitHub](https://github.com/chornberger-c2c/vagrant-ansible-dynamic-inventory/blob/master/vagrant_inventory.py)  
I just upgraded it to be a module intentory plugin not an inventory script.

Add an `inventory.yml` file to your molecule scenario directory with the following contents:

```auto
---
plugin: vagrant
vagrantfile_path: ${MOLECULE_SCENARIO_DIRECTORY}/Vagrantfile
inventory_hostname: host
groups:
  my_machines:
    hosts: {}

```

Your `molecule.yml` file for your scenario should look like this:

```auto
---
ansible:
  executor:
    args:
      ansible_playbook:
        - --inventory=${MOLECULE_SCENARIO_DIRECTORY}/inventory.yml
  cfg:
    defaults:
      collections_path: collections
      library: "$MOLECULE_PROJECT_DIRECTORY/.."
      inventory_plugins: "$MOLECULE_SCENARIO_DIRECTORY/../../plugins/inventory"
    inventory:
      enable_plugins: host_list, script, auto, yaml, ini, toml, vagrant

```

Key highlights:

- `enable_plugins` enables the custom vagrant inventory plugin
- `inventory_plugins` tells ansible to look for plugins in the `plugins/inventory` directory

The `create.yml` playbook for the molecule scenario should look like the following:

```auto
---
- name: Create virtual machine
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Start test VM through vagrant
      ansible.builtin.command:
        cmd: vagrant up
        chdir: "{{ lookup('env', 'MOLECULE_SCENARIO_DIRECTORY') }}"
      register: vagrant_up
      changed_when: "'already running' not in vagrant_up.stderr"
    - name: Add vm to inventory
      ansible.builtin.meta: refresh_inventory
    - name: Validate inventory
      assert:
        that:
          - groups['my_machine'] | length > 0
- name: Wait for vm to be ready
  hosts: "{{ groups['my_machines'] | map('extract', hostvars, 'inventory_hostname') | list }}"
  gather_facts: false
  vars:
    acceptable_systemd_states:
      - running
      - degraded
  tasks:
    - name: Wait for systemd to settle
      ansible.builtin.shell: /bin/sh -c 'systemctl is-system-running --wait || systemctl is-system-running'
      register: systemd_status
      until: systemd_status.rc == 0 or (systemd_status.stdout_lines | last | trim) in acceptable_systemd_states
      failed_when: false
      changed_when: false
      retries: 10
      delay: 3
    - name: Wait for container PID1 to be ready
      ansible.builtin.shell: /bin/bash -lc 'true'
      register: _ready
      retries: 10
      delay: 3
      until: _ready is succeeded

```

This way molecule would start with an empty inventory, during the `create` phase it would execute `vagrant up` and with an inventory refresh it will get the hosts from the custom vagrant inventory plugin.
