Remove Brick from cinder codebase
This patch removes the existing brick initiator code from Cinder. The new os-brick pypi library takes over. The only thing left behind is the local_dev directory as it's not part of os-brick. We should possibly move this elsewhere in a follow up patch. Change-Id: Iaa22b30b852ea055a8698e0faaefa5caff84d090 Depends-On: I0096e76f958e04829b98d5c4c47f49c82b58d8aa
This commit is contained in:
parent
5afa79cd4b
commit
88da45569c
@ -18,11 +18,11 @@
|
||||
import os
|
||||
import os.path
|
||||
|
||||
from os_brick.remotefs import remotefs as remotefs_brick
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.backup import chunkeddriver
|
||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
||||
from cinder import exception
|
||||
from cinder.i18n import _
|
||||
from cinder import utils
|
||||
|
@ -1,9 +1,5 @@
|
||||
Brick is a new library that currently is maintained in Cinder for
|
||||
the Havana release. It will eventually be moved external to Cinder,
|
||||
possibly oslo, or pypi. Any defects found in Brick, should be submitted
|
||||
against Cinder and fixed there, then pulled into other projects that
|
||||
are using brick.
|
||||
Brick has been migrated to a new standalone
|
||||
pypi library called os-brick.
|
||||
|
||||
* Brick is used outside of Cinder and therefore
|
||||
cannot have any dependencies on Cinder and/or
|
||||
it's database.
|
||||
We are leaving the local_dev directory here for the time
|
||||
being until we can migrate it to a new home.
|
||||
|
@ -1,126 +0,0 @@
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Exceptions for the Brick library."""
|
||||
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from cinder.i18n import _, _LE
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BrickException(Exception):
|
||||
"""Base Brick Exception
|
||||
|
||||
To correctly use this class, inherit from it and define
|
||||
a 'msg_fmt' property. That msg_fmt will get printf'd
|
||||
with the keyword arguments provided to the constructor.
|
||||
"""
|
||||
message = _("An unknown exception occurred.")
|
||||
code = 500
|
||||
headers = {}
|
||||
safe = False
|
||||
|
||||
def __init__(self, message=None, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
|
||||
if 'code' not in self.kwargs:
|
||||
try:
|
||||
self.kwargs['code'] = self.code
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if not message:
|
||||
try:
|
||||
message = self.message % kwargs
|
||||
|
||||
except Exception:
|
||||
# kwargs doesn't match a variable in the message
|
||||
# log the issue and the kwargs
|
||||
LOG.exception(_LE("Exception in string format operation. "
|
||||
"msg='%s'"),
|
||||
self.message)
|
||||
for name, value in kwargs.iteritems():
|
||||
LOG.error(_LE("%(n)s: %(v)s"), {'n': name, 'v': value})
|
||||
|
||||
# at least get the core message out if something happened
|
||||
message = self.message
|
||||
|
||||
# Put the message in 'msg' so that we can access it. If we have it in
|
||||
# message it will be overshadowed by the class' message attribute
|
||||
self.msg = message
|
||||
super(BrickException, self).__init__(message)
|
||||
|
||||
def __unicode__(self):
|
||||
return six.text_type(self.msg)
|
||||
|
||||
|
||||
class NotFound(BrickException):
|
||||
message = _("Resource could not be found.")
|
||||
code = 404
|
||||
safe = True
|
||||
|
||||
|
||||
class Invalid(BrickException):
|
||||
message = _("Unacceptable parameters.")
|
||||
code = 400
|
||||
|
||||
|
||||
# Cannot be templated as the error syntax varies.
|
||||
# msg needs to be constructed when raised.
|
||||
class InvalidParameterValue(Invalid):
|
||||
message = _("%(err)s")
|
||||
|
||||
|
||||
class NoFibreChannelHostsFound(BrickException):
|
||||
message = _("We are unable to locate any Fibre Channel devices.")
|
||||
|
||||
|
||||
class NoFibreChannelVolumeDeviceFound(BrickException):
|
||||
message = _("Unable to find a Fibre Channel volume device.")
|
||||
|
||||
|
||||
class VolumeDeviceNotFound(BrickException):
|
||||
message = _("Volume device not found at %(device)s.")
|
||||
|
||||
|
||||
class VolumePathNotRemoved(BrickException):
|
||||
message = _("Volume path %(volume_path)s was not removed in time.")
|
||||
|
||||
|
||||
class VolumeGroupNotFound(BrickException):
|
||||
message = _('Unable to find Volume Group: %(vg_name)s')
|
||||
|
||||
|
||||
class VolumeGroupCreationFailed(BrickException):
|
||||
message = _('Failed to create Volume Group: %(vg_name)s')
|
||||
|
||||
|
||||
class ISCSITargetCreateFailed(BrickException):
|
||||
message = _("Failed to create iscsi target for volume %(volume_id)s.")
|
||||
|
||||
|
||||
class ISCSITargetRemoveFailed(BrickException):
|
||||
message = _("Failed to remove iscsi target for volume %(volume_id)s.")
|
||||
|
||||
|
||||
class ISCSITargetAttachFailed(BrickException):
|
||||
message = _("Failed to attach iSCSI target for volume %(volume_id)s.")
|
||||
|
||||
|
||||
class ProtocolNotSupported(BrickException):
|
||||
message = _("Connect to volume via protocol %(protocol)s not supported.")
|
@ -1,34 +0,0 @@
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Generic exec utility that allows us to set the
|
||||
execute and root_helper attributes for putils.
|
||||
Some projects need their own execute wrapper
|
||||
and root_helper settings, so this provides that hook.
|
||||
"""
|
||||
|
||||
from oslo_concurrency import processutils as putils
|
||||
|
||||
|
||||
class Executor(object):
|
||||
def __init__(self, root_helper, execute=putils.execute,
|
||||
*args, **kwargs):
|
||||
self.set_execute(execute)
|
||||
self.set_root_helper(root_helper)
|
||||
|
||||
def set_execute(self, execute):
|
||||
self._execute = execute
|
||||
|
||||
def set_root_helper(self, helper):
|
||||
self._root_helper = helper
|
File diff suppressed because it is too large
Load Diff
@ -1,30 +0,0 @@
|
||||
# Copyright 2013 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
|
||||
|
||||
class HostDriver(object):
|
||||
|
||||
def get_all_block_devices(self):
|
||||
"""Get the list of all block devices seen in /dev/disk/by-path/."""
|
||||
files = []
|
||||
dir = "/dev/disk/by-path/"
|
||||
if os.path.isdir(dir):
|
||||
files = os.listdir(dir)
|
||||
devices = []
|
||||
for file in files:
|
||||
devices.append(dir + file)
|
||||
return devices
|
@ -1,212 +0,0 @@
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Generic linux Fibre Channel utilities."""
|
||||
|
||||
import errno
|
||||
|
||||
from oslo_concurrency import processutils as putils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.brick.initiator import linuxscsi
|
||||
from cinder.i18n import _LW
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LinuxFibreChannel(linuxscsi.LinuxSCSI):
|
||||
def __init__(self, root_helper, execute=putils.execute,
|
||||
*args, **kwargs):
|
||||
super(LinuxFibreChannel, self).__init__(root_helper, execute,
|
||||
*args, **kwargs)
|
||||
|
||||
def rescan_hosts(self, hbas):
|
||||
for hba in hbas:
|
||||
self.echo_scsi_command("/sys/class/scsi_host/%s/scan"
|
||||
% hba['host_device'], "- - -")
|
||||
|
||||
def get_fc_hbas(self):
|
||||
"""Get the Fibre Channel HBA information."""
|
||||
out = None
|
||||
try:
|
||||
out, _err = self._execute('systool', '-c', 'fc_host', '-v',
|
||||
run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
except putils.ProcessExecutionError as exc:
|
||||
# This handles the case where rootwrap is used
|
||||
# and systool is not installed
|
||||
# 96 = nova.cmd.rootwrap.RC_NOEXECFOUND:
|
||||
if exc.exit_code == 96:
|
||||
LOG.warning(_LW("systool is not installed"))
|
||||
return []
|
||||
except OSError as exc:
|
||||
# This handles the case where rootwrap is NOT used
|
||||
# and systool is not installed
|
||||
if exc.errno == errno.ENOENT:
|
||||
LOG.warning(_LW("systool is not installed"))
|
||||
return []
|
||||
|
||||
# No FC HBAs were found
|
||||
if out is None:
|
||||
return []
|
||||
|
||||
lines = out.split('\n')
|
||||
# ignore the first 2 lines
|
||||
lines = lines[2:]
|
||||
hbas = []
|
||||
hba = {}
|
||||
lastline = None
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
# 2 newlines denotes a new hba port
|
||||
if line == '' and lastline == '':
|
||||
if len(hba) > 0:
|
||||
hbas.append(hba)
|
||||
hba = {}
|
||||
else:
|
||||
val = line.split('=')
|
||||
if len(val) == 2:
|
||||
key = val[0].strip().replace(" ", "")
|
||||
value = val[1].strip()
|
||||
hba[key] = value.replace('"', '')
|
||||
lastline = line
|
||||
|
||||
return hbas
|
||||
|
||||
def get_fc_hbas_info(self):
|
||||
"""Get Fibre Channel WWNs and device paths from the system, if any."""
|
||||
|
||||
# Note(walter-boring) modern Linux kernels contain the FC HBA's in /sys
|
||||
# and are obtainable via the systool app
|
||||
hbas = self.get_fc_hbas()
|
||||
if not hbas:
|
||||
return []
|
||||
|
||||
hbas_info = []
|
||||
for hba in hbas:
|
||||
wwpn = hba['port_name'].replace('0x', '')
|
||||
wwnn = hba['node_name'].replace('0x', '')
|
||||
device_path = hba['ClassDevicepath']
|
||||
device = hba['ClassDevice']
|
||||
hbas_info.append({'port_name': wwpn,
|
||||
'node_name': wwnn,
|
||||
'host_device': device,
|
||||
'device_path': device_path})
|
||||
return hbas_info
|
||||
|
||||
def get_fc_wwpns(self):
|
||||
"""Get Fibre Channel WWPNs from the system, if any."""
|
||||
|
||||
# Note(walter-boring) modern Linux kernels contain the FC HBA's in /sys
|
||||
# and are obtainable via the systool app
|
||||
hbas = self.get_fc_hbas()
|
||||
|
||||
wwpns = []
|
||||
if hbas:
|
||||
for hba in hbas:
|
||||
if hba['port_state'] == 'Online':
|
||||
wwpn = hba['port_name'].replace('0x', '')
|
||||
wwpns.append(wwpn)
|
||||
|
||||
return wwpns
|
||||
|
||||
def get_fc_wwnns(self):
|
||||
"""Get Fibre Channel WWNNs from the system, if any."""
|
||||
|
||||
# Note(walter-boring) modern Linux kernels contain the FC HBA's in /sys
|
||||
# and are obtainable via the systool app
|
||||
hbas = self.get_fc_hbas()
|
||||
if not hbas:
|
||||
return []
|
||||
|
||||
wwnns = []
|
||||
if hbas:
|
||||
for hba in hbas:
|
||||
if hba['port_state'] == 'Online':
|
||||
wwnn = hba['node_name'].replace('0x', '')
|
||||
wwnns.append(wwnn)
|
||||
|
||||
return wwnns
|
||||
|
||||
|
||||
class LinuxFibreChannelS390X(LinuxFibreChannel):
|
||||
def __init__(self, root_helper, execute=putils.execute,
|
||||
*args, **kwargs):
|
||||
super(LinuxFibreChannelS390X, self).__init__(root_helper, execute,
|
||||
*args, **kwargs)
|
||||
|
||||
def get_fc_hbas_info(self):
|
||||
"""Get Fibre Channel WWNs and device paths from the system, if any."""
|
||||
|
||||
hbas = self.get_fc_hbas()
|
||||
if not hbas:
|
||||
return []
|
||||
|
||||
hbas_info = []
|
||||
for hba in hbas:
|
||||
if hba['port_state'] == 'Online':
|
||||
wwpn = hba['port_name'].replace('0x', '')
|
||||
wwnn = hba['node_name'].replace('0x', '')
|
||||
device_path = hba['ClassDevicepath']
|
||||
device = hba['ClassDevice']
|
||||
hbas_info.append({'port_name': wwpn,
|
||||
'node_name': wwnn,
|
||||
'host_device': device,
|
||||
'device_path': device_path})
|
||||
return hbas_info
|
||||
|
||||
def configure_scsi_device(self, device_number, target_wwn, lun):
|
||||
"""Write the LUN to the port's unit_add attribute.
|
||||
|
||||
If auto-discovery of LUNs is disabled on s390 platforms
|
||||
luns need to be added to the configuration through the
|
||||
unit_add interface
|
||||
"""
|
||||
LOG.debug("Configure lun for s390: device_number=(%(device_num)s) "
|
||||
"target_wwn=(%(target_wwn)s) target_lun=(%(target_lun)s)",
|
||||
{'device_num': device_number,
|
||||
'target_wwn': target_wwn,
|
||||
'target_lun': lun})
|
||||
zfcp_device_command = ("/sys/bus/ccw/drivers/zfcp/%s/%s/unit_add" %
|
||||
(device_number, target_wwn))
|
||||
LOG.debug("unit_add call for s390 execute: %s", zfcp_device_command)
|
||||
try:
|
||||
self.echo_scsi_command(zfcp_device_command, lun)
|
||||
except putils.ProcessExecutionError as exc:
|
||||
LOG.warning(_LW("unit_add call for s390 failed exit (%(code)s), "
|
||||
"stderr (%(stderr)s)"),
|
||||
{'code': exc.exit_code, 'stderr': exc.stderr})
|
||||
|
||||
def deconfigure_scsi_device(self, device_number, target_wwn, lun):
|
||||
"""Write the LUN to the port's unit_remove attribute.
|
||||
|
||||
If auto-discovery of LUNs is disabled on s390 platforms
|
||||
luns need to be removed from the configuration through the
|
||||
unit_remove interface
|
||||
"""
|
||||
LOG.debug("Deconfigure lun for s390: "
|
||||
"device_number=(%(device_num)s) "
|
||||
"target_wwn=(%(target_wwn)s) target_lun=(%(target_lun)s)",
|
||||
{'device_num': device_number,
|
||||
'target_wwn': target_wwn,
|
||||
'target_lun': lun})
|
||||
zfcp_device_command = ("/sys/bus/ccw/drivers/zfcp/%s/%s/unit_remove" %
|
||||
(device_number, target_wwn))
|
||||
LOG.debug("unit_remove call for s390 execute: %s", zfcp_device_command)
|
||||
try:
|
||||
self.echo_scsi_command(zfcp_device_command, lun)
|
||||
except putils.ProcessExecutionError as exc:
|
||||
LOG.warning(_LW("unit_remove call for s390 failed exit (%(code)s)"
|
||||
", stderr (%(stderr)s)"),
|
||||
{'code': exc.exit_code, 'stderr': exc.stderr})
|
@ -1,232 +0,0 @@
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Generic linux scsi subsystem and Multipath utilities.
|
||||
|
||||
Note, this is not iSCSI.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
|
||||
from oslo_concurrency import processutils as putils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.brick import exception
|
||||
from cinder.brick import executor
|
||||
from cinder.i18n import _LW, _LE
|
||||
from cinder.openstack.common import loopingcall
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MULTIPATH_ERROR_REGEX = re.compile("\w{3} \d+ \d\d:\d\d:\d\d \|.*$")
|
||||
MULTIPATH_WWID_REGEX = re.compile("\((?P<wwid>.+)\)")
|
||||
|
||||
|
||||
class LinuxSCSI(executor.Executor):
|
||||
def __init__(self, root_helper, execute=putils.execute,
|
||||
*args, **kwargs):
|
||||
super(LinuxSCSI, self).__init__(root_helper, execute,
|
||||
*args, **kwargs)
|
||||
|
||||
def echo_scsi_command(self, path, content):
|
||||
"""Used to echo strings to scsi subsystem."""
|
||||
|
||||
args = ["-a", path]
|
||||
kwargs = dict(process_input=content,
|
||||
run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
self._execute('tee', *args, **kwargs)
|
||||
|
||||
def get_name_from_path(self, path):
|
||||
"""Translates /dev/disk/by-path/ entry to /dev/sdX."""
|
||||
|
||||
name = os.path.realpath(path)
|
||||
if name.startswith("/dev/"):
|
||||
return name
|
||||
else:
|
||||
return None
|
||||
|
||||
def remove_scsi_device(self, device):
|
||||
"""Removes a scsi device based upon /dev/sdX name."""
|
||||
|
||||
path = "/sys/block/%s/device/delete" % device.replace("/dev/", "")
|
||||
if os.path.exists(path):
|
||||
# flush any outstanding IO first
|
||||
self.flush_device_io(device)
|
||||
|
||||
LOG.debug("Remove SCSI device(%(dev)s) with %(path)s",
|
||||
{'dev': device, 'path': path})
|
||||
self.echo_scsi_command(path, "1")
|
||||
|
||||
def wait_for_volume_removal(self, volume_path):
|
||||
"""This is used to ensure that volumes are gone."""
|
||||
|
||||
def _wait_for_volume_removal(volume_path):
|
||||
LOG.debug("Waiting for SCSI mount point %s to be removed.",
|
||||
volume_path)
|
||||
if os.path.exists(volume_path):
|
||||
if self.tries >= self.scan_attempts:
|
||||
LOG.error(_LE("Exceeded the number of attempts to detect "
|
||||
"volume removal."))
|
||||
raise exception.VolumePathNotRemoved(
|
||||
volume_path=volume_path)
|
||||
|
||||
LOG.debug("%(path)s still exists, rescanning. Try number: "
|
||||
"%(tries)s",
|
||||
{'path': volume_path, 'tries': self.tries})
|
||||
self.tries = self.tries + 1
|
||||
else:
|
||||
LOG.debug("SCSI mount point %s has been removed.", volume_path)
|
||||
raise loopingcall.LoopingCallDone()
|
||||
|
||||
# Setup a loop here to give the kernel time
|
||||
# to remove the volume from /dev/disk/by-path/
|
||||
self.tries = 0
|
||||
self.scan_attempts = 3
|
||||
timer = loopingcall.FixedIntervalLoopingCall(
|
||||
_wait_for_volume_removal, volume_path)
|
||||
timer.start(interval=2).wait()
|
||||
|
||||
def get_device_info(self, device):
|
||||
(out, _err) = self._execute('sg_scan', device, run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
dev_info = {'device': device, 'host': None,
|
||||
'channel': None, 'id': None, 'lun': None}
|
||||
if out:
|
||||
line = out.strip()
|
||||
line = line.replace(device + ": ", "")
|
||||
info = line.split(" ")
|
||||
|
||||
for item in info:
|
||||
if '=' in item:
|
||||
pair = item.split('=')
|
||||
dev_info[pair[0]] = pair[1]
|
||||
elif 'scsi' in item:
|
||||
dev_info['host'] = item.replace('scsi', '')
|
||||
|
||||
return dev_info
|
||||
|
||||
def remove_multipath_device(self, multipath_name):
|
||||
"""This removes LUNs associated with a multipath device
|
||||
and the multipath device itself.
|
||||
"""
|
||||
|
||||
LOG.debug("remove multipath device %s", multipath_name)
|
||||
mpath_dev = self.find_multipath_device(multipath_name)
|
||||
if mpath_dev:
|
||||
devices = mpath_dev['devices']
|
||||
LOG.debug("multipath LUNs to remove %s", devices)
|
||||
for device in devices:
|
||||
self.remove_scsi_device(device['device'])
|
||||
self.flush_multipath_device(mpath_dev['id'])
|
||||
|
||||
def flush_device_io(self, device):
|
||||
"""This is used to flush any remaining IO in the buffers."""
|
||||
try:
|
||||
LOG.debug("Flushing IO for device %s", device)
|
||||
self._execute('blockdev', '--flushbufs', device, run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
except putils.ProcessExecutionError as exc:
|
||||
LOG.warning(_LW("Failed to flush IO buffers prior to removing"
|
||||
" device: (%(code)s)"),
|
||||
{'code': exc.exit_code})
|
||||
|
||||
def flush_multipath_device(self, device):
|
||||
try:
|
||||
LOG.debug("Flush multipath device %s", device)
|
||||
self._execute('multipath', '-f', device, run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
except putils.ProcessExecutionError as exc:
|
||||
LOG.warning(_LW("multipath call failed exit (%(code)s)"),
|
||||
{'code': exc.exit_code})
|
||||
|
||||
def flush_multipath_devices(self):
|
||||
try:
|
||||
self._execute('multipath', '-F', run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
except putils.ProcessExecutionError as exc:
|
||||
LOG.warning(_LW("multipath call failed exit (%(code)s)"),
|
||||
{'code': exc.exit_code})
|
||||
|
||||
def find_multipath_device(self, device):
|
||||
"""Find a multipath device associated with a LUN device name.
|
||||
|
||||
device can be either a /dev/sdX entry or a multipath id.
|
||||
"""
|
||||
|
||||
mdev = None
|
||||
devices = []
|
||||
out = None
|
||||
try:
|
||||
(out, _err) = self._execute('multipath', '-l', device,
|
||||
run_as_root=True,
|
||||
root_helper=self._root_helper)
|
||||
except putils.ProcessExecutionError as exc:
|
||||
LOG.warning(_LW("multipath call failed exit (%(code)s)"),
|
||||
{'code': exc.exit_code})
|
||||
return None
|
||||
|
||||
if out:
|
||||
lines = out.strip()
|
||||
lines = lines.split("\n")
|
||||
lines = [line for line in lines
|
||||
if not re.match(MULTIPATH_ERROR_REGEX, line)]
|
||||
if lines:
|
||||
|
||||
# Use the device name, be it the WWID, mpathN or custom alias
|
||||
# of a device to build the device path. This should be the
|
||||
# first item on the first line of output from `multipath -l
|
||||
# ${path}` or `multipath -l ${wwid}`..
|
||||
mdev_name = lines[0].split(" ")[0]
|
||||
mdev = '/dev/mapper/%s' % mdev_name
|
||||
|
||||
# Find the WWID for the LUN if we are using mpathN or aliases.
|
||||
wwid_search = MULTIPATH_WWID_REGEX.search(lines[0])
|
||||
if wwid_search is not None:
|
||||
mdev_id = wwid_search.group('wwid')
|
||||
else:
|
||||
mdev_id = mdev_name
|
||||
|
||||
# Confirm that the device is present.
|
||||
try:
|
||||
os.stat(mdev)
|
||||
except OSError:
|
||||
LOG.warning(_LW("Couldn't find multipath device %s"), mdev)
|
||||
return None
|
||||
|
||||
LOG.debug("Found multipath device = %(mdev)s",
|
||||
{'mdev': mdev})
|
||||
device_lines = lines[3:]
|
||||
for dev_line in device_lines:
|
||||
if dev_line.find("policy") != -1:
|
||||
continue
|
||||
|
||||
dev_line = dev_line.lstrip(' |-`')
|
||||
dev_info = dev_line.split()
|
||||
address = dev_info[0].split(":")
|
||||
|
||||
dev = {'device': '/dev/%s' % dev_info[1],
|
||||
'host': address[0], 'channel': address[1],
|
||||
'id': address[2], 'lun': address[3]
|
||||
}
|
||||
|
||||
devices.append(dev)
|
||||
|
||||
if mdev is not None:
|
||||
info = {"device": mdev,
|
||||
"id": mdev_id,
|
||||
"name": mdev_name,
|
||||
"devices": devices}
|
||||
return info
|
||||
return None
|
@ -22,12 +22,12 @@ import math
|
||||
import os
|
||||
import re
|
||||
|
||||
from os_brick import executor
|
||||
from oslo_concurrency import processutils as putils
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from cinder.brick import exception
|
||||
from cinder.brick import executor
|
||||
from cinder import exception
|
||||
from cinder.i18n import _LE, _LI
|
||||
from cinder import utils
|
||||
|
||||
|
@ -1,174 +0,0 @@
|
||||
# Copyright (c) 2013 OpenStack Foundation
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Remote filesystem client utilities."""
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
|
||||
from oslo_concurrency import processutils as putils
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from cinder.brick import exception
|
||||
from cinder.i18n import _, _LI
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RemoteFsClient(object):
|
||||
|
||||
def __init__(self, mount_type, root_helper,
|
||||
execute=putils.execute, *args, **kwargs):
|
||||
|
||||
self._mount_type = mount_type
|
||||
if mount_type == "nfs":
|
||||
self._mount_base = kwargs.get('nfs_mount_point_base', None)
|
||||
if not self._mount_base:
|
||||
raise exception.InvalidParameterValue(
|
||||
err=_('nfs_mount_point_base required'))
|
||||
self._mount_options = kwargs.get('nfs_mount_options', None)
|
||||
self._check_nfs_options()
|
||||
elif mount_type == "cifs":
|
||||
self._mount_base = kwargs.get('smbfs_mount_point_base', None)
|
||||
if not self._mount_base:
|
||||
raise exception.InvalidParameterValue(
|
||||
err=_('smbfs_mount_point_base required'))
|
||||
self._mount_options = kwargs.get('smbfs_mount_options', None)
|
||||
elif mount_type == "glusterfs":
|
||||
self._mount_base = kwargs.get('glusterfs_mount_point_base', None)
|
||||
if not self._mount_base:
|
||||
raise exception.InvalidParameterValue(
|
||||
err=_('glusterfs_mount_point_base required'))
|
||||
self._mount_options = None
|
||||
else:
|
||||
raise exception.ProtocolNotSupported(protocol=mount_type)
|
||||
self.root_helper = root_helper
|
||||
self.set_execute(execute)
|
||||
|
||||
def set_execute(self, execute):
|
||||
self._execute = execute
|
||||
|
||||
def _get_hash_str(self, base_str):
|
||||
"""Return a string that represents hash of base_str
|
||||
(in a hex format).
|
||||
"""
|
||||
return hashlib.md5(base_str).hexdigest()
|
||||
|
||||
def get_mount_point(self, device_name):
|
||||
"""Get Mount Point.
|
||||
|
||||
:param device_name: example 172.18.194.100:/var/nfs
|
||||
"""
|
||||
return os.path.join(self._mount_base,
|
||||
self._get_hash_str(device_name))
|
||||
|
||||
def _read_mounts(self):
|
||||
(out, _err) = self._execute('mount', check_exit_code=0)
|
||||
lines = out.split('\n')
|
||||
mounts = {}
|
||||
for line in lines:
|
||||
tokens = line.split()
|
||||
if 2 < len(tokens):
|
||||
device = tokens[0]
|
||||
mnt_point = tokens[2]
|
||||
mounts[mnt_point] = device
|
||||
return mounts
|
||||
|
||||
def mount(self, share, flags=None):
|
||||
"""Mount given share."""
|
||||
mount_path = self.get_mount_point(share)
|
||||
|
||||
if mount_path in self._read_mounts():
|
||||
LOG.info(_LI('Already mounted: %s'), mount_path)
|
||||
return
|
||||
|
||||
self._execute('mkdir', '-p', mount_path, check_exit_code=0)
|
||||
if self._mount_type == 'nfs':
|
||||
self._mount_nfs(share, mount_path, flags)
|
||||
else:
|
||||
self._do_mount(self._mount_type, share, mount_path,
|
||||
self._mount_options, flags)
|
||||
|
||||
def _do_mount(self, mount_type, share, mount_path, mount_options=None,
|
||||
flags=None):
|
||||
"""Mounts share based on the specified params."""
|
||||
mnt_cmd = ['mount', '-t', mount_type]
|
||||
if mount_options is not None:
|
||||
mnt_cmd.extend(['-o', mount_options])
|
||||
if flags is not None:
|
||||
mnt_cmd.extend(flags)
|
||||
mnt_cmd.extend([share, mount_path])
|
||||
|
||||
self._execute(*mnt_cmd, root_helper=self.root_helper,
|
||||
run_as_root=True, check_exit_code=0)
|
||||
|
||||
def _mount_nfs(self, nfs_share, mount_path, flags=None):
|
||||
"""Mount nfs share using present mount types."""
|
||||
mnt_errors = {}
|
||||
|
||||
# This loop allows us to first try to mount with NFS 4.1 for pNFS
|
||||
# support but falls back to mount NFS 4 or NFS 3 if either the client
|
||||
# or server do not support it.
|
||||
for mnt_type in sorted(self._nfs_mount_type_opts.keys(), reverse=True):
|
||||
options = self._nfs_mount_type_opts[mnt_type]
|
||||
try:
|
||||
self._do_mount('nfs', nfs_share, mount_path, options, flags)
|
||||
LOG.debug('Mounted %(sh)s using %(mnt_type)s.',
|
||||
{'sh': nfs_share, 'mnt_type': mnt_type})
|
||||
return
|
||||
except Exception as e:
|
||||
mnt_errors[mnt_type] = six.text_type(e)
|
||||
LOG.debug('Failed to do %s mount.', mnt_type)
|
||||
raise exception.BrickException(_("NFS mount failed for share %(sh)s. "
|
||||
"Error - %(error)s")
|
||||
% {'sh': nfs_share,
|
||||
'error': mnt_errors})
|
||||
|
||||
def _check_nfs_options(self):
|
||||
"""Checks and prepares nfs mount type options."""
|
||||
self._nfs_mount_type_opts = {'nfs': self._mount_options}
|
||||
nfs_vers_opt_patterns = ['^nfsvers', '^vers', '^v[\d]']
|
||||
for opt in nfs_vers_opt_patterns:
|
||||
if self._option_exists(self._mount_options, opt):
|
||||
return
|
||||
|
||||
# pNFS requires NFS 4.1. The mount.nfs4 utility does not automatically
|
||||
# negotiate 4.1 support, we have to ask for it by specifying two
|
||||
# options: vers=4 and minorversion=1.
|
||||
pnfs_opts = self._update_option(self._mount_options, 'vers', '4')
|
||||
pnfs_opts = self._update_option(pnfs_opts, 'minorversion', '1')
|
||||
self._nfs_mount_type_opts['pnfs'] = pnfs_opts
|
||||
|
||||
def _option_exists(self, options, opt_pattern):
|
||||
"""Checks if the option exists in nfs options and returns position."""
|
||||
options = [x.strip() for x in options.split(',')] if options else []
|
||||
pos = 0
|
||||
for opt in options:
|
||||
pos = pos + 1
|
||||
if re.match(opt_pattern, opt, flags=0):
|
||||
return pos
|
||||
return 0
|
||||
|
||||
def _update_option(self, options, option, value=None):
|
||||
"""Update option if exists else adds it and returns new options."""
|
||||
opts = [x.strip() for x in options.split(',')] if options else []
|
||||
pos = self._option_exists(options, option)
|
||||
if pos:
|
||||
opts.pop(pos - 1)
|
||||
opt = '%s=%s' % (option, value) if value else option
|
||||
opts.append(opt)
|
||||
return ",".join(opts) if len(opts) > 1 else opts[0]
|
@ -687,6 +687,18 @@ class ReadOnlyFieldError(CinderException):
|
||||
msg_fmt = _('Cannot modify readonly field %(field)s')
|
||||
|
||||
|
||||
class VolumeGroupNotFound(CinderException):
|
||||
msg_fmt = _('Unable to find Volume Group: %(vg_name)s')
|
||||
|
||||
|
||||
class VolumeGroupCreationFailed(CinderException):
|
||||
msg_fmt = _('Failed to create Volume Group: %(vg_name)s')
|
||||
|
||||
|
||||
class VolumeDeviceNotFound(CinderException):
|
||||
msg_fmt = _('Volume device not found at %(device)s.')
|
||||
|
||||
|
||||
# Driver specific exceptions
|
||||
# Coraid
|
||||
class CoraidException(VolumeDriverException):
|
||||
|
@ -27,11 +27,11 @@ import tempfile
|
||||
import zlib
|
||||
|
||||
import mock
|
||||
from os_brick.remotefs import remotefs as remotefs_brick
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.backup.drivers import nfs
|
||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,66 +0,0 @@
|
||||
|
||||
# Copyright 2010 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 cinder.brick import exception
|
||||
from cinder import test
|
||||
|
||||
import six
|
||||
|
||||
|
||||
class BrickExceptionTestCase(test.TestCase):
|
||||
def test_default_error_msg(self):
|
||||
class FakeBrickException(exception.BrickException):
|
||||
message = "default message"
|
||||
|
||||
exc = FakeBrickException()
|
||||
self.assertEqual(six.text_type(exc), 'default message')
|
||||
|
||||
def test_error_msg(self):
|
||||
self.assertEqual(six.text_type(exception.BrickException('test')),
|
||||
'test')
|
||||
|
||||
def test_default_error_msg_with_kwargs(self):
|
||||
class FakeBrickException(exception.BrickException):
|
||||
message = "default message: %(code)s"
|
||||
|
||||
exc = FakeBrickException(code=500)
|
||||
self.assertEqual(six.text_type(exc), 'default message: 500')
|
||||
|
||||
def test_error_msg_exception_with_kwargs(self):
|
||||
# NOTE(dprince): disable format errors for this test
|
||||
self.flags(fatal_exception_format_errors=False)
|
||||
|
||||
class FakeBrickException(exception.BrickException):
|
||||
message = "default message: %(mispelled_code)s"
|
||||
|
||||
exc = FakeBrickException(code=500)
|
||||
self.assertEqual(six.text_type(exc),
|
||||
'default message: %(mispelled_code)s')
|
||||
|
||||
def test_default_error_code(self):
|
||||
class FakeBrickException(exception.BrickException):
|
||||
code = 404
|
||||
|
||||
exc = FakeBrickException()
|
||||
self.assertEqual(exc.kwargs['code'], 404)
|
||||
|
||||
def test_error_code_from_kwarg(self):
|
||||
class FakeBrickException(exception.BrickException):
|
||||
code = 500
|
||||
|
||||
exc = FakeBrickException(code=404)
|
||||
self.assertEqual(exc.kwargs['code'], 404)
|
@ -1,245 +0,0 @@
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os.path
|
||||
import string
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.brick.initiator import linuxfc
|
||||
from cinder import test
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LinuxFCTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(LinuxFCTestCase, self).setUp()
|
||||
self.cmds = []
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
self.lfc = linuxfc.LinuxFibreChannel(None, execute=self.fake_execute)
|
||||
|
||||
def fake_execute(self, *cmd, **kwargs):
|
||||
self.cmds.append(string.join(cmd))
|
||||
return "", None
|
||||
|
||||
def test_rescan_hosts(self):
|
||||
hbas = [{'host_device': 'foo'},
|
||||
{'host_device': 'bar'}, ]
|
||||
self.lfc.rescan_hosts(hbas)
|
||||
expected_commands = ['tee -a /sys/class/scsi_host/foo/scan',
|
||||
'tee -a /sys/class/scsi_host/bar/scan']
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
def test_get_fc_hbas_fail(self):
|
||||
def fake_exec1(a, b, c, d, run_as_root=True, root_helper='sudo'):
|
||||
raise OSError
|
||||
|
||||
def fake_exec2(a, b, c, d, run_as_root=True, root_helper='sudo'):
|
||||
return None, 'None found'
|
||||
|
||||
self.stubs.Set(self.lfc, "_execute", fake_exec1)
|
||||
hbas = self.lfc.get_fc_hbas()
|
||||
self.assertEqual(0, len(hbas))
|
||||
self.stubs.Set(self.lfc, "_execute", fake_exec2)
|
||||
hbas = self.lfc.get_fc_hbas()
|
||||
self.assertEqual(0, len(hbas))
|
||||
|
||||
def test_get_fc_hbas(self):
|
||||
def fake_exec(a, b, c, d, run_as_root=True, root_helper='sudo'):
|
||||
return SYSTOOL_FC, None
|
||||
self.stubs.Set(self.lfc, "_execute", fake_exec)
|
||||
hbas = self.lfc.get_fc_hbas()
|
||||
self.assertEqual(2, len(hbas))
|
||||
hba1 = hbas[0]
|
||||
self.assertEqual(hba1["ClassDevice"], "host0")
|
||||
hba2 = hbas[1]
|
||||
self.assertEqual(hba2["ClassDevice"], "host2")
|
||||
|
||||
def test_get_fc_hbas_info(self):
|
||||
def fake_exec(a, b, c, d, run_as_root=True, root_helper='sudo'):
|
||||
return SYSTOOL_FC, None
|
||||
self.stubs.Set(self.lfc, "_execute", fake_exec)
|
||||
hbas_info = self.lfc.get_fc_hbas_info()
|
||||
expected_info = [{'device_path': '/sys/devices/pci0000:20/'
|
||||
'0000:20:03.0/0000:21:00.0/'
|
||||
'host0/fc_host/host0',
|
||||
'host_device': 'host0',
|
||||
'node_name': '50014380242b9751',
|
||||
'port_name': '50014380242b9750'},
|
||||
{'device_path': '/sys/devices/pci0000:20/'
|
||||
'0000:20:03.0/0000:21:00.1/'
|
||||
'host2/fc_host/host2',
|
||||
'host_device': 'host2',
|
||||
'node_name': '50014380242b9753',
|
||||
'port_name': '50014380242b9752'}, ]
|
||||
self.assertEqual(expected_info, hbas_info)
|
||||
|
||||
def test_get_fc_wwpns(self):
|
||||
def fake_exec(a, b, c, d, run_as_root=True, root_helper='sudo'):
|
||||
return SYSTOOL_FC, None
|
||||
self.stubs.Set(self.lfc, "_execute", fake_exec)
|
||||
wwpns = self.lfc.get_fc_wwpns()
|
||||
expected_wwpns = ['50014380242b9750', '50014380242b9752']
|
||||
self.assertEqual(expected_wwpns, wwpns)
|
||||
|
||||
def test_get_fc_wwnns(self):
|
||||
def fake_exec(a, b, c, d, run_as_root=True, root_helper='sudo'):
|
||||
return SYSTOOL_FC, None
|
||||
self.stubs.Set(self.lfc, "_execute", fake_exec)
|
||||
wwnns = self.lfc.get_fc_wwpns()
|
||||
expected_wwnns = ['50014380242b9750', '50014380242b9752']
|
||||
self.assertEqual(expected_wwnns, wwnns)
|
||||
|
||||
SYSTOOL_FC = """
|
||||
Class = "fc_host"
|
||||
|
||||
Class Device = "host0"
|
||||
Class Device path = "/sys/devices/pci0000:20/0000:20:03.0/\
|
||||
0000:21:00.0/host0/fc_host/host0"
|
||||
dev_loss_tmo = "16"
|
||||
fabric_name = "0x100000051ea338b9"
|
||||
issue_lip = <store method only>
|
||||
max_npiv_vports = "0"
|
||||
node_name = "0x50014380242b9751"
|
||||
npiv_vports_inuse = "0"
|
||||
port_id = "0x960d0d"
|
||||
port_name = "0x50014380242b9750"
|
||||
port_state = "Online"
|
||||
port_type = "NPort (fabric via point-to-point)"
|
||||
speed = "8 Gbit"
|
||||
supported_classes = "Class 3"
|
||||
supported_speeds = "1 Gbit, 2 Gbit, 4 Gbit, 8 Gbit"
|
||||
symbolic_name = "QMH2572 FW:v4.04.04 DVR:v8.03.07.12-k"
|
||||
system_hostname = ""
|
||||
tgtid_bind_type = "wwpn (World Wide Port Name)"
|
||||
uevent =
|
||||
vport_create = <store method only>
|
||||
vport_delete = <store method only>
|
||||
|
||||
Device = "host0"
|
||||
Device path = "/sys/devices/pci0000:20/0000:20:03.0/0000:21:00.0/host0"
|
||||
edc = <store method only>
|
||||
optrom_ctl = <store method only>
|
||||
reset = <store method only>
|
||||
uevent = "DEVTYPE=scsi_host"
|
||||
|
||||
|
||||
Class Device = "host2"
|
||||
Class Device path = "/sys/devices/pci0000:20/0000:20:03.0/\
|
||||
0000:21:00.1/host2/fc_host/host2"
|
||||
dev_loss_tmo = "16"
|
||||
fabric_name = "0x100000051ea33b79"
|
||||
issue_lip = <store method only>
|
||||
max_npiv_vports = "0"
|
||||
node_name = "0x50014380242b9753"
|
||||
npiv_vports_inuse = "0"
|
||||
port_id = "0x970e09"
|
||||
port_name = "0x50014380242b9752"
|
||||
port_state = "Online"
|
||||
port_type = "NPort (fabric via point-to-point)"
|
||||
speed = "8 Gbit"
|
||||
supported_classes = "Class 3"
|
||||
supported_speeds = "1 Gbit, 2 Gbit, 4 Gbit, 8 Gbit"
|
||||
symbolic_name = "QMH2572 FW:v4.04.04 DVR:v8.03.07.12-k"
|
||||
system_hostname = ""
|
||||
tgtid_bind_type = "wwpn (World Wide Port Name)"
|
||||
uevent =
|
||||
vport_create = <store method only>
|
||||
vport_delete = <store method only>
|
||||
|
||||
Device = "host2"
|
||||
Device path = "/sys/devices/pci0000:20/0000:20:03.0/0000:21:00.1/host2"
|
||||
edc = <store method only>
|
||||
optrom_ctl = <store method only>
|
||||
reset = <store method only>
|
||||
uevent = "DEVTYPE=scsi_host"
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class LinuxFCS390XTestCase(LinuxFCTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(LinuxFCS390XTestCase, self).setUp()
|
||||
self.cmds = []
|
||||
self.stubs.Set(os.path, 'exists', lambda x: True)
|
||||
self.lfc = linuxfc.LinuxFibreChannelS390X(None,
|
||||
execute=self.fake_execute)
|
||||
|
||||
def test_get_fc_hbas_info(self):
|
||||
def fake_exec(a, b, c, d, run_as_root=True, root_helper='sudo'):
|
||||
return SYSTOOL_FC_S390X, None
|
||||
self.stubs.Set(self.lfc, "_execute", fake_exec)
|
||||
hbas_info = self.lfc.get_fc_hbas_info()
|
||||
expected = [{'device_path': '/sys/devices/css0/0.0.02ea/'
|
||||
'0.0.3080/host0/fc_host/host0',
|
||||
'host_device': 'host0',
|
||||
'node_name': '1234567898765432',
|
||||
'port_name': 'c05076ffe680a960'}]
|
||||
self.assertEqual(expected, hbas_info)
|
||||
|
||||
def test_configure_scsi_device(self):
|
||||
device_number = "0.0.2319"
|
||||
target_wwn = "0x50014380242b9751"
|
||||
lun = 1
|
||||
self.lfc.configure_scsi_device(device_number, target_wwn, lun)
|
||||
expected_commands = [('tee -a /sys/bus/ccw/drivers/zfcp/'
|
||||
'0.0.2319/0x50014380242b9751/unit_add')]
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
def test_deconfigure_scsi_device(self):
|
||||
device_number = "0.0.2319"
|
||||
target_wwn = "0x50014380242b9751"
|
||||
lun = 1
|
||||
self.lfc.deconfigure_scsi_device(device_number, target_wwn, lun)
|
||||
expected_commands = [('tee -a /sys/bus/ccw/drivers/zfcp/'
|
||||
'0.0.2319/0x50014380242b9751/unit_remove')]
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
SYSTOOL_FC_S390X = """
|
||||
Class = "fc_host"
|
||||
|
||||
Class Device = "host0"
|
||||
Class Device path = "/sys/devices/css0/0.0.02ea/0.0.3080/host0/fc_host/host0"
|
||||
active_fc4s = "0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \
|
||||
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \
|
||||
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 "
|
||||
dev_loss_tmo = "60"
|
||||
maxframe_size = "2112 bytes"
|
||||
node_name = "0x1234567898765432"
|
||||
permanent_port_name = "0xc05076ffe6803081"
|
||||
port_id = "0x010014"
|
||||
port_name = "0xc05076ffe680a960"
|
||||
port_state = "Online"
|
||||
port_type = "NPIV VPORT"
|
||||
serial_number = "IBM00000000000P30"
|
||||
speed = "8 Gbit"
|
||||
supported_classes = "Class 2, Class 3"
|
||||
supported_fc4s = "0x00 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \
|
||||
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 \
|
||||
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 "
|
||||
supported_speeds = "2 Gbit, 4 Gbit"
|
||||
symbolic_name = "IBM 2827 00000000000P30 \
|
||||
PCHID: 0308 NPIV UlpId: 01EA0A00 DEVNO: 0.0.1234 NAME: dummy"
|
||||
tgtid_bind_type = "wwpn (World Wide Port Name)"
|
||||
uevent =
|
||||
|
||||
Device = "host0"
|
||||
Device path = "/sys/devices/css0/0.0.02ea/0.0.3080/host0"
|
||||
uevent = "DEVTYPE=scsi_host"
|
||||
|
||||
"""
|
@ -1,258 +0,0 @@
|
||||
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import string
|
||||
|
||||
import mock
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.brick import exception
|
||||
from cinder.brick.initiator import linuxscsi
|
||||
from cinder import test
|
||||
from cinder.tests.unit import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LinuxSCSITestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(LinuxSCSITestCase, self).setUp()
|
||||
self.cmds = []
|
||||
self.stubs.Set(os.path, 'realpath', lambda x: '/dev/sdc')
|
||||
self.linuxscsi = linuxscsi.LinuxSCSI(None, execute=self.fake_execute)
|
||||
self.fake_stat_result = os.stat(__file__)
|
||||
|
||||
def fake_execute(self, *cmd, **kwargs):
|
||||
self.cmds.append(string.join(cmd))
|
||||
return "", None
|
||||
|
||||
def fake_stat(self, path):
|
||||
return self.fake_stat_result
|
||||
|
||||
def test_echo_scsi_command(self):
|
||||
self.linuxscsi.echo_scsi_command("/some/path", "1")
|
||||
expected_commands = ['tee -a /some/path']
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
def test_get_name_from_path(self):
|
||||
device_name = "/dev/sdc"
|
||||
self.stubs.Set(os.path, 'realpath', lambda x: device_name)
|
||||
disk_path = ("/dev/disk/by-path/ip-10.10.220.253:3260-"
|
||||
"iscsi-iqn.2000-05.com.3pardata:21810002ac00383d-lun-0")
|
||||
name = self.linuxscsi.get_name_from_path(disk_path)
|
||||
self.assertEqual(name, device_name)
|
||||
self.stubs.Set(os.path, 'realpath', lambda x: "bogus")
|
||||
name = self.linuxscsi.get_name_from_path(disk_path)
|
||||
self.assertIsNone(name)
|
||||
|
||||
def test_remove_scsi_device(self):
|
||||
self.stubs.Set(os.path, "exists", lambda x: False)
|
||||
self.linuxscsi.remove_scsi_device("/dev/sdc")
|
||||
expected_commands = []
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
self.stubs.Set(os.path, "exists", lambda x: True)
|
||||
self.linuxscsi.remove_scsi_device("/dev/sdc")
|
||||
expected_commands = [
|
||||
('blockdev --flushbufs /dev/sdc'),
|
||||
('tee -a /sys/block/sdc/device/delete')]
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
@mock.patch('cinder.openstack.common.loopingcall.FixedIntervalLoopingCall',
|
||||
new=utils.ZeroIntervalLoopingCall)
|
||||
def test_wait_for_volume_removal(self):
|
||||
fake_path = '/dev/disk/by-path/fake-iscsi-iqn-lun-0'
|
||||
self.stubs.Set(os.path, "exists", lambda x: True)
|
||||
self.assertRaises(exception.VolumePathNotRemoved,
|
||||
self.linuxscsi.wait_for_volume_removal,
|
||||
fake_path)
|
||||
|
||||
self.stubs.Set(os.path, "exists", lambda x: False)
|
||||
self.linuxscsi.wait_for_volume_removal(fake_path)
|
||||
expected_commands = []
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
def test_flush_multipath_device(self):
|
||||
self.linuxscsi.flush_multipath_device('/dev/dm-9')
|
||||
expected_commands = [('multipath -f /dev/dm-9')]
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
def test_flush_multipath_devices(self):
|
||||
self.linuxscsi.flush_multipath_devices()
|
||||
expected_commands = [('multipath -F')]
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
def test_remove_multipath_device(self):
|
||||
def fake_find_multipath_device(device):
|
||||
devices = [{'device': '/dev/sde', 'host': 0,
|
||||
'channel': 0, 'id': 0, 'lun': 1},
|
||||
{'device': '/dev/sdf', 'host': 2,
|
||||
'channel': 0, 'id': 0, 'lun': 1}, ]
|
||||
|
||||
info = {"device": "dm-3",
|
||||
"id": "350002ac20398383d",
|
||||
"devices": devices}
|
||||
return info
|
||||
|
||||
self.stubs.Set(os.path, "exists", lambda x: True)
|
||||
self.stubs.Set(self.linuxscsi, 'find_multipath_device',
|
||||
fake_find_multipath_device)
|
||||
|
||||
self.linuxscsi.remove_multipath_device('/dev/dm-3')
|
||||
expected_commands = [
|
||||
('blockdev --flushbufs /dev/sde'),
|
||||
('tee -a /sys/block/sde/device/delete'),
|
||||
('blockdev --flushbufs /dev/sdf'),
|
||||
('tee -a /sys/block/sdf/device/delete'),
|
||||
('multipath -f 350002ac20398383d'), ]
|
||||
self.assertEqual(expected_commands, self.cmds)
|
||||
|
||||
def test_find_multipath_device_3par_ufn(self):
|
||||
def fake_execute(*cmd, **kwargs):
|
||||
out = ("mpath6 (350002ac20398383d) dm-3 3PARdata,VV\n"
|
||||
"size=2.0G features='0' hwhandler='0' wp=rw\n"
|
||||
"`-+- policy='round-robin 0' prio=-1 status=active\n"
|
||||
" |- 0:0:0:1 sde 8:64 active undef running\n"
|
||||
" `- 2:0:0:1 sdf 8:80 active undef running\n"
|
||||
)
|
||||
return out, None
|
||||
|
||||
self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
|
||||
self.stubs.SmartSet(os, 'stat', self.fake_stat)
|
||||
|
||||
info = self.linuxscsi.find_multipath_device('/dev/sde')
|
||||
LOG.error("info = %s" % info)
|
||||
|
||||
self.assertEqual("350002ac20398383d", info['id'])
|
||||
self.assertEqual("mpath6", info['name'])
|
||||
self.assertEqual("/dev/mapper/mpath6", info['device'])
|
||||
|
||||
self.assertEqual("/dev/sde", info['devices'][0]['device'])
|
||||
self.assertEqual("0", info['devices'][0]['host'])
|
||||
self.assertEqual("0", info['devices'][0]['id'])
|
||||
self.assertEqual("0", info['devices'][0]['channel'])
|
||||
self.assertEqual("1", info['devices'][0]['lun'])
|
||||
|
||||
self.assertEqual("/dev/sdf", info['devices'][1]['device'])
|
||||
self.assertEqual("2", info['devices'][1]['host'])
|
||||
self.assertEqual("0", info['devices'][1]['id'])
|
||||
self.assertEqual("0", info['devices'][1]['channel'])
|
||||
self.assertEqual("1", info['devices'][1]['lun'])
|
||||
|
||||
def test_find_multipath_device_svc(self):
|
||||
def fake_execute(*cmd, **kwargs):
|
||||
out = ("36005076da00638089c000000000004d5 dm-2 IBM,2145\n"
|
||||
"size=954M features='1 queue_if_no_path' hwhandler='0'"
|
||||
" wp=rw\n"
|
||||
"|-+- policy='round-robin 0' prio=-1 status=active\n"
|
||||
"| |- 6:0:2:0 sde 8:64 active undef running\n"
|
||||
"| `- 6:0:4:0 sdg 8:96 active undef running\n"
|
||||
"`-+- policy='round-robin 0' prio=-1 status=enabled\n"
|
||||
" |- 6:0:3:0 sdf 8:80 active undef running\n"
|
||||
" `- 6:0:5:0 sdh 8:112 active undef running\n"
|
||||
)
|
||||
return out, None
|
||||
|
||||
self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
|
||||
self.stubs.SmartSet(os, 'stat', self.fake_stat)
|
||||
|
||||
info = self.linuxscsi.find_multipath_device('/dev/sde')
|
||||
LOG.error("info = %s" % info)
|
||||
|
||||
self.assertEqual("36005076da00638089c000000000004d5", info["id"])
|
||||
self.assertEqual("36005076da00638089c000000000004d5", info["name"])
|
||||
self.assertEqual("/dev/mapper/36005076da00638089c000000000004d5",
|
||||
info["device"])
|
||||
|
||||
self.assertEqual("/dev/sde", info['devices'][0]['device'])
|
||||
self.assertEqual("6", info['devices'][0]['host'])
|
||||
self.assertEqual("0", info['devices'][0]['channel'])
|
||||
self.assertEqual("2", info['devices'][0]['id'])
|
||||
self.assertEqual("0", info['devices'][0]['lun'])
|
||||
|
||||
self.assertEqual("/dev/sdf", info['devices'][2]['device'])
|
||||
self.assertEqual("6", info['devices'][2]['host'])
|
||||
self.assertEqual("0", info['devices'][2]['channel'])
|
||||
self.assertEqual("3", info['devices'][2]['id'])
|
||||
self.assertEqual("0", info['devices'][2]['lun'])
|
||||
|
||||
def test_find_multipath_device_ds8000(self):
|
||||
def fake_execute(*cmd, **kwargs):
|
||||
out = ("36005076303ffc48e0000000000000101 dm-2 IBM,2107900\n"
|
||||
"size=1.0G features='1 queue_if_no_path' hwhandler='0'"
|
||||
" wp=rw\n"
|
||||
"`-+- policy='round-robin 0' prio=-1 status=active\n"
|
||||
" |- 6:0:2:0 sdd 8:64 active undef running\n"
|
||||
" `- 6:1:0:3 sdc 8:32 active undef running\n"
|
||||
)
|
||||
return out, None
|
||||
|
||||
self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
|
||||
self.stubs.SmartSet(os, 'stat', self.fake_stat)
|
||||
|
||||
info = self.linuxscsi.find_multipath_device('/dev/sdd')
|
||||
LOG.error("info = %s" % info)
|
||||
|
||||
self.assertEqual("36005076303ffc48e0000000000000101", info["id"])
|
||||
self.assertEqual("36005076303ffc48e0000000000000101", info["name"])
|
||||
self.assertEqual("/dev/mapper/36005076303ffc48e0000000000000101",
|
||||
info["device"])
|
||||
|
||||
self.assertEqual("/dev/sdd", info['devices'][0]['device'])
|
||||
self.assertEqual("6", info['devices'][0]['host'])
|
||||
self.assertEqual("0", info['devices'][0]['channel'])
|
||||
self.assertEqual("2", info['devices'][0]['id'])
|
||||
self.assertEqual("0", info['devices'][0]['lun'])
|
||||
|
||||
self.assertEqual("/dev/sdc", info['devices'][1]['device'])
|
||||
self.assertEqual("6", info['devices'][1]['host'])
|
||||
self.assertEqual("1", info['devices'][1]['channel'])
|
||||
self.assertEqual("0", info['devices'][1]['id'])
|
||||
self.assertEqual("3", info['devices'][1]['lun'])
|
||||
|
||||
def test_find_multipath_device_with_error(self):
|
||||
def fake_execute(*cmd, **kwargs):
|
||||
out = ("Oct 13 10:24:01 | /lib/udev/scsi_id exitted with 1\n"
|
||||
"36005076303ffc48e0000000000000101 dm-2 IBM,2107900\n"
|
||||
"size=1.0G features='1 queue_if_no_path' hwhandler='0'"
|
||||
" wp=rw\n"
|
||||
"`-+- policy='round-robin 0' prio=-1 status=active\n"
|
||||
" |- 6:0:2:0 sdd 8:64 active undef running\n"
|
||||
" `- 6:1:0:3 sdc 8:32 active undef running\n"
|
||||
)
|
||||
return out, None
|
||||
|
||||
self.stubs.Set(self.linuxscsi, '_execute', fake_execute)
|
||||
self.stubs.SmartSet(os, 'stat', self.fake_stat)
|
||||
|
||||
info = self.linuxscsi.find_multipath_device('/dev/sdd')
|
||||
LOG.error("info = %s" % info)
|
||||
|
||||
self.assertEqual("36005076303ffc48e0000000000000101", info["id"])
|
||||
self.assertEqual("36005076303ffc48e0000000000000101", info["name"])
|
||||
self.assertEqual("/dev/mapper/36005076303ffc48e0000000000000101",
|
||||
info["device"])
|
||||
|
||||
self.assertEqual("/dev/sdd", info['devices'][0]['device'])
|
||||
self.assertEqual("6", info['devices'][0]['host'])
|
||||
self.assertEqual("0", info['devices'][0]['channel'])
|
||||
self.assertEqual("2", info['devices'][0]['id'])
|
||||
self.assertEqual("0", info['devices'][0]['lun'])
|
||||
|
||||
self.assertEqual("/dev/sdc", info['devices'][1]['device'])
|
||||
self.assertEqual("6", info['devices'][1]['host'])
|
||||
self.assertEqual("1", info['devices'][1]['channel'])
|
||||
self.assertEqual("0", info['devices'][1]['id'])
|
||||
self.assertEqual("3", info['devices'][1]['lun'])
|
@ -16,8 +16,8 @@ from mox3 import mox
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.brick import exception
|
||||
from cinder.brick.local_dev import lvm as brick
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.volume import configuration as conf
|
||||
|
||||
|
@ -1,173 +0,0 @@
|
||||
# (c) Copyright 2013 OpenStack Foundation
|
||||
# All Rights Reserved
|
||||
#
|
||||
# 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.
|
||||
|
||||
import mock
|
||||
from oslo_log import log as logging
|
||||
|
||||
from cinder.brick import exception
|
||||
from cinder.brick.remotefs import remotefs
|
||||
from cinder.i18n import _
|
||||
from cinder import test
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BrickRemoteFsTestCase(test.TestCase):
|
||||
TEST_EXPORT = '1.2.3.4/export1'
|
||||
TEST_MNT_BASE = '/mnt/test'
|
||||
TEST_HASH = '4d664fd43b6ff86d80a4ea969c07b3b9'
|
||||
TEST_MNT_POINT = TEST_MNT_BASE + '/' + TEST_HASH
|
||||
|
||||
def setUp(self):
|
||||
super(BrickRemoteFsTestCase, self).setUp()
|
||||
self._nfsclient = remotefs.RemoteFsClient(
|
||||
'nfs', 'sudo', nfs_mount_point_base=self.TEST_MNT_BASE)
|
||||
|
||||
def test_get_hash_str(self):
|
||||
"""_get_hash_str should calculation correct value."""
|
||||
|
||||
self.assertEqual(self.TEST_HASH,
|
||||
self._nfsclient._get_hash_str(self.TEST_EXPORT))
|
||||
|
||||
def test_get_mount_point(self):
|
||||
mnt_point = self._nfsclient.get_mount_point(self.TEST_EXPORT)
|
||||
self.assertEqual(mnt_point, self.TEST_MNT_POINT)
|
||||
|
||||
def test_mount_nfs_should_mount_correctly(self):
|
||||
mox = self.mox
|
||||
client = self._nfsclient
|
||||
|
||||
mox.StubOutWithMock(client, '_execute')
|
||||
client._execute('mount', check_exit_code=0).AndReturn(("", ""))
|
||||
client._execute('mkdir', '-p', self.TEST_MNT_POINT,
|
||||
check_exit_code=0).AndReturn(("", ""))
|
||||
client._execute('mount', '-t', 'nfs', '-o', 'vers=4,minorversion=1',
|
||||
self.TEST_EXPORT,
|
||||
self.TEST_MNT_POINT,
|
||||
root_helper='sudo', run_as_root=True,
|
||||
check_exit_code=0).AndReturn(("", ""))
|
||||
mox.ReplayAll()
|
||||
|
||||
client.mount(self.TEST_EXPORT)
|
||||
|
||||
mox.VerifyAll()
|
||||
|
||||
def test_mount_nfs_with_specific_vers(self):
|
||||
opts = ['vers=2,nointr', 'nfsvers=3,lock', 'nolock,v2', 'v4.0']
|
||||
for opt in opts:
|
||||
client = remotefs.RemoteFsClient(
|
||||
'nfs', 'sudo', nfs_mount_point_base=self.TEST_MNT_BASE,
|
||||
nfs_mount_options=opt)
|
||||
|
||||
client._read_mounts = mock.Mock(return_value=[])
|
||||
client._execute = mock.Mock(return_value=True)
|
||||
|
||||
client.mount(self.TEST_EXPORT)
|
||||
client._execute.assert_any_call('mkdir', '-p', self.TEST_MNT_POINT,
|
||||
check_exit_code=0)
|
||||
client._execute.assert_any_call('mount', '-t', 'nfs', '-o',
|
||||
opt, self.TEST_EXPORT,
|
||||
self.TEST_MNT_POINT,
|
||||
root_helper='sudo',
|
||||
run_as_root=True,
|
||||
check_exit_code=0)
|
||||
|
||||
def test_mount_nfs_with_fallback_no_vers(self):
|
||||
def execute(*args, **kwargs):
|
||||
if 'mkdir' in args:
|
||||
return True
|
||||
elif 'mount' in args:
|
||||
if 'lock,nointr,vers=4,minorversion=1' in args:
|
||||
raise Exception()
|
||||
else:
|
||||
return True
|
||||
else:
|
||||
self.fail(_("Unexpected call to _execute."))
|
||||
|
||||
opts = 'lock,nointr'
|
||||
client = remotefs.RemoteFsClient(
|
||||
'nfs', 'sudo', nfs_mount_point_base=self.TEST_MNT_BASE,
|
||||
nfs_mount_options=opts)
|
||||
|
||||
client._read_mounts = mock.Mock(return_value=[])
|
||||
client._execute = mock.Mock(wraps=execute)
|
||||
|
||||
client.mount(self.TEST_EXPORT)
|
||||
client._execute.assert_any_call('mkdir', '-p', self.TEST_MNT_POINT,
|
||||
check_exit_code=0)
|
||||
client._execute.assert_any_call('mount', '-t', 'nfs', '-o',
|
||||
'lock,nointr,vers=4,minorversion=1',
|
||||
self.TEST_EXPORT,
|
||||
self.TEST_MNT_POINT,
|
||||
root_helper='sudo',
|
||||
run_as_root=True,
|
||||
check_exit_code=0)
|
||||
client._execute.assert_any_call('mount', '-t', 'nfs', '-o',
|
||||
'lock,nointr',
|
||||
self.TEST_EXPORT,
|
||||
self.TEST_MNT_POINT,
|
||||
root_helper='sudo',
|
||||
run_as_root=True,
|
||||
check_exit_code=0)
|
||||
|
||||
def test_mount_nfs_with_fallback_all_fail(self):
|
||||
def execute(*args, **kwargs):
|
||||
if 'mkdir' in args:
|
||||
return True
|
||||
else:
|
||||
raise Exception(_("mount failed."))
|
||||
|
||||
opts = 'lock,nointr'
|
||||
client = remotefs.RemoteFsClient(
|
||||
'nfs', 'sudo', nfs_mount_point_base=self.TEST_MNT_BASE,
|
||||
nfs_mount_options=opts)
|
||||
|
||||
client._read_mounts = mock.Mock(return_value=[])
|
||||
client._execute = mock.Mock(wraps=execute)
|
||||
self.assertRaises(exception.BrickException, client.mount,
|
||||
self.TEST_EXPORT)
|
||||
|
||||
def test_mount_nfs_should_not_remount(self):
|
||||
mox = self.mox
|
||||
client = self._nfsclient
|
||||
|
||||
line = "%s on %s type nfs (rw)\n" % (self.TEST_EXPORT,
|
||||
self.TEST_MNT_POINT)
|
||||
mox.StubOutWithMock(client, '_execute')
|
||||
client._execute('mount', check_exit_code=0).AndReturn((line, ""))
|
||||
mox.ReplayAll()
|
||||
|
||||
client.mount(self.TEST_EXPORT)
|
||||
|
||||
mox.VerifyAll()
|
||||
|
||||
def test_nfs_mount_options(self):
|
||||
opts = 'test_nfs_mount_options'
|
||||
client = remotefs.RemoteFsClient(
|
||||
'nfs', 'sudo', nfs_mount_point_base=self.TEST_MNT_BASE,
|
||||
nfs_mount_options=opts)
|
||||
self.assertEqual(opts, client._mount_options)
|
||||
|
||||
def test_nfs_mount_point_base(self):
|
||||
base = '/mnt/test/nfs/mount/point/base'
|
||||
client = remotefs.RemoteFsClient('nfs', 'sudo',
|
||||
nfs_mount_point_base=base)
|
||||
self.assertEqual(base, client._mount_base)
|
||||
|
||||
def test_glusterfs_mount_point_base(self):
|
||||
base = '/mnt/test/glusterfs/mount/point/base'
|
||||
client = remotefs.RemoteFsClient('glusterfs', 'sudo',
|
||||
glusterfs_mount_point_base=base)
|
||||
self.assertEqual(base, client._mount_base)
|
@ -22,11 +22,11 @@ import time
|
||||
import traceback
|
||||
|
||||
import mock
|
||||
import os_brick
|
||||
from oslo_concurrency import processutils as putils
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder import brick
|
||||
from cinder import compute
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
@ -123,7 +123,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
||||
def test_set_execute(self):
|
||||
drv = self._driver
|
||||
|
||||
rfsclient = brick.remotefs.remotefs.RemoteFsClient
|
||||
rfsclient = os_brick.remotefs.remotefs.RemoteFsClient
|
||||
|
||||
with mock.patch.object(rfsclient, 'set_execute') as mock_set_execute:
|
||||
def my_execute(*a, **k):
|
||||
@ -151,7 +151,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
||||
"""_mount_glusterfs common case usage."""
|
||||
drv = self._driver
|
||||
|
||||
with mock.patch.object(brick.remotefs.remotefs.RemoteFsClient,
|
||||
with mock.patch.object(os_brick.remotefs.remotefs.RemoteFsClient,
|
||||
'mount') as mock_mount:
|
||||
drv._mount_glusterfs(self.TEST_EXPORT1)
|
||||
|
||||
@ -162,7 +162,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
||||
"""
|
||||
drv = self._driver
|
||||
|
||||
with mock.patch.object(brick.remotefs.remotefs.RemoteFsClient,
|
||||
with mock.patch.object(os_brick.remotefs.remotefs.RemoteFsClient,
|
||||
'mount') as mock_mount:
|
||||
|
||||
mock_mount.side_effect = exception.GlusterfsException()
|
||||
@ -182,7 +182,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
||||
drv = self._driver
|
||||
hashed_path = '/mnt/test/abcdefabcdef'
|
||||
|
||||
with mock.patch.object(brick.remotefs.remotefs.RemoteFsClient,
|
||||
with mock.patch.object(os_brick.remotefs.remotefs.RemoteFsClient,
|
||||
'get_mount_point') as mock_get_mount_point:
|
||||
mock_get_mount_point.return_value = hashed_path
|
||||
|
||||
@ -351,7 +351,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
||||
mock_get_file_mode,\
|
||||
mock.patch.object(tempfile, 'NamedTemporaryFile') as \
|
||||
mock_named_temp,\
|
||||
mock.patch.object(brick.remotefs.remotefs.RemoteFsClient,
|
||||
mock.patch.object(os_brick.remotefs.remotefs.RemoteFsClient,
|
||||
'mount') as mock_mount:
|
||||
drv._load_shares_config = self._fake_load_shares_config
|
||||
mock_named_temp.return_value = self._fake_NamedTemporaryFile
|
||||
|
@ -1252,7 +1252,7 @@ class BrickUtils(test.TestCase):
|
||||
"""
|
||||
|
||||
@mock.patch('cinder.utils.CONF')
|
||||
@mock.patch('cinder.brick.initiator.connector.get_connector_properties')
|
||||
@mock.patch('os_brick.initiator.connector.get_connector_properties')
|
||||
@mock.patch('cinder.utils.get_root_helper')
|
||||
def test_brick_get_connector_properties(self, mock_helper, mock_get,
|
||||
mock_conf):
|
||||
@ -1263,7 +1263,7 @@ class BrickUtils(test.TestCase):
|
||||
False, False)
|
||||
self.assertEqual(mock_get.return_value, output)
|
||||
|
||||
@mock.patch('cinder.brick.initiator.connector.InitiatorConnector.factory')
|
||||
@mock.patch('os_brick.initiator.connector.InitiatorConnector.factory')
|
||||
@mock.patch('cinder.utils.get_root_helper')
|
||||
def test_brick_get_connector(self, mock_helper, mock_factory):
|
||||
output = utils.brick_get_connector('protocol')
|
||||
|
@ -29,6 +29,7 @@ import time
|
||||
import eventlet
|
||||
import mock
|
||||
from mox3 import mox
|
||||
import os_brick
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_serialization import jsonutils
|
||||
@ -5215,7 +5216,7 @@ class GenericVolumeDriverTestCase(DriverTestCase):
|
||||
backup_service = self.mox.CreateMock(backup_driver.BackupDriver)
|
||||
root_helper = 'sudo cinder-rootwrap /etc/cinder/rootwrap.conf'
|
||||
self.mox.StubOutWithMock(self.volume.driver.db, 'volume_get')
|
||||
self.mox.StubOutWithMock(cinder.brick.initiator.connector,
|
||||
self.mox.StubOutWithMock(os_brick.initiator.connector,
|
||||
'get_connector_properties')
|
||||
self.mox.StubOutWithMock(self.volume.driver, '_attach_volume')
|
||||
self.mox.StubOutWithMock(os, 'getuid')
|
||||
@ -5226,7 +5227,7 @@ class GenericVolumeDriverTestCase(DriverTestCase):
|
||||
|
||||
self.volume.driver.db.volume_get(self.context, vol['id']).\
|
||||
AndReturn(vol)
|
||||
cinder.brick.initiator.connector.\
|
||||
os_brick.initiator.connector.\
|
||||
get_connector_properties(root_helper, CONF.my_ip, False, False).\
|
||||
AndReturn(properties)
|
||||
self.volume.driver._attach_volume(self.context, vol, properties).\
|
||||
@ -5250,7 +5251,7 @@ class GenericVolumeDriverTestCase(DriverTestCase):
|
||||
attach_info = {'device': {'path': '/dev/null'}}
|
||||
root_helper = 'sudo cinder-rootwrap /etc/cinder/rootwrap.conf'
|
||||
backup_service = self.mox.CreateMock(backup_driver.BackupDriver)
|
||||
self.mox.StubOutWithMock(cinder.brick.initiator.connector,
|
||||
self.mox.StubOutWithMock(os_brick.initiator.connector,
|
||||
'get_connector_properties')
|
||||
self.mox.StubOutWithMock(self.volume.driver, '_attach_volume')
|
||||
self.mox.StubOutWithMock(os, 'getuid')
|
||||
@ -5259,7 +5260,7 @@ class GenericVolumeDriverTestCase(DriverTestCase):
|
||||
self.mox.StubOutWithMock(self.volume.driver, '_detach_volume')
|
||||
self.mox.StubOutWithMock(self.volume.driver, 'terminate_connection')
|
||||
|
||||
cinder.brick.initiator.connector.\
|
||||
os_brick.initiator.connector.\
|
||||
get_connector_properties(root_helper, CONF.my_ip, False, False).\
|
||||
AndReturn(properties)
|
||||
self.volume.driver._attach_volume(self.context, vol, properties).\
|
||||
@ -5622,7 +5623,7 @@ class LVMVolumeDriverTestCase(DriverTestCase):
|
||||
|
||||
@mock.patch.object(utils, 'temporary_chown')
|
||||
@mock.patch.object(fileutils, 'file_open')
|
||||
@mock.patch.object(cinder.brick.initiator.connector,
|
||||
@mock.patch.object(os_brick.initiator.connector,
|
||||
'get_connector_properties')
|
||||
@mock.patch.object(db, 'volume_get')
|
||||
def test_backup_volume(self, mock_volume_get,
|
||||
|
@ -17,8 +17,8 @@ Mock unit tests for the NetApp nfs storage driver
|
||||
"""
|
||||
|
||||
import mock
|
||||
from os_brick.remotefs import remotefs as remotefs_brick
|
||||
|
||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
||||
from cinder import test
|
||||
from cinder import utils
|
||||
from cinder.volume.drivers.netapp.dataontap import nfs_base
|
||||
|
@ -17,8 +17,8 @@ Mock unit tests for the NetApp cmode nfs storage driver
|
||||
"""
|
||||
|
||||
import mock
|
||||
from os_brick.remotefs import remotefs as remotefs_brick
|
||||
|
||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
||||
from cinder import test
|
||||
from cinder.tests.unit.volume.drivers.netapp import fakes as na_fakes
|
||||
from cinder import utils
|
||||
|
@ -35,6 +35,7 @@ from xml import sax
|
||||
from xml.sax import expatreader
|
||||
from xml.sax import saxutils
|
||||
|
||||
from os_brick.initiator import connector
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
@ -44,7 +45,6 @@ from oslo_utils import timeutils
|
||||
import retrying
|
||||
import six
|
||||
|
||||
from cinder.brick.initiator import connector
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE
|
||||
|
||||
|
@ -17,12 +17,12 @@ import errno
|
||||
import os
|
||||
import stat
|
||||
|
||||
from os_brick.remotefs import remotefs as remotefs_brick
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE, _LI, _LW
|
||||
from cinder.image import image_utils
|
||||
|
@ -25,7 +25,6 @@ from oslo_log import log as logging
|
||||
from oslo_utils import importutils
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder.brick import exception as brick_exception
|
||||
from cinder.brick.local_dev import lvm as lvm
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE, _LI, _LW
|
||||
@ -262,7 +261,7 @@ class LVMVolumeDriver(driver.VolumeDriver):
|
||||
executor=self._execute,
|
||||
lvm_conf=lvm_conf_file)
|
||||
|
||||
except brick_exception.VolumeGroupNotFound:
|
||||
except exception.VolumeGroupNotFound:
|
||||
message = (_("Volume Group %s does not exist") %
|
||||
self.configuration.volume_group)
|
||||
raise exception.VolumeBackendAPIException(data=message)
|
||||
|
@ -17,13 +17,13 @@ import errno
|
||||
import os
|
||||
import time
|
||||
|
||||
from os_brick.remotefs import remotefs as remotefs_brick
|
||||
from oslo_concurrency import processutils as putils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import units
|
||||
import six
|
||||
|
||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE, _LI, _LW
|
||||
from cinder.image import image_utils
|
||||
|
@ -15,12 +15,12 @@
|
||||
|
||||
import os
|
||||
|
||||
from os_brick.remotefs import remotefs
|
||||
from oslo_concurrency import processutils as putils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder.brick.remotefs import remotefs
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LI, _LW
|
||||
from cinder.image import image_utils
|
||||
|
@ -19,10 +19,10 @@ import sys
|
||||
if sys.platform == 'win32':
|
||||
import wmi
|
||||
|
||||
from os_brick.remotefs import remotefs
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from cinder.brick.remotefs import remotefs
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE, _LI
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user