Merge branch 'devel20191029'

This commit is contained in:
Marek Marczykowski-Górecki 2019-11-12 23:11:30 +01:00
commit ba105e89c6
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724
9 changed files with 143 additions and 4 deletions

View File

@ -713,6 +713,18 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
yield from self.app.remove_pool(self.arg)
self.app.save()
@qubes.api.method('admin.pool.volume.List', no_payload=True,
scope='global', read=True)
@asyncio.coroutine
def pool_volume_list(self):
self.enforce(self.dest.name == 'dom0')
self.enforce(self.arg in self.app.pools.keys())
pool = self.app.pools[self.arg]
volume_names = self.fire_event_for_filter(pool.volumes.keys())
return ''.join('{}\n'.format(name) for name in volume_names)
@qubes.api.method('admin.pool.Set.revisions_to_keep',
scope='global', write=True)
@asyncio.coroutine

View File

@ -309,11 +309,21 @@ class QubesHost:
:raises NotImplementedError: when not under Xen
"""
try:
self._physinfo = self.app.xc.physinfo()
self._physinfo = self.app.vmm.xc.physinfo()
except AttributeError:
raise NotImplementedError('This function requires Xen hypervisor')
return int(self._physinfo['free_memory'])
def is_iommu_supported(self):
"""Check if IOMMU is supported on this platform"""
if self._physinfo is None:
try:
self._physinfo = self.app.vmm.xc.physinfo()
except AttributeError:
raise NotImplementedError(
'This function requires Xen hypervisor')
return 'hvm_directio' in self._physinfo['virt_caps']
def get_vm_stats(self, previous_time=None, previous=None, only_vm=None):
"""Measure cpu usage for all domains at once.

View File

@ -28,6 +28,7 @@ import os
import os.path
import re
import subprocess
from contextlib import suppress
import qubes.storage
@ -394,6 +395,17 @@ class FileVolume(qubes.storage.Volume):
iso_date = qubes.storage.isodate(seconds).split('.', 1)[0]
return {'old': iso_date}
@property
def size(self):
with suppress(FileNotFoundError):
self._size = os.path.getsize(self.path)
return self._size
@size.setter
def size(self, _):
raise qubes.storage.StoragePoolException(
"You shouldn't use volume size setter, use resize method instead")
@property
def usage(self):
''' Returns the actualy used space '''

View File

@ -209,8 +209,7 @@ class LinuxKernel(Pool):
[pool for pool in app.pools.values() if pool is not self],
self.dir_path)
@property
def volumes(self):
def list_volumes(self):
''' Return all known kernel volumes '''
return [LinuxModules(self.dir_path,
kernel_version,

View File

@ -2570,6 +2570,18 @@ class TC_00_VMs(AdminAPITestCase):
with self.assertRaises(qubes.exc.QubesVMNotRunningError):
self.call_mgmt_func(b'admin.vm.Console', b'test-vm1')
def test_700_pool_volume_list(self):
self.app.pools = {
'pool1': unittest.mock.Mock(config={
'param1': 'value1', 'param2': 'value2'},
usage=102400,
size=204800,
volumes={'vol1': unittest.mock.Mock(),
'vol2': unittest.mock.Mock()})
}
value = self.call_mgmt_func(b'admin.pool.volume.List', b'dom0', b'pool1')
self.assertEqual(value, 'vol1\nvol2\n')
def test_990_vm_unexpected_payload(self):
methods_with_no_payload = [
b'admin.vm.List',
@ -2677,6 +2689,7 @@ class TC_00_VMs(AdminAPITestCase):
b'admin.deviceclass.List',
b'admin.vmclass.List',
b'admin.vm.List',
b'admin.pool.volume.List',
b'admin.label.List',
b'admin.label.Get',
b'admin.label.Remove',
@ -2760,6 +2773,7 @@ class TC_00_VMs(AdminAPITestCase):
b'admin.label.Create',
b'admin.label.Get',
b'admin.label.Remove',
b'admin.pool.volume.List',
b'admin.property.List',
b'admin.property.Get',
b'admin.property.Set',

View File

@ -153,6 +153,56 @@ class TC_20_QubesHost(qubes.tests.QubesTestCase):
('xc.domain_getinfo', (1, 1), {}),
])
def test_010_iommu_supported(self):
self.app.vmm.configure_mock(**{
'xc.physinfo.return_value': {
'hw_caps': '...',
'scrub_memory': 0,
'virt_caps': 'hvm hvm_directio',
'nr_cpus': 4,
'threads_per_core': 1,
'cpu_khz': 3400001,
'nr_nodes': 1,
'free_memory': 234752,
'cores_per_socket': 4,
'total_memory': 16609720
}
})
self.assertEqual(self.qubes_host.is_iommu_supported(), True)
def test_011_iommu_supported(self):
self.app.vmm.configure_mock(**{
'xc.physinfo.return_value': {
'hw_caps': '...',
'scrub_memory': 0,
'virt_caps': 'hvm hvm_directio pv pv_directio',
'nr_cpus': 4,
'threads_per_core': 1,
'cpu_khz': 3400001,
'nr_nodes': 1,
'free_memory': 234752,
'cores_per_socket': 4,
'total_memory': 16609720
}
})
self.assertEqual(self.qubes_host.is_iommu_supported(), True)
def test_010_iommu_supported(self):
self.app.vmm.configure_mock(**{
'xc.physinfo.return_value': {
'hw_caps': '...',
'scrub_memory': 0,
'virt_caps': 'hvm pv',
'nr_cpus': 4,
'threads_per_core': 1,
'cpu_khz': 3400001,
'nr_nodes': 1,
'free_memory': 234752,
'cores_per_socket': 4,
'total_memory': 16609720
}
})
self.assertEqual(self.qubes_host.is_iommu_supported(), False)
class TC_30_VMCollection(qubes.tests.QubesTestCase):

View File

@ -302,6 +302,35 @@ class StorageTestMixin(object):
'head -c {} /dev/zero 2>&1 | diff -q /dev/xvde - 2>&1'.format(size),
user='root')
def test_005_size_after_clone(self):
'''Test snapshot volume non-persistence'''
return self.loop.run_until_complete(
self._test_005_size_after_clone())
@asyncio.coroutine
def _test_005_size_after_clone(self):
size = 128 * 1024 * 1024
volume_config = {
'pool': self.pool.name,
'size': size,
'save_on_stop': True,
'rw': True,
}
testvol = self.vm1.storage.init_volume('testvol', volume_config)
yield from qubes.utils.coro_maybe(testvol.create())
self.assertEquals(testvol.size, size)
volume_config = {
'pool': self.pool.name,
'size': size // 2,
'save_on_stop': True,
'rw': True,
}
testvol2 = self.vm2.storage.init_volume('testvol2', volume_config)
yield from qubes.utils.coro_maybe(testvol2.create())
self.assertEquals(testvol2.size, size // 2)
yield from qubes.utils.coro_maybe(testvol2.import_volume(testvol))
self.assertEquals(testvol2.size, size)
class StorageFile(StorageTestMixin, qubes.tests.SystemTestCase):
def init_pool(self):

View File

@ -250,7 +250,7 @@ class TC_03_KernelPool(qubes.tests.QubesTestCase):
def test_002_pool_volumes(self):
""" List volumes """
volumes = self.app.pools[self.POOL_NAME].volumes
volumes = list(self.app.pools[self.POOL_NAME].volumes)
self.assertEqual(len(volumes), 1)
vol = volumes[0]
self.assertEqual(vol.vid, 'dummy')

View File

@ -1115,6 +1115,19 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM):
self.libvirt_domain.createWithFlags(
libvirt.VIR_DOMAIN_START_PAUSED)
except libvirt.libvirtError as exc:
# missing IOMMU?
if self.virt_mode == 'hvm' and \
list(self.devices['pci'].persistent()) and \
not self.app.host.is_iommu_supported():
exc = qubes.exc.QubesException(
'Failed to start an HVM qube with PCI devices assigned '
'- hardware does not support IOMMU/VT-d/AMD-Vi')
self.log.error('Start failed: %s', str(exc))
yield from self.fire_event_async('domain-start-failed',
reason=str(exc))
yield from self.storage.stop()
raise exc
except Exception as exc:
self.log.error('Start failed: %s', str(exc))
# let anyone receiving domain-pre-start know that startup failed