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:
parent
cc1ac0b859
commit
04a215fb83
@ -630,6 +630,11 @@ class QubesAdminAPI(qubes.api.AbstractQubesAPI):
|
|||||||
if pool_usage is not None:
|
if pool_usage is not None:
|
||||||
other_info += 'usage={}\n'.format(pool_usage)
|
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:
|
try:
|
||||||
included_in = pool.included_in(self.app)
|
included_in = pool.included_in(self.app)
|
||||||
if included_in:
|
if included_in:
|
||||||
|
@ -795,6 +795,17 @@ class Pool:
|
|||||||
def usage(self):
|
def usage(self):
|
||||||
''' Space used in the pool in bytes, or None if unknown '''
|
''' 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):
|
def _not_implemented(self, method_name):
|
||||||
''' Helper for emitting helpful `NotImplementedError` exceptions '''
|
''' Helper for emitting helpful `NotImplementedError` exceptions '''
|
||||||
msg = "Pool driver {!s} has {!s}() not implemented"
|
msg = "Pool driver {!s} has {!s}() not implemented"
|
||||||
|
@ -195,10 +195,28 @@ class ThinPool(qubes.storage.Pool):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
return 0
|
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',
|
_init_cache_cmd = ['lvs', '--noheadings', '-o',
|
||||||
'vg_name,pool_lv,name,lv_size,data_percent,lv_attr,origin',
|
'vg_name,pool_lv,name,lv_size,data_percent,lv_attr,origin,lv_metadata_size,'
|
||||||
'--units', 'b', '--separator', ';']
|
'metadata_percent', '--units', 'b', '--separator', ';']
|
||||||
|
|
||||||
def _parse_lvm_cache(lvm_output):
|
def _parse_lvm_cache(lvm_output):
|
||||||
result = {}
|
result = {}
|
||||||
@ -206,14 +224,20 @@ def _parse_lvm_cache(lvm_output):
|
|||||||
for line in lvm_output.splitlines():
|
for line in lvm_output.splitlines():
|
||||||
line = line.decode().strip()
|
line = line.decode().strip()
|
||||||
pool_name, pool_lv, name, size, usage_percent, attr, \
|
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]:
|
if '' in [pool_name, name, size, usage_percent]:
|
||||||
continue
|
continue
|
||||||
name = pool_name + "/" + name
|
name = pool_name + "/" + name
|
||||||
size = int(size[:-1]) # Remove 'B' suffix
|
size = int(size[:-1]) # Remove 'B' suffix
|
||||||
usage = int(size / 100 * float(usage_percent))
|
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,
|
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
|
return result
|
||||||
|
|
||||||
|
@ -582,20 +582,21 @@ class TC_00_VMs(AdminAPITestCase):
|
|||||||
'pool1': unittest.mock.Mock(config={
|
'pool1': unittest.mock.Mock(config={
|
||||||
'param1': 'value1', 'param2': 'value2'},
|
'param1': 'value1', 'param2': 'value2'},
|
||||||
usage=102400,
|
usage=102400,
|
||||||
size=204800)
|
size=204800,
|
||||||
|
usage_details={'metadata_size': 500})
|
||||||
}
|
}
|
||||||
self.app.pools['pool1'].included_in.return_value = None
|
self.app.pools['pool1'].included_in.return_value = None
|
||||||
value = self.call_mgmt_func(b'admin.pool.Info', b'dom0', b'pool1')
|
value = self.call_mgmt_func(b'admin.pool.Info', b'dom0', b'pool1')
|
||||||
|
|
||||||
self.assertEqual(value,
|
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)
|
self.assertFalse(self.app.save.called)
|
||||||
|
|
||||||
def test_151_pool_info_unsupported_size(self):
|
def test_151_pool_info_unsupported_size(self):
|
||||||
self.app.pools = {
|
self.app.pools = {
|
||||||
'pool1': unittest.mock.Mock(config={
|
'pool1': unittest.mock.Mock(config={
|
||||||
'param1': 'value1', 'param2': 'value2'},
|
'param1': 'value1', 'param2': 'value2'},
|
||||||
size=None, usage=None),
|
size=None, usage=None, usage_details={}),
|
||||||
}
|
}
|
||||||
self.app.pools['pool1'].included_in.return_value = None
|
self.app.pools['pool1'].included_in.return_value = None
|
||||||
value = self.call_mgmt_func(b'admin.pool.Info', b'dom0', b'pool1')
|
value = self.call_mgmt_func(b'admin.pool.Info', b'dom0', b'pool1')
|
||||||
|
Loading…
Reference in New Issue
Block a user