diff --git a/salt/modules/virt.py b/salt/modules/virt.py index 8d0d802636ed..edb00dc41f26 100644 --- a/salt/modules/virt.py +++ b/salt/modules/virt.py @@ -243,14 +243,6 @@ def __get_conn(**kwargs): return conn -def _get_domain_types(**kwargs): - ''' - Return the list of possible values for the type attribute. - ''' - caps = capabilities(**kwargs) - return sorted(set([x for y in [guest['arch']['domains'].keys() for guest in caps['guests']] for x in y])) - - def _get_domain(conn, *vms, **kwargs): ''' Return a domain object for the named VM or return domain object for all VMs. @@ -538,6 +530,8 @@ def _gen_xml(name, diskp, nicp, hypervisor, + os_type, + arch, graphics=None, **kwargs): ''' @@ -607,6 +601,9 @@ def _gen_xml(name, context['nics'] = nicp + context['os_type'] = os_type + context['arch'] = arch + fn_ = 'libvirt_domain.jinja' try: template = JINJA.get_template(fn_) @@ -1107,6 +1104,8 @@ def init(name, enable_vnc=False, enable_qcow=False, graphics=None, + os_type=None, + arch=None, **kwargs): ''' Initialize a new vm @@ -1165,6 +1164,16 @@ def init(name, Dictionary providing details on the graphics device to create. (Default: ``None``) See :ref:`init-graphics-def` for more details on the possible values. + .. versionadded:: Fluorine + :param os_type: + type of virtualization as found in the ``//os/type`` element of the libvirt definition. + The default value is taken from the host capabilities, with a preference for ``hvm``. + + .. versionadded:: Fluorine + :param arch: + architecture of the virtual machine. The default value is taken from the host capabilities, + but ``x86_64`` is prefed over ``i686``. + .. versionadded:: Fluorine :param enable_qcow: ``True`` to create a QCOW2 overlay image, rather than copying the image @@ -1327,7 +1336,10 @@ def init(name, virt: images: /data/my/vm/images/ ''' - hypervisors = _get_domain_types(**kwargs) + caps = capabilities(**kwargs) + os_types = sorted(set([guest['os_type'] for guest in caps['guests']])) + arches = sorted(set([guest['arch']['name'] for guest in caps['guests']])) + hypervisors = sorted(set([x for y in [guest['arch']['domains'].keys() for guest in caps['guests']] for x in y])) hypervisor = __salt__['config.get']('libvirt:hypervisor', hypervisor) if hypervisor is not None: salt.utils.versions.warn_until( @@ -1448,7 +1460,10 @@ def init(name, '\'enable_vnc\' will be removed in {version}. ') graphics = {'type': 'vnc'} - vm_xml = _gen_xml(name, cpu, mem, diskp, nicp, hypervisor, graphics, **kwargs) + os_type = 'hvm' if 'hvm' in os_types else os_types[0] + arch = 'x86_64' if 'x86_64' in arches else arches[0] + + vm_xml = _gen_xml(name, cpu, mem, diskp, nicp, hypervisor, os_type, arch, graphics, **kwargs) conn = __get_conn(**kwargs) try: conn.defineXML(vm_xml) @@ -1692,6 +1707,8 @@ def update(name, _disk_profile(disk_profile, hypervisor, disks, name, **kwargs), _get_merged_nics(hypervisor, nic_profile, interfaces), hypervisor, + domain.OSType(), + desc.find('.//os/type').get('arch'), graphics, **kwargs)) @@ -2378,7 +2395,8 @@ def get_profiles(hypervisor=None, **kwargs): ''' ret = {} - hypervisors = _get_domain_types(**kwargs) + caps = capabilities(**kwargs) + hypervisors = sorted(set([x for y in [guest['arch']['domains'].keys() for guest in caps['guests']] for x in y])) default_hypervisor = 'kvm' if 'kvm' in hypervisors else hypervisors[0] if not hypervisor: diff --git a/salt/states/virt.py b/salt/states/virt.py index b28ed6f16ca9..fe155f93d729 100644 --- a/salt/states/virt.py +++ b/salt/states/virt.py @@ -253,7 +253,9 @@ def running(name, update=False, connection=None, username=None, - password=None): + password=None, + os_type=None, + arch=None): ''' Starts an existing guest, or defines and starts a new VM with specified arguments. @@ -326,6 +328,17 @@ def running(name, :param password: password to connect with, overriding defaults .. versionadded:: Fluorine + :param os_type: + type of virtualization as found in the ``//os/type`` element of the libvirt definition. + The default value is taken from the host capabilities, with a preference for ``hvm``. + Only used when creating a new virtual machine. + + .. versionadded:: Neon + :param arch: + architecture of the virtual machine. The default value is taken from the host capabilities, + but ``x86_64`` is prefed over ``i686``. Only used when creating a new virtual machine. + + .. versionadded:: Neon .. rubric:: Example States @@ -429,6 +442,8 @@ def running(name, __salt__['virt.init'](name, cpu=cpu, mem=mem, + os_type=os_type, + arch=arch, image=image, hypervisor=vm_type, disk=disk_profile, diff --git a/salt/templates/virt/libvirt_domain.jinja b/salt/templates/virt/libvirt_domain.jinja index b35704f71374..8d4e0cb3133f 100644 --- a/salt/templates/virt/libvirt_domain.jinja +++ b/salt/templates/virt/libvirt_domain.jinja @@ -3,7 +3,7 @@ {{ cpu }} {{ mem }} - hvm + {{ os_type }} {% for dev in boot_dev %} {% endfor %} diff --git a/tests/unit/modules/test_virt.py b/tests/unit/modules/test_virt.py index 1a8f3cdf98a1..77b0487827ee 100644 --- a/tests/unit/modules/test_virt.py +++ b/tests/unit/modules/test_virt.py @@ -116,10 +116,14 @@ def test_boot_default_dev(self): 512, diskp, nicp, - 'kvm' + 'kvm', + 'hvm', + 'x86_64' ) root = ET.fromstring(xml_data) self.assertEqual(root.find('os/boot').attrib['dev'], 'hd') + self.assertEqual(root.find('os/type').attrib['arch'], 'x86_64') + self.assertEqual(root.find('os/type').text, 'hvm') def test_boot_custom_dev(self): ''' @@ -134,6 +138,8 @@ def test_boot_custom_dev(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', boot_dev='cdrom' ) root = ET.fromstring(xml_data) @@ -152,6 +158,8 @@ def test_boot_multiple_devs(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', boot_dev='cdrom network' ) root = ET.fromstring(xml_data) @@ -171,6 +179,8 @@ def test_gen_xml_for_serial_console(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', serial_type='pty', console=True ) @@ -191,6 +201,8 @@ def test_gen_xml_for_telnet_console(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', serial_type='tcp', console=True, telnet_port=22223 @@ -213,6 +225,8 @@ def test_gen_xml_for_telnet_console_unspecified_port(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', serial_type='tcp', console=True ) @@ -234,6 +248,8 @@ def test_gen_xml_for_serial_no_console(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', serial_type='pty', console=False ) @@ -254,6 +270,8 @@ def test_gen_xml_for_telnet_no_console(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', serial_type='tcp', console=False, ) @@ -273,7 +291,9 @@ def test_gen_xml_nographics_default(self): 512, diskp, nicp, - 'kvm' + 'kvm', + 'hvm', + 'x86_64' ) root = ET.fromstring(xml_data) self.assertIsNone(root.find('devices/graphics')) @@ -291,6 +311,8 @@ def test_gen_xml_vnc_default(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', graphics={'type': 'vnc', 'port': 1234, 'tlsPort': 5678, 'listen': {'type': 'address', 'address': 'myhost'}}, ) @@ -316,6 +338,8 @@ def test_gen_xml_spice_default(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', graphics={'type': 'spice'}, ) root = ET.fromstring(xml_data) @@ -338,6 +362,8 @@ def test_gen_xml_spice(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', graphics={'type': 'spice', 'port': 1234, 'tls_port': 5678, 'listen': {'type': 'none'}}, ) root = ET.fromstring(xml_data) @@ -431,6 +457,8 @@ def test_gen_xml_for_kvm_default_profile(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', ) root = ET.fromstring(xml_data) self.assertEqual(root.attrib['type'], 'kvm') @@ -473,6 +501,8 @@ def test_gen_xml_for_esxi_default_profile(self): diskp, nicp, 'vmware', + 'hvm', + 'x86_64', ) root = ET.fromstring(xml_data) self.assertEqual(root.attrib['type'], 'vmware') @@ -527,6 +557,8 @@ def test_gen_xml_for_esxi_custom_profile(self): diskp, nicp, 'vmware', + 'hvm', + 'x86_64', ) root = ET.fromstring(xml_data) self.assertEqual(root.attrib['type'], 'vmware') @@ -563,6 +595,8 @@ def test_gen_xml_for_kvm_custom_profile(self): diskp, nicp, 'kvm', + 'hvm', + 'x86_64', ) root = ET.fromstring(xml_data) self.assertEqual(root.attrib['type'], 'kvm') @@ -633,7 +667,9 @@ def test_controller_for_esxi(self): 512, diskp, nicp, - 'vmware' + 'vmware', + 'hvm', + 'x86_64', ) root = ET.fromstring(xml_data) controllers = root.findall('.//devices/controller') @@ -653,7 +689,9 @@ def test_controller_for_kvm(self): 512, diskp, nicp, - 'kvm' + 'kvm', + 'hvm', + 'x86_64', ) root = ET.fromstring(xml_data) controllers = root.findall('.//devices/controller') @@ -757,6 +795,9 @@ def test_update(self): 1048576 1048576 1 + + hvm + @@ -802,6 +843,7 @@ def test_update(self): ''' domain_mock = self.set_mock_vm('myvm', xml) + domain_mock.OSType = MagicMock(return_value='hvm') define_mock = MagicMock(return_value=True) self.mock_conn.defineXML = define_mock diff --git a/tests/unit/states/test_virt.py b/tests/unit/states/test_virt.py index 52648c9cecf0..acf8ae51b16c 100644 --- a/tests/unit/states/test_virt.py +++ b/tests/unit/states/test_virt.py @@ -253,6 +253,7 @@ def test_running(self): mem=2048, image='/path/to/img.qcow2'), ret) init_mock.assert_called_with('myvm', cpu=2, mem=2048, image='/path/to/img.qcow2', + os_type=None, arch=None, disk=None, disks=None, nic=None, interfaces=None, graphics=None, hypervisor=None, seed=True, install=True, pub_key=None, priv_key=None, @@ -289,6 +290,8 @@ def test_running(self): self.assertDictEqual(virt.running('myvm', cpu=2, mem=2048, + os_type='linux', + arch='i686', vm_type='qemu', disk_profile='prod', disks=disks, @@ -305,6 +308,8 @@ def test_running(self): init_mock.assert_called_with('myvm', cpu=2, mem=2048, + os_type='linux', + arch='i686', image=None, disk='prod', disks=disks,