Merge "Remove Brick from cinder codebase"
This commit is contained in:
commit
e26120354f
cinder
backup/drivers
brick
exception.pytests/unit
backup/drivers
brick
test_brick_connector.pytest_brick_exception.pytest_brick_linuxfc.pytest_brick_linuxscsi.pytest_brick_lvm.pytest_brick_remotefs.py
test_glusterfs.pytest_utils.pytest_volume.pyvolume/drivers/netapp/dataontap
volume/drivers
@ -18,11 +18,11 @@
|
|||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
|
from os_brick.remotefs import remotefs as remotefs_brick
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from cinder.backup import chunkeddriver
|
from cinder.backup import chunkeddriver
|
||||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _
|
from cinder.i18n import _
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
Brick is a new library that currently is maintained in Cinder for
|
Brick has been migrated to a new standalone
|
||||||
the Havana release. It will eventually be moved external to Cinder,
|
pypi library called os-brick.
|
||||||
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 is used outside of Cinder and therefore
|
We are leaving the local_dev directory here for the time
|
||||||
cannot have any dependencies on Cinder and/or
|
being until we can migrate it to a new home.
|
||||||
it's database.
|
|
||||||
|
@ -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 os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from os_brick import executor
|
||||||
from oslo_concurrency import processutils as putils
|
from oslo_concurrency import processutils as putils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
|
|
||||||
from cinder.brick import exception
|
from cinder import exception
|
||||||
from cinder.brick import executor
|
|
||||||
from cinder.i18n import _LE, _LI
|
from cinder.i18n import _LE, _LI
|
||||||
from cinder import utils
|
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')
|
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
|
# Driver specific exceptions
|
||||||
# Coraid
|
# Coraid
|
||||||
class CoraidException(VolumeDriverException):
|
class CoraidException(VolumeDriverException):
|
||||||
|
@ -27,11 +27,11 @@ import tempfile
|
|||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from os_brick.remotefs import remotefs as remotefs_brick
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from cinder.backup.drivers import nfs
|
from cinder.backup.drivers import nfs
|
||||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
|
||||||
from cinder import context
|
from cinder import context
|
||||||
from cinder import db
|
from cinder import db
|
||||||
from cinder import exception
|
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_concurrency import processutils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from cinder.brick import exception
|
|
||||||
from cinder.brick.local_dev import lvm as brick
|
from cinder.brick.local_dev import lvm as brick
|
||||||
|
from cinder import exception
|
||||||
from cinder import test
|
from cinder import test
|
||||||
from cinder.volume import configuration as conf
|
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 traceback
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
import os_brick
|
||||||
from oslo_concurrency import processutils as putils
|
from oslo_concurrency import processutils as putils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
|
||||||
from cinder import brick
|
|
||||||
from cinder import compute
|
from cinder import compute
|
||||||
from cinder import context
|
from cinder import context
|
||||||
from cinder import db
|
from cinder import db
|
||||||
@ -123,7 +123,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||||||
def test_set_execute(self):
|
def test_set_execute(self):
|
||||||
drv = self._driver
|
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:
|
with mock.patch.object(rfsclient, 'set_execute') as mock_set_execute:
|
||||||
def my_execute(*a, **k):
|
def my_execute(*a, **k):
|
||||||
@ -151,7 +151,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||||||
"""_mount_glusterfs common case usage."""
|
"""_mount_glusterfs common case usage."""
|
||||||
drv = self._driver
|
drv = self._driver
|
||||||
|
|
||||||
with mock.patch.object(brick.remotefs.remotefs.RemoteFsClient,
|
with mock.patch.object(os_brick.remotefs.remotefs.RemoteFsClient,
|
||||||
'mount') as mock_mount:
|
'mount') as mock_mount:
|
||||||
drv._mount_glusterfs(self.TEST_EXPORT1)
|
drv._mount_glusterfs(self.TEST_EXPORT1)
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||||||
"""
|
"""
|
||||||
drv = self._driver
|
drv = self._driver
|
||||||
|
|
||||||
with mock.patch.object(brick.remotefs.remotefs.RemoteFsClient,
|
with mock.patch.object(os_brick.remotefs.remotefs.RemoteFsClient,
|
||||||
'mount') as mock_mount:
|
'mount') as mock_mount:
|
||||||
|
|
||||||
mock_mount.side_effect = exception.GlusterfsException()
|
mock_mount.side_effect = exception.GlusterfsException()
|
||||||
@ -182,7 +182,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||||||
drv = self._driver
|
drv = self._driver
|
||||||
hashed_path = '/mnt/test/abcdefabcdef'
|
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:
|
'get_mount_point') as mock_get_mount_point:
|
||||||
mock_get_mount_point.return_value = hashed_path
|
mock_get_mount_point.return_value = hashed_path
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ class GlusterFsDriverTestCase(test.TestCase):
|
|||||||
mock_get_file_mode,\
|
mock_get_file_mode,\
|
||||||
mock.patch.object(tempfile, 'NamedTemporaryFile') as \
|
mock.patch.object(tempfile, 'NamedTemporaryFile') as \
|
||||||
mock_named_temp,\
|
mock_named_temp,\
|
||||||
mock.patch.object(brick.remotefs.remotefs.RemoteFsClient,
|
mock.patch.object(os_brick.remotefs.remotefs.RemoteFsClient,
|
||||||
'mount') as mock_mount:
|
'mount') as mock_mount:
|
||||||
drv._load_shares_config = self._fake_load_shares_config
|
drv._load_shares_config = self._fake_load_shares_config
|
||||||
mock_named_temp.return_value = self._fake_NamedTemporaryFile
|
mock_named_temp.return_value = self._fake_NamedTemporaryFile
|
||||||
|
@ -1252,7 +1252,7 @@ class BrickUtils(test.TestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@mock.patch('cinder.utils.CONF')
|
@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')
|
@mock.patch('cinder.utils.get_root_helper')
|
||||||
def test_brick_get_connector_properties(self, mock_helper, mock_get,
|
def test_brick_get_connector_properties(self, mock_helper, mock_get,
|
||||||
mock_conf):
|
mock_conf):
|
||||||
@ -1263,7 +1263,7 @@ class BrickUtils(test.TestCase):
|
|||||||
False, False)
|
False, False)
|
||||||
self.assertEqual(mock_get.return_value, output)
|
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')
|
@mock.patch('cinder.utils.get_root_helper')
|
||||||
def test_brick_get_connector(self, mock_helper, mock_factory):
|
def test_brick_get_connector(self, mock_helper, mock_factory):
|
||||||
output = utils.brick_get_connector('protocol')
|
output = utils.brick_get_connector('protocol')
|
||||||
|
@ -29,6 +29,7 @@ import time
|
|||||||
import eventlet
|
import eventlet
|
||||||
import mock
|
import mock
|
||||||
from mox3 import mox
|
from mox3 import mox
|
||||||
|
import os_brick
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
@ -5215,7 +5216,7 @@ class GenericVolumeDriverTestCase(DriverTestCase):
|
|||||||
backup_service = self.mox.CreateMock(backup_driver.BackupDriver)
|
backup_service = self.mox.CreateMock(backup_driver.BackupDriver)
|
||||||
root_helper = 'sudo cinder-rootwrap /etc/cinder/rootwrap.conf'
|
root_helper = 'sudo cinder-rootwrap /etc/cinder/rootwrap.conf'
|
||||||
self.mox.StubOutWithMock(self.volume.driver.db, 'volume_get')
|
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')
|
'get_connector_properties')
|
||||||
self.mox.StubOutWithMock(self.volume.driver, '_attach_volume')
|
self.mox.StubOutWithMock(self.volume.driver, '_attach_volume')
|
||||||
self.mox.StubOutWithMock(os, 'getuid')
|
self.mox.StubOutWithMock(os, 'getuid')
|
||||||
@ -5226,7 +5227,7 @@ class GenericVolumeDriverTestCase(DriverTestCase):
|
|||||||
|
|
||||||
self.volume.driver.db.volume_get(self.context, vol['id']).\
|
self.volume.driver.db.volume_get(self.context, vol['id']).\
|
||||||
AndReturn(vol)
|
AndReturn(vol)
|
||||||
cinder.brick.initiator.connector.\
|
os_brick.initiator.connector.\
|
||||||
get_connector_properties(root_helper, CONF.my_ip, False, False).\
|
get_connector_properties(root_helper, CONF.my_ip, False, False).\
|
||||||
AndReturn(properties)
|
AndReturn(properties)
|
||||||
self.volume.driver._attach_volume(self.context, vol, properties).\
|
self.volume.driver._attach_volume(self.context, vol, properties).\
|
||||||
@ -5250,7 +5251,7 @@ class GenericVolumeDriverTestCase(DriverTestCase):
|
|||||||
attach_info = {'device': {'path': '/dev/null'}}
|
attach_info = {'device': {'path': '/dev/null'}}
|
||||||
root_helper = 'sudo cinder-rootwrap /etc/cinder/rootwrap.conf'
|
root_helper = 'sudo cinder-rootwrap /etc/cinder/rootwrap.conf'
|
||||||
backup_service = self.mox.CreateMock(backup_driver.BackupDriver)
|
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')
|
'get_connector_properties')
|
||||||
self.mox.StubOutWithMock(self.volume.driver, '_attach_volume')
|
self.mox.StubOutWithMock(self.volume.driver, '_attach_volume')
|
||||||
self.mox.StubOutWithMock(os, 'getuid')
|
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, '_detach_volume')
|
||||||
self.mox.StubOutWithMock(self.volume.driver, 'terminate_connection')
|
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).\
|
get_connector_properties(root_helper, CONF.my_ip, False, False).\
|
||||||
AndReturn(properties)
|
AndReturn(properties)
|
||||||
self.volume.driver._attach_volume(self.context, vol, 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(utils, 'temporary_chown')
|
||||||
@mock.patch.object(fileutils, 'file_open')
|
@mock.patch.object(fileutils, 'file_open')
|
||||||
@mock.patch.object(cinder.brick.initiator.connector,
|
@mock.patch.object(os_brick.initiator.connector,
|
||||||
'get_connector_properties')
|
'get_connector_properties')
|
||||||
@mock.patch.object(db, 'volume_get')
|
@mock.patch.object(db, 'volume_get')
|
||||||
def test_backup_volume(self, mock_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
|
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 test
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
from cinder.volume.drivers.netapp.dataontap import nfs_base
|
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
|
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 test
|
||||||
from cinder.tests.unit.volume.drivers.netapp import fakes as na_fakes
|
from cinder.tests.unit.volume.drivers.netapp import fakes as na_fakes
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
|
@ -35,6 +35,7 @@ from xml import sax
|
|||||||
from xml.sax import expatreader
|
from xml.sax import expatreader
|
||||||
from xml.sax import saxutils
|
from xml.sax import saxutils
|
||||||
|
|
||||||
|
from os_brick.initiator import connector
|
||||||
from oslo_concurrency import lockutils
|
from oslo_concurrency import lockutils
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -44,7 +45,6 @@ from oslo_utils import timeutils
|
|||||||
import retrying
|
import retrying
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from cinder.brick.initiator import connector
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE
|
from cinder.i18n import _, _LE
|
||||||
|
|
||||||
|
@ -17,12 +17,12 @@ import errno
|
|||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
|
|
||||||
|
from os_brick.remotefs import remotefs as remotefs_brick
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
|
||||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LI, _LW
|
from cinder.i18n import _, _LE, _LI, _LW
|
||||||
from cinder.image import image_utils
|
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 importutils
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
|
||||||
from cinder.brick import exception as brick_exception
|
|
||||||
from cinder.brick.local_dev import lvm as lvm
|
from cinder.brick.local_dev import lvm as lvm
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LI, _LW
|
from cinder.i18n import _, _LE, _LI, _LW
|
||||||
@ -262,7 +261,7 @@ class LVMVolumeDriver(driver.VolumeDriver):
|
|||||||
executor=self._execute,
|
executor=self._execute,
|
||||||
lvm_conf=lvm_conf_file)
|
lvm_conf=lvm_conf_file)
|
||||||
|
|
||||||
except brick_exception.VolumeGroupNotFound:
|
except exception.VolumeGroupNotFound:
|
||||||
message = (_("Volume Group %s does not exist") %
|
message = (_("Volume Group %s does not exist") %
|
||||||
self.configuration.volume_group)
|
self.configuration.volume_group)
|
||||||
raise exception.VolumeBackendAPIException(data=message)
|
raise exception.VolumeBackendAPIException(data=message)
|
||||||
|
@ -17,13 +17,13 @@ import errno
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from os_brick.remotefs import remotefs as remotefs_brick
|
||||||
from oslo_concurrency import processutils as putils
|
from oslo_concurrency import processutils as putils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LI, _LW
|
from cinder.i18n import _, _LE, _LI, _LW
|
||||||
from cinder.image import image_utils
|
from cinder.image import image_utils
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from os_brick.remotefs import remotefs
|
||||||
from oslo_concurrency import processutils as putils
|
from oslo_concurrency import processutils as putils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_utils import units
|
from oslo_utils import units
|
||||||
|
|
||||||
from cinder.brick.remotefs import remotefs
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LI, _LW
|
from cinder.i18n import _, _LI, _LW
|
||||||
from cinder.image import image_utils
|
from cinder.image import image_utils
|
||||||
|
@ -19,10 +19,10 @@ import sys
|
|||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
import wmi
|
import wmi
|
||||||
|
|
||||||
|
from os_brick.remotefs import remotefs
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from cinder.brick.remotefs import remotefs
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LI
|
from cinder.i18n import _, _LE, _LI
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user