Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/189-add-interfaces.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- virt - implement the gathering of Dom interface names and mac addresses as per FR https://github.com/ansible-collections/community.libvirt/issues/189
3 changes: 2 additions & 1 deletion plugins/doc_fragments/virt.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class ModuleDocFragment(object):
command:
description:
- In addition to state management, various non-idempotent commands are available.
choices: [ create, define, destroy, freemem, get_xml, info, list_vms, nodeinfo, pause, shutdown, start, status, stop, undefine, unpause, uuid, virttype ]
choices: [ create, define, destroy, freemem, get_xml, get_interfaces, info, list_vms, nodeinfo, pause, shutdown, start, status,
stop, undefine, unpause, uuid, virttype ]
type: str
"""

Expand Down
22 changes: 21 additions & 1 deletion plugins/modules/virt.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
VIRT_UNAVAILABLE = 2

ALL_COMMANDS = []
VM_COMMANDS = ['create', 'define', 'destroy', 'get_xml', 'pause', 'shutdown', 'status', 'start', 'stop', 'undefine', 'unpause', 'uuid']
VM_COMMANDS = ['create', 'define', 'destroy', 'get_xml', 'get_interfaces', 'pause', 'shutdown', 'status', 'start', 'stop', 'undefine', 'unpause', 'uuid']
HOST_COMMANDS = ['freemem', 'info', 'list_vms', 'nodeinfo', 'virttype']
ALL_COMMANDS.extend(VM_COMMANDS)
ALL_COMMANDS.extend(HOST_COMMANDS)
Expand Down Expand Up @@ -315,6 +315,19 @@ def get_uuid(self, vmid):
vm = self.conn.lookupByName(vmid)
return vm.UUIDString()

def get_interfaces(self, vmid):
dom_xml = self.get_xml(vmid)
root = etree.fromstring(dom_xml)
interfaces = root.findall("./devices/interface")
interfaces_dict = {}
interfaces_dict['network_interfaces'] = {}
for interface in interfaces:
interfaces_dict["network_interfaces"].update(
{interface.find("source").get("bridge"):
{"mac": interface.find("mac").get("address"),
"pci_bus": interface.find("address").get("bus")}})
return interfaces_dict


class Virt(object):

Expand Down Expand Up @@ -490,6 +503,13 @@ def get_uuid(self, vmid):
self.__get_conn()
return self.conn.get_uuid(vmid)

def get_interfaces(self, vmid):
"""
Get Interface Name and Mac Address from xml
"""
self.__get_conn()
return self.conn.get_interfaces(vmid)


# A dict of interface types (found in their `type` attribute) to the
# corresponding "source" attribute name of their <source> elements
Expand Down
8 changes: 8 additions & 0 deletions tests/integration/targets/virt_interfaces/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
vm_name: fedora-test
vm_ram_mb: 256
vm_vcpus: 1
libvirt_disk_path: "/var/lib/libvirt/images"
libvirt_disk_size: "1"
libvirt_pool_name: "default"
mac_address: "52:54:00:94:e4:a0"
36 changes: 36 additions & 0 deletions tests/integration/targets/virt_interfaces/files/Dockerfile_Fedora
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
FROM fedora:latest

RUN dnf install @virtualization -y

RUN dnf update -y && \
dnf install -y \
bridge-utils \
dmidecode \
dnsmasq \
ebtables \
iproute \
iptables \
edk2-ovmf \
qemu-kvm \
tini \
python3-pip \
python3-libvirt \
python3-lxml \
&& \
dnf clean all

RUN ln -s /usr/bin/qemu-system-x86_64 /usr/libexec/qemu-kvm

RUN sed -i '/^#stdio_handler/ a\stdio_handler = "file"' /etc/libvirt/qemu.conf

COPY config/pools/* /etc/libvirt/storage/
COPY config/networks/* /etc/libvirt/qemu/networks/
RUN mkdir -p /etc/libvirt/storage/autostart /etc/libvirt/qemu/networks/autostart && \
for pool in /etc/libvirt/storage/*.xml; do \
ln -sf "../${pool##*/}" /etc/libvirt/storage/autostart/; \
done && \
for net in /etc/libvirt/qemu/networks/*.xml; do \
ln -sf "../${net##*/}" /etc/libvirt/qemu/networks/autostart/; \
done

CMD ["/usr/bin/tini", "/usr/sbin/libvirtd"]
37 changes: 37 additions & 0 deletions tests/integration/targets/virt_interfaces/files/Dockerfile_Ubuntu
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
FROM ubuntu:24.04

RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get update && \
apt-get -y install \
bridge-utils \
dmidecode \
dnsmasq \
ebtables \
iproute2 \
iptables \
libvirt-clients \
libvirt-daemon-system \
ovmf \
# qemu-efi \
qemu-kvm \
tini \
&& \
apt-get clean

RUN apt install python3-pip python3-libvirt python3-lxml -y

RUN ln -s /usr/bin/qemu-system-amd64 /usr/libexec/qemu-kvm

RUN sed -i '/^#stdio_handler/ a\stdio_handler = "file"' /etc/libvirt/qemu.conf

COPY config/pools/* /etc/libvirt/storage/
COPY config/networks/* /etc/libvirt/qemu/networks/
RUN mkdir -p /etc/libvirt/storage/autostart /etc/libvirt/qemu/networks/autostart && \
for pool in /etc/libvirt/storage/*.xml; do \
ln -sf "../${pool##*/}" /etc/libvirt/storage/autostart/; \
done && \
for net in /etc/libvirt/qemu/networks/*.xml; do \
ln -sf "../${net##*/}" /etc/libvirt/qemu/networks/autostart/; \
done

CMD ["/usr/bin/tini", "/usr/sbin/libvirtd"]
57 changes: 57 additions & 0 deletions tests/integration/targets/virt_interfaces/files/vm_template.xml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<domain type='kvm'>
<name>{{ vm_name }}</name>
<memory unit='MiB'>{{ vm_ram_mb }}</memory>
<vcpu placement='static'>{{ vm_vcpus }}</vcpu>
<os>
<type arch='x86_64' machine='q35'>hvm</type>
<boot dev='hd'/>
</os>
<cpu mode="host-passthrough" check="none" migratable="on"/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<clock offset="utc">
<timer name="rtc" tickpolicy="catchup"/>
<timer name="pit" tickpolicy="delay"/>
<timer name="hpet" present="no"/>
</clock>
<devices>
<emulator>/usr/libexec/qemu-kvm</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='{{ libvirt_disk_path }}/{{ vm_name }}.qcow2'/>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
</disk>
<channel type="unix">
<target type="virtio" name="org.qemu.guest_agent.0"/>
<address type="virtio-serial" controller="0" bus="0" port="1"/>
</channel>
<input type='tablet' bus='usb'>
<address type='usb' bus='0' port='1'/>
</input>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type="vnc" port="-1" autoport="yes">
<listen type="address"/>
</graphics>
<video>
<model type="virtio" heads="1" primary="yes"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x01" function="0x0"/>
</video>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
</memballoon>
<rng model='virtio'>
<backend model='random'>/dev/urandom</backend>
<address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/>
</rng>
<interface type="network">
<mac address='{{ mac_address }}'/>
<source network="default"/>
<model type="virtio"/>
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</interface>

</devices>
</domain>
37 changes: 37 additions & 0 deletions tests/integration/targets/virt_interfaces/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
- name: Create VM XML definition
template:
src: files/vm_template.xml.j2
dest: "/tmp/{{ vm_name }}.xml"

- name: Define VM
community.libvirt.virt:
command: define
xml: "{{ lookup('file', '/tmp/' + vm_name + '.xml') }}"
uri: qemu:///system

- name: Validate the VM
community.libvirt.virt:
command: list_vms
register: vm_list

- name: Show VMs
debug:
var: vm_list

- name: register vm info
community.libvirt.virt:
command: get_interfaces
name: "{{ vm_name }}"
register: vminfo

- name: debug result
debug:
msg: "{{ vminfo }}"

- name: Assert Mac Address present
assert:
that:
- "vminfo['network_interfaces']['null']['mac'] == mac_address"
fail_msg: "Mac address does not match or is missing. Expected: {{ mac_address }}, Got: {{ vminfo['network_interfaces']['null']['mac'] }}"
success_msg: "Original variable from defaults: {{ mac_address }} found in netowrking output"