Fix starting VM with kernel=None
When dom0 do not provide the kernel, it should also not set kernel command line in libvirt config. Otherwise qemu in stubdom fails to start because it get -append option without -kernel, which is illegal configuration. Fixes QubesOS/qubes-issues#3339
This commit is contained in:
		
							parent
							
								
									fd45378041
								
							
						
					
					
						commit
						466bf89aae
					
				@ -28,6 +28,8 @@ import datetime
 | 
				
			|||||||
import lxml.etree
 | 
					import lxml.etree
 | 
				
			||||||
import unittest.mock
 | 
					import unittest.mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import qubes
 | 
					import qubes
 | 
				
			||||||
import qubes.exc
 | 
					import qubes.exc
 | 
				
			||||||
import qubes.config
 | 
					import qubes.config
 | 
				
			||||||
@ -147,6 +149,7 @@ class QubesVMTestsMixin(object):
 | 
				
			|||||||
        super(QubesVMTestsMixin, self).setUp()
 | 
					        super(QubesVMTestsMixin, self).setUp()
 | 
				
			||||||
        self.app = qubes.tests.vm.TestApp()
 | 
					        self.app = qubes.tests.vm.TestApp()
 | 
				
			||||||
        self.app.vmm.offline_mode = True
 | 
					        self.app.vmm.offline_mode = True
 | 
				
			||||||
 | 
					        self.app.default_kernel = None
 | 
				
			||||||
        # when full test run is called, extensions are loaded by earlier
 | 
					        # when full test run is called, extensions are loaded by earlier
 | 
				
			||||||
        # tests, but if just this test class is run, load them manually here,
 | 
					        # tests, but if just this test class is run, load them manually here,
 | 
				
			||||||
        # to have the same behaviour
 | 
					        # to have the same behaviour
 | 
				
			||||||
@ -583,6 +586,14 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
 | 
				
			|||||||
        vm = self.get_vm(uuid=my_uuid)
 | 
					        vm = self.get_vm(uuid=my_uuid)
 | 
				
			||||||
        vm.netvm = None
 | 
					        vm.netvm = None
 | 
				
			||||||
        vm.virt_mode = 'pv'
 | 
					        vm.virt_mode = 'pv'
 | 
				
			||||||
 | 
					        with unittest.mock.patch('qubes.config.qubes_base_dir',
 | 
				
			||||||
 | 
					                '/tmp/qubes-test'):
 | 
				
			||||||
 | 
					            kernel_dir = '/tmp/qubes-test/vm-kernels/dummy'
 | 
				
			||||||
 | 
					            os.makedirs(kernel_dir, exist_ok=True)
 | 
				
			||||||
 | 
					            open(os.path.join(kernel_dir, 'vmlinuz'), 'w').close()
 | 
				
			||||||
 | 
					            open(os.path.join(kernel_dir, 'initramfs'), 'w').close()
 | 
				
			||||||
 | 
					            self.addCleanup(shutil.rmtree, '/tmp/qubes-test')
 | 
				
			||||||
 | 
					            vm.kernel = 'dummy'
 | 
				
			||||||
        # tests for storage are later
 | 
					        # tests for storage are later
 | 
				
			||||||
        vm.volumes['kernel'] = unittest.mock.Mock(**{
 | 
					        vm.volumes['kernel'] = unittest.mock.Mock(**{
 | 
				
			||||||
            'kernels_dir': '/tmp/kernel',
 | 
					            'kernels_dir': '/tmp/kernel',
 | 
				
			||||||
@ -620,8 +631,6 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
 | 
				
			|||||||
            <loader type="rom">hvmloader</loader>
 | 
					            <loader type="rom">hvmloader</loader>
 | 
				
			||||||
            <boot dev="cdrom" />
 | 
					            <boot dev="cdrom" />
 | 
				
			||||||
            <boot dev="hd" />
 | 
					            <boot dev="hd" />
 | 
				
			||||||
            <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
 | 
					 | 
				
			||||||
            <cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH rd.plymouth.enable=0 plymouth.enable=0 nopat</cmdline>
 | 
					 | 
				
			||||||
        </os>
 | 
					        </os>
 | 
				
			||||||
        <features>
 | 
					        <features>
 | 
				
			||||||
            <pae/>
 | 
					            <pae/>
 | 
				
			||||||
@ -634,6 +643,7 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
 | 
				
			|||||||
        <on_reboot>destroy</on_reboot>
 | 
					        <on_reboot>destroy</on_reboot>
 | 
				
			||||||
        <on_crash>destroy</on_crash>
 | 
					        <on_crash>destroy</on_crash>
 | 
				
			||||||
        <devices>
 | 
					        <devices>
 | 
				
			||||||
 | 
					            <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
 | 
				
			||||||
            <emulator type="stubdom-linux" />
 | 
					            <emulator type="stubdom-linux" />
 | 
				
			||||||
            <input type="tablet" bus="usb"/>
 | 
					            <input type="tablet" bus="usb"/>
 | 
				
			||||||
            <video>
 | 
					            <video>
 | 
				
			||||||
@ -651,6 +661,69 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
 | 
				
			|||||||
        self.assertXMLEqual(lxml.etree.XML(libvirt_xml),
 | 
					        self.assertXMLEqual(lxml.etree.XML(libvirt_xml),
 | 
				
			||||||
            lxml.etree.XML(expected))
 | 
					            lxml.etree.XML(expected))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_600_libvirt_xml_hvm_dom0_kernel(self):
 | 
				
			||||||
 | 
					        expected = '''<domain type="xen">
 | 
				
			||||||
 | 
					        <name>test-inst-test</name>
 | 
				
			||||||
 | 
					        <uuid>7db78950-c467-4863-94d1-af59806384ea</uuid>
 | 
				
			||||||
 | 
					        <memory unit="MiB">500</memory>
 | 
				
			||||||
 | 
					        <currentMemory unit="MiB">400</currentMemory>
 | 
				
			||||||
 | 
					        <vcpu placement="static">2</vcpu>
 | 
				
			||||||
 | 
					        <cpu mode='host-passthrough'>
 | 
				
			||||||
 | 
					            <!-- disable nested HVM -->
 | 
				
			||||||
 | 
					            <feature name='vmx' policy='disable'/>
 | 
				
			||||||
 | 
					            <feature name='svm' policy='disable'/>
 | 
				
			||||||
 | 
					            <!-- disable SMAP inside VM, because of Linux bug -->
 | 
				
			||||||
 | 
					            <feature name='smap' policy='disable'/>
 | 
				
			||||||
 | 
					        </cpu>
 | 
				
			||||||
 | 
					        <os>
 | 
				
			||||||
 | 
					            <type arch="x86_64" machine="xenfv">hvm</type>
 | 
				
			||||||
 | 
					                <!--
 | 
				
			||||||
 | 
					                     For the libxl backend libvirt switches between OVMF (UEFI)
 | 
				
			||||||
 | 
					                     and SeaBIOS based on the loader type. This has nothing to
 | 
				
			||||||
 | 
					                     do with the hvmloader binary.
 | 
				
			||||||
 | 
					                -->
 | 
				
			||||||
 | 
					            <loader type="rom">hvmloader</loader>
 | 
				
			||||||
 | 
					            <boot dev="cdrom" />
 | 
				
			||||||
 | 
					            <boot dev="hd" />
 | 
				
			||||||
 | 
					            <cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH rd.plymouth.enable=0 plymouth.enable=0 nopat</cmdline>
 | 
				
			||||||
 | 
					        </os>
 | 
				
			||||||
 | 
					        <features>
 | 
				
			||||||
 | 
					            <pae/>
 | 
				
			||||||
 | 
					            <acpi/>
 | 
				
			||||||
 | 
					            <apic/>
 | 
				
			||||||
 | 
					            <viridian/>
 | 
				
			||||||
 | 
					        </features>
 | 
				
			||||||
 | 
					        <clock offset="variable" adjustment="0" basis="localtime" />
 | 
				
			||||||
 | 
					        <on_poweroff>destroy</on_poweroff>
 | 
				
			||||||
 | 
					        <on_reboot>destroy</on_reboot>
 | 
				
			||||||
 | 
					        <on_crash>destroy</on_crash>
 | 
				
			||||||
 | 
					        <devices>
 | 
				
			||||||
 | 
					            <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
 | 
				
			||||||
 | 
					            <emulator type="stubdom-linux" />
 | 
				
			||||||
 | 
					            <input type="tablet" bus="usb"/>
 | 
				
			||||||
 | 
					            <video>
 | 
				
			||||||
 | 
					                <model type="vga"/>
 | 
				
			||||||
 | 
					            </video>
 | 
				
			||||||
 | 
					            <graphics type="qubes"/>
 | 
				
			||||||
 | 
					        </devices>
 | 
				
			||||||
 | 
					        </domain>
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        my_uuid = '7db78950-c467-4863-94d1-af59806384ea'
 | 
				
			||||||
 | 
					        vm = self.get_vm(uuid=my_uuid)
 | 
				
			||||||
 | 
					        vm.netvm = None
 | 
				
			||||||
 | 
					        vm.virt_mode = 'hvm'
 | 
				
			||||||
 | 
					        with unittest.mock.patch('qubes.config.qubes_base_dir',
 | 
				
			||||||
 | 
					                '/tmp/qubes-test'):
 | 
				
			||||||
 | 
					            kernel_dir = '/tmp/qubes-test/vm-kernels/dummy'
 | 
				
			||||||
 | 
					            os.makedirs(kernel_dir, exist_ok=True)
 | 
				
			||||||
 | 
					            open(os.path.join(kernel_dir, 'vmlinuz'), 'w').close()
 | 
				
			||||||
 | 
					            open(os.path.join(kernel_dir, 'initramfs'), 'w').close()
 | 
				
			||||||
 | 
					            self.addCleanup(shutil.rmtree, '/tmp/qubes-test')
 | 
				
			||||||
 | 
					            vm.kernel = 'dummy'
 | 
				
			||||||
 | 
					        libvirt_xml = vm.create_config_file()
 | 
				
			||||||
 | 
					        self.assertXMLEqual(lxml.etree.XML(libvirt_xml),
 | 
				
			||||||
 | 
					            lxml.etree.XML(expected))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_600_libvirt_xml_pvh(self):
 | 
					    def test_600_libvirt_xml_pvh(self):
 | 
				
			||||||
        expected = '''<domain type="xen">
 | 
					        expected = '''<domain type="xen">
 | 
				
			||||||
        <name>test-inst-test</name>
 | 
					        <name>test-inst-test</name>
 | 
				
			||||||
@ -701,6 +774,14 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
 | 
				
			|||||||
        vm = self.get_vm(uuid=my_uuid)
 | 
					        vm = self.get_vm(uuid=my_uuid)
 | 
				
			||||||
        vm.netvm = None
 | 
					        vm.netvm = None
 | 
				
			||||||
        vm.virt_mode = 'pvh'
 | 
					        vm.virt_mode = 'pvh'
 | 
				
			||||||
 | 
					        with unittest.mock.patch('qubes.config.qubes_base_dir',
 | 
				
			||||||
 | 
					                '/tmp/qubes-test'):
 | 
				
			||||||
 | 
					            kernel_dir = '/tmp/qubes-test/vm-kernels/dummy'
 | 
				
			||||||
 | 
					            os.makedirs(kernel_dir, exist_ok=True)
 | 
				
			||||||
 | 
					            open(os.path.join(kernel_dir, 'vmlinuz'), 'w').close()
 | 
				
			||||||
 | 
					            open(os.path.join(kernel_dir, 'initramfs'), 'w').close()
 | 
				
			||||||
 | 
					            self.addCleanup(shutil.rmtree, '/tmp/qubes-test')
 | 
				
			||||||
 | 
					            vm.kernel = 'dummy'
 | 
				
			||||||
        # tests for storage are later
 | 
					        # tests for storage are later
 | 
				
			||||||
        vm.volumes['kernel'] = unittest.mock.Mock(**{
 | 
					        vm.volumes['kernel'] = unittest.mock.Mock(**{
 | 
				
			||||||
            'kernels_dir': '/tmp/kernel',
 | 
					            'kernels_dir': '/tmp/kernel',
 | 
				
			||||||
@ -738,8 +819,6 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
 | 
				
			|||||||
            <loader type="rom">hvmloader</loader>
 | 
					            <loader type="rom">hvmloader</loader>
 | 
				
			||||||
            <boot dev="cdrom" />
 | 
					            <boot dev="cdrom" />
 | 
				
			||||||
            <boot dev="hd" />
 | 
					            <boot dev="hd" />
 | 
				
			||||||
            <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
 | 
					 | 
				
			||||||
            <cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH rd.plymouth.enable=0 plymouth.enable=0 nopat</cmdline>
 | 
					 | 
				
			||||||
        </os>
 | 
					        </os>
 | 
				
			||||||
        <features>
 | 
					        <features>
 | 
				
			||||||
            <pae/>
 | 
					            <pae/>
 | 
				
			||||||
@ -759,6 +838,7 @@ class TC_90_QubesVM(QubesVMTestsMixin, qubes.tests.QubesTestCase):
 | 
				
			|||||||
                <backenddomain name="test-inst-netvm" />
 | 
					                <backenddomain name="test-inst-netvm" />
 | 
				
			||||||
                <script path="vif-route-qubes" />
 | 
					                <script path="vif-route-qubes" />
 | 
				
			||||||
            </interface>
 | 
					            </interface>
 | 
				
			||||||
 | 
					            <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
 | 
				
			||||||
            <emulator type="stubdom-linux" />
 | 
					            <emulator type="stubdom-linux" />
 | 
				
			||||||
            <input type="tablet" bus="usb"/>
 | 
					            <input type="tablet" bus="usb"/>
 | 
				
			||||||
            <video>
 | 
					            <video>
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,6 @@
 | 
				
			|||||||
                <loader type="{{ "pflash" if vm.features.check_with_template('uefi', False) else "rom" }}">hvmloader</loader>
 | 
					                <loader type="{{ "pflash" if vm.features.check_with_template('uefi', False) else "rom" }}">hvmloader</loader>
 | 
				
			||||||
                <boot dev="cdrom" />
 | 
					                <boot dev="cdrom" />
 | 
				
			||||||
                <boot dev="hd" />
 | 
					                <boot dev="hd" />
 | 
				
			||||||
            <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
 | 
					 | 
				
			||||||
            {% else %}
 | 
					            {% else %}
 | 
				
			||||||
                {% if vm.virt_mode == 'pvh' %}
 | 
					                {% if vm.virt_mode == 'pvh' %}
 | 
				
			||||||
                    <type arch="x86_64" machine="xenfv">hvm</type>
 | 
					                    <type arch="x86_64" machine="xenfv">hvm</type>
 | 
				
			||||||
@ -43,7 +42,9 @@
 | 
				
			|||||||
                <kernel>{{ vm.storage.kernels_dir }}/vmlinuz</kernel>
 | 
					                <kernel>{{ vm.storage.kernels_dir }}/vmlinuz</kernel>
 | 
				
			||||||
                <initrd>{{ vm.storage.kernels_dir }}/initramfs</initrd>
 | 
					                <initrd>{{ vm.storage.kernels_dir }}/initramfs</initrd>
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
            <cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH rd.plymouth.enable=0 plymouth.enable=0 {{ vm.kernelopts }}</cmdline>
 | 
					            {% if vm.kernel %}
 | 
				
			||||||
 | 
					                <cmdline>root=/dev/mapper/dmroot ro nomodeset console=hvc0 rd_NO_PLYMOUTH rd.plymouth.enable=0 plymouth.enable=0 {{ vm.kernelopts }}</cmdline>
 | 
				
			||||||
 | 
					            {% endif %}
 | 
				
			||||||
        {% endblock %}
 | 
					        {% endblock %}
 | 
				
			||||||
    </os>
 | 
					    </os>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -145,6 +146,7 @@
 | 
				
			|||||||
            {% endfor %}
 | 
					            {% endfor %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {% if vm.virt_mode == 'hvm' %}
 | 
					            {% if vm.virt_mode == 'hvm' %}
 | 
				
			||||||
 | 
					                <!-- server_ip is the address of stubdomain. It hosts it's own DNS server. -->
 | 
				
			||||||
                <emulator
 | 
					                <emulator
 | 
				
			||||||
                    {% if vm.features.check_with_template('linux-stubdom', True) %}
 | 
					                    {% if vm.features.check_with_template('linux-stubdom', True) %}
 | 
				
			||||||
                        type="stubdom-linux"
 | 
					                        type="stubdom-linux"
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,8 @@ added as needed.
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class libvirtError(Exception):
 | 
					class libvirtError(Exception):
 | 
				
			||||||
    pass
 | 
					    def get_error_code(self):
 | 
				
			||||||
 | 
					        return VIR_ERR_NO_DOMAIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class virConnect:
 | 
					class virConnect:
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
@ -30,3 +31,5 @@ VIR_DOMAIN_SHUTDOWN = 4
 | 
				
			|||||||
VIR_DOMAIN_SHUTOFF = 5
 | 
					VIR_DOMAIN_SHUTOFF = 5
 | 
				
			||||||
VIR_DOMAIN_CRASHED = 6
 | 
					VIR_DOMAIN_CRASHED = 6
 | 
				
			||||||
VIR_DOMAIN_PMSUSPENDED = 7
 | 
					VIR_DOMAIN_PMSUSPENDED = 7
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VIR_ERR_NO_DOMAIN = 0
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user