Adding support for FibreChannelConnector for PPC64

For PPC64 architecture there is a different behavior to discover
the host-devices and scsi disk rescan. Adding implementation for
the same.

Change-Id: Id2283195d2b6002175079070a0ff0a137a9d6806
This commit is contained in:
Chhavi Agarwal 2017-04-17 08:37:13 -04:00
parent a3eebbb77f
commit 67e1a39a7e
5 changed files with 174 additions and 0 deletions

View File

@ -31,12 +31,15 @@ MULTIPATH_PATH_CHECK_REGEX = re.compile("\s+\d+:\d+:\d+:\d+\s+")
PLATFORM_ALL = 'ALL'
PLATFORM_x86 = 'X86'
PLATFORM_S390 = 'S390'
PLATFORM_PPC64 = 'PPC64'
OS_TYPE_ALL = 'ALL'
OS_TYPE_LINUX = 'LINUX'
OS_TYPE_WINDOWS = 'WIN'
S390X = "s390x"
S390 = "s390"
PPC64 = "ppc64"
PPC64LE = "ppc64le"
ISCSI = "ISCSI"
ISER = "ISER"

View File

@ -49,12 +49,15 @@ MULTIPATH_PATH_CHECK_REGEX = re.compile("\s+\d+:\d+:\d+:\d+\s+")
PLATFORM_ALL = 'ALL'
PLATFORM_x86 = 'X86'
PLATFORM_S390 = 'S390'
PLATFORM_PPC64 = 'PPC64'
OS_TYPE_ALL = 'ALL'
OS_TYPE_LINUX = 'LINUX'
OS_TYPE_WINDOWS = 'WIN'
S390X = "s390x"
S390 = "s390"
PPC64 = "ppc64"
PPC64LE = "ppc64le"
ISCSI = "ISCSI"
ISER = "ISER"
@ -83,6 +86,8 @@ connector_list = [
'os_brick.initiator.connectors.fibre_channel.FibreChannelConnector',
('os_brick.initiator.connectors.fibre_channel_s390x.'
'FibreChannelConnectorS390X'),
('os_brick.initiator.connectors.fibre_channel_ppc64.'
'FibreChannelConnectorPPC64'),
'os_brick.initiator.connectors.aoe.AoEConnector',
'os_brick.initiator.connectors.remotefs.RemoteFsConnector',
'os_brick.initiator.connectors.rbd.RBDConnector',
@ -167,6 +172,13 @@ _connector_mapping_linux_s390x = {
'os_brick.initiator.connectors.gpfs.GPFSConnector',
}
# Mapping for the PPC64 platform
_connector_mapping_linux_ppc64 = {
initiator.FIBRE_CHANNEL:
('os_brick.initiator.connectors.fibre_channel_ppc64.'
'FibreChannelConnectorPPC64'),
}
# Mapping for the windows connectors
_connector_mapping_windows = {
initiator.ISCSI:
@ -257,6 +269,9 @@ class InitiatorConnector(object):
_mapping = _connector_mapping_windows
elif arch in (initiator.S390, initiator.S390X):
_mapping = _connector_mapping_linux_s390x
elif arch in (initiator.PPC64, initiator.PPC64LE):
_mapping = _connector_mapping_linux_ppc64
else:
_mapping = _connector_mapping_linux

View File

@ -0,0 +1,65 @@
# 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 oslo_log import log as logging
from os_brick import initiator
from os_brick.initiator.connectors import fibre_channel
from os_brick.initiator import linuxfc
LOG = logging.getLogger(__name__)
class FibreChannelConnectorPPC64(fibre_channel.FibreChannelConnector):
"""Connector class to attach/detach Fibre Channel volumes on PPC64 arch."""
platform = initiator.PLATFORM_PPC64
def __init__(self, root_helper, driver=None,
execute=None, use_multipath=False,
device_scan_attempts=initiator.DEVICE_SCAN_ATTEMPTS_DEFAULT,
*args, **kwargs):
super(FibreChannelConnectorPPC64, self).__init__(
root_helper,
driver=driver,
execute=execute,
device_scan_attempts=device_scan_attempts,
*args, **kwargs)
self._linuxfc = linuxfc.LinuxFibreChannelPPC64(root_helper, execute)
self.use_multipath = use_multipath
def set_execute(self, execute):
super(FibreChannelConnectorPPC64, self).set_execute(execute)
self._linuxscsi.set_execute(execute)
self._linuxfc.set_execute(execute)
def _get_host_devices(self, possible_devs, lun):
host_devices = []
for pci_num, target_wwn in possible_devs:
host_device = "/dev/disk/by-path/fc-%s-lun-%s" % (
target_wwn,
self._linuxscsi.process_lun_id(lun))
host_devices.append(host_device)
return host_devices
def _get_possible_volume_paths(self, connection_properties, hbas):
ports = connection_properties['target_wwn']
it_map = connection_properties['initiator_target_map']
for hba in hbas:
if hba['node_name'] in it_map.keys():
hba['target_wwn'] = it_map.get(hba['node_name'])
possible_devs = self._get_possible_devices(hbas, ports)
lun = connection_properties.get('target_lun', 0)
host_paths = self._get_host_devices(possible_devs, lun)
return host_paths

View File

@ -265,3 +265,51 @@ class LinuxFibreChannelS390X(LinuxFibreChannel):
LOG.warning("unit_remove call for s390 failed exit %(code)s, "
"stderr %(stderr)s",
{'code': exc.exit_code, 'stderr': exc.stderr})
class LinuxFibreChannelPPC64(LinuxFibreChannel):
def _get_hba_channel_scsi_target(self, hba, wwpn):
"""Try to get the HBA channel and SCSI target for an HBA.
This method works for Fibre Channel targets iterating over all the
target wwpn port and finding the c, t, l. so caller should expect us to
return either None or an empty list.
"""
# Leave only the number from the host_device field (ie: host6)
host_device = hba['host_device']
if host_device and len(host_device) > 4:
host_device = host_device[4:]
path = '/sys/class/fc_transport/target%s:' % host_device
cmd = 'grep -l %(wwpn)s %(path)s*/port_name' % {'wwpn': wwpn,
'path': path}
try:
out, _err = self._execute(cmd, shell=True)
return [line.split('/')[4].split(':')[1:]
for line in out.split('\n') if line.startswith(path)]
except Exception as exc:
LOG.error("Could not get HBA channel and SCSI target ID, "
"reason: %s", exc)
return None
def rescan_hosts(self, hbas, target_lun):
for hba in hbas:
# Try to get HBA channel and SCSI target to use as filters
for wwpn in hba['target_wwn']:
cts = self._get_hba_channel_scsi_target(hba, wwpn)
# If we couldn't get the channel and target use wildcards
if not cts:
cts = [('-', '-')]
for hba_channel, target_id in cts:
LOG.debug('Scanning host %(host)s (wwpn: %(wwpn)s, c: '
'%(channel)s, t: %(target)s, l: %(lun)s)',
{'host': hba['host_device'],
'wwpn': hba['target_wwn'],
'channel': hba_channel,
'target': target_id,
'lun': target_lun})
self.echo_scsi_command(
"/sys/class/scsi_host/%s/scan" % hba['host_device'],
"%(c)s %(t)s %(l)s" % {'c': hba_channel,
't': target_id,
'l': target_lun})

View File

@ -0,0 +1,43 @@
# (c) Copyright 2013 IBM Company
#
# 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 os_brick.initiator.connectors import fibre_channel_ppc64
from os_brick.initiator import linuxscsi
from os_brick.tests.initiator import test_connector
class FibreChannelConnectorPPC64TestCase(test_connector.ConnectorTestCase):
def setUp(self):
super(FibreChannelConnectorPPC64TestCase, self).setUp()
self.connector = fibre_channel_ppc64.FibreChannelConnectorPPC64(
None, execute=self.fake_execute, use_multipath=False)
self.assertIsNotNone(self.connector)
self.assertIsNotNone(self.connector._linuxfc)
self.assertEqual(self.connector._linuxfc.__class__.__name__,
"LinuxFibreChannelPPC64")
self.assertIsNotNone(self.connector._linuxscsi)
@mock.patch.object(linuxscsi.LinuxSCSI, 'process_lun_id', return_value='2')
def test_get_host_devices(self, mock_process_lun_id):
lun = 2
possible_devs = [(3, "0x5005076802232ade"),
(3, "0x5005076802332ade"), ]
devices = self.connector._get_host_devices(possible_devs, lun)
self.assertEqual(2, len(devices))
device_path = "/dev/disk/by-path/fc-0x5005076802232ade-lun-2"
self.assertEqual(devices[0], device_path)
device_path = "/dev/disk/by-path/fc-0x5005076802332ade-lun-2"
self.assertEqual(devices[1], device_path)