tests: booting VM from ISO image
Check two cases: if ISO image is in dom0 and if its in a VM. QubesOS/qubes-issues#3339
This commit is contained in:
parent
96bd734852
commit
9a4d2abf1f
@ -1061,6 +1061,37 @@ class SystemTestCase(QubesTestCase):
|
|||||||
shutil.rmtree(mountpoint)
|
shutil.rmtree(mountpoint)
|
||||||
subprocess.check_call(['sudo', 'losetup', '-d', loopdev])
|
subprocess.check_call(['sudo', 'losetup', '-d', loopdev])
|
||||||
|
|
||||||
|
def create_bootable_iso(self):
|
||||||
|
'''Create simple bootable ISO image.
|
||||||
|
Type 'poweroff' to it to terminate that VM.
|
||||||
|
'''
|
||||||
|
isolinux_cfg = (
|
||||||
|
'prompt 1\n'
|
||||||
|
'label poweroff\n'
|
||||||
|
' kernel poweroff.c32\n'
|
||||||
|
)
|
||||||
|
output_fd, output_path = tempfile.mkstemp('.iso')
|
||||||
|
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||||
|
try:
|
||||||
|
shutil.copy('/usr/share/syslinux/isolinux.bin', tmp_dir)
|
||||||
|
shutil.copy('/usr/share/syslinux/ldlinux.c32', tmp_dir)
|
||||||
|
shutil.copy('/usr/share/syslinux/poweroff.c32', tmp_dir)
|
||||||
|
with open(os.path.join(tmp_dir, 'isolinux.cfg'), 'w') as cfg:
|
||||||
|
cfg.write(isolinux_cfg)
|
||||||
|
subprocess.check_call(['genisoimage', '-o', output_path,
|
||||||
|
'-c', 'boot.cat',
|
||||||
|
'-b', 'isolinux.bin',
|
||||||
|
'-no-emul-boot',
|
||||||
|
'-boot-load-size', '4',
|
||||||
|
'-boot-info-table',
|
||||||
|
'-q',
|
||||||
|
tmp_dir])
|
||||||
|
except FileNotFoundError:
|
||||||
|
self.skipTest('syslinux or genisoimage not installed')
|
||||||
|
os.close(output_fd)
|
||||||
|
self.addCleanup(os.unlink, output_path)
|
||||||
|
return output_path
|
||||||
|
|
||||||
def create_local_file(self, filename, content, mode='w'):
|
def create_local_file(self, filename, content, mode='w'):
|
||||||
with open(filename, mode) as file:
|
with open(filename, mode) as file:
|
||||||
file.write(content)
|
file.write(content)
|
||||||
|
@ -32,6 +32,8 @@ import unittest
|
|||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
|
import pkg_resources
|
||||||
|
|
||||||
import qubes
|
import qubes
|
||||||
import qubes.firewall
|
import qubes.firewall
|
||||||
import qubes.tests
|
import qubes.tests
|
||||||
@ -82,6 +84,30 @@ class TC_00_Basic(qubes.tests.SystemTestCase):
|
|||||||
self.loop.run_until_complete(asyncio.sleep(0.1))
|
self.loop.run_until_complete(asyncio.sleep(0.1))
|
||||||
self.assertTrue(flag)
|
self.assertTrue(flag)
|
||||||
|
|
||||||
|
@unittest.skipUnless(
|
||||||
|
spawn.find_executable('xdotool'), "xdotool not installed")
|
||||||
|
def test_120_start_standalone_with_cdrom_dom0(self):
|
||||||
|
vmname = self.make_vm_name('appvm')
|
||||||
|
self.vm = self.app.add_new_vm('StandaloneVM', label='red', name=vmname)
|
||||||
|
self.loop.run_until_complete(self.vm.create_on_disk())
|
||||||
|
self.vm.kernel = None
|
||||||
|
|
||||||
|
iso_path = self.create_bootable_iso()
|
||||||
|
# start the VM using qvm-start tool, to test --cdrom option there
|
||||||
|
p = self.loop.run_until_complete(asyncio.create_subprocess_exec(
|
||||||
|
'qvm-start', '--cdrom=dom0:' + iso_path, self.vm.name,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
|
(stdout, _) = self.loop.run_until_complete(p.communicate())
|
||||||
|
self.assertEqual(p.returncode, 0, stdout)
|
||||||
|
# check if VM do not crash instantly
|
||||||
|
self.loop.run_until_complete(asyncio.sleep(5))
|
||||||
|
self.assertTrue(self.vm.is_running())
|
||||||
|
# Type 'poweroff'
|
||||||
|
subprocess.check_call(['xdotool', 'search', '--name', self.vm.name,
|
||||||
|
'type', 'poweroff\r'])
|
||||||
|
self.loop.run_until_complete(asyncio.sleep(1))
|
||||||
|
self.assertFalse(self.vm.is_running())
|
||||||
|
|
||||||
def _test_200_on_domain_start(self, vm, event, **_kwargs):
|
def _test_200_on_domain_start(self, vm, event, **_kwargs):
|
||||||
'''Simulate domain crash just after startup'''
|
'''Simulate domain crash just after startup'''
|
||||||
vm.libvirt_domain.destroy()
|
vm.libvirt_domain.destroy()
|
||||||
@ -649,6 +675,48 @@ class TC_05_StandaloneVMMixin(object):
|
|||||||
# some safety margin for FS metadata
|
# some safety margin for FS metadata
|
||||||
self.assertGreater(int(new_size.strip()), 19 * 1024 ** 2)
|
self.assertGreater(int(new_size.strip()), 19 * 1024 ** 2)
|
||||||
|
|
||||||
|
class TC_06_AppVMMixin(object):
|
||||||
|
template = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TC_06_AppVMMixin, self).setUp()
|
||||||
|
self.init_default_template(self.template)
|
||||||
|
|
||||||
|
@unittest.skipUnless(
|
||||||
|
spawn.find_executable('xdotool'), "xdotool not installed")
|
||||||
|
def test_121_start_standalone_with_cdrom_vm(self):
|
||||||
|
cdrom_vmname = self.make_vm_name('cdrom')
|
||||||
|
self.cdrom_vm = self.app.add_new_vm('AppVM', label='red',
|
||||||
|
name=cdrom_vmname)
|
||||||
|
self.loop.run_until_complete(self.cdrom_vm.create_on_disk())
|
||||||
|
self.loop.run_until_complete(self.cdrom_vm.start())
|
||||||
|
iso_path = self.create_bootable_iso()
|
||||||
|
with open(iso_path, 'rb') as iso_f:
|
||||||
|
self.loop.run_until_complete(
|
||||||
|
self.cdrom_vm.run_for_stdio('cat > /home/user/boot.iso',
|
||||||
|
stdin=iso_f))
|
||||||
|
|
||||||
|
vmname = self.make_vm_name('appvm')
|
||||||
|
self.vm = self.app.add_new_vm('StandaloneVM', label='red', name=vmname)
|
||||||
|
self.loop.run_until_complete(self.vm.create_on_disk())
|
||||||
|
self.vm.kernel = None
|
||||||
|
|
||||||
|
# start the VM using qvm-start tool, to test --cdrom option there
|
||||||
|
p = self.loop.run_until_complete(asyncio.create_subprocess_exec(
|
||||||
|
'qvm-start', '--cdrom=' + cdrom_vmname + ':/home/user/boot.iso',
|
||||||
|
self.vm.name,
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
|
||||||
|
(stdout, _) = self.loop.run_until_complete(p.communicate())
|
||||||
|
self.assertEqual(p.returncode, 0, stdout)
|
||||||
|
# check if VM do not crash instantly
|
||||||
|
self.loop.run_until_complete(asyncio.sleep(5))
|
||||||
|
self.assertTrue(self.vm.is_running())
|
||||||
|
# Type 'poweroff'
|
||||||
|
subprocess.check_call(['xdotool', 'search', '--name', self.vm.name,
|
||||||
|
'type', 'poweroff\r'])
|
||||||
|
self.loop.run_until_complete(asyncio.sleep(1))
|
||||||
|
self.assertFalse(self.vm.is_running())
|
||||||
|
|
||||||
|
|
||||||
def load_tests(loader, tests, pattern):
|
def load_tests(loader, tests, pattern):
|
||||||
for template in qubes.tests.list_templates():
|
for template in qubes.tests.list_templates():
|
||||||
@ -657,6 +725,11 @@ def load_tests(loader, tests, pattern):
|
|||||||
'TC_05_StandaloneVM_' + template,
|
'TC_05_StandaloneVM_' + template,
|
||||||
(TC_05_StandaloneVMMixin, qubes.tests.SystemTestCase),
|
(TC_05_StandaloneVMMixin, qubes.tests.SystemTestCase),
|
||||||
{'template': template})))
|
{'template': template})))
|
||||||
|
tests.addTests(loader.loadTestsFromTestCase(
|
||||||
|
type(
|
||||||
|
'TC_06_AppVM_' + template,
|
||||||
|
(TC_06_AppVMMixin, qubes.tests.SystemTestCase),
|
||||||
|
{'template': template})))
|
||||||
|
|
||||||
return tests
|
return tests
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user