Merge "Migrate LVM driver to privsep"
This commit is contained in:
commit
7489a8e687
39
manila/privsep/common.py
Normal file
39
manila/privsep/common.py
Normal file
@ -0,0 +1,39 @@
|
||||
# Copyright 2021 Red Hat, Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from manila import exception
|
||||
from manila import utils as manila_utils
|
||||
from oslo_log import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def execute_with_retries(action, action_args, max_retries):
|
||||
|
||||
@manila_utils.retry(
|
||||
retry_param=exception.ProcessExecutionError, backoff_rate=2,
|
||||
retries=max_retries)
|
||||
def execute():
|
||||
try:
|
||||
action(*action_args)
|
||||
return True
|
||||
except exception.ProcessExecutionError:
|
||||
LOG.exception("Recovering from a failed execute.")
|
||||
raise
|
||||
|
||||
try:
|
||||
execute()
|
||||
except exception.ProcessExecutionError:
|
||||
LOG.exception("Failed to run command. Tries exhausted.")
|
||||
raise
|
36
manila/privsep/filesystem.py
Normal file
36
manila/privsep/filesystem.py
Normal file
@ -0,0 +1,36 @@
|
||||
# Copyright 2021 Red Hat, Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Helpers for filesystem commands
|
||||
"""
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
import manila.privsep
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def e2fsck(device_path):
|
||||
return processutils.execute('e2fsck', '-y', '-f', device_path)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def tune2fs(device_path):
|
||||
return processutils.execute('tune2fs', '-U', 'random', device_path)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def make_filesystem(ext_version, device_name):
|
||||
return processutils.execute(f'mkfs.{ext_version}', device_name)
|
78
manila/privsep/lvm.py
Normal file
78
manila/privsep/lvm.py
Normal file
@ -0,0 +1,78 @@
|
||||
# Copyright 2021 Red Hat, Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Helpers for lvm related routines
|
||||
"""
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
import manila.privsep
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def lvremove(vg_name, lv_name):
|
||||
processutils.execute('lvremove', '-f', f'{vg_name}/{lv_name}')
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def lvcreate(lv_size, lv_name, vg_name, mirrors=0, region_size=0):
|
||||
extra_params = []
|
||||
|
||||
if mirrors:
|
||||
extra_params += ['-m', mirrors, '--nosync']
|
||||
if region_size:
|
||||
extra_params += ['-R', region_size]
|
||||
|
||||
processutils.execute(
|
||||
'lvcreate', '-Wy', '--yes', '-L', f'{lv_size}G', '-n', lv_name,
|
||||
vg_name, *extra_params)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def lv_snapshot_create(snapshot_size, snap_name, orig_lv_name):
|
||||
size_str = '%sG' % snapshot_size
|
||||
processutils.execute(
|
||||
'lvcreate', '-L', size_str, '--name', snap_name,
|
||||
'--snapshot', orig_lv_name)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def get_vgs(vg_name):
|
||||
out, err = processutils.execute(
|
||||
'vgs', vg_name, '--rows', '--units', 'g',)
|
||||
return out, err
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def list_vgs_get_name():
|
||||
out, err = processutils.execute('vgs', '--noheadings', '-o', 'name')
|
||||
return out, err
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def lvconvert(vg_name, snapshot_name):
|
||||
processutils.execute(
|
||||
'lvconvert', '--merge', f'{vg_name}/{snapshot_name}')
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def lvrename(vg_name, lv_name, new_name):
|
||||
processutils.execute(
|
||||
'lvrename', vg_name, lv_name, new_name)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def lvextend(lv_name, new_size):
|
||||
processutils.execute('lvextend', '-L', '%sG' % new_size, '-r', lv_name)
|
72
manila/privsep/os.py
Normal file
72
manila/privsep/os.py
Normal file
@ -0,0 +1,72 @@
|
||||
# Copyright 2021 Red Hat, Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Helpers for os basic commands
|
||||
"""
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
|
||||
from manila import exception
|
||||
|
||||
import manila.privsep
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def rmdir(dir_path):
|
||||
processutils.execute('rmdir', dir_path)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def is_data_definition_direct_io_supported(src_str, dest_str):
|
||||
try:
|
||||
processutils.execute(
|
||||
'dd', 'count=0', f'if={src_str}', f'of={dest_str}',
|
||||
'iflag=direct', 'oflag=direct')
|
||||
is_direct_io_supported = True
|
||||
except exception.ProcessExecutionError:
|
||||
is_direct_io_supported = False
|
||||
|
||||
return is_direct_io_supported
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def data_definition(src_str, dest_str, size_in_g, use_direct_io=False):
|
||||
extra_flags = []
|
||||
if use_direct_io:
|
||||
extra_flags += ['iflag=direct', 'oflag=direct']
|
||||
processutils.execute(
|
||||
'dd', 'if=%s' % src_str, 'of=%s' % dest_str, 'count=%d' % size_in_g,
|
||||
'bs=1M', *extra_flags)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def umount(mount_path):
|
||||
processutils.execute('umount', '-f', mount_path)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def mount(device_name, mount_path):
|
||||
processutils.execute('mount', device_name, mount_path)
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def list_mounts():
|
||||
out, err = processutils.execute('mount', '-l')
|
||||
return out, err
|
||||
|
||||
|
||||
@manila.privsep.sys_admin_pctxt.entrypoint
|
||||
def chmod(permission_level_str, mount_path):
|
||||
processutils.execute('chmod', permission_level_str, mount_path)
|
@ -23,6 +23,7 @@ import math
|
||||
import os
|
||||
import re
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_utils import importutils
|
||||
@ -30,6 +31,10 @@ from oslo_utils import timeutils
|
||||
|
||||
from manila import exception
|
||||
from manila.i18n import _
|
||||
from manila.privsep import common as privsep_common
|
||||
from manila.privsep import filesystem as privsep_filesystem
|
||||
from manila.privsep import lvm as privsep_lvm
|
||||
from manila.privsep import os as privsep_os
|
||||
from manila.share import driver
|
||||
from manila.share.drivers import generic
|
||||
from manila.share import utils as share_utils
|
||||
@ -67,8 +72,11 @@ CONF.register_opts(generic.share_opts)
|
||||
class LVMMixin(driver.ExecuteMixin):
|
||||
def check_for_setup_error(self):
|
||||
"""Returns an error if prerequisites aren't met."""
|
||||
out, err = self._execute('vgs', '--noheadings', '-o', 'name',
|
||||
run_as_root=True)
|
||||
try:
|
||||
out, err = privsep_lvm.list_vgs_get_name()
|
||||
except processutils.ProcessExecutionError:
|
||||
msg = _("Failed to get LVM volume group names.")
|
||||
raise exception.ShareBackendException(msg=msg)
|
||||
volume_groups = out.split()
|
||||
if self.configuration.lvm_share_volume_group not in volume_groups:
|
||||
msg = (_("Share volume group %s doesn't exist.")
|
||||
@ -81,32 +89,46 @@ class LVMMixin(driver.ExecuteMixin):
|
||||
|
||||
def _allocate_container(self, share):
|
||||
sizestr = '%sG' % share['size']
|
||||
cmd = ['lvcreate', '-Wy', '--yes', '-L', sizestr, '-n', share['name'],
|
||||
self.configuration.lvm_share_volume_group]
|
||||
mirrors = 0
|
||||
region_size = 0
|
||||
if self.configuration.lvm_share_mirrors:
|
||||
cmd += ['-m', self.configuration.lvm_share_mirrors, '--nosync']
|
||||
mirrors = self.configuration.lvm_share_mirrors
|
||||
terras = int(sizestr[:-1]) / 1024.0
|
||||
if terras >= 1.5:
|
||||
rsize = int(2 ** math.ceil(math.log(terras) / math.log(2)))
|
||||
# NOTE(vish): Next power of two for region size. See:
|
||||
# http://red.ht/U2BPOD
|
||||
cmd += ['-R', str(rsize)]
|
||||
|
||||
self._try_execute(*cmd, run_as_root=True)
|
||||
region_size = str(rsize)
|
||||
action_args = [
|
||||
share['size'],
|
||||
share['name'],
|
||||
self.configuration.lvm_share_volume_group,
|
||||
mirrors,
|
||||
region_size
|
||||
]
|
||||
privsep_common.execute_with_retries(
|
||||
privsep_lvm.lvcreate, action_args,
|
||||
self.configuration.num_shell_tries)
|
||||
device_name = self._get_local_path(share)
|
||||
self._execute('mkfs.%s' % self.configuration.share_volume_fstype,
|
||||
device_name, run_as_root=True)
|
||||
try:
|
||||
privsep_filesystem.make_filesystem(
|
||||
self.configuration.share_volume_fstype, device_name)
|
||||
except processutils.ProcessExecutionError:
|
||||
raise
|
||||
|
||||
def _extend_container(self, share, device_name, size):
|
||||
cmd = ['lvextend', '-L', '%sG' % size, '-r', device_name]
|
||||
self._try_execute(*cmd, run_as_root=True)
|
||||
privsep_common.execute_with_retries(
|
||||
privsep_lvm.lvextend, [device_name, size],
|
||||
self.configuration.num_shell_tries)
|
||||
|
||||
def _deallocate_container(self, share_name):
|
||||
"""Deletes a logical volume for share."""
|
||||
try:
|
||||
self._try_execute('lvremove', '-f', "%s/%s" %
|
||||
(self.configuration.lvm_share_volume_group,
|
||||
share_name), run_as_root=True)
|
||||
action_args = [
|
||||
self.configuration.lvm_share_volume_group, share_name]
|
||||
privsep_common.execute_with_retries(
|
||||
privsep_lvm.lvremove, action_args,
|
||||
self.configuration.num_shell_tries)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
err_pattern = re.compile(".*failed to find.*|.*not found.*",
|
||||
re.IGNORECASE)
|
||||
@ -119,10 +141,11 @@ class LVMMixin(driver.ExecuteMixin):
|
||||
"""Creates a snapshot."""
|
||||
orig_lv_name = "%s/%s" % (self.configuration.lvm_share_volume_group,
|
||||
snapshot['share_name'])
|
||||
self._try_execute(
|
||||
'lvcreate', '-L',
|
||||
'%sG' % snapshot['share']['size'], '--name', snapshot['name'],
|
||||
'--snapshot', orig_lv_name, run_as_root=True)
|
||||
action_args = [
|
||||
snapshot['share']['size'], snapshot['name'], orig_lv_name]
|
||||
privsep_common.execute_with_retries(
|
||||
privsep_lvm.lv_snapshot_create, action_args,
|
||||
self.configuration.num_shell_tries)
|
||||
|
||||
self._set_random_uuid_to_device(snapshot)
|
||||
|
||||
@ -135,10 +158,12 @@ class LVMMixin(driver.ExecuteMixin):
|
||||
# a recently checked filesystem.
|
||||
# See: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=857336
|
||||
device_path = self._get_local_path(share_or_snapshot)
|
||||
self._execute('e2fsck', '-y', '-f', device_path, run_as_root=True)
|
||||
self._execute(
|
||||
'tune2fs', '-U', 'random', device_path, run_as_root=True,
|
||||
)
|
||||
try:
|
||||
privsep_filesystem.e2fsck(device_path)
|
||||
privsep_filesystem.tune2fs(device_path)
|
||||
except processutils.ProcessExecutionError:
|
||||
msg = _("Failed to check or modify filesystems.")
|
||||
raise exception.ShareBackendException(msg=msg)
|
||||
|
||||
def create_snapshot(self, context, snapshot, share_server=None):
|
||||
self._create_snapshot(context, snapshot)
|
||||
@ -224,10 +249,12 @@ class LVMShareDriver(LVMMixin, driver.ShareDriver):
|
||||
super(LVMShareDriver, self)._update_share_stats(data)
|
||||
|
||||
def get_share_server_pools(self, share_server=None):
|
||||
out, err = self._execute('vgs',
|
||||
self.configuration.lvm_share_volume_group,
|
||||
'--rows', '--units', 'g',
|
||||
run_as_root=True)
|
||||
try:
|
||||
out, err = privsep_lvm.get_vgs(
|
||||
self.configuration.lvm_share_volume_group)
|
||||
except processutils.ProcessExecutionError:
|
||||
msg = _("Failed to list LVM Volume Groups.")
|
||||
raise exception.ShareBackendException(msg=msg)
|
||||
total_size = re.findall(r"VSize\s[0-9.]+g", out)[0][6:-1]
|
||||
free_size = re.findall(r"VFree\s[0-9.]+g", out)[0][6:-1]
|
||||
return [{
|
||||
@ -279,7 +306,7 @@ class LVMShareDriver(LVMMixin, driver.ShareDriver):
|
||||
retries=retries)
|
||||
def _unmount_device_with_retry():
|
||||
try:
|
||||
self._execute('umount', '-f', mount_path, run_as_root=True)
|
||||
privsep_os.umount(mount_path)
|
||||
except exception.ProcessExecutionError as exc:
|
||||
if 'is busy' in exc.stderr.lower():
|
||||
raise exception.ShareBusyException(
|
||||
@ -294,7 +321,11 @@ class LVMShareDriver(LVMMixin, driver.ShareDriver):
|
||||
|
||||
_unmount_device_with_retry()
|
||||
# remove dir
|
||||
self._execute('rmdir', mount_path, run_as_root=True)
|
||||
try:
|
||||
privsep_os.rmdir(mount_path)
|
||||
except exception.ProcessExecutionError:
|
||||
msg = _("Failed to remove the directory.")
|
||||
raise exception.ShareBackendException(msg=msg)
|
||||
|
||||
def ensure_shares(self, context, shares):
|
||||
updates = {}
|
||||
@ -362,12 +393,10 @@ class LVMShareDriver(LVMMixin, driver.ShareDriver):
|
||||
mount_path = self._get_mount_path(share_or_snapshot)
|
||||
self._execute('mkdir', '-p', mount_path)
|
||||
try:
|
||||
self._execute('mount', device_name, mount_path,
|
||||
run_as_root=True, check_exit_code=True)
|
||||
self._execute('chmod', '777', mount_path,
|
||||
run_as_root=True, check_exit_code=True)
|
||||
privsep_os.mount(device_name, mount_path)
|
||||
privsep_os.chmod('777', mount_path)
|
||||
except exception.ProcessExecutionError:
|
||||
out, err = self._execute('mount', '-l', run_as_root=True)
|
||||
out, err = privsep_os.list_mounts()
|
||||
if device_name in out:
|
||||
LOG.warning("%s is already mounted", device_name)
|
||||
else:
|
||||
@ -381,19 +410,18 @@ class LVMShareDriver(LVMMixin, driver.ShareDriver):
|
||||
|
||||
def _copy_volume(self, srcstr, deststr, size_in_g):
|
||||
# Use O_DIRECT to avoid thrashing the system buffer cache
|
||||
extra_flags = ['iflag=direct', 'oflag=direct']
|
||||
|
||||
# Check whether O_DIRECT is supported
|
||||
try:
|
||||
self._execute('dd', 'count=0', 'if=%s' % srcstr, 'of=%s' % deststr,
|
||||
*extra_flags, run_as_root=True)
|
||||
except exception.ProcessExecutionError:
|
||||
extra_flags = []
|
||||
use_direct_io = (
|
||||
privsep_os.is_data_definition_direct_io_supported(srcstr, deststr))
|
||||
|
||||
# Perform the copy
|
||||
self._execute('dd', 'if=%s' % srcstr, 'of=%s' % deststr,
|
||||
'count=%d' % (size_in_g * 1024), 'bs=1M',
|
||||
*extra_flags, run_as_root=True)
|
||||
try:
|
||||
privsep_os.data_definition(
|
||||
srcstr, deststr, (size_in_g * 1024),
|
||||
use_direct_io=use_direct_io)
|
||||
except exception.ProcessExecutionError:
|
||||
msg = _("Failed while copying from the snapshot to the share.")
|
||||
raise exception.ShareBackendException(msg=msg)
|
||||
|
||||
def extend_share(self, share, new_size, share_server=None):
|
||||
device_name = self._get_local_path(share)
|
||||
@ -412,9 +440,12 @@ class LVMShareDriver(LVMMixin, driver.ShareDriver):
|
||||
# Unmount the share filesystem
|
||||
self._unmount_device(share)
|
||||
# Merge the snapshot LV back into the share, reverting it
|
||||
snap_lv_name = "%s/%s" % (self.configuration.lvm_share_volume_group,
|
||||
try:
|
||||
privsep_lvm.lvconvert(self.configuration.lvm_share_volume_group,
|
||||
snapshot['name'])
|
||||
self._execute('lvconvert', '--merge', snap_lv_name, run_as_root=True)
|
||||
except exception.ProcessExecutionError:
|
||||
msg = _('Failed to revert the share to the given snapshot.')
|
||||
raise exception.ShareBackendException(msg=msg)
|
||||
|
||||
# Now recreate the snapshot that was destroyed by the merge
|
||||
self._create_snapshot(context, snapshot)
|
||||
|
@ -25,6 +25,10 @@ from oslo_utils import timeutils
|
||||
from manila.common import constants as const
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila.privsep import common as privsep_common
|
||||
from manila.privsep import filesystem
|
||||
from manila.privsep import lvm as privsep_lvm
|
||||
from manila.privsep import os as os_routines
|
||||
from manila.share import configuration
|
||||
from manila.share.drivers import lvm
|
||||
from manila import test
|
||||
@ -134,29 +138,28 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
])
|
||||
|
||||
def test_check_for_setup_error(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
return '\n fake1\n fakevg\n fake2\n', ''
|
||||
out, err = '\n fake1\n fakevg\n fake2\n', ''
|
||||
self.mock_object(privsep_lvm, 'list_vgs_get_name',
|
||||
mock.Mock(return_value=(out, err)))
|
||||
|
||||
expected_exec = ['vgs --noheadings -o name']
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
self._driver.check_for_setup_error()
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
|
||||
privsep_lvm.list_vgs_get_name.assert_called_once()
|
||||
|
||||
def test_check_for_setup_error_no_vg(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
return '\n fake0\n fake1\n fake2\n', ''
|
||||
|
||||
fake_utils.fake_execute_set_repliers([('vgs --noheadings -o name',
|
||||
exec_runner)])
|
||||
out = '\n fake0\n fake1\n fake2\n'
|
||||
err = ''
|
||||
self.mock_object(privsep_lvm, 'list_vgs_get_name',
|
||||
mock.Mock(return_value=(out, err)))
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self._driver.check_for_setup_error)
|
||||
|
||||
def test_check_for_setup_error_no_export_ips(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
return '\n fake1\n fakevg\n fake2\n', ''
|
||||
out = '\n fake1\n fakevg\n fake2\n'
|
||||
err = ''
|
||||
self.mock_object(privsep_lvm, 'list_vgs_get_name',
|
||||
mock.Mock(return_value=(out, err)))
|
||||
|
||||
fake_utils.fake_execute_set_repliers([('vgs --noheadings -o name',
|
||||
exec_runner)])
|
||||
CONF.set_default('lvm_share_export_ips', None)
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self._driver.check_for_setup_error)
|
||||
@ -176,17 +179,22 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
def test_create_share(self):
|
||||
CONF.set_default('lvm_share_mirrors', 0)
|
||||
self._driver._mount_device = mock.Mock()
|
||||
lv_create_mock = privsep_lvm.lvcreate = mock.Mock()
|
||||
lv_create_args = [
|
||||
self.share['size'], self.share['name'],
|
||||
CONF.lvm_share_volume_group, 0, 0]
|
||||
self.mock_object(privsep_common, 'execute_with_retries')
|
||||
self.mock_object(filesystem, 'make_filesystem')
|
||||
|
||||
ret = self._driver.create_share(self._context, self.share,
|
||||
self.share_server)
|
||||
|
||||
self._driver._mount_device.assert_called_with(
|
||||
self.share, '/dev/mapper/fakevg-fakename')
|
||||
expected_exec = [
|
||||
'lvcreate -Wy --yes -L 1G -n fakename fakevg',
|
||||
'mkfs.ext4 /dev/mapper/fakevg-fakename',
|
||||
]
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
privsep_common.execute_with_retries.assert_called_once_with(
|
||||
lv_create_mock, lv_create_args, CONF.num_shell_tries)
|
||||
filesystem.make_filesystem.assert_called_once_with(
|
||||
'ext4', '/dev/mapper/fakevg-fakename')
|
||||
self.assertEqual(self._helper_nfs.create_exports.return_value, ret)
|
||||
|
||||
def test_create_share_from_snapshot(self):
|
||||
@ -199,6 +207,21 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
mount_share = '/dev/mapper/fakevg-fakename'
|
||||
mount_snapshot = '/dev/mapper/fakevg-fakename'
|
||||
self._helper_nfs.create_export.return_value = 'fakelocation'
|
||||
lv_create_mock = privsep_lvm.lvcreate = mock.Mock()
|
||||
lv_create_args = [
|
||||
self.share['size'], self.share['name'],
|
||||
CONF.lvm_share_volume_group, 0, 0]
|
||||
|
||||
self.mock_object(privsep_common, 'execute_with_retries')
|
||||
self.mock_object(os_routines, 'is_data_definition_direct_io_supported',
|
||||
mock.Mock(return_value=True))
|
||||
self.mock_object(os_routines, 'data_definition')
|
||||
self.mock_object(os_routines, 'mount')
|
||||
self.mock_object(os_routines, 'chmod')
|
||||
self.mock_object(filesystem, 'make_filesystem')
|
||||
self.mock_object(filesystem, 'e2fsck')
|
||||
self.mock_object(filesystem, 'tune2fs')
|
||||
|
||||
self._driver.create_share_from_snapshot(self._context,
|
||||
self.share,
|
||||
snapshot_instance,
|
||||
@ -206,44 +229,59 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
|
||||
self._driver._mount_device.assert_called_with(self.share,
|
||||
mount_snapshot)
|
||||
expected_exec = [
|
||||
'lvcreate -Wy --yes -L 1G -n fakename fakevg',
|
||||
'mkfs.ext4 /dev/mapper/fakevg-fakename',
|
||||
'e2fsck -y -f %s' % mount_share,
|
||||
'tune2fs -U random %s' % mount_share,
|
||||
("dd count=0 if=%s of=%s iflag=direct oflag=direct" %
|
||||
(mount_snapshot, mount_share)),
|
||||
("dd if=%s of=%s count=1024 bs=1M iflag=direct oflag=direct" %
|
||||
(mount_snapshot, mount_share)),
|
||||
]
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
privsep_common.execute_with_retries.assert_called_once_with(
|
||||
lv_create_mock, lv_create_args, 3)
|
||||
filesystem.make_filesystem.assert_called_once_with(
|
||||
'ext4', '/dev/mapper/fakevg-fakename')
|
||||
filesystem.e2fsck.assert_called_once_with(
|
||||
mount_share)
|
||||
filesystem.tune2fs.assert_called_once_with(
|
||||
mount_share)
|
||||
(os_routines.is_data_definition_direct_io_supported
|
||||
.assert_called_once_with(
|
||||
mount_snapshot, mount_share))
|
||||
os_routines.data_definition.assert_called_once_with(
|
||||
mount_snapshot, mount_share, (self.share['size'] * 1024),
|
||||
use_direct_io=True)
|
||||
|
||||
def test_create_share_mirrors(self):
|
||||
share = fake_share(size='2048')
|
||||
CONF.set_default('lvm_share_mirrors', 2)
|
||||
lv_create_mock = privsep_lvm.lvcreate = mock.Mock()
|
||||
lv_create_args = [
|
||||
'2048', self.share['name'],
|
||||
CONF.lvm_share_volume_group, 2, '2']
|
||||
|
||||
self._driver._mount_device = mock.Mock()
|
||||
self.mock_object(privsep_common, 'execute_with_retries')
|
||||
self.mock_object(filesystem, 'make_filesystem')
|
||||
|
||||
ret = self._driver.create_share(self._context, share,
|
||||
self.share_server)
|
||||
|
||||
self._driver._mount_device.assert_called_with(
|
||||
share, '/dev/mapper/fakevg-fakename')
|
||||
expected_exec = [
|
||||
'lvcreate -Wy --yes -L 2048G -n fakename fakevg -m 2 --nosync'
|
||||
' -R 2', 'mkfs.ext4 /dev/mapper/fakevg-fakename']
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
privsep_common.execute_with_retries.assert_called_once_with(
|
||||
lv_create_mock, lv_create_args, 3)
|
||||
filesystem.make_filesystem.assert_called_once_with(
|
||||
'ext4', '/dev/mapper/fakevg-fakename')
|
||||
self.assertEqual(self._helper_nfs.create_exports.return_value, ret)
|
||||
|
||||
def test_deallocate_container(self):
|
||||
expected_exec = ['lvremove -f fakevg/fakename']
|
||||
mock_lvremove = privsep_lvm.lvremove = mock.Mock()
|
||||
self.mock_object(privsep_common, 'execute_with_retries')
|
||||
|
||||
self._driver._deallocate_container(self.share['name'])
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
|
||||
privsep_common.execute_with_retries.assert_called_once_with(
|
||||
mock_lvremove, [CONF.lvm_share_volume_group, self.share['name']], 3
|
||||
)
|
||||
|
||||
def test_deallocate_container_error(self):
|
||||
def _fake_exec(*args, **kwargs):
|
||||
raise exception.ProcessExecutionError(stderr="error")
|
||||
|
||||
self.mock_object(self._driver, '_try_execute', _fake_exec)
|
||||
self.mock_object(privsep_common, 'execute_with_retries', _fake_exec)
|
||||
self.assertRaises(exception.ProcessExecutionError,
|
||||
self._driver._deallocate_container,
|
||||
self.share['name'])
|
||||
@ -255,7 +293,7 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
def _fake_exec(*args, **kwargs):
|
||||
raise exception.ProcessExecutionError(stderr=error_msg)
|
||||
|
||||
self.mock_object(self._driver, '_try_execute', _fake_exec)
|
||||
self.mock_object(privsep_common, 'execute_with_retries', _fake_exec)
|
||||
self._driver._deallocate_container(self.share['name'])
|
||||
|
||||
@mock.patch.object(lvm.LVMShareDriver, '_update_share_stats', mock.Mock())
|
||||
@ -272,74 +310,94 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
self._driver._update_share_stats.assert_called_once_with()
|
||||
|
||||
def test__unmount_device_not_mounted(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
umount_msg = (
|
||||
"umount: /opt/stack/data/manila/mnt/share-fake-share: not "
|
||||
"mounted.\n"
|
||||
)
|
||||
raise exception.ProcessExecutionError(stderr=umount_msg)
|
||||
self._os.path.exists.return_value = True
|
||||
mount_path = self._get_mount_path(self.share)
|
||||
expected_exec = "umount -f %s" % (mount_path)
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec, exec_runner)])
|
||||
error_msg = (
|
||||
"umount: /opt/stack/data/manila/mnt/share-fake-share: not "
|
||||
"mounted.\n")
|
||||
umount_exception = exception.ProcessExecutionError(stderr=error_msg)
|
||||
self.mock_object(
|
||||
os_routines, 'umount', mock.Mock(side_effect=umount_exception))
|
||||
self.mock_object(os_routines, 'rmdir')
|
||||
self._os.path.exists.return_value = True
|
||||
|
||||
self._driver._unmount_device(self.share, raise_if_missing=False)
|
||||
|
||||
self._os.path.exists.assert_called_with(mount_path)
|
||||
os_routines.umount.assert_called_once_with(mount_path)
|
||||
|
||||
def test__unmount_device_is_busy_error(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError(stderr='device is busy')
|
||||
error_msg = 'device is busy'
|
||||
umount_exception = exception.ProcessExecutionError(stderr=error_msg)
|
||||
self.mock_object(
|
||||
os_routines, 'umount', mock.Mock(side_effect=umount_exception))
|
||||
self._os.path.exists.return_value = True
|
||||
mount_path = self._get_mount_path(self.share)
|
||||
expected_exec = [
|
||||
"umount -f %s" % (mount_path),
|
||||
]
|
||||
fake_utils.fake_execute_set_repliers([(expected_exec[0], exec_runner)])
|
||||
|
||||
self.assertRaises(exception.ShareBusyException,
|
||||
self._driver._unmount_device,
|
||||
self.share)
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
os_routines.umount.assert_called_once_with(mount_path)
|
||||
|
||||
def test__unmount_device_error(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError(stderr='fake error')
|
||||
error_msg = 'fake error'
|
||||
mount_path = self._get_mount_path(self.share)
|
||||
umount_exception = exception.ProcessExecutionError(stderr=error_msg)
|
||||
self.mock_object(
|
||||
os_routines, 'umount', mock.Mock(side_effect=umount_exception))
|
||||
self._os.path.exists.return_value = True
|
||||
cmd = "umount -f %s" % (mount_path)
|
||||
fake_utils.fake_execute_set_repliers([(cmd, exec_runner)])
|
||||
|
||||
self.assertRaises(processutils.ProcessExecutionError,
|
||||
self._driver._unmount_device,
|
||||
self.share)
|
||||
self._os.path.exists.assert_called_with(mount_path)
|
||||
os_routines.umount.assert_called_once_with(mount_path)
|
||||
|
||||
def test__unmount_device_rmdir_error(self):
|
||||
def exec_runner(*ignore_args, **ignore_kwargs):
|
||||
raise exception.ProcessExecutionError(stderr='fake error')
|
||||
error_msg = 'fake error'
|
||||
mount_path = self._get_mount_path(self.share)
|
||||
umount_exception = exception.ProcessExecutionError(stderr=error_msg)
|
||||
self.mock_object(os_routines, 'umount')
|
||||
self.mock_object(os_routines, 'rmdir',
|
||||
mock.Mock(side_effect=umount_exception))
|
||||
self._os.path.exists.return_value = True
|
||||
cmd = "rmdir %s" % (mount_path)
|
||||
fake_utils.fake_execute_set_repliers([(cmd, exec_runner)])
|
||||
self.assertRaises(processutils.ProcessExecutionError,
|
||||
|
||||
self.assertRaises(exception.ShareBackendException,
|
||||
self._driver._unmount_device,
|
||||
self.share)
|
||||
self._os.path.exists.assert_called_with(mount_path)
|
||||
os_routines.umount.assert_called_once_with(mount_path)
|
||||
os_routines.rmdir.assert_called_once_with(mount_path)
|
||||
|
||||
def test_create_snapshot(self):
|
||||
mock_lv_create = privsep_lvm.lvcreate = mock.Mock()
|
||||
orig_lv_name = "%s/%s" % (CONF.lvm_share_volume_group,
|
||||
self.snapshot['share_name'])
|
||||
device_path = '/dev/mapper/fakevg-%s' % self.snapshot['name']
|
||||
lv_create_args = [
|
||||
self.snapshot['share']['size'], self.snapshot['share']['name'],
|
||||
orig_lv_name]
|
||||
|
||||
self.mock_object(privsep_common, 'execute_with_retries')
|
||||
self.mock_object(filesystem, 'e2fsck')
|
||||
self.mock_object(filesystem, 'tune2fs')
|
||||
self.mock_object(os_routines, 'mount')
|
||||
self.mock_object(os_routines, 'chmod')
|
||||
|
||||
self._driver.create_snapshot(self._context, self.snapshot,
|
||||
self.share_server)
|
||||
mount_path = self._get_mount_path(self.snapshot)
|
||||
expected_exec = [
|
||||
("lvcreate -L 1G --name fakesnapshotname --snapshot "
|
||||
"%s/fakename" % (CONF.lvm_share_volume_group,)),
|
||||
"e2fsck -y -f /dev/mapper/fakevg-%s" % self.snapshot['name'],
|
||||
"tune2fs -U random /dev/mapper/fakevg-%s" % self.snapshot['name'],
|
||||
"mkdir -p " + mount_path,
|
||||
"mount /dev/mapper/fakevg-fakesnapshotname " + mount_path,
|
||||
"chmod 777 " + mount_path,
|
||||
]
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
privsep_common.execute_with_retries(
|
||||
mock_lv_create, lv_create_args, CONF.num_shell_tries)
|
||||
filesystem.e2fsck.assert_called_once_with(device_path)
|
||||
filesystem.tune2fs.assert_called_once_with(device_path)
|
||||
os_routines.mount.assert_called_once_with(
|
||||
"/dev/mapper/fakevg-fakesnapshotname", mount_path)
|
||||
os_routines.chmod.assert_called_once_with(
|
||||
'777', mount_path)
|
||||
|
||||
def test_ensure_share(self):
|
||||
device_name = '/dev/mapper/fakevg-fakename'
|
||||
@ -360,20 +418,32 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
|
||||
def test_delete_snapshot(self):
|
||||
mount_path = self._get_mount_path(self.snapshot)
|
||||
expected_exec = [
|
||||
'umount -f %s' % mount_path,
|
||||
'rmdir %s' % mount_path,
|
||||
'lvremove -f fakevg/fakesnapshotname',
|
||||
]
|
||||
self.mock_object(os_routines, 'umount')
|
||||
self.mock_object(os_routines, 'rmdir')
|
||||
self.mock_object(privsep_common, 'execute_with_retries')
|
||||
self.mock_object(self._driver, '_deallocate_container')
|
||||
|
||||
self._driver.delete_snapshot(self._context, self.snapshot,
|
||||
self.share_server)
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
|
||||
os_routines.umount.assert_called_once_with(mount_path)
|
||||
os_routines.rmdir.assert_called_once_with(mount_path)
|
||||
self._driver._deallocate_container.assert_called_once_with(
|
||||
self.snapshot['name'])
|
||||
|
||||
def test_delete_share_invalid_share(self):
|
||||
self.mock_object(self._driver, '_unmount_device')
|
||||
self.mock_object(self._driver, '_deallocate_container')
|
||||
self._driver._get_helper = mock.Mock(
|
||||
side_effect=exception.InvalidShare(reason='fake'))
|
||||
|
||||
self._driver.delete_share(self._context, self.share, self.share_server)
|
||||
|
||||
self._driver._unmount_device.assert_called_once_with(
|
||||
self.share, raise_if_missing=False, retry_busy_device=True)
|
||||
self._driver._deallocate_container.assert_called_once_with(
|
||||
self.share['name'])
|
||||
|
||||
def test_delete_share_process_execution_error(self):
|
||||
self.mock_object(
|
||||
self._helper_nfs,
|
||||
@ -421,13 +491,18 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
|
||||
def test_mount_device(self):
|
||||
mount_path = self._get_mount_path(self.share)
|
||||
ret = self._driver._mount_device(self.share, 'fakedevice')
|
||||
self.mock_object(os_routines, 'mount')
|
||||
self.mock_object(os_routines, 'chmod')
|
||||
expected_exec = [
|
||||
"mkdir -p %s" % (mount_path,),
|
||||
"mount fakedevice %s" % (mount_path,),
|
||||
"chmod 777 %s" % (mount_path,),
|
||||
]
|
||||
device_name = 'fakedevice'
|
||||
|
||||
ret = self._driver._mount_device(self.share, device_name)
|
||||
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
os_routines.mount.assert_called_once_with(device_name, mount_path)
|
||||
os_routines.chmod.assert_called_once_with('777', mount_path)
|
||||
self.assertEqual(mount_path, ret)
|
||||
|
||||
def test_mount_device_already(self):
|
||||
@ -438,19 +513,22 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
return 'fakedevice', ''
|
||||
|
||||
self.mock_object(self._driver, '_execute', exec_runner)
|
||||
self.mock_object(os_routines, 'mount')
|
||||
self.mock_object(os_routines, 'chmod')
|
||||
mount_path = self._get_mount_path(self.share)
|
||||
|
||||
ret = self._driver._mount_device(self.share, 'fakedevice')
|
||||
self.assertEqual(mount_path, ret)
|
||||
|
||||
def test_mount_device_error(self):
|
||||
def exec_runner(*args, **kwargs):
|
||||
if 'mount' in args and '-l' not in args:
|
||||
raise exception.ProcessExecutionError()
|
||||
else:
|
||||
return 'fake', ''
|
||||
self.mock_object(self._driver, '_execute')
|
||||
self.mock_object(
|
||||
os_routines, 'mount',
|
||||
mock.Mock(side_effect=exception.ProcessExecutionError))
|
||||
self.mock_object(
|
||||
os_routines, 'list_mounts',
|
||||
mock.Mock(return_value=('fake', '')))
|
||||
|
||||
self.mock_object(self._driver, '_execute', exec_runner)
|
||||
self.assertRaises(exception.ProcessExecutionError,
|
||||
self._driver._mount_device, self.share, 'fakedevice')
|
||||
|
||||
@ -477,8 +555,9 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
] if retry_busy_device else [None, None]
|
||||
mount_path = self._get_mount_path(self.share)
|
||||
self._os.path.exists.return_value = True
|
||||
self.mock_object(self._driver, '_execute', mock.Mock(
|
||||
self.mock_object(os_routines, 'umount', mock.Mock(
|
||||
side_effect=execute_sideeffects))
|
||||
self.mock_object(os_routines, 'rmdir')
|
||||
|
||||
self._driver._unmount_device(self.share,
|
||||
retry_busy_device=retry_busy_device)
|
||||
@ -486,11 +565,9 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
num_of_times_umount_is_called = 3 if retry_busy_device else 1
|
||||
|
||||
self._os.path.exists.assert_called_with(mount_path)
|
||||
self._driver._execute.assert_has_calls([
|
||||
mock.call('umount', '-f', mount_path, run_as_root=True),
|
||||
] * num_of_times_umount_is_called + [
|
||||
mock.call('rmdir', mount_path, run_as_root=True)
|
||||
])
|
||||
os_routines.umount.assert_has_calls([
|
||||
mock.call(mount_path)] * num_of_times_umount_is_called)
|
||||
os_routines.rmdir.assert_called_once_with(mount_path)
|
||||
|
||||
def test_extend_share(self):
|
||||
local_path = self._driver._get_local_path(self.share)
|
||||
@ -515,15 +592,13 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
'fake_command', run_as_root=True, check_exit_code=True)
|
||||
|
||||
def test_extend_container(self):
|
||||
self.mock_object(self._driver, '_try_execute')
|
||||
mock_lvextend = privsep_lvm.lvextend = mock.Mock()
|
||||
|
||||
self.mock_object(privsep_common, 'execute_with_retries')
|
||||
self._driver._extend_container(self.share, 'device_name', 3)
|
||||
self._driver._try_execute.assert_called_once_with(
|
||||
'lvextend',
|
||||
'-L',
|
||||
'3G',
|
||||
'-r',
|
||||
'device_name',
|
||||
run_as_root=True)
|
||||
|
||||
privsep_common.execute_with_retries.assert_called_once_with(
|
||||
mock_lvextend, ['device_name', 3], CONF.num_shell_tries)
|
||||
|
||||
def test_get_share_server_pools(self):
|
||||
expected_result = [{
|
||||
@ -533,30 +608,32 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
'reserved_percentage': 0,
|
||||
'reserved_snapshot_percentage': 0,
|
||||
}, ]
|
||||
out, err = "VSize 33g VFree 22g", None
|
||||
self.mock_object(
|
||||
self._driver,
|
||||
'_execute',
|
||||
mock.Mock(return_value=("VSize 33g VFree 22g", None)))
|
||||
privsep_lvm, 'get_vgs', mock.Mock(return_value=(out, err)))
|
||||
|
||||
self.assertEqual(expected_result,
|
||||
self._driver.get_share_server_pools())
|
||||
self._driver._execute.assert_called_once_with(
|
||||
'vgs', 'fakevg', '--rows', '--units', 'g', run_as_root=True)
|
||||
|
||||
def test_copy_volume_error(self):
|
||||
def _fake_exec(*args, **kwargs):
|
||||
if 'count=0' in args:
|
||||
raise exception.ProcessExecutionError()
|
||||
@ddt.data(True, False)
|
||||
def test_copy_volume_error(self, use_direct_io):
|
||||
src_str = 'src'
|
||||
dest_str = 'dest'
|
||||
self.mock_object(
|
||||
os_routines, 'is_data_definition_direct_io_supported',
|
||||
mock.Mock(return_value=use_direct_io))
|
||||
self.mock_object(
|
||||
os_routines, 'data_definition',
|
||||
mock.Mock(side_effect=exception.ProcessExecutionError))
|
||||
|
||||
self.mock_object(self._driver, '_execute',
|
||||
mock.Mock(side_effect=_fake_exec))
|
||||
self._driver._copy_volume('src', 'dest', 1)
|
||||
self._driver._execute.assert_any_call('dd', 'count=0', 'if=src',
|
||||
'of=dest', 'iflag=direct',
|
||||
'oflag=direct', run_as_root=True)
|
||||
self._driver._execute.assert_any_call('dd', 'if=src', 'of=dest',
|
||||
'count=1024', 'bs=1M',
|
||||
run_as_root=True)
|
||||
self.assertRaises(
|
||||
exception.ShareBackendException,
|
||||
self._driver._copy_volume, src_str, dest_str, 1)
|
||||
(os_routines.is_data_definition_direct_io_supported
|
||||
.assert_called_once_with(
|
||||
src_str, dest_str))
|
||||
os_routines.data_definition.assert_called_once_with(
|
||||
src_str, dest_str, (1 * 1024), use_direct_io=use_direct_io)
|
||||
|
||||
@ddt.data((['1.1.1.1'], 4), (['1001::1001'], 6))
|
||||
@ddt.unpack
|
||||
@ -576,37 +653,38 @@ class LVMShareDriverTestCase(test.TestCase):
|
||||
self.assertEqual(version == 6, self._driver._stats['ipv6_support'])
|
||||
|
||||
def test_revert_to_snapshot(self):
|
||||
mock_update_access = self.mock_object(self._helper_nfs,
|
||||
'update_access')
|
||||
share_local_path = '/dev/mapper/fakevg-fakename'
|
||||
snapshot_local_path = '/dev/mapper/fakevg-fakesnapshotname'
|
||||
mock_update_access = self.mock_object(
|
||||
self._helper_nfs, 'update_access')
|
||||
mock__unmount_device = self.mock_object(
|
||||
self._driver, '_unmount_device')
|
||||
mock_lvconvert = self.mock_object(privsep_lvm, 'lvconvert')
|
||||
mock_create_snapshot = self.mock_object(
|
||||
self._driver, '_create_snapshot')
|
||||
mock_mount_device = self.mock_object(
|
||||
self._driver, '_mount_device')
|
||||
mock_get_local_path = self.mock_object(
|
||||
self._driver, '_get_local_path',
|
||||
mock.Mock(side_effect=[share_local_path, snapshot_local_path]))
|
||||
snapshot_parent_share = self.snapshot['share']
|
||||
|
||||
self._driver.revert_to_snapshot(self._context, self.snapshot,
|
||||
[], [], self.share_server)
|
||||
snap_lv = "%s/fakesnapshotname" % (CONF.lvm_share_volume_group)
|
||||
share_lv = "%s/fakename" % (CONF.lvm_share_volume_group)
|
||||
share_mount_path = self._get_mount_path(self.snapshot['share'])
|
||||
snapshot_mount_path = self._get_mount_path(self.snapshot)
|
||||
expected_exec = [
|
||||
('umount -f %s' % snapshot_mount_path),
|
||||
("rmdir %s" % snapshot_mount_path),
|
||||
("umount -f %s" % share_mount_path),
|
||||
("rmdir %s" % share_mount_path),
|
||||
("lvconvert --merge %s" % snap_lv),
|
||||
("lvcreate -L 1G --name fakesnapshotname --snapshot %s" %
|
||||
share_lv),
|
||||
("e2fsck -y -f /dev/mapper/%s-fakesnapshotname" %
|
||||
CONF.lvm_share_volume_group),
|
||||
("tune2fs -U random /dev/mapper/%s-fakesnapshotname" %
|
||||
CONF.lvm_share_volume_group),
|
||||
("mkdir -p %s" % share_mount_path),
|
||||
("mount /dev/mapper/%s-fakename %s" %
|
||||
(CONF.lvm_share_volume_group, share_mount_path)),
|
||||
("chmod 777 %s" % share_mount_path),
|
||||
("mkdir -p %s" % snapshot_mount_path),
|
||||
("mount /dev/mapper/fakevg-fakesnapshotname "
|
||||
"%s" % snapshot_mount_path),
|
||||
("chmod 777 %s" % snapshot_mount_path),
|
||||
]
|
||||
self.assertEqual(expected_exec, fake_utils.fake_execute_get_log())
|
||||
self.assertEqual(4, mock_update_access.call_count)
|
||||
mock__unmount_device.assert_has_calls(
|
||||
[mock.call(self.snapshot), mock.call(self.snapshot['share'])])
|
||||
mock_lvconvert.assert_called_once_with(
|
||||
CONF.lvm_share_volume_group, self.snapshot['name'])
|
||||
mock_create_snapshot.assert_called_once_with(
|
||||
self._context, self.snapshot)
|
||||
mock_mount_device.assert_has_calls(
|
||||
[mock.call(snapshot_parent_share, share_local_path),
|
||||
mock.call(self.snapshot, snapshot_local_path)]
|
||||
)
|
||||
mock_get_local_path.assert_has_calls(
|
||||
[mock.call(snapshot_parent_share),
|
||||
mock.call(self.snapshot)])
|
||||
|
||||
def test_snapshot_update_access(self):
|
||||
access_rules = [{
|
||||
|
Loading…
x
Reference in New Issue
Block a user