Skip to main content

Physical or Virtual With Ansible

Author
Jeffrey Forman

Part of my 2024 goal was to make my homelab easier to manage: spinning up virtual machines, rolling out updates, generally managing things should take less work. That includes managing the inventory of homelab machines, a mix of bare metal, virtual machines, or containers on a Proxmox cluster.

Things start with a source of truth, what I hope to use Netbox. Netbox contains APIs for managing inventories of IP addresses and prefixes, machines, virtual machines, etc.

But before I store/update all the devices in Netbox, I need to determine if they are physical or virtual, since each requires using different Ansible modules when inserting the objects into Netbox.

Enter Ansible facts, a dictionary of information gleaned from each host upon running Ansible.

There are a few ansible facts available to determine the physical or virtual-ness of a host:

  • ansible_virtualization_role
  • ansible_virtualization_tech_guest
  • ansible_virtualization_tech_host
  • ansible_virtualization_type

The below table are the combinations I’ve found that, when all true, determine the machine type.

Machine Typeansible_virtualization_roleansible_virtualization_tech_guestansible_virtualization_tech_hostansible_virtualization_type
Physicalhost[][kvm]kvm
Virtual Machineguest[kvm][]kvm
Container (lxc)guest[lxc, container][kvm]lxc

I’m going to use platform_type as the Ansible variable that is set when a host type has been determined. I’ve written the playbook to exclude the host from further processing if the type cannot be determined.

I’ve split up the yaml so that one can merely include platform_detection.yaml at the beginning of their playbook.

playbook.yaml:


- name: playbook to include platform detection logic
  hosts: all
  gather_facts: true
  tasks:
  - name: include platform detection tasks
    ansible.builtin.include_tasks:
      file: platform_detection.yaml

platform_detection.yaml:

---
- name: set initial detected state to false
  set_fact:
    is_detected: false

- name: check if platform is a virtual machine
  set_fact:
    is_detected: true
    platform_type: virtual
  when:
    - ansible_virtualization_role == "guest"
    - "'kvm' in ansible_virtualization_tech_guest"

- name: check if platform is an lxc container
  set_fact:
    is_detected: true
    platform_type: container
  when:
    - ansible_virtualization_role == "guest"
    - "'container' in ansible_virtualization_tech_guest"
    - "'lxc' in ansible_virtualization_tech_guest"

- name: check if platform is a physical machine
  set_fact:
    is_detected: true
    platform_type: physical
  when:
    - ansible_virtualization_role == "host"
    - ansible_virtualization_tech_guest|length == 0

- name: end the play for a host whose platform we couldn't detect
  ansible.builtin.meta: end_host
  when:
    - is_detected is false

- name: print platform type
  ansible.builtin.debug:
    msg: "Platform type: {{ platform_type }}, detected: {{ is_detected }}"

The ansible.builtin.meta: end_host task is used to exclude hosts whose platform type was unable to be deduced.

The variable to use in when conditions for tasks which need to know the platform type is platform_type variable, whose values are either physical, virtual, or container.

Now I can use the platform type to decide which Ansible netbox module to use when inserting/updating entries.

But that’s for another post.