Proxmox role testing with molecule

Hello,

I wrote a small role for installing a guest on proxmox and would like to test it with molecule. I would like to test it in an existing proxmox cluster.
I’m wondering how to do it? It seems molecule expects some kind of container as test environment, where proxmox is installed inside?
Would be interrested in a good tutorial or at least in an example how to handle this test scenario.
Thanks a lot!
Thomas

Hi there!

You don’t have to run proxmox inside the container (I don’t think it will work as well as it does). You have multiple options going forward:

  • Provide a PVE node externally for the role to use/abuse in order to test. Be sure to add logic to molecule to clean up after itself/before it starts the test to ensure the PVE node is sane.
  • Use a different method of creating the test node. You’re not limited to using podman/docker containers. As long as you’re able to script it with Ansible, you can have molecule run a playbook in order to create your testenvironment on a different PVE node, use terraform etc.
    See the docs here for more information: Playbook Testing - Ansible Molecule. In this example they still use podman, but if you change the commands they used to deploy, for example a KVM with a PVE image on it, that’s possible as well!

Good luck!

1 Like

Seems I missed a lot of documentation :innocent:
Thanks a lot! I found some ideas how to solve it.

Now, I created a configuration for testing with molecule with two scenarios (The same role β€œpve_guest” with two different variable sets):

pve_guest/
β”œβ”€β”€ README.md
β”œβ”€β”€ defaults
β”‚   └── main.yml
β”œβ”€β”€ meta
β”‚   └── main.yml
β”œβ”€β”€ molecule
β”‚   β”œβ”€β”€ default
β”‚   β”‚   β”œβ”€β”€ cleanup.yml
β”‚   β”‚   β”œβ”€β”€ create.yml
β”‚   β”‚   β”œβ”€β”€ destroy.yml
β”‚   β”‚   β”œβ”€β”€ molecule.yml
β”‚   β”‚   └── verify.yml
β”‚   β”œβ”€β”€ inventory
β”‚   β”‚   └── inventory.yml
β”‚   β”œβ”€β”€ requirements.yml
β”‚   └── sc01
β”‚       β”œβ”€β”€ cleanup.yml -> ../default/cleanup.yml
β”‚       β”œβ”€β”€ converge.yml
β”‚       β”œβ”€β”€ converge_01.yml
β”‚       β”œβ”€β”€ molecule.yml
β”‚       β”œβ”€β”€ verify.yml
β”‚       └── verify_01.yml
β”œβ”€β”€ tasks
β”‚   β”œβ”€β”€ cleanup_guests.yml
β”‚   β”œβ”€β”€ create_lxc.yml
β”‚   β”œβ”€β”€ create_qemu.yml
β”‚   └── main.yml
└── vars
    └── main.yml

I can run the test:

[root@ansible-dev-container pve_guest]# molecule --version
molecule 25.9.0 using python 3.13 
    ansible:2.19.2
    default:25.9.0 from molecule

[root@ansible-dev-container pve_guest]# molecule test --report --command-borders
INFO     default ➜ discovery: scenario test matrix: dependency, cleanup, create, cleanup, destroy
INFO     default ➜ create: Executing
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ ansible-playbook --inventory /root/.ansible/tmp/molecule.IqEM.default/inventory
  β”‚   --skip-tags molecule-notest,notest
  β”‚   --inventory=../inventory/ /workspaces/ansible/roles/pve_guest/molecule/default/create.yml
  β”‚ 
  β”‚ 
  β”‚ PLAY [Create (default)] ********************************************************
  β”‚ 
  β”‚ TASK [Debug] *******************************************************************
  β”‚ ok: [test-pve-guest] => {
  β”‚     "msg": "test-pve-guest"
  β”‚ }
  β”‚ 
  β”‚ PLAY RECAP *********************************************************************
  β”‚ test-pve-guest             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  β”‚ 
  └─ Return code: 0 ─────────────────────────────────────────────────────────────────
INFO     default ➜ create: Executed: Successful
INFO     default ➜ prerun: Performing prerun with role_name_check=0...
INFO     default ➜ dependency: Executing
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ ansible-galaxy install
  β”‚   --role-file molecule/requirements.yml
  β”‚ 
  β”‚ Starting galaxy collection install process
  β”‚ Nothing to do. All requested collections are already installed. If you want to reinstall them, consider using `--force`.
  └─ Return code: 0 ─────────────────────────────────────────────────────────────────
INFO     default ➜ dependency: Dependency completed successfully.
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ ansible-galaxy collection
  β”‚   install
  β”‚   --requirements-file molecule/requirements.yml
  β”‚ 
  β”‚ Starting galaxy collection install process
  β”‚ Nothing to do. All requested collections are already installed. If you want to reinstall them, consider using `--force`.
  └─ Return code: 0 ─────────────────────────────────────────────────────────────────
INFO     default ➜ dependency: Dependency completed successfully.
INFO     default ➜ dependency: Executed: Successful
INFO     default ➜ cleanup: Executing
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ ansible-playbook --inventory /root/.ansible/tmp/molecule.IqEM.default/inventory
  β”‚   --skip-tags molecule-notest,notest
  β”‚   --inventory=../inventory/ /workspaces/ansible/roles/pve_guest/molecule/default/cleanup.yml
  β”‚ 
  β”‚ 
  β”‚ PLAY [Cleanup (default)] *******************************************************
  β”‚ 
  β”‚ TASK [Debug] *******************************************************************
  β”‚ ok: [test-pve-guest] => {
  β”‚     "msg": "test-pve-guest"
  β”‚ }
  β”‚ 
  β”‚ PLAY RECAP *********************************************************************
  β”‚ test-pve-guest             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  β”‚ 
  └─ Return code: 0 ─────────────────────────────────────────────────────────────────
INFO     default ➜ cleanup: Executed: Successful
INFO     default ➜ cleanup: Executing
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ ansible-playbook --inventory /root/.ansible/tmp/molecule.IqEM.default/inventory
  β”‚   --skip-tags molecule-notest,notest
  β”‚   --inventory=../inventory/ /workspaces/ansible/roles/pve_guest/molecule/default/cleanup.yml
  β”‚ 
  β”‚ 
  β”‚ PLAY [Cleanup (default)] *******************************************************
  β”‚ 
  β”‚ TASK [Debug] *******************************************************************
  β”‚ ok: [test-pve-guest] => {
  β”‚     "msg": "test-pve-guest"
  β”‚ }
  β”‚ 
  β”‚ PLAY RECAP *********************************************************************
  β”‚ test-pve-guest             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  β”‚ 
  └─ Return code: 0 ─────────────────────────────────────────────────────────────────
INFO     default ➜ cleanup: Executed: Successful
INFO     default ➜ destroy: Executing
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ ansible-playbook --inventory /root/.ansible/tmp/molecule.IqEM.default/inventory
  β”‚   --skip-tags molecule-notest,notest
  β”‚   --inventory=../inventory/ /workspaces/ansible/roles/pve_guest/molecule/default/destroy.yml
  β”‚ 
  β”‚ 
  β”‚ PLAY [Destroy (default)] *******************************************************
  β”‚ 
  β”‚ TASK [Debug] *******************************************************************
  β”‚ ok: [test-pve-guest] => {
  β”‚     "msg": "test-pve-guest"
  β”‚ }
  β”‚ 
  β”‚ PLAY RECAP *********************************************************************
  β”‚ test-pve-guest             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
  β”‚ 
  └─ Return code: 0 ─────────────────────────────────────────────────────────────────
INFO     default ➜ destroy: Executed: Successful
INFO     Molecule executed 3 scenarios (3 successful)

DETAILS                                                                        
default ➜ create: Executed: Successful

default ➜ dependency: Executed: Successful
default ➜ cleanup: Executed: Successful
default ➜ cleanup: Executed: Successful

default ➜ destroy: Executed: Successful

SCENARIO RECAP                                                                 
default                   : actions=1  successful=1  disabled=0  skipped=0  missing=0  failed=0
default                   : actions=3  successful=2  disabled=0  skipped=0  missing=0  failed=0
default                   : actions=1  successful=1  disabled=0  skipped=0  missing=0  failed=0

[root@ansible-dev-container pve_guest]# 

If I run the β€œsc01” scenario with

molecule test -s sc01 --report --command-borders

then only the β€œcreate” and β€œdestroy” playbook are used from the default scenario; the configuration (molecule.yml) and all other plays are not available. Is this correct? Or is there a mistake in my configuration?

My configuration:

[root@ansible-dev-container pve_guest]# cat molecule/default/molecule.yml 
# code: language=ansible

---
# Dependency management (download roles/collections)
dependency:
  name: galaxy
  options:
    ignore-certs: false
    ignore-errors: false
    role-file: molecule/requirements.yml
    requirements-file: molecule/requirements.yml

ansible:
  cfg:
    defaults:
      host_key_checking: false
      inventory: ../inventory/
  env:
    ANSIBLE_DEPRECATION_WARNINGS: "0"  # mute the DEFAULT_MANAGED_STR warning (See changelog ansible 2.19)
  executor:
    backend: ansible-playbook
    args:
      ansible_playbook:
        - --inventory=../inventory/

scenario:
  test_sequence:
    - dependency
    - cleanup
    - create
    - cleanup
    - destroy

shared_state: true


[root@ansible-dev-container pve_guest]# cat molecule/sc01/molecule.yml 
# code: language=ansible

---
# Dependency management (download roles/collections)
dependency:
  name: galaxy
  options:
    ignore-certs: false
    ignore-errors: false
    role-file: molecule/requirements.yml
    requirements-file: molecule/requirements.yml

ansible:
  cfg:
    defaults:
      host_key_checking: false
      inventory: ../inventory/
  env:
    ANSIBLE_DEPRECATION_WARNINGS: "0"  # mute the DEFAULT_MANAGED_STR warning (See changelog ansible 2.19)
  executor:
    backend: ansible-playbook
    args:
      ansible_playbook:
        - --inventory=../inventory/

scenario:  test_sequence:
    - create
    - dependency
    - syntax
    - cleanup
    - converge
    - idempotence
    - verify
    - cleanup
    - converge converge_01.yml
    - idempotence converge_01.yml
    - verify verify_01.yml
    - cleanup
    - destroy

shared_state: true
[root@ansible-dev-container pve_guest]# 

Thanks a lot for your help!
Thomas

A few hours try & error later: The cleanup.yml from the default scenario can be used in this way:

# pve_guest/molecule/sc01/molecule.yml
---
ansible:
  playbooks:
    cleanup: ../default/cleanup.yml

scenario:
  test_sequence:
    - create
    - syntax
    - cleanup
    - converge
    - idempotence
    - verify
    - cleanup
    - destroy

And a central ansible configuration is possible as well, but a bit weired.
The config.yml must be placed in ~/.config/molecule.config.yml or in <git_root>/.config/molecule/config.yml.

But there is still a miracle.

Structure is now:

pve_guest/
β”œβ”€β”€ .ansible
β”‚   β”œβ”€β”€ collections
β”‚   └── roles
β”œβ”€β”€ .config
β”‚   └── molecule
β”‚       └── config.yml
β”œβ”€β”€ .git
β”‚   └── ...
β”œβ”€β”€ README.md
β”œβ”€β”€ defaults
β”‚   └── main.yml
β”œβ”€β”€ meta
β”‚   └── main.yml
β”œβ”€β”€ molecule
β”‚   β”œβ”€β”€ default
β”‚   β”‚   β”œβ”€β”€ cleanup.yml
β”‚   β”‚   β”œβ”€β”€ create.yml
β”‚   β”‚   β”œβ”€β”€ destroy.yml
β”‚   β”‚   β”œβ”€β”€ molecule.yml
β”‚   β”‚   └── verify.yml
β”‚   β”œβ”€β”€ inventory
β”‚   β”‚   └── inventory.yml
β”‚   β”œβ”€β”€ requirements.yml
β”‚   └── sc01
β”‚       β”œβ”€β”€ converge.yml
β”‚       β”œβ”€β”€ molecule.yml
β”‚       └── verify.yml
β”œβ”€β”€ tasks
β”‚   β”œβ”€β”€ cleanup_guests.yml
β”‚   β”œβ”€β”€ create_lxc.yml
β”‚   β”œβ”€β”€ create_qemu.yml
β”‚   └── main.yml
└── vars
    └── main.yml

The config.yml:

---
# Dependency management (download roles/collections)
dependency:
  name: galaxy
  options:
    ignore-certs: false
    ignore-errors: false
    role-file: molecule/requirements.yml
    requirements-file: molecule/requirements.yml

ansible:
  cfg:
    defaults:
      host_key_checking: false
      deprecation_warnings: false
      # inventory: "inventory/" ## <= funktioniert nicht, da BasisDir unklar

  # env:
    # ANSIBLE_DEPRECATION_WARNINGS: "0"  # mute the DEFAULT_MANAGED_STR warning (See changelog ansible 2.19)

  executor:
    backend: ansible-playbook
    args:
      ansible_playbook:
        - --inventory=../inventory/

The ansible => cfg => defaults => inventory setting did not work, but the playbook arg --inventory is working.
Which path should I use here to get the first setting working?

Thanks a lot,
Thomas

CC @DevTools molecule ansible-molecule

Some feedback on latest Molecule. Looks like the new version of Molecule being used here :slightly_smiling_face: