Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
40 changes: 39 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,37 @@ 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")
interface_type_map = {
'network': 'NAT',
'direct': 'macvtap',
'bridge': 'bridge'
}
interface_counter = 0
interfaces_dict = {}
interfaces_dict['network_interfaces'] = {}
for interface in interfaces:
interface_counter += 1
interface_type = interface.get('type')
source = interface.find("source").get({
'bridge': 'bridge',
'direct': 'dev',
'network': 'network'
}.get(interface_type))
mac_address = interface.find("mac").get("address")
pci_bus = interface.find("address").get("bus")
interface_info = {
"type": interface_type_map.get(interface_type, interface_type),
"mac": mac_address,
"pci_bus": pci_bus,
"source": source
}
interfaces_dict['network_interfaces'].update({"interface_{0}".format(interface_counter): interface_info})
return interfaces_dict


class Virt(object):

Expand Down Expand Up @@ -490,6 +521,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
9 changes: 9 additions & 0 deletions tests/integration/targets/virt_interfaces/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
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"
mac_address_2: "52:54:00:94:e4:a1"
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"]
63 changes: 63 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,63 @@
<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>
<interface type="network">
<mac address='{{ mac_address_2 }}'/>
<source network="default"/>
<model type="virtio"/>
<address type="pci" domain="0x0000" bus="0x02" slot="0x00" function="0x0"/>
</interface>

</devices>
</domain>
45 changes: 45 additions & 0 deletions tests/integration/targets/virt_interfaces/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
- 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 First Mac Address present
assert:
that:
- "vminfo['network_interfaces']['interface_1']['mac'] == mac_address"
fail_msg: "Mac address does not match or is missing. Expected: {{ mac_address }}, Got: {{ vminfo['network_interfaces']['interface_1']['mac'] }}"
success_msg: "Original variable from defaults: {{ mac_address }} found in netowrking output"


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