Add metadata info to LVM AdminAPI

Added usage_details method to Pool class
(returns a dictionary with detailed information
on pool usage) and LVM implementation that returns
metadata info.
Needed for QubesOS/qubes-issues#5053
This commit is contained in:
Marta Marczykowska-Górecka 2019-08-08 14:10:19 +02:00
parent cc1ac0b859
commit 04a215fb83
No known key found for this signature in database
GPG Key ID: 9A752C30B26FD04B
4 changed files with 48 additions and 7 deletions

View File

@ -630,6 +630,11 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
if pool_usage is not None:
other_info += 'usage={}\n'.format(pool_usage)
pool_details = pool.usage_details
for name in pool_details:
if name not in ['data_size', 'data_usage']:
other_info += '{}={}\n'.format(name, pool_details[name])
try:
included_in = pool.included_in(self.app)
if included_in:

View File

@ -795,6 +795,17 @@ class Pool:
def usage(self):
''' Space used in the pool in bytes, or None if unknown '''
@property
def usage_details(self):
"""Detailed information about pool usage as a dictionary
Contains data_usage for usage in bytes and data_size for pool
size; other implementations may add more implementation-specific
detail"""
return {
'data_usage': self.usage,
'data_size': self.size
}
def _not_implemented(self, method_name):
''' Helper for emitting helpful `NotImplementedError` exceptions '''
msg = "Pool driver {!s} has {!s}() not implemented"

View File

@ -195,10 +195,28 @@ class ThinPool(qubes.storage.Pool):
except KeyError:
return 0
@property
def usage_details(self):
result = {}
result['data_size'] = self.size
result['data_usage'] = self.usage
try:
metadata_size = qubes.storage.lvm.size_cache[
self.volume_group + '/' + self.thin_pool]['metadata_size']
metadata_usage = qubes.storage.lvm.size_cache[
self.volume_group + '/' + self.thin_pool]['metadata_usage']
except KeyError:
metadata_size = None
metadata_usage = None
result['metadata_size'] = metadata_size
result['metadata_usage'] = metadata_usage
return result
_init_cache_cmd = ['lvs', '--noheadings', '-o',
'vg_name,pool_lv,name,lv_size,data_percent,lv_attr,origin',
'--units', 'b', '--separator', ';']
'vg_name,pool_lv,name,lv_size,data_percent,lv_attr,origin,lv_metadata_size,'
'metadata_percent', '--units', 'b', '--separator', ';']
def _parse_lvm_cache(lvm_output):
result = {}
@ -206,14 +224,20 @@ def _parse_lvm_cache(lvm_output):
for line in lvm_output.splitlines():
line = line.decode().strip()
pool_name, pool_lv, name, size, usage_percent, attr, \
origin = line.split(';', 6)
origin, metadata_size, metadata_percent = line.split(';', 8)
if '' in [pool_name, name, size, usage_percent]:
continue
name = pool_name + "/" + name
size = int(size[:-1]) # Remove 'B' suffix
usage = int(size / 100 * float(usage_percent))
if metadata_size:
metadata_size = int(metadata_size[:-1])
metadata_usage = int(metadata_size / 100 * float(metadata_percent))
else:
metadata_usage = None
result[name] = {'size': size, 'usage': usage, 'pool_lv': pool_lv,
'attr': attr, 'origin': origin}
'attr': attr, 'origin': origin, 'metadata_size': metadata_size,
'metadata_usage': metadata_usage}
return result

View File

@ -582,20 +582,21 @@ class TC_00_VMs(AdminAPITestCase):
'pool1': unittest.mock.Mock(config={
'param1': 'value1', 'param2': 'value2'},
usage=102400,
size=204800)
size=204800,
usage_details={'metadata_size': 500})
}
self.app.pools['pool1'].included_in.return_value = None
value = self.call_mgmt_func(b'admin.pool.Info', b'dom0', b'pool1')
self.assertEqual(value,
'param1=value1\nparam2=value2\nsize=204800\nusage=102400\n')
'param1=value1\nparam2=value2\nsize=204800\nusage=102400\nmetadata_size=500\n')
self.assertFalse(self.app.save.called)
def test_151_pool_info_unsupported_size(self):
self.app.pools = {
'pool1': unittest.mock.Mock(config={
'param1': 'value1', 'param2': 'value2'},
size=None, usage=None),
size=None, usage=None, usage_details={}),
}
self.app.pools['pool1'].included_in.return_value = None
value = self.call_mgmt_func(b'admin.pool.Info', b'dom0', b'pool1')