Skip to content
Open
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
4 changes: 4 additions & 0 deletions roles/libvirt_manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ cifmw_libvirt_manager_configuration:
target: (Hypervisor hostname you want to deploy the family on. Optional)
uefi: (boolean, toggle UEFI boot. Optional, defaults to false)
bootmenu_enable: (string, toggle bootmenu. Optional, defaults to "no")
boot_order: (list, optional. Ordered list of boot devices. Valid values are 'hd' or 'disk' for disk boot, and 'network' for network boot. Example: ['hd', 'network'] will attempt disk boot first, then network boot. The boot order is applied after all devices are attached to the VM.)
networkconfig: (dict or list[dict], [network-config](https://cloudinit.readthedocs.io/en/latest/reference/network-config-format-v2.html#network-config-v2) v2 config, needed if a static ip address should be defined at boot time in absence of a dhcp server in special scenarios. Optional)
devices: (dict, optional, defaults to {}. The keys are the VMs of that type that needs devices to be attached, and the values are lists of strings, where each string must contain a valid <hostdev/> libvirt XML element that will be passed to virsh attach-device)
dhcp_options: (list, optional, defaults to []. List of DHCP options to apply to all VMs of this type. Format: ["option_number,value", ...])
Expand Down Expand Up @@ -167,6 +168,9 @@ cifmw_libvirt_manager_configuration:
memory: 8
cpus: 4
bootmenu_enable: "yes"
boot_order:
- hd
- network
nets:
- public
networks:
Expand Down
20 changes: 20 additions & 0 deletions roles/libvirt_manager/molecule/boot_order/cleanup.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
# Copyright 2025 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Cleanup
vars:
molecule_scenario: boot_order
ansible.builtin.import_playbook: ../deploy_layout/cleanup.yml
238 changes: 238 additions & 0 deletions roles/libvirt_manager/molecule/boot_order/converge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
---
# Copyright 2025 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

- name: Test boot_order configuration
hosts: instance
gather_facts: true
vars_files:
- vars/net-def.yml
vars:
ansible_user_dir: "{{ lookup('env', 'HOME') }}"
cifmw_basedir: "/opt/basedir"
cifmw_libvirt_manager_configuration:
vms:
# Test VM with disk first, then network boot
disk_first:
amount: 1
disksize: 10
memory: 1
cpus: 1
disk_file_name: 'blank'
boot_order:
- hd
- network
nets:
- public
- osp_trunk
# Test VM with network first, then disk boot
net_first:
amount: 1
disksize: 10
memory: 1
cpus: 1
disk_file_name: 'blank'
boot_order:
- network
- disk
nets:
- public
- osp_trunk
# Test VM with only network boot
net_only:
amount: 1
disksize: 10
memory: 1
cpus: 1
disk_file_name: 'blank'
boot_order:
- network
nets:
- public
# Test VM without boot_order (should not have boot order attributes)
no_boot_order:
amount: 1
disksize: 10
memory: 1
cpus: 1
disk_file_name: 'blank'
nets:
- public
networks:
public: |-
<network>
<name>public</name>
<forward mode='nat'/>
<bridge name='public' stp='on' delay='0'/>
<dns enable="no"/>
<ip
family='ipv4'
address='{{ _networks.public.range | ansible.utils.nthhost(1) }}'
prefix='24'>
</ip>
</network>
osp_trunk: |-
<network>
<name>osp_trunk</name>
<forward mode='nat'/>
<bridge name='osp_trunk' stp='on' delay='0'/>
<dns enable="no"/>
<ip
family='ipv4'
address='{{ _networks.osp_trunk.range | ansible.utils.nthhost(1) }}'
prefix='24'>
</ip>
</network>
tasks:
- name: Load networking definition
ansible.builtin.include_vars:
file: input.yml
name: cifmw_networking_definition

- name: Deploy layout with boot_order configurations
ansible.builtin.import_role:
name: libvirt_manager
tasks_from: deploy_layout

- name: Verify boot_order configurations
block:
# Test 1: Verify disk-first VM has correct boot order
- name: Get disk_first VM XML
register: _disk_first_xml
community.libvirt.virt:
command: "get_xml"
name: "cifmw-disk-first-0"
uri: "qemu:///system"

- name: Check disk boot order in disk-first VM
register: _disk_first_disk_boot
community.general.xml:
xmlstring: "{{ _disk_first_xml.get_xml }}"
xpath: "/domain/devices/disk[@device='disk']/boot"
content: "attribute"

- name: Check interface boot order in disk-first VM
register: _disk_first_net_boot
community.general.xml:
xmlstring: "{{ _disk_first_xml.get_xml }}"
xpath: "/domain/devices/interface[1]/boot"
content: "attribute"

- name: Assert disk-first VM has correct boot order
ansible.builtin.assert:
that:
- _disk_first_disk_boot.matches[0].boot.order == "1"
- _disk_first_net_boot.matches[0].boot.order == "2"
quiet: true
msg: >-
Expected disk boot order=1 and network boot order=2,
got disk={{ _disk_first_disk_boot.matches[0].boot.order }}
and network={{ _disk_first_net_boot.matches[0].boot.order }}

# Test 2: Verify network-first VM has correct boot order
- name: Get net_first VM XML
register: _net_first_xml
community.libvirt.virt:
command: "get_xml"
name: "cifmw-net-first-0"
uri: "qemu:///system"

- name: Check disk boot order in network-first VM
register: _net_first_disk_boot
community.general.xml:
xmlstring: "{{ _net_first_xml.get_xml }}"
xpath: "/domain/devices/disk[@device='disk']/boot"
content: "attribute"

- name: Check interface boot order in network-first VM
register: _net_first_net_boot
community.general.xml:
xmlstring: "{{ _net_first_xml.get_xml }}"
xpath: "/domain/devices/interface[1]/boot"
content: "attribute"

- name: Assert network-first VM has correct boot order
ansible.builtin.assert:
that:
- _net_first_net_boot.matches[0].boot.order == "1"
- _net_first_disk_boot.matches[0].boot.order == "2"
quiet: true
msg: >-
Expected network boot order=1 and disk boot order=2,
got network={{ _net_first_net_boot.matches[0].boot.order }}
and disk={{ _net_first_disk_boot.matches[0].boot.order }}

# Test 3: Verify network-only VM has only network boot
- name: Get net_only VM XML
register: _net_only_xml
community.libvirt.virt:
command: "get_xml"
name: "cifmw-net-only-0"
uri: "qemu:///system"

- name: Check interface boot order in network-only VM
register: _net_only_net_boot
community.general.xml:
xmlstring: "{{ _net_only_xml.get_xml }}"
xpath: "/domain/devices/interface[1]/boot"
content: "attribute"

- name: Check disk boot order in network-only VM (should not exist)
register: _net_only_disk_boot
failed_when: false
community.general.xml:
xmlstring: "{{ _net_only_xml.get_xml }}"
xpath: "/domain/devices/disk[@device='disk']/boot"
content: "attribute"

- name: Assert network-only VM has correct boot order
ansible.builtin.assert:
that:
- _net_only_net_boot.matches[0].boot.order == "1"
- _net_only_disk_boot.matches | default([]) | length == 0
quiet: true
msg: >-
Expected only network boot with order=1,
got network={{ _net_only_net_boot.matches[0].boot.order }}
and disk boot count={{ _net_only_disk_boot.matches | default([]) | length }}

# Test 4: Verify VM without boot_order has no boot order attributes
- name: Get no_boot_order VM XML
register: _no_boot_order_xml
community.libvirt.virt:
command: "get_xml"
name: "cifmw-no-boot-order-0"
uri: "qemu:///system"

- name: Check for any boot order attributes in no-boot-order VM
register: _no_boot_order_check
failed_when: false
community.general.xml:
xmlstring: "{{ _no_boot_order_xml.get_xml }}"
xpath: "/domain/devices//boot"
content: "attribute"

- name: Assert no-boot-order VM has no boot order attributes
ansible.builtin.assert:
that:
- _no_boot_order_check.matches | default([]) | length == 0
quiet: true
msg: >-
Expected no boot order attributes,
but found {{ _no_boot_order_check.matches | default([]) | length }} boot elements

- name: Output success message
ansible.builtin.debug:
msg: "All boot_order validations passed successfully!"
6 changes: 6 additions & 0 deletions roles/libvirt_manager/molecule/boot_order/molecule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
log: true

provisioner:
name: ansible
log: true
19 changes: 19 additions & 0 deletions roles/libvirt_manager/molecule/boot_order/prepare.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
# Copyright 2025 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.


- name: Prepare
ansible.builtin.import_playbook: ../deploy_layout/prepare.yml
50 changes: 50 additions & 0 deletions roles/libvirt_manager/molecule/boot_order/vars/input.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
# Copyright 2025 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

networks:
ctlplane:
network: "192.168.140.0/24"
gateway: "192.168.140.1"
mtu: 1500
group-templates:
disk_firsts:
network-template:
range:
start: 10
length: 1
networks:
ctlplane: {}
net_firsts:
network-template:
range:
start: 20
length: 1
networks:
ctlplane: {}
net_onlys:
network-template:
range:
start: 30
length: 1
networks:
ctlplane: {}
no_boot_orders:
network-template:
range:
start: 40
length: 1
networks:
ctlplane: {}
23 changes: 23 additions & 0 deletions roles/libvirt_manager/molecule/boot_order/vars/net-def.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
# Copyright 2025 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

_networks:
osp_trunk:
default: true
range: "192.168.140.0/24"
mtu: 1500
public:
range: "192.168.110.0/24"
Loading
Loading