Enable ZFS to work with datasets and all locales
This fixes two bugs (independently) to get nova-lxd to work with datasets (pool/set) as well as pools (just 'pool'). It also, switches the attributes to use the '-p' option with 'zfs list' and 'zpool list' which returns the values in bytes rather than human readable format, which is more useful in nova-lxd. Change-Id: I2eb1b3ba7bd482e680933808414a3992a9a1feba Closes-Bug: #1756900 Closes-Bug: #1757371
This commit is contained in:
parent
bd4378a74f
commit
97cb7ea742
|
@ -1176,6 +1176,34 @@ class LXDDriverTest(test.NoDBTestCase):
|
|||
|
||||
self.assertEqual(expected, value)
|
||||
|
||||
@mock.patch.object(driver.utils, 'execute')
|
||||
def test__get_zpool_info(self, execute):
|
||||
# first test with a zpool; should make 3 calls to execute
|
||||
execute.side_effect = [
|
||||
('1\n', None),
|
||||
('2\n', None),
|
||||
('3\n', None)
|
||||
]
|
||||
expected = {
|
||||
'total': 1,
|
||||
'used': 2,
|
||||
'available': 3,
|
||||
}
|
||||
self.assertEqual(expected, driver._get_zpool_info('lxd'))
|
||||
|
||||
# then test with a zfs dataset; should just be 2 calls
|
||||
execute.reset_mock()
|
||||
execute.side_effect = [
|
||||
('10\n', None),
|
||||
('20\n', None),
|
||||
]
|
||||
expected = {
|
||||
'total': 30,
|
||||
'used': 10,
|
||||
'available': 20,
|
||||
}
|
||||
self.assertEqual(expected, driver._get_zpool_info('lxd/dataset'))
|
||||
|
||||
@mock.patch('socket.gethostname', mock.Mock(return_value='fake_hostname'))
|
||||
@mock.patch('nova.virt.lxd.driver.open')
|
||||
@mock.patch.object(driver.utils, 'execute')
|
||||
|
@ -1210,9 +1238,9 @@ class LXDDriverTest(test.NoDBTestCase):
|
|||
'Core(s) per socket: 5\n'
|
||||
'Thread(s) per core: 4\n\n',
|
||||
None),
|
||||
('2.17T\n', None),
|
||||
('200.4G\n', None),
|
||||
('1.8T\n', None)
|
||||
('2385940232273\n', None), # 2.17T
|
||||
('215177861529\n', None), # 200.4G
|
||||
('1979120929996\n', None) # 1.8T
|
||||
]
|
||||
|
||||
meminfo = mock.MagicMock()
|
||||
|
|
|
@ -66,7 +66,6 @@ import psutil
|
|||
from oslo_concurrency import lockutils
|
||||
from nova.compute import task_states
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import strutils
|
||||
from nova.virt import firewall
|
||||
|
||||
_ = i18n._
|
||||
|
@ -192,23 +191,43 @@ def _get_fs_info(path):
|
|||
'used': used}
|
||||
|
||||
|
||||
def _get_zpool_info(pool):
|
||||
"""Get free/used/total disk space in a zfs pool."""
|
||||
def _get_zpool_attribute(attribute):
|
||||
value, err = utils.execute('zpool', 'list',
|
||||
def _get_zpool_info(pool_or_dataset):
|
||||
"""Get the free/used/total diskspace in a zfs pool or dataset.
|
||||
A dataset is distinguished by having a '/' in the string.
|
||||
|
||||
:param pool_or_dataset: The string name of the pool or dataset
|
||||
:type pool_or_dataset: str
|
||||
:returns: dictionary with keys 'total', 'available', 'used'
|
||||
:rtype: Dict[str, int]
|
||||
:raises: :class:`exception.NovaException`
|
||||
:raises: :class:`oslo.concurrency.PorcessExecutionError`
|
||||
:raises: :class:`OSError`
|
||||
"""
|
||||
def _get_zfs_attribute(cmd, attribute):
|
||||
value, err = utils.execute(cmd, 'list',
|
||||
'-o', attribute,
|
||||
'-H', pool,
|
||||
'-H',
|
||||
'-p',
|
||||
pool_or_dataset,
|
||||
run_as_root=True)
|
||||
if err:
|
||||
msg = _('Unable to parse zpool output.')
|
||||
msg = _('Unable to parse zfs output.')
|
||||
raise exception.NovaException(msg)
|
||||
value = strutils.string_to_bytes('{}B'.format(value.strip()),
|
||||
return_int=True)
|
||||
value = int(value.strip())
|
||||
return value
|
||||
|
||||
total = _get_zpool_attribute('size')
|
||||
used = _get_zpool_attribute('alloc')
|
||||
available = _get_zpool_attribute('free')
|
||||
if '/' in pool_or_dataset:
|
||||
# it's a dataset:
|
||||
# for zfs datasets we only have 'available' and 'used' and so need to
|
||||
# construct the total from available and used.
|
||||
used = _get_zfs_attribute('zfs', 'used')
|
||||
available = _get_zfs_attribute('zfs', 'available')
|
||||
total = available + used
|
||||
else:
|
||||
# otherwise it's a zpool
|
||||
total = _get_zfs_attribute('zpool', 'size')
|
||||
used = _get_zfs_attribute('zpool', 'alloc')
|
||||
available = _get_zfs_attribute('zpool', 'free')
|
||||
return {'total': total,
|
||||
'available': available,
|
||||
'used': used}
|
||||
|
|
Loading…
Reference in New Issue