diff --git a/library/cluster_vm.py b/library/cluster_vm.py index dfbc17085..116a3d689 100644 --- a/library/cluster_vm.py +++ b/library/cluster_vm.py @@ -201,6 +201,13 @@ - Optional parameter relevant only if I(command) is C(clone) type: bool default: false + additional_disks: + description: + - List of qcow2 file paths for additional disks + - Device names (vdb, vdc, ...) are assigned automatically + - Optional parameter relevant only if I(command) is C(create) + type: list + default: [] disk_bus: description: - Disk bus type to use for the VM's disk (virtio, scsi, ide, etc.) @@ -311,6 +318,16 @@ cpu: 4 memory: 2048 +# Create a VM with additional disks +- name: Create guest0 with an extra data disk + cluster_vm: + name: guest0 + command: create + system_image: my_disk.qcow2 + xml: "{{ lookup('template', 'my_vm_config.xml.j2') }}" + additional_disks: + - additional_data.qcow2 + # Remove a VM - name: Remove guest0 cluster_vm: @@ -548,7 +565,7 @@ def check_parameters(parameters, commands_list): command=dict(type="str", required=True, choices=commands_list), name=dict(type="str", required=False, aliases=["guest"]), xml=dict(type="str", required=False), - data_disk=dict(type="str", required=False), + additional_disks=dict(type="list", required=False, default=[]), force=dict(type="bool", required=False, default=False), enable=dict(type="bool", required=False, default=True), system_image=dict(type="str", required=False), @@ -668,6 +685,7 @@ def check_parameters(parameters, commands_list): "clear_pacemaker_utilization", False ) disk_bus = args.get("disk_bus", "virtio") + additional_disks = args.get("additional_disks", []) vm_name_command_list = commands_list.copy() vm_name_command_list.remove("list_vms") @@ -689,6 +707,13 @@ def check_parameters(parameters, commands_list): module.fail_json( msg="`system_image` doesn't exist or is not a file`" ) + for i, filepath in enumerate(additional_disks): + if not os.path.isfile(filepath): + module.fail_json( + msg="additional_disks[{}] '{}' doesn't exist or is not a file".format( + i, filepath + ) + ) vm_options = { "name": vm_name, "base_xml": vm_config, @@ -710,6 +735,7 @@ def check_parameters(parameters, commands_list): "pacemaker_params": pacemaker_params, "pacemaker_utilization": pacemaker_utilization, "disk_bus": disk_bus, + "additional_disks": additional_disks, } vm_manager.create(vm_options) elif command == "clone": diff --git a/roles/deploy_vm_manager/files/vm_manager b/roles/deploy_vm_manager/files/vm_manager index 80ab2ac02..bdd5209cc 160000 --- a/roles/deploy_vm_manager/files/vm_manager +++ b/roles/deploy_vm_manager/files/vm_manager @@ -1 +1 @@ -Subproject commit 80ab2ac02241ffde1988ab42fa6fff8023dfff23 +Subproject commit bdd5209ccac8d11fd4b849b2b25c7a0f5de8dfba diff --git a/roles/deploy_vms_cluster/README.md b/roles/deploy_vms_cluster/README.md index 8f9c1714b..a8e475aa1 100644 --- a/roles/deploy_vms_cluster/README.md +++ b/roles/deploy_vms_cluster/README.md @@ -66,38 +66,38 @@ This templated XML file offers default behaviors and configurations to launch VM It can be a good starting point if you plan to deploy your VM on SEAPATH, however, for any production setup, it is recommended to create your own XML file. Below is a list of the VMs member variables that can be used with this XML file. None of these variables are required. -| Member variable | Derived variable | Type | Default | Comments | -|-----------------|------------------|-----------------|-----------|-----------------------------------------------------------------------------------------------------------------------------| -| uuid | | Integer | random | Libvirt UUID of the VM | -| description | | String | Test VM | Libvirt description of the VM | -| memory | | Integer | 2048 | RAM of the VM in MiB | -| additional_disk | | List of strings | | Additional disks to give to the VM. The main disk is given by the vm_disk variable | -| vm_features | | List of strings | | List of vm features to enable. Possible values are "rt", "isolated", "secure-boot", "dpdk", "memballoon", "graphic-console" | -| | rt | | | Enable real time tweaks (priority, cgroup, scheduler, etc ...). Depends on `cpuset` | -| | isolated | | | Pin vCPU to hypervisor CPUs. Depends on `cpuset` | -| | secure-boot | | | Enable secure boot | -| | dpdk | | | Connect the VM to a DPDK OVS bridge port. Depends on `dpdk` | -| | memballoon | | | Enable memory ballooning for the VM. | -| | graphic-console | | | Add a graphic console (VNC) with video and tablet input to the VM | -| graphics_listen | | String | 127.0.0.1 | Address on which the VNC server listens. Depends on `graphic-console` in `vm_features` | -| cpuset | | List of int | | List of hypervisor CPU cores to use in the case of an isolated/RT VM | -| emulatorpin | | Integer | | Hypervisor CPU on which to pin the QEMU thread running the VM. If not set, the thread is not pinned. | -| nb_cpu | | Integer | 1 | Number of vCPU for the VM. Fallback to `cpuset` size if defined. | -| sriov | | List of strings | | List of SRIOV pools to use. | -| pci_passthrough | | List of dict | | List of dictionaries defining devices to passthrough to the VM. Each entry must contain: | -| | domain | Integer | | PCI domain of the device | -| | bus | Integer | | PCI bus of the device | -| | slot | Integer | | PCI slot of the device | -| | function | Integer | | PCI function of the device | -| bridges | | List of dicts | | List of Linux bridges to use. Each entry must define: | -| | name | String | | Name of the bridge to connect to | -| | mac_address | String | | Mac address of the virtual NIC of the VM on this bridge | -| ovs | | List of dicts | | List of OVS ports to use. Each element must contain: | -| | ovs_port | String | | OVS port to use for this interface | -| | mad_address | String | | Mac address of this interface | -| dpdk | | List of dicts | | List of Open vSwitch ports on which to enable dpdk. Depends on `dpdk` in `vm_features`. Each element must contain: | -| | ovs_port | | | OVS port on which to enable DPDK | -| | cpu_nb | | | Hypervisor CPU to use for this port (100% of the cpu time will be used) | +| Member variable | Derived variable | Type | Default | Comments | +|-----------------|------------------|-----------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------| +| uuid | | Integer | random | Libvirt UUID of the VM | +| description | | String | Test VM | Libvirt description of the VM | +| memory | | Integer | 2048 | RAM of the VM in MiB | +| additional_disk | | List of strings | | Additional disks to give to the VM. Each entry is a path to a qcow2 disk image. Device names (vdb, vdc, ...) are assigned automatically. | +| vm_features | | List of strings | | List of vm features to enable. Possible values are "rt", "isolated", "secure-boot", "dpdk", "memballoon", "graphic-console" | +| | rt | | | Enable real time tweaks (priority, cgroup, scheduler, etc ...). Depends on `cpuset` | +| | isolated | | | Pin vCPU to hypervisor CPUs. Depends on `cpuset` | +| | secure-boot | | | Enable secure boot | +| | dpdk | | | Connect the VM to a DPDK OVS bridge port. Depends on `dpdk` | +| | memballoon | | | Enable memory ballooning for the VM. | +| | graphic-console | | | Add a graphic console (VNC) with video and tablet input to the VM | +| graphics_listen | | String | 127.0.0.1 | Address on which the VNC server listens. Depends on `graphic-console` in `vm_features` | +| cpuset | | List of int | | List of hypervisor CPU cores to use in the case of an isolated/RT VM | +| emulatorpin | | Integer | | Hypervisor CPU on which to pin the QEMU thread running the VM. If not set, the thread is not pinned. | +| nb_cpu | | Integer | 1 | Number of vCPU for the VM. Fallback to `cpuset` size if defined. | +| sriov | | List of strings | | List of SRIOV pools to use. | +| pci_passthrough | | List of dict | | List of dictionaries defining devices to passthrough to the VM. Each entry must contain: | +| | domain | Integer | | PCI domain of the device | +| | bus | Integer | | PCI bus of the device | +| | slot | Integer | | PCI slot of the device | +| | function | Integer | | PCI function of the device | +| bridges | | List of dicts | | List of Linux bridges to use. Each entry must define: | +| | name | String | | Name of the bridge to connect to | +| | mac_address | String | | Mac address of the virtual NIC of the VM on this bridge | +| ovs | | List of dicts | | List of OVS ports to use. Each element must contain: | +| | ovs_port | String | | OVS port to use for this interface | +| | mad_address | String | | Mac address of this interface | +| dpdk | | List of dicts | | List of Open vSwitch ports on which to enable dpdk. Depends on `dpdk` in `vm_features`. Each element must contain: | +| | ovs_port | | | OVS port on which to enable DPDK | +| | cpu_nb | | | Hypervisor CPU to use for this port (100% of the cpu time will be used) | ## Example Playbook diff --git a/roles/deploy_vms_cluster/tasks/main.yml b/roles/deploy_vms_cluster/tasks/main.yml index d58e9eda1..ca760ebc3 100644 --- a/roles/deploy_vms_cluster/tasks/main.yml +++ b/roles/deploy_vms_cluster/tasks/main.yml @@ -69,6 +69,18 @@ vars: ansible_remote_tmp: "{{ deploy_vms_cluster_qcow2tmpuploadfolder | default(omit) }}" when: deploy_vms_cluster_disk_copy | bool + - name: "Copy additional disk on target for {{ item }}" + ansible.builtin.copy: + src: "{{ add_disk }}" + dest: "{{ deploy_vms_cluster_qcow2tmpuploadfolder }}/additional_{{ add_disk_idx }}.qcow2" + mode: "0644" + vars: + ansible_remote_tmp: "{{ deploy_vms_cluster_qcow2tmpuploadfolder | default(omit) }}" + loop: "{{ hostvars[item].additional_disk | default([]) }}" + loop_control: + loop_var: add_disk + index_var: add_disk_idx + when: deploy_vms_cluster_disk_copy | bool - name: "Create {{ item }}" cluster_vm: name: "{{ item }}" @@ -86,6 +98,7 @@ preferred_host: "{{ hostvars[item].preferred_host | default(omit) }}" crm_config_cmd: "{{ hostvars[item].crm_config_cmd | default(omit) }}" disk_bus: "{{ hostvars[item].disk_bus | default(omit) }}" + additional_disks: "{{ range(hostvars[item].additional_disk | default([]) | length) | map('string') | map('regex_replace', '^(.+)$', deploy_vms_cluster_qcow2tmpuploadfolder ~ '/additional_\\1.qcow2') | list }}" xml: >- {{ lookup('file', hostvars[item].xml_path) if hostvars[item].xml_path is defined @@ -93,10 +106,18 @@ if hostvars[item].vm_template is defined else lookup('file',deploy_vms_cluster_vms_disks_directory + '/' + item + '.xml') | replace('\n', '') }} - - name: Remove temporary file + - name: Remove temporary system disk file ansible.builtin.file: path: "{{ vm_file_dest }}" state: absent + - name: "Remove temporary additional disk files for {{ item }}" + ansible.builtin.file: + path: "{{ deploy_vms_cluster_qcow2tmpuploadfolder }}/additional_{{ add_disk_idx }}.qcow2" + state: absent + loop: "{{ hostvars[item].additional_disk | default([]) }}" + loop_control: + loop_var: add_disk + index_var: add_disk_idx - name: Wait for VM connections ansible.builtin.wait_for_connection: delegate_to: "{{ item }}" diff --git a/roles/deploy_vms_standalone/README.md b/roles/deploy_vms_standalone/README.md index 5beaa613c..88ef80509 100644 --- a/roles/deploy_vms_standalone/README.md +++ b/roles/deploy_vms_standalone/README.md @@ -50,39 +50,39 @@ This templated XML file offers default behaviors and configurations to launch VM It can be a good starting point if you plan to deploy your VM on SEAPATH, however, for any production setup, it is recommended to create your own XML file. Below is a list of the VMs member variables that can be used with this XML file. None of these variables are required. -| Member variable | Derived variable | Type | Default | Comments | -|-----------------|------------------|-----------------|-----------|-----------------------------------------------------------------------------------------------------------------------------| -| uuid | | Integer | random | Libvirt UUID of the VM | -| description | | String | Test VM | Libvirt description of the VM | -| autostart | | Bool | true | Set the VM to autostart on hypervisor boot | -| memory | | Integer | 2048 | RAM of the VM in MiB | -| additional_disk | | List of strings | | Additional disks to give to the VM. The main disk is given by the vm_disk variable | -| vm_features | | List of strings | | List of vm features to enable. Possible values are "rt", "isolated", "secure-boot", "dpdk", "memballoon", "graphic-console" | -| | rt | | | Enable real time tweaks (priority, cgroup, scheduler, etc ...). Depends on `cpuset` | -| | isolated | | | Pin vCPU to hypervisor CPUs. Depends on `cpuset` | -| | secure-boot | | | Enable secure boot | -| | dpdk | | | Connect the VM to a DPDK OVS bridge port. Depends on `dpdk` | -| | memballoon | | | Enable memory ballooning for the VM. | -| | graphic-console | | | Add a graphic console (VNC) with video and tablet input to the VM | -| graphics_listen | | String | 127.0.0.1 | Address on which the VNC server listens. Depends on `graphic-console` in `vm_features` | -| cpuset | | List of int | | List of hypervisor CPU cores to use in the case of an isolated/RT VM | -| emulatorpin | | Integer | | Hypervisor CPU on which to pin the QEMU thread running the VM. If not set, the thread is not pinned. | -| nb_cpu | | Integer | 1 | Number of vCPU for the VM. Fallback to `cpuset` size if defined. | -| sriov | | List of strings | | List of SRIOV pools to use. | -| pci_passthrough | | List of dict | | List of dictionaries defining devices to passthrough to the VM. Each entry must contain: | -| | domain | Integer | | PCI domain of the device | -| | bus | Integer | | PCI bus of the device | -| | slot | Integer | | PCI slot of the device | -| | function | Integer | | PCI function of the device | -| bridges | | List of dicts | | List of Linux bridges to use. Each entry must define: | -| | name | String | | Name of the bridge to connect to | -| | mac_address | String | | Mac address of the virtual NIC of the VM on this bridge | -| ovs | | List of dicts | | List of OVS ports to use. Each element must contain: | -| | ovs_port | String | | OVS port to use for this interface | -| | mad_address | String | | Mac address of this interface | -| dpdk | | List of dicts | | List of Open vSwitch ports on which to enable dpdk. Depends on `dpdk` in `vm_features`. Each element must contain: | -| | ovs_port | | | OVS port on which to enable DPDK | -| | cpu_nb | | | Hypervisor CPU to use for this port (100% of the cpu time will be used) | +| Member variable | Derived variable | Type | Default | Comments | +|-----------------|------------------|-----------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------| +| uuid | | Integer | random | Libvirt UUID of the VM | +| description | | String | Test VM | Libvirt description of the VM | +| autostart | | Bool | true | Set the VM to autostart on hypervisor boot | +| memory | | Integer | 2048 | RAM of the VM in MiB | +| additional_disk | | List of strings | | Additional disks to give to the VM. Each entry is a path to a qcow2 disk image. Device names (vdb, vdc, ...) are assigned automatically. | +| vm_features | | List of strings | | List of vm features to enable. Possible values are "rt", "isolated", "secure-boot", "dpdk", "memballoon", "graphic-console" | +| | rt | | | Enable real time tweaks (priority, cgroup, scheduler, etc ...). Depends on `cpuset` | +| | isolated | | | Pin vCPU to hypervisor CPUs. Depends on `cpuset` | +| | secure-boot | | | Enable secure boot | +| | dpdk | | | Connect the VM to a DPDK OVS bridge port. Depends on `dpdk` | +| | memballoon | | | Enable memory ballooning for the VM. | +| | graphic-console | | | Add a graphic console (VNC) with video and tablet input to the VM | +| graphics_listen | | String | 127.0.0.1 | Address on which the VNC server listens. Depends on `graphic-console` in `vm_features` | +| cpuset | | List of int | | List of hypervisor CPU cores to use in the case of an isolated/RT VM | +| emulatorpin | | Integer | | Hypervisor CPU on which to pin the QEMU thread running the VM. If not set, the thread is not pinned. | +| nb_cpu | | Integer | 1 | Number of vCPU for the VM. Fallback to `cpuset` size if defined. | +| sriov | | List of strings | | List of SRIOV pools to use. | +| pci_passthrough | | List of dict | | List of dictionaries defining devices to passthrough to the VM. Each entry must contain: | +| | domain | Integer | | PCI domain of the device | +| | bus | Integer | | PCI bus of the device | +| | slot | Integer | | PCI slot of the device | +| | function | Integer | | PCI function of the device | +| bridges | | List of dicts | | List of Linux bridges to use. Each entry must define: | +| | name | String | | Name of the bridge to connect to | +| | mac_address | String | | Mac address of the virtual NIC of the VM on this bridge | +| ovs | | List of dicts | | List of OVS ports to use. Each element must contain: | +| | ovs_port | String | | OVS port to use for this interface | +| | mad_address | String | | Mac address of this interface | +| dpdk | | List of dicts | | List of Open vSwitch ports on which to enable dpdk. Depends on `dpdk` in `vm_features`. Each element must contain: | +| | ovs_port | | | OVS port on which to enable DPDK | +| | cpu_nb | | | Hypervisor CPU to use for this port (100% of the cpu time will be used) | ## Example Playbook diff --git a/roles/deploy_vms_standalone/tasks/copy_additional_disk.yml b/roles/deploy_vms_standalone/tasks/copy_additional_disk.yml new file mode 100644 index 000000000..af6194954 --- /dev/null +++ b/roles/deploy_vms_standalone/tasks/copy_additional_disk.yml @@ -0,0 +1,15 @@ +# Copyright (C) 2024 RTE +# SPDX-License-Identifier: Apache-2.0 + +--- +- name: "Copy additional disk {{ _vm_name ~ ' - ' ~ (add_disk | basename) }}" + ansible.builtin.copy: + src: "{{ add_disk }}" + dest: "{{ deploy_vms_standalone_disk_pool }}/{{ add_disk | basename }}" + mode: "0644" + vars: + ansible_remote_tmp: "{{ deploy_vms_standalone_qcow2tmpuploadfolder | default(omit) }}" + loop: "{{ hostvars[_vm_name].additional_disk }}" + loop_control: + loop_var: add_disk + label: "{{ _vm_name }} - {{ add_disk | basename }}" diff --git a/roles/deploy_vms_standalone/tasks/main.yml b/roles/deploy_vms_standalone/tasks/main.yml index 0f95cf292..8893da93c 100644 --- a/roles/deploy_vms_standalone/tasks/main.yml +++ b/roles/deploy_vms_standalone/tasks/main.yml @@ -77,6 +77,16 @@ - item not in deploy_vms_standalone_all_vms.list_vms or (item in deploy_vms_standalone_all_vms.list_vms and hostvars[item].force is defined and hostvars[item].force) loop: "{{ groups['VMs'] }}" +- name: Copy additional disks on target + ansible.builtin.include_tasks: copy_additional_disk.yml + vars: + _vm_name: "{{ item }}" + loop: "{{ groups['VMs'] }}" + when: + - hostvars[item].additional_disk is defined + - deploy_vms_standalone_disk_copy | bool + - item not in deploy_vms_standalone_all_vms.list_vms or (item in deploy_vms_standalone_all_vms.list_vms and hostvars[item].force is defined and hostvars[item].force) + - name: Add main disk to disk list # This is only done in standalone because the disk is handled by vm-manager in the cluster ansible.builtin.set_fact: diff --git a/templates/vm/guest.xml.j2 b/templates/vm/guest.xml.j2 index 878cd02f1..27ce0c6bf 100644 --- a/templates/vm/guest.xml.j2 +++ b/templates/vm/guest.xml.j2 @@ -116,17 +116,17 @@ {% endif %} {% if vm.standalone_main_disk is defined %} - + {% endif %} -{% if vm.additional_disk is defined %} -{% for disk in vm.additional_disk %} +{% if vm.additional_disk is defined and vm.standalone_main_disk is defined %} +{% for file in vm.additional_disk %} - - - + + + {% endfor %} {% endif %}