Ensure ZFS pool management is idempotent

As block device configuration is called from the
config-changed hook, it's vital that the code for
managing the zfs pool is idempotent.

Add a helper to query pool information and ensure
that the ZFS pool does not already exist before
attempting creation.

Change-Id: I4f4ad9c4cdb73b77e8b3a9367b81ec1566bacd59
Signed-off-by: Chuck Short <chuck.short@canonical.com>
This commit is contained in:
Chuck Short 2016-04-20 13:31:03 -04:00 committed by James Page
parent a1f354a0dc
commit abc021285c
2 changed files with 59 additions and 3 deletions

View File

@ -74,6 +74,7 @@ LXD_SOURCE_PACKAGES = [
LXD_GIT = 'github.com/lxc/lxd'
DEFAULT_LOOPBACK_SIZE = '10G'
PW_LENGTH = 16
ZFS_POOL_NAME = 'lxd'
def install_lxd():
@ -232,13 +233,18 @@ def configure_lxd_block():
elif config('storage-type') == 'zfs':
status_set('maintenance',
'Configuring zfs container storage')
if ZFS_POOL_NAME in zpools():
log('ZFS pool already exist; skipping zfs configuration')
return
if config('overwrite'):
cmd = ['zpool', 'create', '-f', 'lxd', dev]
cmd = ['zpool', 'create', '-f', ZFS_POOL_NAME, dev]
else:
cmd = ['zpool', 'create', 'lxd', dev]
cmd = ['zpool', 'create', ZFS_POOL_NAME, dev]
check_call(cmd)
cmd = ['lxc', 'config', 'set', 'storage.zfs_pool_name', 'lxd']
cmd = ['lxc', 'config', 'set', 'storage.zfs_pool_name',
ZFS_POOL_NAME]
check_call(cmd)
@ -447,3 +453,20 @@ def assess_status():
status_set('active', 'Unit is ready')
else:
status_set('blocked', 'LXD is not running')
def zpools():
'''
Query the currently configured ZFS pools
@return: list of strings of pool names
'''
try:
zpools = check_output(['zpool', 'list', '-H']).splitlines()
pools = []
for l in zpools:
l = l.decode('UTF-8')
pools.append(l.split()[0])
return pools
except CalledProcessError:
return []

View File

@ -119,3 +119,36 @@ class TestGetBlockDevices(testing.CharmTestCase):
devices = lxd_utils.get_block_devices()
self.assertEqual(['/dev/vdb', '/dev/vdc'], devices)
ZFS_SINGLE_POOL = """testpool 232G 976M 231G - 7% 0% 1.04x ONLINE -
"""
ZFS_MULTIPLE_POOLS = """testpool 232G 976M 231G - 7% 0% 1.04x ONLINE -
testpool2 232G 976M 231G - 7% 0% 1.04x ONLINE -
"""
class TestZFSPool(testing.CharmTestCase):
"""Tests for hooks.lxd_utils.zpools"""
TO_PATCH = [
'check_output',
]
def setUp(self):
super(TestZFSPool, self).setUp(lxd_utils, self.TO_PATCH)
def test_no_pools(self):
"""When no pools are configured, an empty list is returned"""
self.check_output.return_value = ""
self.assertEqual(lxd_utils.zpools(), [])
def test_single_pool(self):
"""Return a list with a single pool"""
self.check_output.return_value = ZFS_SINGLE_POOL
self.assertEqual(lxd_utils.zpools(), ['testpool'])
def test_multiple_pools(self):
"""Return a list with a multiple pools"""
self.check_output.return_value = ZFS_MULTIPLE_POOLS
self.assertEqual(lxd_utils.zpools(), ['testpool', 'testpool2'])