30c3fb9353
If the charm code is passed symlinks to block devices (as is often the case with newer MAAS substrate versions), resolve links before attempting to use the block device for storage. Charmhelpers were updated as well. Testing done: - Unit tests pass - Tests pass - Multiple Openstack Autopilot deployments pass Change-Id: If966239502d0752c86e46f3f0aee96f43828aa08 Closes-Bug: 1577408 Signed-off-by: Chris Glass <chris.glass@canonical.com>
122 lines
3.1 KiB
Python
122 lines
3.1 KiB
Python
import os
|
|
|
|
from charmhelpers.contrib.storage.linux.utils import (
|
|
is_block_device,
|
|
zap_disk,
|
|
)
|
|
|
|
from charmhelpers.contrib.storage.linux.loopback import (
|
|
ensure_loopback_device,
|
|
)
|
|
|
|
from charmhelpers.contrib.storage.linux.lvm import (
|
|
deactivate_lvm_volume_group,
|
|
is_lvm_physical_volume,
|
|
remove_lvm_physical_volume,
|
|
)
|
|
|
|
from charmhelpers.core.host import (
|
|
mounts,
|
|
umount,
|
|
restart_on_change,
|
|
)
|
|
|
|
from charmhelpers.core.hookenv import (
|
|
log,
|
|
INFO,
|
|
ERROR,
|
|
)
|
|
|
|
from charmhelpers.core.unitdata import (
|
|
HookData,
|
|
kv,
|
|
)
|
|
|
|
DEFAULT_LOOPBACK_SIZE = '5G'
|
|
|
|
|
|
def ensure_block_device(block_device):
|
|
'''
|
|
Confirm block_device, create as loopback if necessary.
|
|
|
|
:param block_device: str: Full path of block device to ensure.
|
|
|
|
:returns: str: Full path of ensured block device.
|
|
'''
|
|
if block_device.startswith("/"):
|
|
# Resolve non-relative link(s) if device is a symlink to a real device.
|
|
# This fixes/prevents bug #1577408.
|
|
real_device = os.path.realpath(block_device)
|
|
if real_device != block_device:
|
|
log('Block device "{}" is a symlink to "{}". Using "{}".'.format(
|
|
block_device, real_device, real_device), level=INFO)
|
|
block_device = real_device
|
|
|
|
_none = ['None', 'none', None]
|
|
if (block_device in _none):
|
|
log('prepare_storage(): Missing required input: '
|
|
'block_device=%s.' % block_device, level=ERROR)
|
|
raise
|
|
|
|
if block_device.startswith('/dev/'):
|
|
bdev = block_device
|
|
elif block_device.startswith('/'):
|
|
_bd = block_device.split('|')
|
|
if len(_bd) == 2:
|
|
bdev, size = _bd
|
|
else:
|
|
bdev = block_device
|
|
size = DEFAULT_LOOPBACK_SIZE
|
|
bdev = ensure_loopback_device(bdev, size)
|
|
else:
|
|
bdev = '/dev/%s' % block_device
|
|
|
|
if not is_block_device(bdev):
|
|
log('Failed to locate valid block device at %s' % bdev, level=ERROR)
|
|
# ignore missing block devices
|
|
return
|
|
|
|
return bdev
|
|
|
|
|
|
def clean_storage(block_device):
|
|
'''
|
|
Ensures a block device is clean. That is:
|
|
- unmounted
|
|
- any lvm volume groups are deactivated
|
|
- any lvm physical device signatures removed
|
|
- partition table wiped
|
|
|
|
:param block_device: str: Full path to block device to clean.
|
|
'''
|
|
for mp, d in mounts():
|
|
if d == block_device:
|
|
log('clean_storage(): Found %s mounted @ %s, unmounting.' %
|
|
(d, mp), level=INFO)
|
|
umount(mp, persist=True)
|
|
|
|
if is_lvm_physical_volume(block_device):
|
|
deactivate_lvm_volume_group(block_device)
|
|
remove_lvm_physical_volume(block_device)
|
|
else:
|
|
zap_disk(block_device)
|
|
|
|
|
|
def is_paused():
|
|
"""Is the unit paused?"""
|
|
with HookData()():
|
|
if kv().get('unit-paused'):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def pause_aware_restart_on_change(restart_map):
|
|
"""Avoids restarting services if config changes when unit is paused."""
|
|
def wrapper(f):
|
|
if is_paused():
|
|
return f
|
|
else:
|
|
return restart_on_change(restart_map)(f)
|
|
return wrapper
|