Adds friendly zone name support
Added user friendly names for zones to include host and storage names along with ids to easily identify the host and storage port details. This is done by extracting the host and storage name from connection info object in the zone manager. The host and storage names are passed to the zone drivers to form a friendly name. The method signature has been changed which accepts host and storage name, with default as None. Also added test cases to test this support. Changes have been made to zone manager test code to accommodate the change in signature of some methods. Moved get_friendly_zone_name method to utils.py so that it can be used by both cisco and brocade drivers Changed cisco driver to accommodate host_name and storage_system parameters in add/delete connection. Implements: blueprint brocade-zone-driver-friendly-zone-names Change-Id: I350493b96901675a1b8910d6104f31c7d677ebda
This commit is contained in:
parent
31141a9ff4
commit
c346612cc7
113
cinder/tests/unit/zonemanager/test_driverutils.py
Normal file
113
cinder/tests/unit/zonemanager/test_driverutils.py
Normal file
@ -0,0 +1,113 @@
|
||||
# (c) Copyright 2015 Brocade Communications Systems Inc.
|
||||
# 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.
|
||||
#
|
||||
|
||||
|
||||
"""Unit tests for friendly zone name."""
|
||||
import ddt
|
||||
import string
|
||||
|
||||
from cinder import test
|
||||
from cinder.zonemanager.drivers import driver_utils
|
||||
|
||||
TEST_CHAR_SET = string.ascii_letters + string.digits
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestDriverUtils(test.TestCase):
|
||||
|
||||
@ddt.data('OSHost10010008c7cff523b01AMCEArray20240002ac000a50')
|
||||
def test_get_friendly_zone_name_valid_hostname_storagesystem(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator-target', "10:00:8c:7c:ff:52:3b:01",
|
||||
"20:24:00:02:ac:00:0a:50", "OS_Host100", 'AMCE'
|
||||
'_Array', "openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('openstack10008c7cff523b0120240002ac000a50')
|
||||
def test_get_friendly_zone_name_hostname_storagesystem_none(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator-target', "10:00:8c:7c:ff:52:3b:01",
|
||||
"20:24:00:02:ac:00:0a:50", None, None,
|
||||
"openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('openstack10008c7cff523b0120240002ac000a50')
|
||||
def test_get_friendly_zone_name_storagesystem_none(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator-target', "10:00:8c:7c:ff:52:3b:01",
|
||||
"20:24:00:02:ac:00:0a:50", "OS_Host100", None,
|
||||
"openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('openstack10008c7cff523b0120240002ac000a50')
|
||||
def test_get_friendly_zone_name_hostname_none(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator-target', "10:00:8c:7c:ff:52:3b:01",
|
||||
"20:24:00:02:ac:00:0a:50", None, "AMCE_Array",
|
||||
"openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('OSHost10010008c7cff523b01')
|
||||
def test_get_friendly_zone_name_initiator_mode(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator', "10:00:8c:7c:ff:52:3b:01", None,
|
||||
"OS_Host100", None, "openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('openstack10008c7cff523b01')
|
||||
def test_get_friendly_zone_name_initiator_mode_hostname_none(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator', "10:00:8c:7c:ff:52:3b:01", None,
|
||||
None, None, "openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('OSHost100XXXX10008c7cff523b01AMCEArrayYYYY20240002ac000a50')
|
||||
def test_get_friendly_zone_name_storagename_length_too_long(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator-target', "10:00:8c:7c:ff:52:3b:01",
|
||||
"20:24:00:02:ac:00:0a:50",
|
||||
"OS_Host100XXXXXXXXXX",
|
||||
"AMCE_ArrayYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
|
||||
"YYYY", "openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('OSHost100XXXX10008c7cff523b01AMCEArrayYYYY20240002ac000a50')
|
||||
def test_get_friendly_zone_name_max_length(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator-target', "10:00:8c:7c:ff:52:3b:01",
|
||||
"20:24:00:02:ac:00:0a:50",
|
||||
"OS_Host100XXXXXXXXXX",
|
||||
"AMCE_ArrayYYYYYYYYYY",
|
||||
"openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('OSHost100XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX10008c7cff523b01')
|
||||
def test_get_friendly_zone_name_initiator_mode_hostname_max_length(self,
|
||||
value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator', "10:00:8c:7c:ff:52:3b:01", None,
|
||||
'OS_Host100XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
|
||||
'XXXXX',
|
||||
None, "openstack", TEST_CHAR_SET))
|
||||
|
||||
@ddt.data('openstack110008c7cff523b0120240002ac000a50')
|
||||
def test_get_friendly_zone_name_invalid_characters(self, value):
|
||||
self.assertEqual(value,
|
||||
driver_utils.get_friendly_zone_name(
|
||||
'initiator-target', "10:00:8c:7c:ff:52:3b:01",
|
||||
"20:24:00:02:ac:00:0a:50", None, "AMCE_Array",
|
||||
"open-stack*1_", TEST_CHAR_SET))
|
@ -29,6 +29,17 @@ from cinder.zonemanager import fc_zone_manager
|
||||
|
||||
fabric_name = 'BRCD_FAB_3'
|
||||
init_target_map = {'10008c7cff523b01': ['20240002ac000a50']}
|
||||
conn_info = {
|
||||
'driver_volume_type': 'fibre_channel',
|
||||
'data': {
|
||||
'target_discovered': True,
|
||||
'target_lun': 1,
|
||||
'target_wwn': '20240002ac000a50',
|
||||
'initiator_target_map': {
|
||||
'10008c7cff523b01': ['20240002ac000a50']
|
||||
}
|
||||
}
|
||||
}
|
||||
fabric_map = {'BRCD_FAB_3': ['20240002ac000a50']}
|
||||
target_list = ['20240002ac000a50']
|
||||
|
||||
@ -60,10 +71,12 @@ class TestFCZoneManager(test.TestCase):
|
||||
with mock.patch.object(self.zm.driver, 'add_connection')\
|
||||
as add_connection_mock:
|
||||
self.zm.driver.get_san_context.return_value = fabric_map
|
||||
self.zm.add_connection(init_target_map)
|
||||
self.zm.add_connection(conn_info)
|
||||
self.zm.driver.get_san_context.assert_called_once_with(target_list)
|
||||
add_connection_mock.assert_called_once_with(fabric_name,
|
||||
init_target_map)
|
||||
init_target_map,
|
||||
None,
|
||||
None)
|
||||
|
||||
@mock.patch('oslo_config.cfg._is_opt_registered', return_value=False)
|
||||
def test_add_connection_error(self, opt_mock):
|
||||
@ -71,17 +84,19 @@ class TestFCZoneManager(test.TestCase):
|
||||
as add_connection_mock:
|
||||
add_connection_mock.side_effect = exception.FCZoneDriverException
|
||||
self.assertRaises(exception.ZoneManagerException,
|
||||
self.zm.add_connection, init_target_map)
|
||||
self.zm.add_connection, conn_info)
|
||||
|
||||
@mock.patch('oslo_config.cfg._is_opt_registered', return_value=False)
|
||||
def test_delete_connection(self, opt_mock):
|
||||
with mock.patch.object(self.zm.driver, 'delete_connection')\
|
||||
as delete_connection_mock:
|
||||
self.zm.driver.get_san_context.return_value = fabric_map
|
||||
self.zm.delete_connection(init_target_map)
|
||||
self.zm.delete_connection(conn_info)
|
||||
self.zm.driver.get_san_context.assert_called_once_with(target_list)
|
||||
delete_connection_mock.assert_called_once_with(fabric_name,
|
||||
init_target_map)
|
||||
init_target_map,
|
||||
None,
|
||||
None)
|
||||
|
||||
@mock.patch('oslo_config.cfg._is_opt_registered', return_value=False)
|
||||
def test_delete_connection_error(self, opt_mock):
|
||||
@ -89,4 +104,4 @@ class TestFCZoneManager(test.TestCase):
|
||||
as del_connection_mock:
|
||||
del_connection_mock.side_effect = exception.FCZoneDriverException
|
||||
self.assertRaises(exception.ZoneManagerException,
|
||||
self.zm.delete_connection, init_target_map)
|
||||
self.zm.delete_connection, conn_info)
|
||||
|
@ -53,8 +53,7 @@ class TestVolumeDriver(test.TestCase):
|
||||
as mock_safe_get:
|
||||
mock_safe_get.return_value = 'fabric'
|
||||
conn_info = self.driver.initialize_connection(None, None)
|
||||
init_target_map = conn_info['data']['initiator_target_map']
|
||||
add_zone_mock.assert_called_once_with(init_target_map)
|
||||
add_zone_mock.assert_called_once_with(conn_info)
|
||||
|
||||
@mock.patch.object(utils, 'require_driver_initialized')
|
||||
def test_initialize_connection_no_decorator(self, utils_mock):
|
||||
@ -77,8 +76,7 @@ class TestVolumeDriver(test.TestCase):
|
||||
as mock_safe_get:
|
||||
mock_safe_get.return_value = 'fabric'
|
||||
conn_info = self.driver.terminate_connection(None, None)
|
||||
init_target_map = conn_info['data']['initiator_target_map']
|
||||
remove_zone_mock.assert_called_once_with(init_target_map)
|
||||
remove_zone_mock.assert_called_once_with(conn_info)
|
||||
|
||||
@mock.patch.object(utils, 'require_driver_initialized')
|
||||
def test_terminate_connection_no_decorator(self, utils_mock):
|
||||
|
@ -41,6 +41,7 @@ brcd_zone_opts = [
|
||||
default=True,
|
||||
help='overridden zoning activation state'),
|
||||
cfg.StrOpt('zone_name_prefix',
|
||||
default='openstack',
|
||||
help='overridden zone name prefix'),
|
||||
cfg.StrOpt('principal_switch_wwn',
|
||||
help='Principal switch WWN of the fabric'),
|
||||
@ -55,7 +56,8 @@ def load_fabric_configurations(fabric_names):
|
||||
fabric_configs = {}
|
||||
for fabric_name in fabric_names:
|
||||
config = configuration.Configuration(brcd_zone_opts, fabric_name)
|
||||
LOG.debug("Loaded FC fabric config %s", fabric_name)
|
||||
LOG.debug("Loaded FC fabric config %(fabricname)s",
|
||||
{'fabricname': fabric_name})
|
||||
fabric_configs[fabric_name] = config
|
||||
|
||||
return fabric_configs
|
||||
|
@ -36,14 +36,17 @@ from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
import string
|
||||
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE, _LI
|
||||
from cinder.i18n import _, _LE, _LI, _LW
|
||||
from cinder.zonemanager.drivers.brocade import brcd_fabric_opts as fabric_opts
|
||||
from cinder.zonemanager.drivers import driver_utils
|
||||
from cinder.zonemanager.drivers import fc_zone_driver
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
SUPPORTED_CHARS = string.ascii_letters + string.digits + '_'
|
||||
brcd_opts = [
|
||||
cfg.StrOpt('brcd_sb_connector',
|
||||
default='cinder.zonemanager.drivers.brocade'
|
||||
@ -64,9 +67,10 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
Version history:
|
||||
1.0 - Initial Brocade FC zone driver
|
||||
1.1 - Implements performance enhancements
|
||||
1.2 - Added support for friendly zone name
|
||||
"""
|
||||
|
||||
VERSION = "1.1"
|
||||
VERSION = "1.2"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(BrcdFCZoneDriver, self).__init__(**kwargs)
|
||||
@ -74,8 +78,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
self.configuration = kwargs.get('configuration', None)
|
||||
if self.configuration:
|
||||
self.configuration.append_config_values(brcd_opts)
|
||||
# Adding a hack to hendle parameters from super classes
|
||||
# in case configured with multi backend.
|
||||
# Adding a hack to handle parameters from super classes
|
||||
# in case configured with multiple back ends.
|
||||
fabric_names = self.configuration.safe_get('fc_fabric_names')
|
||||
base_san_opts = []
|
||||
if not fabric_names:
|
||||
@ -109,7 +113,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
[wwn_str[i:i + 2] for i in range(0, len(wwn_str), 2)])
|
||||
|
||||
@lockutils.synchronized('brcd', 'fcfabric-', True)
|
||||
def add_connection(self, fabric, initiator_target_map):
|
||||
def add_connection(self, fabric, initiator_target_map, host_name=None,
|
||||
storage_system=None):
|
||||
"""Concrete implementation of add_connection.
|
||||
|
||||
Based on zoning policy and state of each I-T pair, list of zone
|
||||
@ -121,22 +126,27 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
:param fabric: Fabric name from cinder.conf file
|
||||
:param initiator_target_map: Mapping of initiator to list of targets
|
||||
"""
|
||||
LOG.debug("Add connection for Fabric: %s", fabric)
|
||||
LOG.info(_LI("BrcdFCZoneDriver - Add connection "
|
||||
"for I-T map: %s"), initiator_target_map)
|
||||
LOG.info(_LI("BrcdFCZoneDriver - Add connection for fabric "
|
||||
"%(fabric)s for I-T map: %(i_t_map)s"),
|
||||
{'fabric': fabric,
|
||||
'i_t_map': initiator_target_map})
|
||||
zoning_policy = self.configuration.zoning_policy
|
||||
zoning_policy_fab = self.fabric_configs[fabric].safe_get(
|
||||
'zoning_policy')
|
||||
if zoning_policy_fab:
|
||||
zoning_policy = zoning_policy_fab
|
||||
zone_name_prefix = self.fabric_configs[fabric].safe_get(
|
||||
'zone_name_prefix')
|
||||
if not zone_name_prefix:
|
||||
zone_name_prefix = 'openstack'
|
||||
zone_activate = self.fabric_configs[fabric].safe_get(
|
||||
'zone_activate')
|
||||
if zoning_policy_fab:
|
||||
zoning_policy = zoning_policy_fab
|
||||
LOG.info(_LI("Zoning policy for Fabric %(policy)s"),
|
||||
{'policy': zoning_policy})
|
||||
if (zoning_policy != 'initiator'
|
||||
and zoning_policy != 'initiator-target'):
|
||||
LOG.info(_LI("Zoning policy is not valid, "
|
||||
"no zoning will be performed."))
|
||||
return
|
||||
|
||||
LOG.info(_LI("Zoning policy for Fabric %s"), zoning_policy)
|
||||
cli_client = self._get_cli_client(fabric)
|
||||
cfgmap_from_fabric = self._get_active_zone_set(cli_client)
|
||||
|
||||
@ -154,24 +164,37 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
target = t.lower()
|
||||
zone_members = [self.get_formatted_wwn(initiator),
|
||||
self.get_formatted_wwn(target)]
|
||||
zone_name = (zone_name_prefix
|
||||
+ initiator.replace(':', '')
|
||||
+ target.replace(':', ''))
|
||||
zone_name = driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
zone_name_prefix,
|
||||
SUPPORTED_CHARS)
|
||||
if (
|
||||
len(cfgmap_from_fabric) == 0 or (
|
||||
zone_name not in zone_names)):
|
||||
zone_map[zone_name] = zone_members
|
||||
else:
|
||||
# This is I-T zoning, skip if zone already exists.
|
||||
LOG.info(_LI("Zone exists in I-T mode. "
|
||||
"Skipping zone creation %s"), zone_name)
|
||||
LOG.info(_LI("Zone exists in I-T mode. Skipping "
|
||||
"zone creation for %(zonename)s"),
|
||||
{'zonename': zone_name})
|
||||
elif zoning_policy == 'initiator':
|
||||
zone_members = [self.get_formatted_wwn(initiator)]
|
||||
for t in t_list:
|
||||
target = t.lower()
|
||||
zone_members.append(self.get_formatted_wwn(target))
|
||||
|
||||
zone_name = zone_name_prefix + initiator.replace(':', '')
|
||||
zone_name = driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
zone_name_prefix,
|
||||
SUPPORTED_CHARS)
|
||||
|
||||
if len(zone_names) > 0 and (zone_name in zone_names):
|
||||
zone_members = zone_members + filter(
|
||||
@ -179,13 +202,9 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
cfgmap_from_fabric['zones'][zone_name])
|
||||
|
||||
zone_map[zone_name] = zone_members
|
||||
else:
|
||||
msg = _("Zoning Policy: %s, not "
|
||||
"recognized") % zoning_policy
|
||||
LOG.error(msg)
|
||||
raise exception.FCZoneDriverException(msg)
|
||||
|
||||
LOG.info(_LI("Zone map to add: %s"), zone_map)
|
||||
LOG.info(_LI("Zone map to add: %(zonemap)s"),
|
||||
{'zonemap': zone_map})
|
||||
|
||||
if len(zone_map) > 0:
|
||||
try:
|
||||
@ -199,10 +218,12 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
msg = _("Failed to add zoning configuration.")
|
||||
LOG.exception(msg)
|
||||
raise exception.FCZoneDriverException(msg)
|
||||
LOG.debug("Zones added successfully: %s", zone_map)
|
||||
LOG.debug("Zones added successfully: %(zonemap)s",
|
||||
{'zonemap': zone_map})
|
||||
|
||||
@lockutils.synchronized('brcd', 'fcfabric-', True)
|
||||
def delete_connection(self, fabric, initiator_target_map):
|
||||
def delete_connection(self, fabric, initiator_target_map, host_name=None,
|
||||
storage_system=None):
|
||||
"""Concrete implementation of delete_connection.
|
||||
|
||||
Based on zoning policy and state of each I-T pair, list of zones
|
||||
@ -212,22 +233,21 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
:param fabric: Fabric name from cinder.conf file
|
||||
:param initiator_target_map: Mapping of initiator to list of targets
|
||||
"""
|
||||
LOG.debug("Delete connection for fabric: %s", fabric)
|
||||
LOG.info(_LI("BrcdFCZoneDriver - Delete connection for I-T map: %s"),
|
||||
initiator_target_map)
|
||||
LOG.info(_LI("BrcdFCZoneDriver - Delete connection for fabric "
|
||||
"%(fabric)s for I-T map: %(i_t_map)s"),
|
||||
{'fabric': fabric,
|
||||
'i_t_map': initiator_target_map})
|
||||
zoning_policy = self.configuration.zoning_policy
|
||||
zoning_policy_fab = self.fabric_configs[fabric].safe_get(
|
||||
'zoning_policy')
|
||||
if zoning_policy_fab:
|
||||
zoning_policy = zoning_policy_fab
|
||||
zone_name_prefix = self.fabric_configs[fabric].safe_get(
|
||||
'zone_name_prefix')
|
||||
if not zone_name_prefix:
|
||||
zone_name_prefix = 'openstack'
|
||||
zone_activate = self.fabric_configs[fabric].safe_get(
|
||||
'zone_activate')
|
||||
|
||||
LOG.info(_LI("Zoning policy for fabric %s"), zoning_policy)
|
||||
if zoning_policy_fab:
|
||||
zoning_policy = zoning_policy_fab
|
||||
LOG.info(_LI("Zoning policy for fabric %(policy)s"),
|
||||
{'policy': zoning_policy})
|
||||
conn = self._get_cli_client(fabric)
|
||||
cfgmap_from_fabric = self._get_active_zone_set(conn)
|
||||
|
||||
@ -238,7 +258,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
# Based on zoning policy, get zone member list and push changes to
|
||||
# fabric. This operation could result in an update for zone config
|
||||
# with new member list or deleting zones from active cfg.
|
||||
LOG.debug("zone config from Fabric: %s", cfgmap_from_fabric)
|
||||
LOG.debug("zone config from Fabric: %(cfgmap)s",
|
||||
{'cfgmap': cfgmap_from_fabric})
|
||||
for initiator_key in initiator_target_map.keys():
|
||||
initiator = initiator_key.lower()
|
||||
formatted_initiator = self.get_formatted_wwn(initiator)
|
||||
@ -249,15 +270,20 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
# In this case, zone needs to be deleted.
|
||||
for t in t_list:
|
||||
target = t.lower()
|
||||
zone_name = (
|
||||
zone_name_prefix
|
||||
+ initiator.replace(':', '')
|
||||
+ target.replace(':', ''))
|
||||
LOG.debug("Zone name to del: %s", zone_name)
|
||||
zone_name = driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
zone_name_prefix,
|
||||
SUPPORTED_CHARS)
|
||||
LOG.debug("Zone name to delete: %(zonename)s",
|
||||
{'zonename': zone_name})
|
||||
if len(zone_names) > 0 and (zone_name in zone_names):
|
||||
# delete zone.
|
||||
LOG.debug("Added zone to delete to "
|
||||
"list: %s", zone_name)
|
||||
LOG.debug("Added zone to delete to list: %(zonename)s",
|
||||
{'zonename': zone_name})
|
||||
zones_to_delete.append(zone_name)
|
||||
|
||||
elif zoning_policy == 'initiator':
|
||||
@ -266,7 +292,14 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
target = t.lower()
|
||||
zone_members.append(self.get_formatted_wwn(target))
|
||||
|
||||
zone_name = zone_name_prefix + initiator.replace(':', '')
|
||||
zone_name = driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
zone_name_prefix,
|
||||
SUPPORTED_CHARS)
|
||||
|
||||
if (zone_names and (zone_name in zone_names)):
|
||||
filtered_members = filter(
|
||||
@ -278,22 +311,25 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
# filtered list and if it is non-empty, add initiator
|
||||
# to it and update zone if filtered list is empty, we
|
||||
# remove that zone.
|
||||
LOG.debug("Zone delete - I mode: "
|
||||
"filtered targets: %s", filtered_members)
|
||||
LOG.debug("Zone delete - initiator mode: "
|
||||
"filtered targets: %(targets)s",
|
||||
{'targets': filtered_members})
|
||||
if filtered_members:
|
||||
filtered_members.append(formatted_initiator)
|
||||
LOG.debug("Filtered zone members to "
|
||||
"update: %s", filtered_members)
|
||||
LOG.debug("Filtered zone members to update: "
|
||||
"%(members)s", {'members': filtered_members})
|
||||
zone_map[zone_name] = filtered_members
|
||||
LOG.debug("Filtered zone Map to "
|
||||
"update: %s", zone_map)
|
||||
LOG.debug("Filtered zone map to update: %(zonemap)s",
|
||||
{'zonemap': zone_map})
|
||||
else:
|
||||
zones_to_delete.append(zone_name)
|
||||
else:
|
||||
LOG.info(_LI("Zoning Policy: %s, not "
|
||||
"recognized"), zoning_policy)
|
||||
LOG.debug("Final Zone map to update: %s", zone_map)
|
||||
LOG.debug("Final Zone list to delete: %s", zones_to_delete)
|
||||
LOG.warning(_LW("Zoning policy not recognized: %(policy)s"),
|
||||
{'policy': zoning_policy})
|
||||
LOG.debug("Final zone map to update: %(zonemap)s",
|
||||
{'zonemap': zone_map})
|
||||
LOG.debug("Final zone list to delete: %(zones)s",
|
||||
{'zones': zones_to_delete})
|
||||
try:
|
||||
# Update zone membership.
|
||||
if zone_map:
|
||||
@ -333,13 +369,14 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
fabric_map = {}
|
||||
fc_fabric_names = self.configuration.fc_fabric_names
|
||||
fabrics = [x.strip() for x in fc_fabric_names.split(',')]
|
||||
LOG.debug("Fabric List: %s", fabrics)
|
||||
LOG.debug("Target wwn List: %s", target_wwn_list)
|
||||
LOG.debug("Fabric List: %(fabrics)s", {'fabrics': fabrics})
|
||||
LOG.debug("Target WWN list: %(targetwwns)s",
|
||||
{'targetwwns': target_wwn_list})
|
||||
if len(fabrics) > 0:
|
||||
for t in target_wwn_list:
|
||||
formatted_target_list.append(self.get_formatted_wwn(t.lower()))
|
||||
LOG.debug("Formatted Target wwn List:"
|
||||
" %s", formatted_target_list)
|
||||
LOG.debug("Formatted target WWN list: %(targetlist)s",
|
||||
{'targetlist': formatted_target_list})
|
||||
for fabric_name in fabrics:
|
||||
conn = self._get_cli_client(fabric_name)
|
||||
|
||||
@ -348,7 +385,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
nsinfo = None
|
||||
try:
|
||||
nsinfo = conn.get_nameserver_info()
|
||||
LOG.debug("name server info from fabric: %s", nsinfo)
|
||||
LOG.debug("Name server info from fabric: %(nsinfo)s",
|
||||
{'nsinfo': nsinfo})
|
||||
conn.cleanup()
|
||||
except exception.BrocadeZoningCliException:
|
||||
if not conn.is_supported_firmware():
|
||||
@ -368,17 +406,19 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
nsinfo)
|
||||
|
||||
if visible_targets:
|
||||
LOG.info(_LI("Filtered targets for SAN is: %s"),
|
||||
{fabric_name: visible_targets})
|
||||
LOG.info(_LI("Filtered targets for SAN is: %(targets)s"),
|
||||
{'targets': visible_targets})
|
||||
# getting rid of the ':' before returning
|
||||
for idx, elem in enumerate(visible_targets):
|
||||
visible_targets[idx] = str(
|
||||
visible_targets[idx]).replace(':', '')
|
||||
fabric_map[fabric_name] = visible_targets
|
||||
else:
|
||||
LOG.debug("No targets are in the nameserver for SAN %s",
|
||||
fabric_name)
|
||||
LOG.debug("Return SAN context output: %s", fabric_map)
|
||||
LOG.debug("No targets found in the nameserver "
|
||||
"for fabric: %(fabric)s",
|
||||
{'fabric': fabric_name})
|
||||
LOG.debug("Return SAN context output: %(fabricmap)s",
|
||||
{'fabricmap': fabric_map})
|
||||
return fabric_map
|
||||
|
||||
def _get_active_zone_set(self, conn):
|
||||
@ -396,7 +436,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
msg = (_("Failed to retrieve active zoning configuration %s")
|
||||
% six.text_type(e))
|
||||
raise exception.FCZoneDriverException(msg)
|
||||
LOG.debug("Active zone set from fabric: %s", cfgmap)
|
||||
LOG.debug("Active zone set from fabric: %(cfgmap)s",
|
||||
{'cfgmap': cfgmap})
|
||||
return cfgmap
|
||||
|
||||
def _get_cli_client(self, fabric):
|
||||
@ -408,7 +449,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
try:
|
||||
cli_client = self.sb_conn_map.get(fabric_ip)
|
||||
if not cli_client:
|
||||
LOG.debug("CLI client not found, creating for %s", fabric_ip)
|
||||
LOG.debug("CLI client not found, creating for %(ip)s",
|
||||
{'ip': fabric_ip})
|
||||
cli_client = importutils.import_object(
|
||||
self.configuration.brcd_sb_connector,
|
||||
ipaddress=fabric_ip,
|
||||
|
@ -16,7 +16,6 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
Common constants used by Brocade FC Zone Driver.
|
||||
"""
|
||||
|
@ -33,15 +33,18 @@ from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
import string
|
||||
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LE, _LI
|
||||
from cinder.zonemanager.drivers.cisco import cisco_fabric_opts as fabric_opts
|
||||
from cinder.zonemanager.drivers import driver_utils
|
||||
from cinder.zonemanager.drivers import fc_zone_driver
|
||||
from cinder.zonemanager import utils as zm_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
SUPPORTED_CHARS = string.ascii_letters + string.digits + '$' + '-' + '^' + '_'
|
||||
cisco_opts = [
|
||||
cfg.StrOpt('cisco_sb_connector',
|
||||
default='cinder.zonemanager.drivers.cisco'
|
||||
@ -61,9 +64,10 @@ class CiscoFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
|
||||
Version history:
|
||||
1.0 - Initial Cisco FC zone driver
|
||||
1.1 - Added friendly zone name support
|
||||
"""
|
||||
|
||||
VERSION = "1.0.0"
|
||||
VERSION = "1.1.0"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(CiscoFCZoneDriver, self).__init__(**kwargs)
|
||||
@ -109,7 +113,8 @@ class CiscoFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
fabric_names)
|
||||
|
||||
@lockutils.synchronized('cisco', 'fcfabric-', True)
|
||||
def add_connection(self, fabric, initiator_target_map):
|
||||
def add_connection(self, fabric, initiator_target_map, host_name=None,
|
||||
storage_system=None):
|
||||
"""Concrete implementation of add_connection.
|
||||
|
||||
Based on zoning policy and state of each I-T pair, list of zone
|
||||
@ -165,10 +170,15 @@ class CiscoFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
zone_members = [
|
||||
zm_utils.get_formatted_wwn(initiator),
|
||||
zm_utils.get_formatted_wwn(target)]
|
||||
zone_name = (self.
|
||||
configuration.cisco_zone_name_prefix
|
||||
+ initiator.replace(':', '')
|
||||
+ target.replace(':', ''))
|
||||
zone_name = (
|
||||
driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
self.configuration.cisco_zone_name_prefix,
|
||||
SUPPORTED_CHARS))
|
||||
if (len(cfgmap_from_fabric) == 0 or (
|
||||
zone_name not in zone_names)):
|
||||
zone_map[zone_name] = zone_members
|
||||
@ -185,8 +195,15 @@ class CiscoFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
zone_members.append(
|
||||
zm_utils.get_formatted_wwn(target))
|
||||
|
||||
zone_name = self.configuration.cisco_zone_name_prefix \
|
||||
+ initiator.replace(':', '')
|
||||
zone_name = (
|
||||
driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
self.configuration.cisco_zone_name_prefix,
|
||||
SUPPORTED_CHARS))
|
||||
|
||||
if len(zone_names) > 0 and (zone_name in zone_names):
|
||||
zone_members = zone_members + filter(
|
||||
@ -228,7 +245,8 @@ class CiscoFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
LOG.debug("Zoning session exists VSAN: %s", zoning_vsan)
|
||||
|
||||
@lockutils.synchronized('cisco', 'fcfabric-', True)
|
||||
def delete_connection(self, fabric, initiator_target_map):
|
||||
def delete_connection(self, fabric, initiator_target_map, host_name=None,
|
||||
storage_system=None):
|
||||
"""Concrete implementation of delete_connection.
|
||||
|
||||
Based on zoning policy and state of each I-T pair, list of zones
|
||||
@ -288,9 +306,14 @@ class CiscoFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
for t in t_list:
|
||||
target = t.lower()
|
||||
zone_name = (
|
||||
self.configuration.cisco_zone_name_prefix
|
||||
+ initiator.replace(':', '')
|
||||
+ target.replace(':', ''))
|
||||
driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
self.configuration.cisco_zone_name_prefix,
|
||||
SUPPORTED_CHARS))
|
||||
LOG.debug("Zone name to del: %s", zone_name)
|
||||
if (len(zone_names) > 0 and (zone_name in zone_names)):
|
||||
# delete zone.
|
||||
@ -305,8 +328,14 @@ class CiscoFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
||||
zone_members.append(
|
||||
zm_utils.get_formatted_wwn(target))
|
||||
|
||||
zone_name = self.configuration.cisco_zone_name_prefix \
|
||||
+ initiator.replace(':', '')
|
||||
zone_name = driver_utils.get_friendly_zone_name(
|
||||
zoning_policy,
|
||||
initiator,
|
||||
target,
|
||||
host_name,
|
||||
storage_system,
|
||||
self.configuration.cisco_zone_name_prefix,
|
||||
SUPPORTED_CHARS)
|
||||
|
||||
if (zone_names and (zone_name in zone_names)):
|
||||
filtered_members = filter(
|
||||
|
79
cinder/zonemanager/drivers/driver_utils.py
Normal file
79
cinder/zonemanager/drivers/driver_utils.py
Normal file
@ -0,0 +1,79 @@
|
||||
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Copyright 2014 OpenStack Foundation
|
||||
#
|
||||
# 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 re
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from cinder.i18n import _LI
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def get_friendly_zone_name(zoning_policy, initiator, target,
|
||||
host_name, storage_system, zone_name_prefix,
|
||||
supported_chars):
|
||||
"""Utility function implementation of _get_friendly_zone_name.
|
||||
|
||||
Get friendly zone name is used to form the zone name
|
||||
based on the details provided by the caller
|
||||
|
||||
:param zoning_policy - determines the zoning policy is either
|
||||
initiator-target or initiator
|
||||
:param initiator - initiator WWN
|
||||
:param target - target WWN
|
||||
:param host_name - Host name returned from Volume Driver
|
||||
:param storage_system - Storage name returned from Volume Driver
|
||||
:param zone_name_prefix - user defined zone prefix configured
|
||||
in cinder.conf
|
||||
:param supported_chars - Supported character set of FC switch vendor.
|
||||
Example: 'abc123_-$'. These are defined in the FC zone drivers.
|
||||
"""
|
||||
if host_name is None:
|
||||
host_name = ''
|
||||
if storage_system is None:
|
||||
storage_system = ''
|
||||
if zoning_policy == 'initiator-target':
|
||||
host_name = host_name[:14]
|
||||
storage_system = storage_system[:14]
|
||||
if len(host_name) > 0 and len(storage_system) > 0:
|
||||
zone_name = (host_name + "_"
|
||||
+ initiator.replace(':', '') + "_"
|
||||
+ storage_system + "_"
|
||||
+ target.replace(':', ''))
|
||||
else:
|
||||
zone_name = (zone_name_prefix
|
||||
+ initiator.replace(':', '')
|
||||
+ target.replace(':', ''))
|
||||
LOG.info(_LI("Zone name created using prefix because either "
|
||||
"host name or storage system is none."))
|
||||
else:
|
||||
host_name = host_name[:47]
|
||||
if len(host_name) > 0:
|
||||
zone_name = (host_name + "_"
|
||||
+ initiator.replace(':', ''))
|
||||
else:
|
||||
zone_name = (zone_name_prefix
|
||||
+ initiator.replace(':', ''))
|
||||
LOG.info(_LI("Zone name created using prefix because host "
|
||||
"name is none."))
|
||||
|
||||
LOG.info(_LI("Friendly zone name after forming: %(zonename)s"),
|
||||
{'zonename': zone_name})
|
||||
zone_name = re.sub('[^%s]' % supported_chars, '', zone_name)
|
||||
return zone_name
|
@ -43,7 +43,8 @@ class FCZoneDriver(fc_common.FCCommon):
|
||||
super(FCZoneDriver, self).__init__(**kwargs)
|
||||
LOG.debug("Initializing FCZoneDriver")
|
||||
|
||||
def add_connection(self, fabric, initiator_target_map):
|
||||
def add_connection(self, fabric, initiator_target_map, host_name=None,
|
||||
storage_system=None):
|
||||
"""Add connection control.
|
||||
|
||||
Abstract method to add connection control.
|
||||
@ -60,7 +61,8 @@ class FCZoneDriver(fc_common.FCCommon):
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete_connection(self, fabric, initiator_target_map):
|
||||
def delete_connection(self, fabric, initiator_target_map, host_name=None,
|
||||
storage_system=None):
|
||||
"""Delete connection control.
|
||||
|
||||
Abstract method to remove connection control.
|
||||
|
@ -40,6 +40,8 @@ from cinder import exception
|
||||
from cinder.i18n import _, _LI
|
||||
from cinder.volume import configuration as config
|
||||
from cinder.zonemanager import fc_common
|
||||
import cinder.zonemanager.fczm_constants as zone_constant
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -59,7 +61,7 @@ zone_manager_opts = [
|
||||
cfg.StrOpt('fc_san_lookup_service',
|
||||
default='cinder.zonemanager.drivers.brocade'
|
||||
'.brcd_fc_san_lookup_service.BrcdFCSanLookupService',
|
||||
help='FC SAN Lookup Service'),
|
||||
help='FC SAN Lookup Service')
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -67,15 +69,17 @@ CONF.register_opts(zone_manager_opts, group='fc-zone-manager')
|
||||
|
||||
|
||||
class ZoneManager(fc_common.FCCommon):
|
||||
|
||||
"""Manages Connection control during attach/detach.
|
||||
|
||||
Version History:
|
||||
1.0 - Initial version
|
||||
1.0.1 - Added __new__ for singleton
|
||||
1.0.2 - Added friendly zone name
|
||||
|
||||
"""
|
||||
|
||||
VERSION = "1.0.1"
|
||||
VERSION = "1.0.2"
|
||||
driver = None
|
||||
fabric_names = []
|
||||
|
||||
@ -90,17 +94,18 @@ class ZoneManager(fc_common.FCCommon):
|
||||
|
||||
self.configuration = config.Configuration(zone_manager_opts,
|
||||
'fc-zone-manager')
|
||||
|
||||
self._build_driver()
|
||||
|
||||
def _build_driver(self):
|
||||
zone_driver = self.configuration.zone_driver
|
||||
LOG.debug("Zone Driver from config: {%s}", zone_driver)
|
||||
LOG.debug("Zone driver from config: %(driver)s",
|
||||
{'driver': zone_driver})
|
||||
|
||||
zm_config = config.Configuration(zone_manager_opts, 'fc-zone-manager')
|
||||
# Initialize vendor specific implementation of FCZoneDriver
|
||||
self.driver = importutils.import_object(
|
||||
zone_driver,
|
||||
configuration=self.configuration)
|
||||
configuration=zm_config)
|
||||
|
||||
def get_zoning_state_ref_count(self, initiator_wwn, target_wwn):
|
||||
"""Zone management state check.
|
||||
@ -113,7 +118,7 @@ class ZoneManager(fc_common.FCCommon):
|
||||
# check the state for I-T pair
|
||||
return count
|
||||
|
||||
def add_connection(self, initiator_target_map):
|
||||
def add_connection(self, conn_info):
|
||||
"""Add connection control.
|
||||
|
||||
Adds connection control for the given initiator target map.
|
||||
@ -125,14 +130,33 @@ class ZoneManager(fc_common.FCCommon):
|
||||
}
|
||||
"""
|
||||
connected_fabric = None
|
||||
host_name = None
|
||||
storage_system = None
|
||||
|
||||
try:
|
||||
initiator_target_map = (
|
||||
conn_info[zone_constant.DATA][zone_constant.IT_MAP])
|
||||
|
||||
if zone_constant.HOST in conn_info[zone_constant.DATA]:
|
||||
host_name = conn_info[
|
||||
zone_constant.DATA][
|
||||
zone_constant.HOST].replace(" ", "_")
|
||||
|
||||
if zone_constant.STORAGE in conn_info[zone_constant.DATA]:
|
||||
storage_system = (
|
||||
conn_info[
|
||||
zone_constant.DATA][
|
||||
zone_constant.STORAGE].replace(" ", "_"))
|
||||
|
||||
for initiator in initiator_target_map.keys():
|
||||
target_list = initiator_target_map[initiator]
|
||||
LOG.debug("Target List: %s", target_list)
|
||||
LOG.debug("Target list : %(targets)s",
|
||||
{'targets': target_list})
|
||||
|
||||
# get SAN context for the target list
|
||||
fabric_map = self.get_san_context(target_list)
|
||||
LOG.debug("Fabric Map after context lookup: %s", fabric_map)
|
||||
LOG.debug("Fabric map after context lookup: %(fabricmap)s",
|
||||
{'fabricmap': fabric_map})
|
||||
# iterate over each SAN and apply connection control
|
||||
for fabric in fabric_map.keys():
|
||||
connected_fabric = fabric
|
||||
@ -141,13 +165,14 @@ class ZoneManager(fc_common.FCCommon):
|
||||
i_t_map = {initiator: t_list}
|
||||
valid_i_t_map = self.get_valid_initiator_target_map(
|
||||
i_t_map, True)
|
||||
LOG.info(_LI("Final filtered map for fabric: %s"),
|
||||
valid_i_t_map)
|
||||
LOG.info(_LI("Final filtered map for fabric: %(i_t_map)s"),
|
||||
{'i_t_map': valid_i_t_map})
|
||||
|
||||
# Call driver to add connection control
|
||||
self.driver.add_connection(fabric, valid_i_t_map)
|
||||
self.driver.add_connection(fabric, valid_i_t_map,
|
||||
host_name, storage_system)
|
||||
|
||||
LOG.info(_LI("Add Connection: Finished iterating "
|
||||
LOG.info(_LI("Add connection: finished iterating "
|
||||
"over all target list"))
|
||||
except Exception as e:
|
||||
msg = _("Failed adding connection for fabric=%(fabric)s: "
|
||||
@ -156,7 +181,7 @@ class ZoneManager(fc_common.FCCommon):
|
||||
LOG.error(msg)
|
||||
raise exception.ZoneManagerException(reason=msg)
|
||||
|
||||
def delete_connection(self, initiator_target_map):
|
||||
def delete_connection(self, conn_info):
|
||||
"""Delete connection.
|
||||
|
||||
Updates/deletes connection control for the given initiator target map.
|
||||
@ -168,16 +193,31 @@ class ZoneManager(fc_common.FCCommon):
|
||||
}
|
||||
"""
|
||||
connected_fabric = None
|
||||
host_name = None
|
||||
storage_system = None
|
||||
|
||||
try:
|
||||
initiator_target_map = (
|
||||
conn_info[zone_constant.DATA][zone_constant.IT_MAP])
|
||||
|
||||
if zone_constant.HOST in conn_info[zone_constant.DATA]:
|
||||
host_name = conn_info[zone_constant.DATA][zone_constant.HOST]
|
||||
|
||||
if zone_constant.STORAGE in conn_info[zone_constant.DATA]:
|
||||
storage_system = (
|
||||
conn_info[
|
||||
zone_constant.DATA][
|
||||
zone_constant.STORAGE].replace(" ", "_"))
|
||||
|
||||
for initiator in initiator_target_map.keys():
|
||||
target_list = initiator_target_map[initiator]
|
||||
LOG.info(_LI("Delete connection Target List: %s"),
|
||||
target_list)
|
||||
LOG.info(_LI("Delete connection target list: %(targets)s"),
|
||||
{'targets': target_list})
|
||||
|
||||
# get SAN context for the target list
|
||||
fabric_map = self.get_san_context(target_list)
|
||||
LOG.debug("Delete connection Fabric Map from SAN "
|
||||
"context: %s", fabric_map)
|
||||
LOG.debug("Delete connection fabric map from SAN "
|
||||
"context: %(fabricmap)s", {'fabricmap': fabric_map})
|
||||
|
||||
# iterate over each SAN and apply connection control
|
||||
for fabric in fabric_map.keys():
|
||||
@ -187,14 +227,17 @@ class ZoneManager(fc_common.FCCommon):
|
||||
i_t_map = {initiator: t_list}
|
||||
valid_i_t_map = self.get_valid_initiator_target_map(
|
||||
i_t_map, False)
|
||||
LOG.info(_LI("Final filtered map for delete "
|
||||
"connection: %s"), valid_i_t_map)
|
||||
LOG.info(_LI("Final filtered map for delete connection: "
|
||||
"%(i_t_map)s"), {'i_t_map': valid_i_t_map})
|
||||
|
||||
# Call driver to delete connection control
|
||||
if len(valid_i_t_map) > 0:
|
||||
self.driver.delete_connection(fabric, valid_i_t_map)
|
||||
self.driver.delete_connection(fabric,
|
||||
valid_i_t_map,
|
||||
host_name,
|
||||
storage_system)
|
||||
|
||||
LOG.debug("Delete Connection - Finished iterating over all"
|
||||
LOG.debug("Delete connection - finished iterating over all"
|
||||
" target list")
|
||||
except Exception as e:
|
||||
msg = _("Failed removing connection for fabric=%(fabric)s: "
|
||||
@ -210,7 +253,7 @@ class ZoneManager(fc_common.FCCommon):
|
||||
to list of target WWNs visible to the fabric.
|
||||
"""
|
||||
fabric_map = self.driver.get_san_context(target_wwn_list)
|
||||
LOG.debug("Got SAN context: %s", fabric_map)
|
||||
LOG.debug("Got SAN context: %(fabricmap)s", {'fabricmap': fabric_map})
|
||||
return fabric_map
|
||||
|
||||
def get_valid_initiator_target_map(self, initiator_target_map,
|
||||
@ -239,5 +282,6 @@ class ZoneManager(fc_common.FCCommon):
|
||||
filtered_i_t_map[initiator] = t_list
|
||||
else:
|
||||
LOG.info(_LI("No targets to add or remove connection for "
|
||||
"I: %s"), initiator)
|
||||
"initiator: %(init_wwn)s"),
|
||||
{'init_wwn': initiator})
|
||||
return filtered_i_t_map
|
||||
|
22
cinder/zonemanager/fczm_constants.py
Normal file
22
cinder/zonemanager/fczm_constants.py
Normal file
@ -0,0 +1,22 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""
|
||||
Common constants used by FC Zone Manager.
|
||||
"""
|
||||
IT_MAP = 'initiator_target_map'
|
||||
DATA = 'data'
|
||||
HOST = 'host_name'
|
||||
STORAGE = 'storage_system'
|
||||
SYSTEM = 'system'
|
@ -34,7 +34,7 @@ LOG.logger.setLevel(logging.DEBUG)
|
||||
def create_zone_manager():
|
||||
"""If zoning is enabled, build the Zone Manager."""
|
||||
config = configuration.Configuration(manager.volume_manager_opts)
|
||||
LOG.debug("Zoning mode: %s", config.safe_get('zoning_mode'))
|
||||
LOG.debug("Zoning mode: %s.", config.safe_get('zoning_mode'))
|
||||
if config.safe_get('zoning_mode') == 'fabric':
|
||||
LOG.debug("FC Zone Manager enabled.")
|
||||
zm = fc_zone_manager.ZoneManager()
|
||||
@ -51,11 +51,11 @@ def create_zone_manager():
|
||||
|
||||
def create_lookup_service():
|
||||
config = configuration.Configuration(manager.volume_manager_opts)
|
||||
LOG.debug("Zoning mode: %s", config.safe_get('zoning_mode'))
|
||||
LOG.debug("Zoning mode: %s.", config.safe_get('zoning_mode'))
|
||||
if config.safe_get('zoning_mode') == 'fabric':
|
||||
LOG.debug("FC Lookup Service enabled.")
|
||||
lookup = fc_san_lookup_service.FCSanLookupService()
|
||||
LOG.info(_LI("Using FC lookup service %s"), lookup.lookup_service)
|
||||
LOG.info(_LI("Using FC lookup service %s."), lookup.lookup_service)
|
||||
return lookup
|
||||
else:
|
||||
LOG.debug("FC Lookup Service not enabled in cinder.conf.")
|
||||
@ -73,6 +73,7 @@ def get_formatted_wwn(wwn_str):
|
||||
|
||||
def AddFCZone(initialize_connection):
|
||||
"""Decorator to add a FC Zone."""
|
||||
|
||||
def decorator(self, *args, **kwargs):
|
||||
conn_info = initialize_connection(self, *args, **kwargs)
|
||||
if not conn_info:
|
||||
@ -82,14 +83,12 @@ def AddFCZone(initialize_connection):
|
||||
|
||||
vol_type = conn_info.get('driver_volume_type', None)
|
||||
if vol_type == 'fibre_channel':
|
||||
|
||||
if 'initiator_target_map' in conn_info['data']:
|
||||
init_target_map = conn_info['data']['initiator_target_map']
|
||||
zm = create_zone_manager()
|
||||
if zm:
|
||||
LOG.debug("Add FC Zone for mapping '%s'.",
|
||||
init_target_map)
|
||||
zm.add_connection(init_target_map)
|
||||
LOG.debug("AddFCZone connection info: %(conninfo)s.",
|
||||
{'conninfo': conn_info})
|
||||
zm.add_connection(conn_info)
|
||||
|
||||
return conn_info
|
||||
|
||||
@ -98,6 +97,7 @@ def AddFCZone(initialize_connection):
|
||||
|
||||
def RemoveFCZone(terminate_connection):
|
||||
"""Decorator for FC drivers to remove zone."""
|
||||
|
||||
def decorator(self, *args, **kwargs):
|
||||
conn_info = terminate_connection(self, *args, **kwargs)
|
||||
if not conn_info:
|
||||
@ -107,14 +107,12 @@ def RemoveFCZone(terminate_connection):
|
||||
|
||||
vol_type = conn_info.get('driver_volume_type', None)
|
||||
if vol_type == 'fibre_channel':
|
||||
|
||||
if 'initiator_target_map' in conn_info['data']:
|
||||
init_target_map = conn_info['data']['initiator_target_map']
|
||||
zm = create_zone_manager()
|
||||
if zm:
|
||||
LOG.debug("Remove FC Zone for mapping '%s'.",
|
||||
init_target_map)
|
||||
zm.delete_connection(init_target_map)
|
||||
LOG.debug("RemoveFCZone connection info: %(conninfo)s.",
|
||||
{'conninfo': conn_info})
|
||||
zm.delete_connection(conn_info)
|
||||
|
||||
return conn_info
|
||||
|
||||
|
10
releasenotes/notes/friendly-zone-names-d5e131d356040de0.yaml
Normal file
10
releasenotes/notes/friendly-zone-names-d5e131d356040de0.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
features:
|
||||
- Cinder FC Zone Manager Friendly Zone Names
|
||||
This feature adds support for Fibre Channel user
|
||||
friendly zone names if implemented by the volume driver.
|
||||
If the volume driver passes the host name and
|
||||
storage system to the Fibre Channel Zone Manager
|
||||
in the conn_info structure, the zone manager
|
||||
will use these names in structuring the zone
|
||||
name to provide a user friendly zone name.
|
Loading…
Reference in New Issue
Block a user