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:
parent
a3eebbb77f
commit
67e1a39a7e
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
65
os_brick/initiator/connectors/fibre_channel_ppc64.py
Normal file
65
os_brick/initiator/connectors/fibre_channel_ppc64.py
Normal 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
|
@ -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})
|
||||
|
@ -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)
|
Loading…
x
Reference in New Issue
Block a user