Adds HTTPS southbound connector for Brocade FC Zone Driver
Set ssl verify to False for HTTPS. Marked 'principal_switch_wwn' parameter from the config options as deprecated. DocImpact Implements: blueprint brocade-zone-driver-virtualfabrics-support Change-Id: I0b40b520580eaa6821c0af29abc6d2497d884ad2
This commit is contained in:
parent
c9457d1452
commit
935aa1a5b4
@ -842,11 +842,15 @@ class FCSanLookupServiceException(CinderException):
|
|||||||
|
|
||||||
|
|
||||||
class BrocadeZoningCliException(CinderException):
|
class BrocadeZoningCliException(CinderException):
|
||||||
message = _("Fibre Channel Zoning CLI error: %(reason)s")
|
message = _("Brocade Fibre Channel Zoning CLI error: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
|
class BrocadeZoningHttpException(CinderException):
|
||||||
|
message = _("Brocade Fibre Channel Zoning HTTP error: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
class CiscoZoningCliException(CinderException):
|
class CiscoZoningCliException(CinderException):
|
||||||
message = _("Fibre Channel Zoning CLI error: %(reason)s")
|
message = _("Cisco Fibre Channel Zoning CLI error: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
class NetAppDriverException(VolumeDriverException):
|
class NetAppDriverException(VolumeDriverException):
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2014 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -143,10 +141,3 @@ class TestBrcdFCSanLookupService(brcd_lookup.BrcdFCSanLookupService,
|
|||||||
self.assertEqual(parsed_switch_port_wwns, return_wwn_list)
|
self.assertEqual(parsed_switch_port_wwns, return_wwn_list)
|
||||||
self.assertRaises(exception.InvalidParameterValue,
|
self.assertRaises(exception.InvalidParameterValue,
|
||||||
self._parse_ns_output, invalid_switch_data)
|
self._parse_ns_output, invalid_switch_data)
|
||||||
|
|
||||||
def test_get_formatted_wwn(self):
|
|
||||||
wwn_list = ['10008c7cff523b01']
|
|
||||||
return_wwn_list = []
|
|
||||||
expected_wwn_list = ['10:00:8c:7c:ff:52:3b:01']
|
|
||||||
return_wwn_list.append(self.get_formatted_wwn(wwn_list[0]))
|
|
||||||
self.assertEqual(expected_wwn_list, return_wwn_list)
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2014 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -24,9 +22,9 @@ from oslo_concurrency import processutils
|
|||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder import test
|
from cinder import test
|
||||||
from cinder.zonemanager.drivers.brocade \
|
from cinder.zonemanager.drivers.brocade import (brcd_fc_zone_client_cli
|
||||||
import brcd_fc_zone_client_cli as client_cli
|
as client_cli)
|
||||||
import cinder.zonemanager.drivers.brocade.fc_zone_constants as ZoneConstant
|
import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant
|
||||||
|
|
||||||
|
|
||||||
nsshow = '20:1a:00:05:1e:e8:e3:29'
|
nsshow = '20:1a:00:05:1e:e8:e3:29'
|
||||||
@ -78,7 +76,7 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_get_switch_info')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_get_switch_info')
|
||||||
def test_get_active_zone_set(self, get_switch_info_mock):
|
def test_get_active_zone_set(self, get_switch_info_mock):
|
||||||
cmd_list = [ZoneConstant.GET_ACTIVE_ZONE_CFG]
|
cmd_list = [zone_constant.GET_ACTIVE_ZONE_CFG]
|
||||||
get_switch_info_mock.return_value = cfgactvshow
|
get_switch_info_mock.return_value = cfgactvshow
|
||||||
active_zoneset_returned = self.get_active_zone_set()
|
active_zoneset_returned = self.get_active_zone_set()
|
||||||
get_switch_info_mock.assert_called_once_with(cmd_list)
|
get_switch_info_mock.assert_called_once_with(cmd_list)
|
||||||
@ -178,7 +176,6 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_get_switch_info')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_get_switch_info')
|
||||||
def test_get_nameserver_info(self, get_switch_info_mock):
|
def test_get_nameserver_info(self, get_switch_info_mock):
|
||||||
ns_info_list = []
|
|
||||||
ns_info_list_expected = ['20:1a:00:05:1e:e8:e3:29']
|
ns_info_list_expected = ['20:1a:00:05:1e:e8:e3:29']
|
||||||
get_switch_info_mock.return_value = (switch_data)
|
get_switch_info_mock.return_value = (switch_data)
|
||||||
ns_info_list = self.get_nameserver_info()
|
ns_info_list = self.get_nameserver_info()
|
||||||
@ -192,7 +189,7 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_ssh_execute')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_ssh_execute')
|
||||||
def test__cfg_save(self, ssh_execute_mock):
|
def test__cfg_save(self, ssh_execute_mock):
|
||||||
cmd_list = [ZoneConstant.CFG_SAVE]
|
cmd_list = [zone_constant.CFG_SAVE]
|
||||||
self._cfg_save()
|
self._cfg_save()
|
||||||
ssh_execute_mock.assert_called_once_with(cmd_list, True, 1)
|
ssh_execute_mock.assert_called_once_with(cmd_list, True, 1)
|
||||||
|
|
||||||
@ -205,7 +202,7 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, 'apply_zone_change')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, 'apply_zone_change')
|
||||||
def test__cfg_trans_abort(self, apply_zone_change_mock):
|
def test__cfg_trans_abort(self, apply_zone_change_mock):
|
||||||
cmd_list = [ZoneConstant.CFG_ZONE_TRANS_ABORT]
|
cmd_list = [zone_constant.CFG_ZONE_TRANS_ABORT]
|
||||||
with mock.patch.object(self, '_is_trans_abortable') \
|
with mock.patch.object(self, '_is_trans_abortable') \
|
||||||
as is_trans_abortable_mock:
|
as is_trans_abortable_mock:
|
||||||
is_trans_abortable_mock.return_value = True
|
is_trans_abortable_mock.return_value = True
|
||||||
@ -215,8 +212,8 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
||||||
def test__is_trans_abortable_true(self, run_ssh_mock):
|
def test__is_trans_abortable_true(self, run_ssh_mock):
|
||||||
cmd_list = [ZoneConstant.CFG_SHOW_TRANS]
|
cmd_list = [zone_constant.CFG_SHOW_TRANS]
|
||||||
run_ssh_mock.return_value = (Stream(ZoneConstant.TRANS_ABORTABLE),
|
run_ssh_mock.return_value = (Stream(zone_constant.TRANS_ABORTABLE),
|
||||||
None)
|
None)
|
||||||
data = self._is_trans_abortable()
|
data = self._is_trans_abortable()
|
||||||
self.assertTrue(data)
|
self.assertTrue(data)
|
||||||
@ -230,7 +227,7 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
||||||
def test__is_trans_abortable_false(self, run_ssh_mock):
|
def test__is_trans_abortable_false(self, run_ssh_mock):
|
||||||
cmd_list = [ZoneConstant.CFG_SHOW_TRANS]
|
cmd_list = [zone_constant.CFG_SHOW_TRANS]
|
||||||
cfgtransshow = 'There is no outstanding zoning transaction'
|
cfgtransshow = 'There is no outstanding zoning transaction'
|
||||||
run_ssh_mock.return_value = (Stream(cfgtransshow), None)
|
run_ssh_mock.return_value = (Stream(cfgtransshow), None)
|
||||||
data = self._is_trans_abortable()
|
data = self._is_trans_abortable()
|
||||||
@ -239,14 +236,14 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
||||||
def test_apply_zone_change(self, run_ssh_mock):
|
def test_apply_zone_change(self, run_ssh_mock):
|
||||||
cmd_list = [ZoneConstant.CFG_SAVE]
|
cmd_list = [zone_constant.CFG_SAVE]
|
||||||
run_ssh_mock.return_value = (None, None)
|
run_ssh_mock.return_value = (None, None)
|
||||||
self.apply_zone_change(cmd_list)
|
self.apply_zone_change(cmd_list)
|
||||||
run_ssh_mock.assert_called_once_with(cmd_list, True, 1)
|
run_ssh_mock.assert_called_once_with(cmd_list, True, 1)
|
||||||
|
|
||||||
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
@mock.patch.object(client_cli.BrcdFCZoneClientCLI, '_run_ssh')
|
||||||
def test__get_switch_info(self, run_ssh_mock):
|
def test__get_switch_info(self, run_ssh_mock):
|
||||||
cmd_list = [ZoneConstant.NS_SHOW]
|
cmd_list = [zone_constant.NS_SHOW]
|
||||||
nsshow_list = [nsshow]
|
nsshow_list = [nsshow]
|
||||||
run_ssh_mock.return_value = (Stream(nsshow), Stream())
|
run_ssh_mock.return_value = (Stream(nsshow), Stream())
|
||||||
switch_data = self._get_switch_info(cmd_list)
|
switch_data = self._get_switch_info(cmd_list)
|
||||||
@ -255,7 +252,6 @@ class TestBrcdFCZoneClientCLI(client_cli.BrcdFCZoneClientCLI, test.TestCase):
|
|||||||
|
|
||||||
def test__parse_ns_output(self):
|
def test__parse_ns_output(self):
|
||||||
invalid_switch_data = [' N 011a00;20:1a:00:05:1e:e8:e3:29']
|
invalid_switch_data = [' N 011a00;20:1a:00:05:1e:e8:e3:29']
|
||||||
return_wwn_list = []
|
|
||||||
expected_wwn_list = ['20:1a:00:05:1e:e8:e3:29']
|
expected_wwn_list = ['20:1a:00:05:1e:e8:e3:29']
|
||||||
return_wwn_list = self._parse_ns_output(switch_data)
|
return_wwn_list = self._parse_ns_output(switch_data)
|
||||||
self.assertEqual(expected_wwn_list, return_wwn_list)
|
self.assertEqual(expected_wwn_list, return_wwn_list)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2014 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -23,6 +21,7 @@ import mock
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import importutils
|
from oslo_utils import importutils
|
||||||
import paramiko
|
import paramiko
|
||||||
|
import requests
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder import test
|
from cinder import test
|
||||||
@ -76,15 +75,16 @@ class BrcdFcZoneDriverBaseTest(object):
|
|||||||
|
|
||||||
configuration.fc_fabric_names = 'BRCD_FAB_1'
|
configuration.fc_fabric_names = 'BRCD_FAB_1'
|
||||||
configuration.fc_fabric_address_BRCD_FAB_1 = '10.24.48.213'
|
configuration.fc_fabric_address_BRCD_FAB_1 = '10.24.48.213'
|
||||||
if (is_normal):
|
configuration.fc_southbound_connector = 'CLI'
|
||||||
|
if is_normal:
|
||||||
configuration.fc_fabric_user_BRCD_FAB_1 = 'admin'
|
configuration.fc_fabric_user_BRCD_FAB_1 = 'admin'
|
||||||
else:
|
else:
|
||||||
configuration.fc_fabric_user_BRCD_FAB_1 = 'invaliduser'
|
configuration.fc_fabric_user_BRCD_FAB_1 = 'invaliduser'
|
||||||
configuration.fc_fabric_password_BRCD_FAB_1 = 'password'
|
configuration.fc_fabric_password_BRCD_FAB_1 = 'password'
|
||||||
|
|
||||||
if (mode == 1):
|
if mode == 1:
|
||||||
configuration.zoning_policy_BRCD_FAB_1 = 'initiator-target'
|
configuration.zoning_policy_BRCD_FAB_1 = 'initiator-target'
|
||||||
elif (mode == 2):
|
elif mode == 2:
|
||||||
configuration.zoning_policy_BRCD_FAB_1 = 'initiator'
|
configuration.zoning_policy_BRCD_FAB_1 = 'initiator'
|
||||||
else:
|
else:
|
||||||
configuration.zoning_policy_BRCD_FAB_1 = 'initiator-target'
|
configuration.zoning_policy_BRCD_FAB_1 = 'initiator-target'
|
||||||
@ -110,40 +110,60 @@ class TestBrcdFcZoneDriver(BrcdFcZoneDriverBaseTest, test.TestCase):
|
|||||||
def fake__get_active_zone_set(self, brcd_sb_connector, fabric_ip):
|
def fake__get_active_zone_set(self, brcd_sb_connector, fabric_ip):
|
||||||
return GlobalVars._active_cfg
|
return GlobalVars._active_cfg
|
||||||
|
|
||||||
|
def get_client(self, protocol='HTTPS'):
|
||||||
|
conn = ('cinder.tests.unit.zonemanager.test_brcd_fc_zone_driver.' +
|
||||||
|
('FakeBrcdFCZoneClientCLI' if protocol == "CLI"
|
||||||
|
else 'FakeBrcdHttpFCZoneClient'))
|
||||||
|
client = importutils.import_object(
|
||||||
|
conn,
|
||||||
|
ipaddress="10.24.48.213",
|
||||||
|
username="admin",
|
||||||
|
password="password",
|
||||||
|
key="/home/stack/.ssh/id_rsa",
|
||||||
|
port=22,
|
||||||
|
protocol=protocol
|
||||||
|
)
|
||||||
|
return client
|
||||||
|
|
||||||
def fake_get_san_context(self, target_wwn_list):
|
def fake_get_san_context(self, target_wwn_list):
|
||||||
fabric_map = {}
|
fabric_map = {}
|
||||||
return fabric_map
|
return fabric_map
|
||||||
|
|
||||||
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_active_zone_set')
|
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
|
||||||
def test_add_connection(self, get_active_zs_mock):
|
def test_add_connection(self, get_southbound_client_mock):
|
||||||
"""Normal flow for i-t mode."""
|
"""Normal flow for i-t mode."""
|
||||||
GlobalVars._is_normal_test = True
|
GlobalVars._is_normal_test = True
|
||||||
GlobalVars._zone_state = []
|
GlobalVars._zone_state = []
|
||||||
get_active_zs_mock.return_value = _active_cfg_before_add
|
GlobalVars._active_cfg = _active_cfg_before_add
|
||||||
|
get_southbound_client_mock.return_value = self.get_client("HTTPS")
|
||||||
self.driver.add_connection('BRCD_FAB_1', _initiator_target_map)
|
self.driver.add_connection('BRCD_FAB_1', _initiator_target_map)
|
||||||
self.assertTrue(_zone_name in GlobalVars._zone_state)
|
self.assertTrue(_zone_name in GlobalVars._zone_state)
|
||||||
|
|
||||||
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_active_zone_set')
|
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
|
||||||
def test_delete_connection(self, get_active_zs_mock):
|
def test_delete_connection(self, get_southbound_client_mock):
|
||||||
GlobalVars._is_normal_test = True
|
GlobalVars._is_normal_test = True
|
||||||
get_active_zs_mock.return_value = _active_cfg_before_delete
|
get_southbound_client_mock.return_value = self.get_client("CLI")
|
||||||
|
GlobalVars._active_cfg = _active_cfg_before_delete
|
||||||
self.driver.delete_connection(
|
self.driver.delete_connection(
|
||||||
'BRCD_FAB_1', _initiator_target_map)
|
'BRCD_FAB_1', _initiator_target_map)
|
||||||
self.assertFalse(_zone_name in GlobalVars._zone_state)
|
self.assertFalse(_zone_name in GlobalVars._zone_state)
|
||||||
|
|
||||||
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_active_zone_set')
|
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
|
||||||
def test_add_connection_for_initiator_mode(self, get_active_zs_mock):
|
def test_add_connection_for_initiator_mode(self, get_southbound_client_mk):
|
||||||
"""Normal flow for i mode."""
|
"""Normal flow for i mode."""
|
||||||
GlobalVars._is_normal_test = True
|
GlobalVars._is_normal_test = True
|
||||||
get_active_zs_mock.return_value = _active_cfg_before_add
|
get_southbound_client_mk.return_value = self.get_client("CLI")
|
||||||
|
GlobalVars._active_cfg = _active_cfg_before_add
|
||||||
self.setup_driver(self.setup_config(True, 2))
|
self.setup_driver(self.setup_config(True, 2))
|
||||||
self.driver.add_connection('BRCD_FAB_1', _initiator_target_map)
|
self.driver.add_connection('BRCD_FAB_1', _initiator_target_map)
|
||||||
self.assertTrue(_zone_name in GlobalVars._zone_state)
|
self.assertTrue(_zone_name in GlobalVars._zone_state)
|
||||||
|
|
||||||
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_active_zone_set')
|
@mock.patch.object(driver.BrcdFCZoneDriver, '_get_southbound_client')
|
||||||
def test_delete_connection_for_initiator_mode(self, get_active_zs_mock):
|
def test_delete_connection_for_initiator_mode(self,
|
||||||
|
get_southbound_client_mk):
|
||||||
GlobalVars._is_normal_test = True
|
GlobalVars._is_normal_test = True
|
||||||
get_active_zs_mock.return_value = _active_cfg_before_delete
|
get_southbound_client_mk.return_value = self.get_client("HTTPS")
|
||||||
|
GlobalVars._active_cfg = _active_cfg_before_delete
|
||||||
self.setup_driver(self.setup_config(True, 2))
|
self.setup_driver(self.setup_config(True, 2))
|
||||||
self.driver.delete_connection(
|
self.driver.delete_connection(
|
||||||
'BRCD_FAB_1', _initiator_target_map)
|
'BRCD_FAB_1', _initiator_target_map)
|
||||||
@ -170,12 +190,7 @@ class TestBrcdFcZoneDriver(BrcdFcZoneDriverBaseTest, test.TestCase):
|
|||||||
_initiator_target_map)
|
_initiator_target_map)
|
||||||
|
|
||||||
|
|
||||||
class FakeBrcdFCZoneClientCLI(object):
|
class FakeClient(object):
|
||||||
def __init__(self, ipaddress, username, password, port):
|
|
||||||
self.firmware_supported = True
|
|
||||||
if not GlobalVars._is_normal_test:
|
|
||||||
raise paramiko.SSHException("Unable to connect to fabric")
|
|
||||||
|
|
||||||
def get_active_zone_set(self):
|
def get_active_zone_set(self):
|
||||||
return GlobalVars._active_cfg
|
return GlobalVars._active_cfg
|
||||||
|
|
||||||
@ -200,7 +215,25 @@ class FakeBrcdFCZoneClientCLI(object):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class FakeBrcdFCZoneClientCLI(FakeClient):
|
||||||
|
def __init__(self, ipaddress, username,
|
||||||
|
password, port, key, protocol):
|
||||||
|
self.firmware_supported = True
|
||||||
|
if not GlobalVars._is_normal_test:
|
||||||
|
raise paramiko.SSHException("Unable to connect to fabric.")
|
||||||
|
|
||||||
|
|
||||||
|
class FakeBrcdHttpFCZoneClient(FakeClient):
|
||||||
|
|
||||||
|
def __init__(self, ipaddress, username,
|
||||||
|
password, port, key, protocol):
|
||||||
|
self.firmware_supported = True
|
||||||
|
if not GlobalVars._is_normal_test:
|
||||||
|
raise requests.exception.HTTPError("Unable to connect to fabric")
|
||||||
|
|
||||||
|
|
||||||
class FakeBrcdFCSanLookupService(object):
|
class FakeBrcdFCSanLookupService(object):
|
||||||
|
|
||||||
def get_device_mapping_from_network(self,
|
def get_device_mapping_from_network(self,
|
||||||
initiator_wwn_list,
|
initiator_wwn_list,
|
||||||
target_wwn_list):
|
target_wwn_list):
|
||||||
@ -208,10 +241,10 @@ class FakeBrcdFCSanLookupService(object):
|
|||||||
initiators = []
|
initiators = []
|
||||||
targets = []
|
targets = []
|
||||||
for i in initiator_wwn_list:
|
for i in initiator_wwn_list:
|
||||||
if (i in _initiator_ns_map[_fabric_wwn]):
|
if i in _initiator_ns_map[_fabric_wwn]:
|
||||||
initiators.append(i)
|
initiators.append(i)
|
||||||
for t in target_wwn_list:
|
for t in target_wwn_list:
|
||||||
if (t in _target_ns_map[_fabric_wwn]):
|
if t in _target_ns_map[_fabric_wwn]:
|
||||||
targets.append(t)
|
targets.append(t)
|
||||||
device_map[_fabric_wwn] = {
|
device_map[_fabric_wwn] = {
|
||||||
'initiator_port_wwn_list': initiators,
|
'initiator_port_wwn_list': initiators,
|
||||||
|
585
cinder/tests/unit/zonemanager/test_brcd_http_fc_zone_client.py
Normal file
585
cinder/tests/unit/zonemanager/test_brcd_http_fc_zone_client.py
Normal file
@ -0,0 +1,585 @@
|
|||||||
|
# (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 brcd fc zone client http(s)."""
|
||||||
|
from mock import patch
|
||||||
|
|
||||||
|
from cinder import exception
|
||||||
|
from cinder import test
|
||||||
|
from cinder.zonemanager.drivers.brocade import (brcd_http_fc_zone_client
|
||||||
|
as client)
|
||||||
|
import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant
|
||||||
|
|
||||||
|
|
||||||
|
cfgs = {'openstack_cfg': 'zone1;zone2'}
|
||||||
|
cfgs_to_delete = {
|
||||||
|
'openstack_cfg': 'zone1;zone2;openstack50060b0000c26604201900051ee8e329'}
|
||||||
|
zones = {'zone1': '20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11',
|
||||||
|
'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11'}
|
||||||
|
|
||||||
|
zones_to_delete = {
|
||||||
|
'zone1': '20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11',
|
||||||
|
'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11',
|
||||||
|
'openstack50060b0000c26604201900051ee8e329':
|
||||||
|
'50:06:0b:00:00:c2:66:04;20:19:00:05:1e:e8:e3:29'}
|
||||||
|
|
||||||
|
alias = {}
|
||||||
|
qlps = {}
|
||||||
|
ifas = {}
|
||||||
|
parsed_raw_zoneinfo = ""
|
||||||
|
random_no = ''
|
||||||
|
session = None
|
||||||
|
active_cfg = 'openstack_cfg'
|
||||||
|
activate = True
|
||||||
|
no_activate = False
|
||||||
|
ns_info = ['10:00:00:05:1e:7c:64:96']
|
||||||
|
nameserver_info = """
|
||||||
|
<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
|
||||||
|
<META HTTP-EQUIV="Expires" CONTENT="-1">
|
||||||
|
<TITLE>NSInfo Page</TITLE>
|
||||||
|
</HEAD>
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN NS INFO
|
||||||
|
|
||||||
|
2;8;020800;N ;10:00:00:05:1e:7c:64:96;20:00:00:05:1e:7c:64:96;[89]""" \
|
||||||
|
"""Brocade-825 | 3.0.4.09 | DCM-X3650-94 | Microsoft Windows Server 2003 R2"""\
|
||||||
|
"""| Service Pack 2";FCP ; 3;20:08:00:05:1e:89:54:a0;"""\
|
||||||
|
"""0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0;000000;port8"""\
|
||||||
|
"""
|
||||||
|
--END NS INFO
|
||||||
|
|
||||||
|
</PRE>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
|
"""
|
||||||
|
mocked_zone_string = 'zonecfginfo=openstack_cfg zone1;zone2 '\
|
||||||
|
'zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 '\
|
||||||
|
'zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 '\
|
||||||
|
'alia1 10:00:00:05:1e:7c:64:96;10:21:10:05:33:0e:96:12 '\
|
||||||
|
'qlp 10:11:f4:ce:46:ae:68:6c;20:11:f4:ce:46:ae:68:6c '\
|
||||||
|
'fa1 20:15:f4:ce:96:ae:68:6c;20:11:f4:ce:46:ae:68:6c '\
|
||||||
|
'openstack_cfg null &saveonly=false'
|
||||||
|
mocked_zone_string_no_activate = 'zonecfginfo=openstack_cfg zone1;zone2 '\
|
||||||
|
'zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 '\
|
||||||
|
'zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 '\
|
||||||
|
'alia1 10:00:00:05:1e:7c:64:96;10:21:10:05:33:0e:96:12 '\
|
||||||
|
'qlp 10:11:f4:ce:46:ae:68:6c;20:11:f4:ce:46:ae:68:6c '\
|
||||||
|
'fa1 20:15:f4:ce:96:ae:68:6c;20:11:f4:ce:46:ae:68:6c &saveonly=true'
|
||||||
|
zone_string_to_post = "zonecfginfo=openstack_cfg "\
|
||||||
|
"openstack50060b0000c26604201900051ee8e329;zone1;zone2 "\
|
||||||
|
"zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"openstack50060b0000c26604201900051ee8e329 "\
|
||||||
|
"50:06:0b:00:00:c2:66:04;20:19:00:05:1e:e8:e3:29 "\
|
||||||
|
"openstack_cfg null &saveonly=false"
|
||||||
|
zone_string_to_post_no_activate = "zonecfginfo=openstack_cfg "\
|
||||||
|
"openstack50060b0000c26604201900051ee8e329;zone1;zone2 "\
|
||||||
|
"zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"openstack50060b0000c26604201900051ee8e329 "\
|
||||||
|
"50:06:0b:00:00:c2:66:04;20:19:00:05:1e:e8:e3:29 &saveonly=true"
|
||||||
|
zone_string_to_post_invalid_request = "zonecfginfo=openstack_cfg "\
|
||||||
|
"openstack50060b0000c26604201900051ee8e32900000000000000000000000000;"\
|
||||||
|
"zone1;zone2 openstack50060b0000c26604201900051ee8e329000000000000000000000"\
|
||||||
|
"00000 50:06:0b:00:00:c2:66:04;20:19:00:05:1e:e8:e3:29 "\
|
||||||
|
"zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 &saveonly=true"
|
||||||
|
zone_string_del_to_post = "zonecfginfo=openstack_cfg zone1;zone2"\
|
||||||
|
" zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"openstack_cfg null &saveonly=false"
|
||||||
|
zone_string_del_to_post_no_active = "zonecfginfo=openstack_cfg zone1;zone2"\
|
||||||
|
" zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 "\
|
||||||
|
"zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 &saveonly=true"
|
||||||
|
zone_post_page = """
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN ZONE_TXN_INFO
|
||||||
|
txnId=34666
|
||||||
|
adId=0
|
||||||
|
user=admin
|
||||||
|
roleUser=admin
|
||||||
|
openTxnOwner=
|
||||||
|
openTxnId=0
|
||||||
|
openTxnAbortable=0
|
||||||
|
txnStarttime=1421916354
|
||||||
|
txnEndtime=1421916355
|
||||||
|
currStateInt=4
|
||||||
|
prevStateInt=3
|
||||||
|
actionInt=5
|
||||||
|
currState=done
|
||||||
|
prevState=progress
|
||||||
|
action=error
|
||||||
|
sessionId=5892021
|
||||||
|
selfAborted=false
|
||||||
|
status=done
|
||||||
|
errorCode=-1
|
||||||
|
errorMessage=Name too long
|
||||||
|
--END ZONE_TXN_INFO
|
||||||
|
</PRE>
|
||||||
|
</BODY>"""
|
||||||
|
zone_post_page_no_error = """
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN ZONE_TXN_INFO
|
||||||
|
txnId=34666
|
||||||
|
adId=0
|
||||||
|
user=admin
|
||||||
|
roleUser=admin
|
||||||
|
openTxnOwner=
|
||||||
|
openTxnId=0
|
||||||
|
openTxnAbortable=0
|
||||||
|
txnStarttime=1421916354
|
||||||
|
txnEndtime=1421916355
|
||||||
|
currStateInt=4
|
||||||
|
prevStateInt=3
|
||||||
|
actionInt=5
|
||||||
|
currState=done
|
||||||
|
prevState=progress
|
||||||
|
action=error
|
||||||
|
sessionId=5892021
|
||||||
|
selfAborted=false
|
||||||
|
status=done
|
||||||
|
errorCode=0
|
||||||
|
errorMessage=
|
||||||
|
--END ZONE_TXN_INFO
|
||||||
|
</PRE>
|
||||||
|
</BODY>"""
|
||||||
|
secinfo_resp = """
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN SECINFO
|
||||||
|
SECURITY = OFF
|
||||||
|
RANDOM = 6281590
|
||||||
|
DefaultPasswdBitmap = 0
|
||||||
|
primaryFCS = no
|
||||||
|
switchType = 66
|
||||||
|
resource = 10.24.48.210
|
||||||
|
REALM = FC Switch Administration
|
||||||
|
AUTHMETHOD = Custom_Basic
|
||||||
|
hasUpfrontLogin=yes
|
||||||
|
AUTHVERSION = 1
|
||||||
|
vfEnabled=false
|
||||||
|
vfSupported=true
|
||||||
|
--END SECINFO
|
||||||
|
</PRE>
|
||||||
|
</BODY>
|
||||||
|
"""
|
||||||
|
authenticate_resp = """<HTML>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN AUTHENTICATE
|
||||||
|
authenticated = yes
|
||||||
|
username=admin
|
||||||
|
userrole=admin
|
||||||
|
adCapable=1
|
||||||
|
currentAD=AD0
|
||||||
|
trueADEnvironment=0
|
||||||
|
adId=0
|
||||||
|
adList=ALL
|
||||||
|
contextType=0
|
||||||
|
--END AUTHENTICATE
|
||||||
|
</PRE>
|
||||||
|
</BODY>
|
||||||
|
"""
|
||||||
|
un_authenticate_resp = """<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
|
||||||
|
<META HTTP-EQUIV="Expires" CONTENT="-1">
|
||||||
|
<TITLE>Authentication</TITLE>
|
||||||
|
</HEAD>
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN AUTHENTICATE
|
||||||
|
authenticated = no
|
||||||
|
errCode = -3
|
||||||
|
authType = Custom_Basic
|
||||||
|
realm = FC Switch Administration
|
||||||
|
--END AUTHENTICATE
|
||||||
|
</PRE>
|
||||||
|
</BODY>
|
||||||
|
</HTML>"""
|
||||||
|
switch_page_resp = """<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
|
||||||
|
<META HTTP-EQUIV="Expires" CONTENT="-1">
|
||||||
|
</HEAD>
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN SWITCH INFORMATION
|
||||||
|
didOffset=96
|
||||||
|
swFWVersion=v7.3.0b_rc1_bld06
|
||||||
|
swDomain=2
|
||||||
|
--END SWITCH INFORMATION
|
||||||
|
</PRE>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
|
"""
|
||||||
|
switch_page_invalid_firm = """<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
|
||||||
|
<META HTTP-EQUIV="Expires" CONTENT="-1">
|
||||||
|
</HEAD>
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN SWITCH INFORMATION
|
||||||
|
didOffset=96
|
||||||
|
swFWVersion=v6.1.1
|
||||||
|
swDomain=2
|
||||||
|
--END SWITCH INFORMATION
|
||||||
|
</PRE>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
|
"""
|
||||||
|
parsed_value = """
|
||||||
|
didOffset=96
|
||||||
|
swFWVersion=v7.3.0b_rc1_bld06
|
||||||
|
swDomain=2
|
||||||
|
"""
|
||||||
|
zone_info = """<HTML>
|
||||||
|
<HEAD>
|
||||||
|
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
|
||||||
|
<META HTTP-EQUIV="Expires" CONTENT="-1">
|
||||||
|
<TITLE>Zone Configuration Information</TITLE>
|
||||||
|
</HEAD>
|
||||||
|
<BODY>
|
||||||
|
<PRE>
|
||||||
|
--BEGIN ZONE CHANGE
|
||||||
|
LastZoneChangeTime=1421926251
|
||||||
|
--END ZONE CHANGE
|
||||||
|
isZoneTxnSupported=true
|
||||||
|
ZoneLicense=true
|
||||||
|
QuickLoopLicense=true
|
||||||
|
DefZoneStatus=noaccess
|
||||||
|
McDataDefaultZone=false
|
||||||
|
McDataSafeZone=false
|
||||||
|
AvailableZoneSize=1043890
|
||||||
|
--BEGIN ZONE INFO
|
||||||
|
openstack_cfg zone1;zone2 """\
|
||||||
|
"""zone1 20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11 """\
|
||||||
|
"""zone2 20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11 """\
|
||||||
|
"""alia1 10:00:00:05:1e:7c:64:96;10:21:10:05:33:0e:96:12 """\
|
||||||
|
"""qlp 10:11:f4:ce:46:ae:68:6c;20:11:f4:ce:46:ae:68:6c """\
|
||||||
|
"""fa1 20:15:f4:ce:96:ae:68:6c;20:11:f4:ce:46:ae:68:6c """\
|
||||||
|
"""openstack_cfg null 1045274"""\
|
||||||
|
"""--END ZONE INFO
|
||||||
|
</PRE>
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
active_zone_set = {
|
||||||
|
'zones':
|
||||||
|
{'zone1':
|
||||||
|
['20:01:00:05:33:0e:96:15', '20:00:00:05:33:0e:93:11'],
|
||||||
|
'zone2':
|
||||||
|
['20:01:00:05:33:0e:96:14', '20:00:00:05:33:0e:93:11']},
|
||||||
|
'active_zone_config': 'openstack_cfg'}
|
||||||
|
updated_zones = {'zone1': '20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11',
|
||||||
|
'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11',
|
||||||
|
'test_updated_zone':
|
||||||
|
'20:01:00:05:33:0e:96:10;20:00:00:05:33:0e:93:11'}
|
||||||
|
updated_cfgs = {'openstack_cfg': 'test_updated_zone;zone1;zone2'}
|
||||||
|
valid_zone_name = "openstack50060b0000c26604201900051ee8e329"
|
||||||
|
|
||||||
|
|
||||||
|
class TestBrcdHttpFCZoneClient(client.BrcdHTTPFCZoneClient, test.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.auth_header = "YWRtaW46cGFzc3dvcmQ6NDM4ODEyNTIw"
|
||||||
|
self.switch_user = "admin"
|
||||||
|
self.switch_pwd = "password"
|
||||||
|
self.protocol = "HTTPS"
|
||||||
|
self.conn = None
|
||||||
|
self.alias = {}
|
||||||
|
self.qlps = {}
|
||||||
|
self.ifas = {}
|
||||||
|
self.parsed_raw_zoneinfo = ""
|
||||||
|
self.random_no = ''
|
||||||
|
self.session = None
|
||||||
|
super(TestBrcdHttpFCZoneClient, self).setUp()
|
||||||
|
|
||||||
|
# override some of the functions
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
test.TestCase.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_create_auth_token(self, connect_mock):
|
||||||
|
connect_mock.return_value = secinfo_resp
|
||||||
|
self.assertEqual("Custom_Basic YWRtaW46cGFzc3dvcmQ6NjI4MTU5MA==",
|
||||||
|
self.create_auth_token())
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_authenticate(self, connect_mock):
|
||||||
|
connect_mock.return_value = authenticate_resp
|
||||||
|
self.assertEqual(
|
||||||
|
(True, "Custom_Basic YWRtaW46eHh4Og=="), self.authenticate())
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_authenticate_failed(self, connect_mock):
|
||||||
|
connect_mock.return_value = un_authenticate_resp
|
||||||
|
self.assertRaises(
|
||||||
|
exception.BrocadeZoningHttpException, self.authenticate)
|
||||||
|
|
||||||
|
def test_get_parsed_data(self):
|
||||||
|
valid_delimiter1 = zone_constant.SWITCHINFO_BEGIN
|
||||||
|
valid_delimiter2 = zone_constant.SWITCHINFO_END
|
||||||
|
invalid_delimiter = "--END SWITCH INFORMATION1"
|
||||||
|
self.assertEqual(parsed_value, self.get_parsed_data(
|
||||||
|
switch_page_resp, valid_delimiter1, valid_delimiter2))
|
||||||
|
self.assertRaises(exception.BrocadeZoningHttpException,
|
||||||
|
self.get_parsed_data,
|
||||||
|
switch_page_resp,
|
||||||
|
valid_delimiter1,
|
||||||
|
invalid_delimiter)
|
||||||
|
self.assertRaises(exception.BrocadeZoningHttpException,
|
||||||
|
self.get_parsed_data,
|
||||||
|
switch_page_resp,
|
||||||
|
invalid_delimiter,
|
||||||
|
valid_delimiter2)
|
||||||
|
|
||||||
|
def test_get_nvp_value(self):
|
||||||
|
valid_keyname = zone_constant.FIRMWARE_VERSION
|
||||||
|
invalid_keyname = "swFWVersion1"
|
||||||
|
self.assertEqual(
|
||||||
|
"v7.3.0b_rc1_bld06", self.get_nvp_value(parsed_value,
|
||||||
|
valid_keyname))
|
||||||
|
self.assertRaises(exception.BrocadeZoningHttpException,
|
||||||
|
self.get_nvp_value,
|
||||||
|
parsed_value,
|
||||||
|
invalid_keyname)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_is_supported_firmware(self, connect_mock):
|
||||||
|
connect_mock.return_value = switch_page_resp
|
||||||
|
self.assertTrue(self.is_supported_firmware())
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_is_supported_firmware_invalid(self, connect_mock):
|
||||||
|
connect_mock.return_value = switch_page_invalid_firm
|
||||||
|
self.assertFalse(self.is_supported_firmware())
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_get_active_zone_set(self, connect_mock):
|
||||||
|
connect_mock.return_value = zone_info
|
||||||
|
returned_zone_map = self.get_active_zone_set()
|
||||||
|
self.assertDictMatch(active_zone_set, returned_zone_map)
|
||||||
|
|
||||||
|
def test_form_zone_string(self):
|
||||||
|
new_alias = {
|
||||||
|
'alia1': '10:00:00:05:1e:7c:64:96;10:21:10:05:33:0e:96:12'}
|
||||||
|
new_qlps = {'qlp': '10:11:f4:ce:46:ae:68:6c;20:11:f4:ce:46:ae:68:6c'}
|
||||||
|
new_ifas = {'fa1': '20:15:f4:ce:96:ae:68:6c;20:11:f4:ce:46:ae:68:6c'}
|
||||||
|
self.assertEqual(mocked_zone_string, self.form_zone_string(
|
||||||
|
cfgs, active_cfg, zones, new_alias, new_qlps, new_ifas, True))
|
||||||
|
self.assertEqual(mocked_zone_string_no_activate, self.form_zone_string(
|
||||||
|
cfgs, active_cfg, zones, new_alias, new_qlps, new_ifas, False))
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'post_zone_data')
|
||||||
|
def test_add_zones_activate(self, post_zone_data_mock):
|
||||||
|
post_zone_data_mock.return_value = ("0", "")
|
||||||
|
self.cfgs = cfgs.copy()
|
||||||
|
self.zones = zones.copy()
|
||||||
|
self.alias = alias.copy()
|
||||||
|
self.qlps = qlps.copy()
|
||||||
|
self.ifas = ifas.copy()
|
||||||
|
self.active_cfg = active_cfg
|
||||||
|
add_zones_info = {valid_zone_name:
|
||||||
|
['50:06:0b:00:00:c2:66:04',
|
||||||
|
'20:19:00:05:1e:e8:e3:29']
|
||||||
|
}
|
||||||
|
self.add_zones(add_zones_info, True)
|
||||||
|
post_zone_data_mock.assert_called_once_with(zone_string_to_post)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'post_zone_data')
|
||||||
|
def test_add_zones_invalid_zone_name(self, post_zone_data_mock):
|
||||||
|
post_zone_data_mock.return_value = ("-1", "Name Too Long")
|
||||||
|
self.cfgs = cfgs.copy()
|
||||||
|
self.zones = zones.copy()
|
||||||
|
self.alias = alias.copy()
|
||||||
|
self.qlps = qlps.copy()
|
||||||
|
self.ifas = ifas.copy()
|
||||||
|
self.active_cfg = active_cfg
|
||||||
|
invalid_zone_name = valid_zone_name + "00000000000000000000000000"
|
||||||
|
add_zones_info = {invalid_zone_name:
|
||||||
|
['50:06:0b:00:00:c2:66:04',
|
||||||
|
'20:19:00:05:1e:e8:e3:29']
|
||||||
|
}
|
||||||
|
self.assertRaises(
|
||||||
|
exception.BrocadeZoningHttpException,
|
||||||
|
self.add_zones, add_zones_info, False)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'post_zone_data')
|
||||||
|
def test_add_zones_no_activate(self, post_zone_data_mock):
|
||||||
|
post_zone_data_mock.return_value = ("0", "")
|
||||||
|
self.cfgs = cfgs.copy()
|
||||||
|
self.zones = zones.copy()
|
||||||
|
self.alias = alias.copy()
|
||||||
|
self.qlps = qlps.copy()
|
||||||
|
self.ifas = ifas.copy()
|
||||||
|
self.active_cfg = active_cfg
|
||||||
|
add_zones_info = {valid_zone_name:
|
||||||
|
['50:06:0b:00:00:c2:66:04',
|
||||||
|
'20:19:00:05:1e:e8:e3:29']
|
||||||
|
}
|
||||||
|
self.add_zones(add_zones_info, False)
|
||||||
|
post_zone_data_mock.assert_called_once_with(
|
||||||
|
zone_string_to_post_no_activate)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'post_zone_data')
|
||||||
|
def test_delete_zones_activate(self, post_zone_data_mock):
|
||||||
|
post_zone_data_mock.return_value = ("0", "")
|
||||||
|
self.cfgs = cfgs_to_delete.copy()
|
||||||
|
self.zones = zones_to_delete.copy()
|
||||||
|
self.alias = alias.copy()
|
||||||
|
self.qlps = qlps.copy()
|
||||||
|
self.ifas = ifas.copy()
|
||||||
|
self.active_cfg = active_cfg
|
||||||
|
delete_zones_info = valid_zone_name
|
||||||
|
|
||||||
|
self.delete_zones(delete_zones_info, True)
|
||||||
|
post_zone_data_mock.assert_called_once_with(zone_string_del_to_post)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'post_zone_data')
|
||||||
|
def test_delete_zones_no_activate(self, post_zone_data_mock):
|
||||||
|
post_zone_data_mock.return_value = ("0", "")
|
||||||
|
self.cfgs = cfgs_to_delete.copy()
|
||||||
|
self.zones = zones_to_delete.copy()
|
||||||
|
self.alias = alias.copy()
|
||||||
|
self.qlps = qlps.copy()
|
||||||
|
self.ifas = ifas.copy()
|
||||||
|
self.active_cfg = active_cfg
|
||||||
|
delete_zones_info = valid_zone_name
|
||||||
|
self.delete_zones(delete_zones_info, False)
|
||||||
|
post_zone_data_mock.assert_called_once_with(
|
||||||
|
zone_string_del_to_post_no_active)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'post_zone_data')
|
||||||
|
def test_delete_zones_invalid_zone_name(self, post_zone_data_mock):
|
||||||
|
post_zone_data_mock.return_value = ("0", "")
|
||||||
|
self.cfgs = cfgs_to_delete.copy()
|
||||||
|
self.zones = zones_to_delete.copy()
|
||||||
|
self.alias = alias.copy()
|
||||||
|
self.qlps = qlps.copy()
|
||||||
|
self.ifas = ifas.copy()
|
||||||
|
self.active_cfg = active_cfg
|
||||||
|
delete_zones_info = 'openstack50060b0000c26604201900051ee8e32'
|
||||||
|
self.assertRaises(exception.BrocadeZoningHttpException,
|
||||||
|
self.delete_zones, delete_zones_info, False)
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_post_zone_data(self, connect_mock):
|
||||||
|
connect_mock.return_value = zone_post_page
|
||||||
|
self.assertEqual(
|
||||||
|
("-1", "Name too long"), self.post_zone_data(zone_string_to_post))
|
||||||
|
connect_mock.return_value = zone_post_page_no_error
|
||||||
|
self.assertEqual(("0", ""), self.post_zone_data(zone_string_to_post))
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_get_nameserver_info(self, connect_mock):
|
||||||
|
connect_mock.return_value = nameserver_info
|
||||||
|
self.assertEqual(ns_info, self.get_nameserver_info())
|
||||||
|
|
||||||
|
def test_delete_update_zones_cfgs(self):
|
||||||
|
|
||||||
|
cfgs = {'openstack_cfg': 'zone1;zone2'}
|
||||||
|
zones = {'zone1': '20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11',
|
||||||
|
'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11'}
|
||||||
|
delete_zones_info = valid_zone_name
|
||||||
|
self.assertEqual(
|
||||||
|
(zones, cfgs, active_cfg),
|
||||||
|
self.delete_update_zones_cfgs(
|
||||||
|
cfgs_to_delete.copy(),
|
||||||
|
zones_to_delete.copy(),
|
||||||
|
delete_zones_info,
|
||||||
|
active_cfg))
|
||||||
|
|
||||||
|
cfgs = {'openstack_cfg': 'zone2'}
|
||||||
|
zones = {'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11'}
|
||||||
|
delete_zones_info = valid_zone_name + ";zone1"
|
||||||
|
self.assertEqual(
|
||||||
|
(zones, cfgs, active_cfg),
|
||||||
|
self.delete_update_zones_cfgs(
|
||||||
|
cfgs_to_delete.copy(),
|
||||||
|
zones_to_delete.copy(),
|
||||||
|
delete_zones_info,
|
||||||
|
active_cfg))
|
||||||
|
|
||||||
|
def test_add_update_zones_cfgs(self):
|
||||||
|
add_zones_info = {valid_zone_name:
|
||||||
|
['50:06:0b:00:00:c2:66:04',
|
||||||
|
'20:19:00:05:1e:e8:e3:29']
|
||||||
|
}
|
||||||
|
updated_cfgs = {
|
||||||
|
'openstack_cfg':
|
||||||
|
valid_zone_name + ';zone1;zone2'}
|
||||||
|
updated_zones = {
|
||||||
|
'zone1': '20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11',
|
||||||
|
'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11',
|
||||||
|
valid_zone_name:
|
||||||
|
'50:06:0b:00:00:c2:66:04;20:19:00:05:1e:e8:e3:29'}
|
||||||
|
self.assertEqual((updated_zones, updated_cfgs, active_cfg),
|
||||||
|
self.add_update_zones_cfgs(
|
||||||
|
cfgs.copy(),
|
||||||
|
zones.copy(),
|
||||||
|
add_zones_info,
|
||||||
|
active_cfg,
|
||||||
|
"openstack_cfg"))
|
||||||
|
|
||||||
|
add_zones_info = {valid_zone_name:
|
||||||
|
['50:06:0b:00:00:c2:66:04',
|
||||||
|
'20:19:00:05:1e:e8:e3:29'],
|
||||||
|
'test4':
|
||||||
|
['20:06:0b:00:00:b2:66:07',
|
||||||
|
'20:10:00:05:1e:b8:c3:19']
|
||||||
|
}
|
||||||
|
updated_cfgs = {
|
||||||
|
'openstack_cfg':
|
||||||
|
'test4;openstack50060b0000c26604201900051ee8e329;zone1;zone2'}
|
||||||
|
updated_zones = {
|
||||||
|
'zone1': '20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11',
|
||||||
|
'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11',
|
||||||
|
valid_zone_name:
|
||||||
|
'50:06:0b:00:00:c2:66:04;20:19:00:05:1e:e8:e3:29',
|
||||||
|
'test4': '20:06:0b:00:00:b2:66:07;20:10:00:05:1e:b8:c3:19'}
|
||||||
|
self.assertEqual(
|
||||||
|
(updated_zones, updated_cfgs, active_cfg),
|
||||||
|
self.add_update_zones_cfgs(
|
||||||
|
cfgs.copy(), zones.copy(), add_zones_info,
|
||||||
|
active_cfg, "openstack_cfg"))
|
||||||
|
|
||||||
|
@patch.object(client.BrcdHTTPFCZoneClient, 'connect')
|
||||||
|
def test_get_zone_info(self, connect_mock):
|
||||||
|
connect_mock.return_value = zone_info
|
||||||
|
self.get_zone_info()
|
||||||
|
self.assertEqual({'openstack_cfg': 'zone1;zone2'}, self.cfgs)
|
||||||
|
self.assertEqual(
|
||||||
|
{'zone1': '20:01:00:05:33:0e:96:15;20:00:00:05:33:0e:93:11',
|
||||||
|
'zone2': '20:01:00:05:33:0e:96:14;20:00:00:05:33:0e:93:11'},
|
||||||
|
self.zones)
|
||||||
|
self.assertEqual('openstack_cfg', self.active_cfg)
|
||||||
|
self.assertEqual(
|
||||||
|
{'alia1': '10:00:00:05:1e:7c:64:96;10:21:10:05:33:0e:96:12'},
|
||||||
|
self.alias)
|
||||||
|
self.assertEqual(
|
||||||
|
{'fa1': '20:15:f4:ce:96:ae:68:6c;20:11:f4:ce:46:ae:68:6c'},
|
||||||
|
self.ifas)
|
||||||
|
self.assertEqual(
|
||||||
|
{'qlp': '10:11:f4:ce:46:ae:68:6c;20:11:f4:ce:46:ae:68:6c'},
|
||||||
|
self.qlps)
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2013 Brocade Communications Systems Inc.
|
# (c) Copyright 2013 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2014 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -16,7 +14,6 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
"""Unit tests for fc san lookup service."""
|
"""Unit tests for fc san lookup service."""
|
||||||
|
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2014 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -21,30 +19,40 @@ from oslo_log import log as logging
|
|||||||
from cinder.volume import configuration
|
from cinder.volume import configuration
|
||||||
|
|
||||||
brcd_zone_opts = [
|
brcd_zone_opts = [
|
||||||
|
cfg.StrOpt('fc_southbound_protocol',
|
||||||
|
default='HTTP',
|
||||||
|
choices=('SSH', 'HTTP', 'HTTPS'),
|
||||||
|
help='South bound connector for the fabric.'),
|
||||||
cfg.StrOpt('fc_fabric_address',
|
cfg.StrOpt('fc_fabric_address',
|
||||||
default='',
|
default='',
|
||||||
help='Management IP of fabric'),
|
help='Management IP of fabric.'),
|
||||||
cfg.StrOpt('fc_fabric_user',
|
cfg.StrOpt('fc_fabric_user',
|
||||||
default='',
|
default='',
|
||||||
help='Fabric user ID'),
|
help='Fabric user ID.'),
|
||||||
cfg.StrOpt('fc_fabric_password',
|
cfg.StrOpt('fc_fabric_password',
|
||||||
default='',
|
default='',
|
||||||
help='Password for user',
|
help='Password for user.',
|
||||||
secret=True),
|
secret=True),
|
||||||
cfg.PortOpt('fc_fabric_port',
|
cfg.PortOpt('fc_fabric_port',
|
||||||
default=22,
|
default=22,
|
||||||
help='Connecting port'),
|
help='Connecting port'),
|
||||||
|
cfg.StrOpt('fc_fabric_ssh_cert_path',
|
||||||
|
default='',
|
||||||
|
help='Local SSH certificate Path.'),
|
||||||
cfg.StrOpt('zoning_policy',
|
cfg.StrOpt('zoning_policy',
|
||||||
default='initiator-target',
|
default='initiator-target',
|
||||||
help='overridden zoning policy'),
|
help='Overridden zoning policy.'),
|
||||||
cfg.BoolOpt('zone_activate',
|
cfg.BoolOpt('zone_activate',
|
||||||
default=True,
|
default=True,
|
||||||
help='overridden zoning activation state'),
|
help='Overridden zoning activation state.'),
|
||||||
cfg.StrOpt('zone_name_prefix',
|
cfg.StrOpt('zone_name_prefix',
|
||||||
default='openstack',
|
default='openstack',
|
||||||
help='overridden zone name prefix'),
|
help='Overridden zone name prefix.'),
|
||||||
cfg.StrOpt('principal_switch_wwn',
|
cfg.StrOpt('principal_switch_wwn',
|
||||||
help='Principal switch WWN of the fabric'),
|
default=None,
|
||||||
|
deprecated_for_removal=True,
|
||||||
|
help='Principal switch WWN of the fabric. This option is not '
|
||||||
|
'used anymore.')
|
||||||
]
|
]
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@ -59,5 +67,4 @@ def load_fabric_configurations(fabric_names):
|
|||||||
LOG.debug("Loaded FC fabric config %(fabricname)s",
|
LOG.debug("Loaded FC fabric config %(fabricname)s",
|
||||||
{'fabricname': fabric_name})
|
{'fabricname': fabric_name})
|
||||||
fabric_configs[fabric_name] = config
|
fabric_configs[fabric_name] = config
|
||||||
|
|
||||||
return fabric_configs
|
return fabric_configs
|
||||||
|
@ -28,6 +28,7 @@ from cinder import utils
|
|||||||
from cinder.zonemanager.drivers.brocade import brcd_fabric_opts as fabric_opts
|
from cinder.zonemanager.drivers.brocade import brcd_fabric_opts as fabric_opts
|
||||||
import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant
|
import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant
|
||||||
from cinder.zonemanager import fc_san_lookup_service as fc_service
|
from cinder.zonemanager import fc_san_lookup_service as fc_service
|
||||||
|
from cinder.zonemanager import utils as fczm_utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -97,10 +98,10 @@ class BrcdFCSanLookupService(fc_service.FCSanLookupService):
|
|||||||
LOG.debug("FC Fabric List: %s", fabrics)
|
LOG.debug("FC Fabric List: %s", fabrics)
|
||||||
if fabrics:
|
if fabrics:
|
||||||
for t in target_wwn_list:
|
for t in target_wwn_list:
|
||||||
formatted_target_list.append(self.get_formatted_wwn(t))
|
formatted_target_list.append(fczm_utils.get_formatted_wwn(t))
|
||||||
|
|
||||||
for i in initiator_wwn_list:
|
for i in initiator_wwn_list:
|
||||||
formatted_initiator_list.append(self.
|
formatted_initiator_list.append(fczm_utils.
|
||||||
get_formatted_wwn(i))
|
get_formatted_wwn(i))
|
||||||
|
|
||||||
for fabric_name in fabrics:
|
for fabric_name in fabrics:
|
||||||
@ -237,11 +238,3 @@ class BrcdFCSanLookupService(fc_service.FCSanLookupService):
|
|||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.InvalidParameterValue(err=msg)
|
raise exception.InvalidParameterValue(err=msg)
|
||||||
return nsinfo_list
|
return nsinfo_list
|
||||||
|
|
||||||
def get_formatted_wwn(self, wwn_str):
|
|
||||||
"""Utility API that formats WWN to insert ':'."""
|
|
||||||
if (len(wwn_str) != 16):
|
|
||||||
return wwn_str.lower()
|
|
||||||
else:
|
|
||||||
return (':'.join([wwn_str[i:i + 2]
|
|
||||||
for i in range(0, len(wwn_str), 2)])).lower()
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2014 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -34,7 +32,7 @@ from cinder import exception
|
|||||||
from cinder.i18n import _, _LE
|
from cinder.i18n import _, _LE
|
||||||
from cinder import ssh_utils
|
from cinder import ssh_utils
|
||||||
from cinder import utils
|
from cinder import utils
|
||||||
import cinder.zonemanager.drivers.brocade.fc_zone_constants as ZoneConstant
|
import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -44,14 +42,17 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
switch_port = '22'
|
switch_port = '22'
|
||||||
switch_user = 'admin'
|
switch_user = 'admin'
|
||||||
switch_pwd = 'none'
|
switch_pwd = 'none'
|
||||||
|
switch_key = 'none'
|
||||||
patrn = re.compile('[;\s]+')
|
patrn = re.compile('[;\s]+')
|
||||||
|
|
||||||
def __init__(self, ipaddress, username, password, port):
|
def __init__(self, ipaddress, username,
|
||||||
"""initializing the client."""
|
password, port, key):
|
||||||
|
"""Initializing the client."""
|
||||||
self.switch_ip = ipaddress
|
self.switch_ip = ipaddress
|
||||||
self.switch_port = port
|
self.switch_port = port
|
||||||
self.switch_user = username
|
self.switch_user = username
|
||||||
self.switch_pwd = password
|
self.switch_pwd = password
|
||||||
|
self.switch_key = key
|
||||||
self.sshpool = None
|
self.sshpool = None
|
||||||
|
|
||||||
def get_active_zone_set(self):
|
def get_active_zone_set(self):
|
||||||
@ -77,7 +78,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
zone_set_name = None
|
zone_set_name = None
|
||||||
try:
|
try:
|
||||||
switch_data = self._get_switch_info(
|
switch_data = self._get_switch_info(
|
||||||
[ZoneConstant.GET_ACTIVE_ZONE_CFG])
|
[zone_constant.GET_ACTIVE_ZONE_CFG])
|
||||||
except exception.BrocadeZoningCliException:
|
except exception.BrocadeZoningCliException:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.error(_LE("Failed getting active zone set "
|
LOG.error(_LE("Failed getting active zone set "
|
||||||
@ -91,7 +92,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
line_split = [x.replace(
|
line_split = [x.replace(
|
||||||
' ',
|
' ',
|
||||||
'') for x in line_split]
|
'') for x in line_split]
|
||||||
if ZoneConstant.CFG_ZONESET in line_split:
|
if zone_constant.CFG_ZONESET in line_split:
|
||||||
zone_set_name = line_split[1]
|
zone_set_name = line_split[1]
|
||||||
continue
|
continue
|
||||||
if line_split[1]:
|
if line_split[1]:
|
||||||
@ -101,10 +102,10 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
zone_member = line_split[2]
|
zone_member = line_split[2]
|
||||||
zone_member_list = zone.get(zone_name)
|
zone_member_list = zone.get(zone_name)
|
||||||
zone_member_list.append(zone_member)
|
zone_member_list.append(zone_member)
|
||||||
zone_set[ZoneConstant.CFG_ZONES] = zone
|
zone_set[zone_constant.CFG_ZONES] = zone
|
||||||
zone_set[ZoneConstant.ACTIVE_ZONE_CONFIG] = zone_set_name
|
zone_set[zone_constant.ACTIVE_ZONE_CONFIG] = zone_set_name
|
||||||
except Exception:
|
except Exception:
|
||||||
# Incase of parsing error here, it should be malformed cli output.
|
# In case of parsing error here, it should be malformed cli output.
|
||||||
msg = _("Malformed zone configuration: (switch=%(switch)s "
|
msg = _("Malformed zone configuration: (switch=%(switch)s "
|
||||||
"zone_config=%(zone_config)s)."
|
"zone_config=%(zone_config)s)."
|
||||||
) % {'switch': self.switch_ip,
|
) % {'switch': self.switch_ip,
|
||||||
@ -137,7 +138,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
if not active_zone_set:
|
if not active_zone_set:
|
||||||
active_zone_set = self.get_active_zone_set()
|
active_zone_set = self.get_active_zone_set()
|
||||||
LOG.debug("Active zone set: %s", active_zone_set)
|
LOG.debug("Active zone set: %s", active_zone_set)
|
||||||
zone_list = active_zone_set[ZoneConstant.CFG_ZONES]
|
zone_list = active_zone_set[zone_constant.CFG_ZONES]
|
||||||
LOG.debug("zone list: %s", zone_list)
|
LOG.debug("zone list: %s", zone_list)
|
||||||
for zone in zones.keys():
|
for zone in zones.keys():
|
||||||
# If zone exists, its an update. Delete & insert
|
# If zone exists, its an update. Delete & insert
|
||||||
@ -172,10 +173,10 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
# Get active zone set from device, as some of the zones
|
# Get active zone set from device, as some of the zones
|
||||||
# could be deleted.
|
# could be deleted.
|
||||||
active_zone_set = self.get_active_zone_set()
|
active_zone_set = self.get_active_zone_set()
|
||||||
cfg_name = active_zone_set[ZoneConstant.ACTIVE_ZONE_CONFIG]
|
cfg_name = active_zone_set[zone_constant.ACTIVE_ZONE_CONFIG]
|
||||||
cmd = None
|
cmd = None
|
||||||
if not cfg_name:
|
if not cfg_name:
|
||||||
cfg_name = ZoneConstant.OPENSTACK_CFG_NAME
|
cfg_name = zone_constant.OPENSTACK_CFG_NAME
|
||||||
cmd = 'cfgcreate "%(zoneset)s", "%(zones)s"' \
|
cmd = 'cfgcreate "%(zoneset)s", "%(zones)s"' \
|
||||||
% {'zoneset': cfg_name, 'zones': zone_with_sep}
|
% {'zoneset': cfg_name, 'zones': zone_with_sep}
|
||||||
else:
|
else:
|
||||||
@ -197,21 +198,21 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
|
|
||||||
def activate_zoneset(self, cfgname):
|
def activate_zoneset(self, cfgname):
|
||||||
"""Method to Activate the zone config. Param cfgname - ZonesetName."""
|
"""Method to Activate the zone config. Param cfgname - ZonesetName."""
|
||||||
cmd_list = [ZoneConstant.ACTIVATE_ZONESET, cfgname]
|
cmd_list = [zone_constant.ACTIVATE_ZONESET, cfgname]
|
||||||
return self._ssh_execute(cmd_list, True, 1)
|
return self._ssh_execute(cmd_list, True, 1)
|
||||||
|
|
||||||
def deactivate_zoneset(self):
|
def deactivate_zoneset(self):
|
||||||
"""Method to deActivate the zone config."""
|
"""Method to deActivate the zone config."""
|
||||||
return self._ssh_execute([ZoneConstant.DEACTIVATE_ZONESET], True, 1)
|
return self._ssh_execute([zone_constant.DEACTIVATE_ZONESET], True, 1)
|
||||||
|
|
||||||
def delete_zones(self, zone_names, activate, active_zone_set=None):
|
def delete_zones(self, zone_names, activate, active_zone_set=None):
|
||||||
"""Delete zones from fabric.
|
"""Delete zones from fabric.
|
||||||
|
|
||||||
Method to delete the active zone config zones
|
Method to delete the active zone config zones
|
||||||
|
|
||||||
params zone_names: zoneNames separated by semicolon
|
:param zone_names: zoneNames separated by semicolon
|
||||||
params activate: True/False
|
:param activate: True/False
|
||||||
params active_zone_set: the active zone set dict retrieved
|
:param active_zone_set: the active zone set dict retrieved
|
||||||
from get_active_zone_set method
|
from get_active_zone_set method
|
||||||
"""
|
"""
|
||||||
active_zoneset_name = None
|
active_zoneset_name = None
|
||||||
@ -219,8 +220,8 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
if not active_zone_set:
|
if not active_zone_set:
|
||||||
active_zone_set = self.get_active_zone_set()
|
active_zone_set = self.get_active_zone_set()
|
||||||
active_zoneset_name = active_zone_set[
|
active_zoneset_name = active_zone_set[
|
||||||
ZoneConstant.ACTIVE_ZONE_CONFIG]
|
zone_constant.ACTIVE_ZONE_CONFIG]
|
||||||
zone_list = active_zone_set[ZoneConstant.CFG_ZONES]
|
zone_list = active_zone_set[zone_constant.CFG_ZONES]
|
||||||
zones = self.patrn.split(''.join(zone_names))
|
zones = self.patrn.split(''.join(zone_names))
|
||||||
cmd = None
|
cmd = None
|
||||||
try:
|
try:
|
||||||
@ -260,8 +261,8 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
return_list = []
|
return_list = []
|
||||||
try:
|
try:
|
||||||
cmd = '%(nsshow)s;%(nscamshow)s' % {
|
cmd = '%(nsshow)s;%(nscamshow)s' % {
|
||||||
'nsshow': ZoneConstant.NS_SHOW,
|
'nsshow': zone_constant.NS_SHOW,
|
||||||
'nscamshow': ZoneConstant.NS_CAM_SHOW}
|
'nscamshow': zone_constant.NS_CAM_SHOW}
|
||||||
cli_output = self._get_switch_info([cmd])
|
cli_output = self._get_switch_info([cmd])
|
||||||
except exception.BrocadeZoningCliException:
|
except exception.BrocadeZoningCliException:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
@ -273,7 +274,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
return return_list
|
return return_list
|
||||||
|
|
||||||
def _cfg_save(self):
|
def _cfg_save(self):
|
||||||
self._ssh_execute([ZoneConstant.CFG_SAVE], True, 1)
|
self._ssh_execute([zone_constant.CFG_SAVE], True, 1)
|
||||||
|
|
||||||
def _zone_delete(self, zone_name):
|
def _zone_delete(self, zone_name):
|
||||||
cmd = 'zonedelete "%(zone_name)s"' % {'zone_name': zone_name}
|
cmd = 'zonedelete "%(zone_name)s"' % {'zone_name': zone_name}
|
||||||
@ -282,17 +283,17 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
def _cfg_trans_abort(self):
|
def _cfg_trans_abort(self):
|
||||||
is_abortable = self._is_trans_abortable()
|
is_abortable = self._is_trans_abortable()
|
||||||
if(is_abortable):
|
if(is_abortable):
|
||||||
self.apply_zone_change([ZoneConstant.CFG_ZONE_TRANS_ABORT])
|
self.apply_zone_change([zone_constant.CFG_ZONE_TRANS_ABORT])
|
||||||
|
|
||||||
def _is_trans_abortable(self):
|
def _is_trans_abortable(self):
|
||||||
is_abortable = False
|
is_abortable = False
|
||||||
stdout, stderr = None, None
|
stdout, stderr = None, None
|
||||||
stdout, stderr = self._run_ssh(
|
stdout, stderr = self._run_ssh(
|
||||||
[ZoneConstant.CFG_SHOW_TRANS], True, 1)
|
[zone_constant.CFG_SHOW_TRANS], True, 1)
|
||||||
output = stdout.splitlines()
|
output = stdout.splitlines()
|
||||||
is_abortable = False
|
is_abortable = False
|
||||||
for line in output:
|
for line in output:
|
||||||
if(ZoneConstant.TRANS_ABORTABLE in line):
|
if(zone_constant.TRANS_ABORTABLE in line):
|
||||||
is_abortable = True
|
is_abortable = True
|
||||||
break
|
break
|
||||||
if stderr:
|
if stderr:
|
||||||
@ -392,6 +393,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
None,
|
None,
|
||||||
self.switch_user,
|
self.switch_user,
|
||||||
self.switch_pwd,
|
self.switch_pwd,
|
||||||
|
self.switch_key,
|
||||||
min_size=1,
|
min_size=1,
|
||||||
max_size=5)
|
max_size=5)
|
||||||
last_exception = None
|
last_exception = None
|
||||||
@ -438,6 +440,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
None,
|
None,
|
||||||
self.switch_user,
|
self.switch_user,
|
||||||
self.switch_pwd,
|
self.switch_pwd,
|
||||||
|
self.switch_key,
|
||||||
min_size=1,
|
min_size=1,
|
||||||
max_size=5)
|
max_size=5)
|
||||||
stdin, stdout, stderr = None, None, None
|
stdin, stdout, stderr = None, None, None
|
||||||
@ -449,7 +452,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
attempts -= 1
|
attempts -= 1
|
||||||
try:
|
try:
|
||||||
stdin, stdout, stderr = ssh.exec_command(command)
|
stdin, stdout, stderr = ssh.exec_command(command)
|
||||||
stdin.write("%s\n" % ZoneConstant.YES)
|
stdin.write("%s\n" % zone_constant.YES)
|
||||||
channel = stdout.channel
|
channel = stdout.channel
|
||||||
exit_status = channel.recv_exit_status()
|
exit_status = channel.recv_exit_status()
|
||||||
LOG.debug("Exit Status from ssh: %s", exit_status)
|
LOG.debug("Exit Status from ssh: %s", exit_status)
|
||||||
@ -499,7 +502,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
def _execute_shell_cmd(self, cmd):
|
def _execute_shell_cmd(self, cmd):
|
||||||
"""Run command over shell for older firmware versions.
|
"""Run command over shell for older firmware versions.
|
||||||
|
|
||||||
We invoke shell and issue the command and return the output.
|
Invokes shell and issue the command and return the output.
|
||||||
This is primarily used for issuing read commands when we are not sure
|
This is primarily used for issuing read commands when we are not sure
|
||||||
if the firmware supports exec_command.
|
if the firmware supports exec_command.
|
||||||
"""
|
"""
|
||||||
@ -512,6 +515,7 @@ class BrcdFCZoneClientCLI(object):
|
|||||||
None,
|
None,
|
||||||
self.switch_user,
|
self.switch_user,
|
||||||
self.switch_pwd,
|
self.switch_pwd,
|
||||||
|
self.switch_key,
|
||||||
min_size=1,
|
min_size=1,
|
||||||
max_size=5)
|
max_size=5)
|
||||||
with self.sshpool.item() as ssh:
|
with self.sshpool.item() as ssh:
|
||||||
@ -545,6 +549,7 @@ exit
|
|||||||
channel.close()
|
channel.close()
|
||||||
except Exception:
|
except Exception:
|
||||||
LOG.exception(_LE('Error closing channel.'))
|
LOG.exception(_LE('Error closing channel.'))
|
||||||
|
LOG.debug("_execute_cmd: stdout to return: %s", stdout)
|
||||||
LOG.debug("_execute_cmd: stderr to return: %s", stderr)
|
LOG.debug("_execute_cmd: stderr to return: %s", stderr)
|
||||||
return (stdout, stderr)
|
return (stdout, stderr)
|
||||||
|
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
# (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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Brocade Zone Connector Factory is responsible to dynamically create the
|
||||||
|
connection object based on the configuration
|
||||||
|
"""
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import importutils
|
||||||
|
|
||||||
|
from cinder.zonemanager.drivers.brocade import fc_zone_constants
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class BrcdFCZoneFactory(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.sb_conn_map = {}
|
||||||
|
|
||||||
|
def get_connector(self, fabric, sb_connector):
|
||||||
|
"""Returns Device Connector.
|
||||||
|
|
||||||
|
Factory method to create and return
|
||||||
|
correct SB connector object based on the protocol
|
||||||
|
"""
|
||||||
|
|
||||||
|
fabric_ip = fabric.safe_get('fc_fabric_address')
|
||||||
|
client = self.sb_conn_map.get(fabric_ip)
|
||||||
|
|
||||||
|
if not client:
|
||||||
|
|
||||||
|
fabric_user = fabric.safe_get('fc_fabric_user')
|
||||||
|
fabric_pwd = fabric.safe_get('fc_fabric_password')
|
||||||
|
fabric_port = fabric.safe_get('fc_fabric_port')
|
||||||
|
fabric_ssh_cert_path = fabric.safe_get('fc_fabric_ssh_cert_path')
|
||||||
|
|
||||||
|
LOG.debug("Client not found. Creating connection client for"
|
||||||
|
" %(ip)s with %(connector)s protocol "
|
||||||
|
"for the user %(user)s at port %(port)s.",
|
||||||
|
{'ip': fabric_ip,
|
||||||
|
'connector': sb_connector,
|
||||||
|
'user': fabric_user,
|
||||||
|
'port': fabric_port})
|
||||||
|
|
||||||
|
if sb_connector.lower() in (fc_zone_constants.HTTP,
|
||||||
|
fc_zone_constants.HTTPS):
|
||||||
|
client = importutils.import_object(
|
||||||
|
"cinder.zonemanager.drivers.brocade."
|
||||||
|
"brcd_http_fc_zone_client.BrcdHTTPFCZoneClient",
|
||||||
|
ipaddress=fabric_ip,
|
||||||
|
username=fabric_user,
|
||||||
|
password=fabric_pwd,
|
||||||
|
port=fabric_port,
|
||||||
|
protocol=sb_connector
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
client = importutils.import_object(
|
||||||
|
"cinder.zonemanager.drivers.brocade."
|
||||||
|
"brcd_fc_zone_client_cli.BrcdFCZoneClientCLI",
|
||||||
|
ipaddress=fabric_ip,
|
||||||
|
username=fabric_user,
|
||||||
|
password=fabric_pwd,
|
||||||
|
key=fabric_ssh_cert_path,
|
||||||
|
port=fabric_port
|
||||||
|
)
|
||||||
|
self.sb_conn_map.update({fabric_ip: client})
|
||||||
|
return client
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2015 Brocade Communications Systems Inc.
|
# (c) Copyright 2015 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2015 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -41,17 +39,18 @@ import string
|
|||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder.i18n import _, _LE, _LI, _LW
|
from cinder.i18n import _, _LE, _LI, _LW
|
||||||
from cinder.zonemanager.drivers.brocade import brcd_fabric_opts as fabric_opts
|
from cinder.zonemanager.drivers.brocade import brcd_fabric_opts as fabric_opts
|
||||||
|
from cinder.zonemanager.drivers.brocade import fc_zone_constants
|
||||||
from cinder.zonemanager.drivers import driver_utils
|
from cinder.zonemanager.drivers import driver_utils
|
||||||
from cinder.zonemanager.drivers import fc_zone_driver
|
from cinder.zonemanager.drivers import fc_zone_driver
|
||||||
|
from cinder.zonemanager import utils
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
SUPPORTED_CHARS = string.ascii_letters + string.digits + '_'
|
SUPPORTED_CHARS = string.ascii_letters + string.digits + '_'
|
||||||
brcd_opts = [
|
brcd_opts = [
|
||||||
cfg.StrOpt('brcd_sb_connector',
|
cfg.StrOpt('brcd_sb_connector',
|
||||||
default='cinder.zonemanager.drivers.brocade'
|
default=fc_zone_constants.HTTP.upper(),
|
||||||
'.brcd_fc_zone_client_cli.BrcdFCZoneClientCLI',
|
help='South bound connector for zoning operation'),
|
||||||
help='Southbound connector for zoning operation'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
@ -68,9 +67,10 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
1.0 - Initial Brocade FC zone driver
|
1.0 - Initial Brocade FC zone driver
|
||||||
1.1 - Implements performance enhancements
|
1.1 - Implements performance enhancements
|
||||||
1.2 - Added support for friendly zone name
|
1.2 - Added support for friendly zone name
|
||||||
|
1.3 - Added HTTP connector support
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = "1.2"
|
VERSION = "1.3"
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(BrcdFCZoneDriver, self).__init__(**kwargs)
|
super(BrcdFCZoneDriver, self).__init__(**kwargs)
|
||||||
@ -103,15 +103,6 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
self.fabric_configs = fabric_opts.load_fabric_configurations(
|
self.fabric_configs = fabric_opts.load_fabric_configurations(
|
||||||
fabric_names)
|
fabric_names)
|
||||||
|
|
||||||
def get_formatted_wwn(self, wwn_str):
|
|
||||||
"""Utility API that formats WWN to insert ':'."""
|
|
||||||
wwn_str = wwn_str.encode('ascii')
|
|
||||||
if len(wwn_str) != 16:
|
|
||||||
return wwn_str
|
|
||||||
else:
|
|
||||||
return b':'.join(
|
|
||||||
[wwn_str[i:i + 2] for i in range(0, len(wwn_str), 2)])
|
|
||||||
|
|
||||||
@lockutils.synchronized('brcd', 'fcfabric-', True)
|
@lockutils.synchronized('brcd', 'fcfabric-', True)
|
||||||
def add_connection(self, fabric, initiator_target_map, host_name=None,
|
def add_connection(self, fabric, initiator_target_map, host_name=None,
|
||||||
storage_system=None):
|
storage_system=None):
|
||||||
@ -147,8 +138,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
"no zoning will be performed."))
|
"no zoning will be performed."))
|
||||||
return
|
return
|
||||||
|
|
||||||
cli_client = self._get_cli_client(fabric)
|
client = self._get_southbound_client(fabric)
|
||||||
cfgmap_from_fabric = self._get_active_zone_set(cli_client)
|
cfgmap_from_fabric = self._get_active_zone_set(client)
|
||||||
|
|
||||||
zone_names = []
|
zone_names = []
|
||||||
if cfgmap_from_fabric.get('zones'):
|
if cfgmap_from_fabric.get('zones'):
|
||||||
@ -158,12 +149,11 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
for initiator_key in initiator_target_map.keys():
|
for initiator_key in initiator_target_map.keys():
|
||||||
zone_map = {}
|
zone_map = {}
|
||||||
initiator = initiator_key.lower()
|
initiator = initiator_key.lower()
|
||||||
t_list = initiator_target_map[initiator_key]
|
target_list = initiator_target_map[initiator_key]
|
||||||
if zoning_policy == 'initiator-target':
|
if zoning_policy == 'initiator-target':
|
||||||
for t in t_list:
|
for target in target_list:
|
||||||
target = t.lower()
|
zone_members = [utils.get_formatted_wwn(initiator),
|
||||||
zone_members = [self.get_formatted_wwn(initiator),
|
utils.get_formatted_wwn(target)]
|
||||||
self.get_formatted_wwn(target)]
|
|
||||||
zone_name = driver_utils.get_friendly_zone_name(
|
zone_name = driver_utils.get_friendly_zone_name(
|
||||||
zoning_policy,
|
zoning_policy,
|
||||||
initiator,
|
initiator,
|
||||||
@ -172,8 +162,7 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
storage_system,
|
storage_system,
|
||||||
zone_name_prefix,
|
zone_name_prefix,
|
||||||
SUPPORTED_CHARS)
|
SUPPORTED_CHARS)
|
||||||
if (
|
if (len(cfgmap_from_fabric) == 0 or (
|
||||||
len(cfgmap_from_fabric) == 0 or (
|
|
||||||
zone_name not in zone_names)):
|
zone_name not in zone_names)):
|
||||||
zone_map[zone_name] = zone_members
|
zone_map[zone_name] = zone_members
|
||||||
else:
|
else:
|
||||||
@ -182,10 +171,9 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
"zone creation for %(zonename)s"),
|
"zone creation for %(zonename)s"),
|
||||||
{'zonename': zone_name})
|
{'zonename': zone_name})
|
||||||
elif zoning_policy == 'initiator':
|
elif zoning_policy == 'initiator':
|
||||||
zone_members = [self.get_formatted_wwn(initiator)]
|
zone_members = [utils.get_formatted_wwn(initiator)]
|
||||||
for t in t_list:
|
for target in target_list:
|
||||||
target = t.lower()
|
zone_members.append(utils.get_formatted_wwn(target))
|
||||||
zone_members.append(self.get_formatted_wwn(target))
|
|
||||||
|
|
||||||
zone_name = driver_utils.get_friendly_zone_name(
|
zone_name = driver_utils.get_friendly_zone_name(
|
||||||
zoning_policy,
|
zoning_policy,
|
||||||
@ -208,11 +196,12 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
|
|
||||||
if len(zone_map) > 0:
|
if len(zone_map) > 0:
|
||||||
try:
|
try:
|
||||||
cli_client.add_zones(
|
client.add_zones(
|
||||||
zone_map, zone_activate,
|
zone_map, zone_activate,
|
||||||
cfgmap_from_fabric)
|
cfgmap_from_fabric)
|
||||||
cli_client.cleanup()
|
client.cleanup()
|
||||||
except exception.BrocadeZoningCliException as brocade_ex:
|
except (exception.BrocadeZoningCliException,
|
||||||
|
exception.BrocadeZoningHttpException) as brocade_ex:
|
||||||
raise exception.FCZoneDriverException(brocade_ex)
|
raise exception.FCZoneDriverException(brocade_ex)
|
||||||
except Exception:
|
except Exception:
|
||||||
msg = _("Failed to add zoning configuration.")
|
msg = _("Failed to add zoning configuration.")
|
||||||
@ -248,7 +237,7 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
zoning_policy = zoning_policy_fab
|
zoning_policy = zoning_policy_fab
|
||||||
LOG.info(_LI("Zoning policy for fabric %(policy)s"),
|
LOG.info(_LI("Zoning policy for fabric %(policy)s"),
|
||||||
{'policy': zoning_policy})
|
{'policy': zoning_policy})
|
||||||
conn = self._get_cli_client(fabric)
|
conn = self._get_southbound_client(fabric)
|
||||||
cfgmap_from_fabric = self._get_active_zone_set(conn)
|
cfgmap_from_fabric = self._get_active_zone_set(conn)
|
||||||
|
|
||||||
zone_names = []
|
zone_names = []
|
||||||
@ -262,7 +251,7 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
{'cfgmap': cfgmap_from_fabric})
|
{'cfgmap': cfgmap_from_fabric})
|
||||||
for initiator_key in initiator_target_map.keys():
|
for initiator_key in initiator_target_map.keys():
|
||||||
initiator = initiator_key.lower()
|
initiator = initiator_key.lower()
|
||||||
formatted_initiator = self.get_formatted_wwn(initiator)
|
formatted_initiator = utils.get_formatted_wwn(initiator)
|
||||||
zone_map = {}
|
zone_map = {}
|
||||||
zones_to_delete = []
|
zones_to_delete = []
|
||||||
t_list = initiator_target_map[initiator_key]
|
t_list = initiator_target_map[initiator_key]
|
||||||
@ -290,7 +279,7 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
zone_members = [formatted_initiator]
|
zone_members = [formatted_initiator]
|
||||||
for t in t_list:
|
for t in t_list:
|
||||||
target = t.lower()
|
target = t.lower()
|
||||||
zone_members.append(self.get_formatted_wwn(target))
|
zone_members.append(utils.get_formatted_wwn(target))
|
||||||
|
|
||||||
zone_name = driver_utils.get_friendly_zone_name(
|
zone_name = driver_utils.get_friendly_zone_name(
|
||||||
zoning_policy,
|
zoning_policy,
|
||||||
@ -353,8 +342,12 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
zone_name_string, zone_activate,
|
zone_name_string, zone_activate,
|
||||||
cfgmap_from_fabric)
|
cfgmap_from_fabric)
|
||||||
conn.cleanup()
|
conn.cleanup()
|
||||||
|
except (exception.BrocadeZoningCliException,
|
||||||
|
exception.BrocadeZoningHttpException) as brocade_ex:
|
||||||
|
raise exception.FCZoneDriverException(brocade_ex)
|
||||||
except Exception:
|
except Exception:
|
||||||
msg = _("Failed to update or delete zoning configuration")
|
msg = _("Failed to update or delete zoning "
|
||||||
|
"configuration.")
|
||||||
LOG.exception(msg)
|
LOG.exception(msg)
|
||||||
raise exception.FCZoneDriverException(msg)
|
raise exception.FCZoneDriverException(msg)
|
||||||
|
|
||||||
@ -364,7 +357,6 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
Look up each SAN configured and return a map of SAN (fabric IP) to
|
Look up each SAN configured and return a map of SAN (fabric IP) to
|
||||||
list of target WWNs visible to the fabric.
|
list of target WWNs visible to the fabric.
|
||||||
"""
|
"""
|
||||||
# TODO(Santhosh Kolathur): consider refactoring to use lookup service.
|
|
||||||
formatted_target_list = []
|
formatted_target_list = []
|
||||||
fabric_map = {}
|
fabric_map = {}
|
||||||
fc_fabric_names = self.configuration.fc_fabric_names
|
fc_fabric_names = self.configuration.fc_fabric_names
|
||||||
@ -374,11 +366,11 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
{'targetwwns': target_wwn_list})
|
{'targetwwns': target_wwn_list})
|
||||||
if len(fabrics) > 0:
|
if len(fabrics) > 0:
|
||||||
for t in target_wwn_list:
|
for t in target_wwn_list:
|
||||||
formatted_target_list.append(self.get_formatted_wwn(t.lower()))
|
formatted_target_list.append(utils.get_formatted_wwn(t))
|
||||||
LOG.debug("Formatted target WWN list: %(targetlist)s",
|
LOG.debug("Formatted target WWN list: %(targetlist)s",
|
||||||
{'targetlist': formatted_target_list})
|
{'targetlist': formatted_target_list})
|
||||||
for fabric_name in fabrics:
|
for fabric_name in fabrics:
|
||||||
conn = self._get_cli_client(fabric_name)
|
conn = self._get_southbound_client(fabric_name)
|
||||||
|
|
||||||
# Get name server data from fabric and get the targets
|
# Get name server data from fabric and get the targets
|
||||||
# logged in.
|
# logged in.
|
||||||
@ -388,12 +380,13 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
LOG.debug("Name server info from fabric: %(nsinfo)s",
|
LOG.debug("Name server info from fabric: %(nsinfo)s",
|
||||||
{'nsinfo': nsinfo})
|
{'nsinfo': nsinfo})
|
||||||
conn.cleanup()
|
conn.cleanup()
|
||||||
except exception.BrocadeZoningCliException:
|
except (exception.BrocadeZoningCliException,
|
||||||
|
exception.BrocadeZoningHttpException):
|
||||||
if not conn.is_supported_firmware():
|
if not conn.is_supported_firmware():
|
||||||
msg = _("Unsupported firmware on switch %s. Make sure "
|
msg = _("Unsupported firmware on switch %s. Make sure "
|
||||||
"switch is running firmware v6.4 or higher"
|
"switch is running firmware v6.4 or higher"
|
||||||
) % conn.switch_ip
|
) % conn.switch_ip
|
||||||
LOG.error(msg)
|
LOG.exception(msg)
|
||||||
raise exception.FCZoneDriverException(msg)
|
raise exception.FCZoneDriverException(msg)
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
LOG.exception(_LE("Error getting name server info."))
|
LOG.exception(_LE("Error getting name server info."))
|
||||||
@ -425,41 +418,47 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver):
|
|||||||
cfgmap = None
|
cfgmap = None
|
||||||
try:
|
try:
|
||||||
cfgmap = conn.get_active_zone_set()
|
cfgmap = conn.get_active_zone_set()
|
||||||
except exception.BrocadeZoningCliException:
|
except (exception.BrocadeZoningCliException,
|
||||||
|
exception.BrocadeZoningHttpException):
|
||||||
if not conn.is_supported_firmware():
|
if not conn.is_supported_firmware():
|
||||||
msg = _("Unsupported firmware on switch %s. Make sure "
|
msg = _("Unsupported firmware on switch %s. Make sure "
|
||||||
"switch is running firmware v6.4 or higher"
|
"switch is running firmware v6.4 or higher"
|
||||||
) % conn.switch_ip
|
) % conn.switch_ip
|
||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise exception.FCZoneDriverException(msg)
|
raise exception.FCZoneDriverException(msg)
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
LOG.exception(_LE("Error getting name server info."))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
msg = (_("Failed to retrieve active zoning configuration %s")
|
msg = (_("Failed to retrieve active zoning configuration %s")
|
||||||
% six.text_type(e))
|
% six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
raise exception.FCZoneDriverException(msg)
|
raise exception.FCZoneDriverException(msg)
|
||||||
LOG.debug("Active zone set from fabric: %(cfgmap)s",
|
LOG.debug("Active zone set from fabric: %(cfgmap)s",
|
||||||
{'cfgmap': cfgmap})
|
{'cfgmap': cfgmap})
|
||||||
return cfgmap
|
return cfgmap
|
||||||
|
|
||||||
def _get_cli_client(self, fabric):
|
def _get_southbound_client(self, fabric):
|
||||||
fabric_ip = self.fabric_configs[fabric].safe_get('fc_fabric_address')
|
"""Implementation to get SouthBound Connector.
|
||||||
fabric_user = self.fabric_configs[fabric].safe_get('fc_fabric_user')
|
|
||||||
fabric_pwd = self.fabric_configs[fabric].safe_get('fc_fabric_password')
|
South bound connector will be
|
||||||
fabric_port = self.fabric_configs[fabric].safe_get('fc_fabric_port')
|
dynamically selected based on the configuration
|
||||||
cli_client = None
|
|
||||||
|
:param fabric: fabric information
|
||||||
|
"""
|
||||||
|
fabric_info = self.fabric_configs[fabric]
|
||||||
|
fc_ip = fabric_info.safe_get('fc_fabric_address')
|
||||||
|
sb_connector = fabric_info.safe_get('fc_southbound_protocol')
|
||||||
|
if sb_connector is None:
|
||||||
|
sb_connector = self.configuration.brcd_sb_connector
|
||||||
try:
|
try:
|
||||||
cli_client = self.sb_conn_map.get(fabric_ip)
|
conn_factory = importutils.import_object(
|
||||||
if not cli_client:
|
"cinder.zonemanager.drivers.brocade."
|
||||||
LOG.debug("CLI client not found, creating for %(ip)s",
|
"brcd_fc_zone_connector_factory."
|
||||||
{'ip': fabric_ip})
|
"BrcdFCZoneFactory")
|
||||||
cli_client = importutils.import_object(
|
client = conn_factory.get_connector(fabric_info,
|
||||||
self.configuration.brcd_sb_connector,
|
sb_connector.upper())
|
||||||
ipaddress=fabric_ip,
|
except Exception:
|
||||||
username=fabric_user,
|
msg = _("Failed to create south bound connector for %s.") % fc_ip
|
||||||
password=fabric_pwd,
|
LOG.exception(msg)
|
||||||
port=fabric_port)
|
|
||||||
self.sb_conn_map[fabric_ip] = cli_client
|
|
||||||
except Exception as e:
|
|
||||||
LOG.error(e)
|
|
||||||
msg = _("Failed to create sb connector for %s") % fabric_ip
|
|
||||||
raise exception.FCZoneDriverException(msg)
|
raise exception.FCZoneDriverException(msg)
|
||||||
return cli_client
|
return client
|
||||||
|
734
cinder/zonemanager/drivers/brocade/brcd_http_fc_zone_client.py
Normal file
734
cinder/zonemanager/drivers/brocade/brcd_http_fc_zone_client.py
Normal file
@ -0,0 +1,734 @@
|
|||||||
|
# (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.
|
||||||
|
#
|
||||||
|
"""
|
||||||
|
Brocade south bound connector to communicate with switch using
|
||||||
|
HTTP or HTTPS protocol.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
import requests
|
||||||
|
import six
|
||||||
|
import time
|
||||||
|
|
||||||
|
from cinder import exception
|
||||||
|
from cinder.i18n import _
|
||||||
|
import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant
|
||||||
|
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class BrcdHTTPFCZoneClient(object):
|
||||||
|
|
||||||
|
def __init__(self, ipaddress, username,
|
||||||
|
password, port, protocol):
|
||||||
|
"""Initializing the client with the parameters passed.
|
||||||
|
|
||||||
|
Creates authentication token and authenticate with switch
|
||||||
|
to ensure the credentials are correct.
|
||||||
|
|
||||||
|
:param ipaddress: IP Address of the device.
|
||||||
|
:param username: User id to login.
|
||||||
|
:param password: User password.
|
||||||
|
:param port: Device Communication port
|
||||||
|
:param protocol: Communication Protocol.
|
||||||
|
"""
|
||||||
|
self.switch_ip = ipaddress
|
||||||
|
self.switch_user = username
|
||||||
|
self.switch_pwd = password
|
||||||
|
self.protocol = protocol
|
||||||
|
self.cfgs = {}
|
||||||
|
self.zones = {}
|
||||||
|
self.alias = {}
|
||||||
|
self.qlps = {}
|
||||||
|
self.ifas = {}
|
||||||
|
self.active_cfg = ''
|
||||||
|
self.parsed_raw_zoneinfo = ""
|
||||||
|
self.random_no = ''
|
||||||
|
self.session = None
|
||||||
|
|
||||||
|
# Create and assign the authentication header based on the credentials
|
||||||
|
self.auth_header = self.create_auth_token()
|
||||||
|
|
||||||
|
# Authenticate with the switch
|
||||||
|
# If authenticated successfully, save the auth status and
|
||||||
|
# create auth header for future communication with the device.
|
||||||
|
self.is_auth, self.auth_header = self.authenticate()
|
||||||
|
|
||||||
|
def connect(self, requestType, requestURL, payload='', header=None):
|
||||||
|
"""Connect to the switch using HTTP/HTTPS protocol.
|
||||||
|
|
||||||
|
:param requestType: Connection Request method
|
||||||
|
:param requestURL: Connection URL
|
||||||
|
:param payload: Data to send with POST request
|
||||||
|
:param header: Request Headers
|
||||||
|
|
||||||
|
:returns: HTTP response data
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if header is None:
|
||||||
|
header = {}
|
||||||
|
header.update({"User-Agent": "OpenStack Zone Driver"})
|
||||||
|
|
||||||
|
# Ensure only one connection is made throughout the life cycle
|
||||||
|
protocol = zone_constant.HTTP
|
||||||
|
if self.protocol == zone_constant.PROTOCOL_HTTPS:
|
||||||
|
protocol = zone_constant.HTTPS
|
||||||
|
if self.session is None:
|
||||||
|
self.session = requests.Session()
|
||||||
|
adapter = requests.adapters.HTTPAdapter(pool_connections=1,
|
||||||
|
pool_maxsize=1)
|
||||||
|
self.session.mount(protocol + '://', adapter)
|
||||||
|
url = protocol + "://" + self.switch_ip + requestURL
|
||||||
|
response = None
|
||||||
|
if requestType == zone_constant.GET_METHOD:
|
||||||
|
response = self.session.get(url,
|
||||||
|
headers=(header),
|
||||||
|
verify=False)
|
||||||
|
elif requestType == zone_constant.POST_METHOD:
|
||||||
|
response = self.session.post(url,
|
||||||
|
payload,
|
||||||
|
headers=(header),
|
||||||
|
verify=False)
|
||||||
|
|
||||||
|
# Throw exception when response status is not OK
|
||||||
|
if response.status_code != zone_constant.STATUS_OK:
|
||||||
|
msg = _("Error while querying page %(url)s on the switch, "
|
||||||
|
"reason %(error)s.") % {'url': url,
|
||||||
|
'error': response.reason}
|
||||||
|
raise exception.BrocadeZoningHttpException(msg)
|
||||||
|
else:
|
||||||
|
return response.text
|
||||||
|
except requests.exceptions.ConnectionError as e:
|
||||||
|
msg = (_("Error while connecting the switch %(switch_id)s "
|
||||||
|
"with protocol %(protocol)s. Error: %(error)s.")
|
||||||
|
% {'switch_id': self.switch_ip,
|
||||||
|
'protocol': self.protocol,
|
||||||
|
'error': six.text_type(e)})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
except exception.BrocadeZoningHttpException as ex:
|
||||||
|
msg = (_("Unexpected status code from the switch %(switch_id)s "
|
||||||
|
"with protocol %(protocol)s for url %(page)s. "
|
||||||
|
"Error: %(error)s")
|
||||||
|
% {'switch_id': self.switch_ip,
|
||||||
|
'protocol': self.protocol,
|
||||||
|
'page': requestURL,
|
||||||
|
'error': six.text_type(ex)})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def create_auth_token(self):
|
||||||
|
"""Create the authentication token.
|
||||||
|
|
||||||
|
Creates the authentication token to use in the authentication header
|
||||||
|
return authentication header (Base64(username:password:random no)).
|
||||||
|
|
||||||
|
:returns: Authentication Header
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Send GET request to secinfo.html to get random number
|
||||||
|
response = self.connect(zone_constant.GET_METHOD,
|
||||||
|
zone_constant.SECINFO_PAGE)
|
||||||
|
parsed_data = self.get_parsed_data(response,
|
||||||
|
zone_constant.SECINFO_BEGIN,
|
||||||
|
zone_constant.SECINFO_END)
|
||||||
|
|
||||||
|
# Extract the random no from secinfo.html response
|
||||||
|
self.random_no = self.get_nvp_value(parsed_data,
|
||||||
|
zone_constant.RANDOM)
|
||||||
|
# Form the authentication string
|
||||||
|
auth_string = (self.switch_user + ":" + self.switch_pwd +
|
||||||
|
":" + self.random_no)
|
||||||
|
auth_token = auth_string.encode(
|
||||||
|
"base64", "strict").strip() # encode in base64 format
|
||||||
|
auth_header = (zone_constant.AUTH_STRING +
|
||||||
|
auth_token) # Build the proper header
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Error while creating authentication token: %s")
|
||||||
|
% six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
return auth_header
|
||||||
|
|
||||||
|
def authenticate(self):
|
||||||
|
"""Authenticate with the switch.
|
||||||
|
|
||||||
|
Returns authentication status with modified authentication
|
||||||
|
header (Base64(username:xxx:random no)).
|
||||||
|
|
||||||
|
:returns: Authentication status
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
headers = {zone_constant.AUTH_HEADER: self.auth_header}
|
||||||
|
try:
|
||||||
|
# GET Request to authenticate.html to verify the credentials
|
||||||
|
response = self.connect(zone_constant.GET_METHOD,
|
||||||
|
zone_constant.AUTHEN_PAGE,
|
||||||
|
header=headers)
|
||||||
|
parsed_data = self.get_parsed_data(response,
|
||||||
|
zone_constant.AUTHEN_BEGIN,
|
||||||
|
zone_constant.AUTHEN_END)
|
||||||
|
isauthenticated = self.get_nvp_value(
|
||||||
|
parsed_data, zone_constant.AUTHENTICATED)
|
||||||
|
if isauthenticated == "yes":
|
||||||
|
# Replace password in the authentication string with xxx
|
||||||
|
auth_string = (self.switch_user +
|
||||||
|
":" + "xxx" + ":" + self.random_no)
|
||||||
|
auth_token = auth_string.encode("base64", "strict").strip()
|
||||||
|
auth_header = zone_constant.AUTH_STRING + auth_token
|
||||||
|
return True, auth_header
|
||||||
|
else:
|
||||||
|
auth_error_code = self.get_nvp_value(parsed_data, "errCode")
|
||||||
|
msg = (_("Authentication failed, verify the switch "
|
||||||
|
"credentials, error code %s.") % auth_error_code)
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Error while authenticating with switch: %s.")
|
||||||
|
% six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def get_session_info(self):
|
||||||
|
"""Get the session information from the switch
|
||||||
|
|
||||||
|
:returns: Connection status information.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
headers = {zone_constant.AUTH_HEADER: self.auth_header}
|
||||||
|
# GET request to session.html
|
||||||
|
response = self.connect(zone_constant.GET_METHOD,
|
||||||
|
zone_constant.SESSION_PAGE_ACTION,
|
||||||
|
header=headers)
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Error while getting session information %s.")
|
||||||
|
% six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def get_parsed_data(self, data, delim1, demil2):
|
||||||
|
"""Return the sub string between the delimiters.
|
||||||
|
|
||||||
|
:param data: String to manipulate
|
||||||
|
:param delim1 : Delimiter 1
|
||||||
|
:param delim2 : Delimiter 2
|
||||||
|
:returns: substring between the delimiters
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
start = data.index(delim1)
|
||||||
|
start = start + len(delim1)
|
||||||
|
end = data.index(demil2)
|
||||||
|
return data[start:end]
|
||||||
|
except ValueError as e:
|
||||||
|
msg = (_("Error while parsing the data: %s.") % six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def get_nvp_value(self, data, keyname):
|
||||||
|
"""Get the value for the key passed.
|
||||||
|
|
||||||
|
:param data: NVP to manipulate
|
||||||
|
:param keyname: Key name
|
||||||
|
:returns: value for the NVP
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
start = data.index(keyname)
|
||||||
|
start = start + len(keyname)
|
||||||
|
temp = data[start:]
|
||||||
|
end = temp.index("\n")
|
||||||
|
return (temp[:end].lstrip('= '))
|
||||||
|
except ValueError as e:
|
||||||
|
msg = (_("Error while getting nvp value: %s.") % six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def get_zone_info(self):
|
||||||
|
"""Parse all the zone information and store it in the dictionary."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.cfgs = {}
|
||||||
|
self.zones = {}
|
||||||
|
self.active_cfg = ''
|
||||||
|
self.alias = {}
|
||||||
|
self.qlps = {}
|
||||||
|
self.ifas = {}
|
||||||
|
headers = {zone_constant.AUTH_HEADER: self.auth_header}
|
||||||
|
# GET request to gzoneinfo.htm
|
||||||
|
response = self.connect(zone_constant.GET_METHOD,
|
||||||
|
zone_constant.ZONE_PAGE,
|
||||||
|
header=headers)
|
||||||
|
# get the zone string from the response
|
||||||
|
self.parsed_raw_zoneinfo = self.get_parsed_data(
|
||||||
|
response,
|
||||||
|
zone_constant.ZONEINFO_BEGIN,
|
||||||
|
zone_constant.ZONEINFO_END).strip("\n")
|
||||||
|
LOG.debug("Original zone string from the switch: %(zoneinfo)s",
|
||||||
|
{'zoneinfo': self.parsed_raw_zoneinfo})
|
||||||
|
# convert the zone string to list
|
||||||
|
zoneinfo = self.parsed_raw_zoneinfo.split()
|
||||||
|
i = 0
|
||||||
|
while i < len(zoneinfo):
|
||||||
|
info = zoneinfo[i]
|
||||||
|
# check for the cfg delimiter
|
||||||
|
if zone_constant.CFG_DELIM in info:
|
||||||
|
# extract the cfg name
|
||||||
|
cfg_name = info.lstrip(zone_constant.CFG_DELIM)
|
||||||
|
# update the dict as
|
||||||
|
# self.cfgs={cfg_name:zone_name1;zone_name2}
|
||||||
|
self.cfgs.update({cfg_name: zoneinfo[i + 1]})
|
||||||
|
i = i + 2
|
||||||
|
# check for the zone delimiter
|
||||||
|
elif zone_constant.ZONE_DELIM in info:
|
||||||
|
# extract the zone name
|
||||||
|
zone_name = info.lstrip(zone_constant.ZONE_DELIM)
|
||||||
|
# update the dict as
|
||||||
|
# self.zones={zone_name:members1;members2}
|
||||||
|
self.zones.update({zone_name: zoneinfo[i + 1]})
|
||||||
|
i = i + 2
|
||||||
|
elif zone_constant.ALIAS_DELIM in info:
|
||||||
|
alias_name = info.lstrip(zone_constant.ALIAS_DELIM)
|
||||||
|
# update the dict as
|
||||||
|
# self.alias={alias_name:members1;members2}
|
||||||
|
self.alias.update({alias_name: zoneinfo[i + 1]})
|
||||||
|
i = i + 2
|
||||||
|
# check for quickloop zones
|
||||||
|
elif zone_constant.QLP_DELIM in info:
|
||||||
|
qlp_name = info.lstrip(zone_constant.QLP_DELIM)
|
||||||
|
# update the map as self.qlps={qlp_name:members1;members2}
|
||||||
|
self.qlps.update({qlp_name: zoneinfo[i + 1]})
|
||||||
|
i = i + 2
|
||||||
|
# check for fabric assist zones
|
||||||
|
elif zone_constant.IFA_DELIM in info:
|
||||||
|
ifa_name = info.lstrip(zone_constant.IFA_DELIM)
|
||||||
|
# update the map as self.ifas={ifa_name:members1;members2}
|
||||||
|
self.ifas.update({ifa_name: zoneinfo[i + 1]})
|
||||||
|
i = i + 2
|
||||||
|
elif zone_constant.ACTIVE_CFG_DELIM in info:
|
||||||
|
# update the string self.active_cfg=cfg_name
|
||||||
|
self.active_cfg = info.lstrip(
|
||||||
|
zone_constant.ACTIVE_CFG_DELIM)
|
||||||
|
if self.active_cfg == zone_constant.DEFAULT_CFG:
|
||||||
|
self.active_cfg = ""
|
||||||
|
i = i + 2
|
||||||
|
else:
|
||||||
|
i = i + 1
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Error while changing VF context %s.") % six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def is_supported_firmware(self):
|
||||||
|
"""Check firmware version is v6.4 or higher.
|
||||||
|
|
||||||
|
This API checks if the firmware version per the plug-in support level.
|
||||||
|
This only checks major and minor version.
|
||||||
|
|
||||||
|
:returns: True if firmware is supported else False.
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
|
||||||
|
isfwsupported = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
headers = {zone_constant.AUTH_HEADER: self.auth_header}
|
||||||
|
# GET request to switch.html
|
||||||
|
response = self.connect(zone_constant.GET_METHOD,
|
||||||
|
zone_constant.SWITCH_PAGE,
|
||||||
|
header=headers)
|
||||||
|
parsed_data = self.get_parsed_data(response,
|
||||||
|
zone_constant.SWITCHINFO_BEGIN,
|
||||||
|
zone_constant.SWITCHINFO_END)
|
||||||
|
|
||||||
|
# get the firmware version nvp value
|
||||||
|
fwVersion = self.get_nvp_value(
|
||||||
|
parsed_data,
|
||||||
|
zone_constant.FIRMWARE_VERSION).lstrip('v')
|
||||||
|
|
||||||
|
ver = fwVersion.split(".")
|
||||||
|
LOG.debug("Firmware version: %(version)s.", {'version': ver})
|
||||||
|
if int(ver[0] + ver[1]) > 63:
|
||||||
|
isfwsupported = True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Error while checking the firmware version %s.")
|
||||||
|
% six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
return isfwsupported
|
||||||
|
|
||||||
|
def get_active_zone_set(self):
|
||||||
|
"""Return the active zone configuration.
|
||||||
|
|
||||||
|
Return active zoneset from fabric. When none of the configurations
|
||||||
|
are active then it will return empty map.
|
||||||
|
|
||||||
|
:returns: Map -- active zone set map in the following format
|
||||||
|
{
|
||||||
|
'zones':
|
||||||
|
{'openstack50060b0000c26604201900051ee8e329':
|
||||||
|
['50060b0000c26604', '201900051ee8e329']
|
||||||
|
},
|
||||||
|
'active_zone_config': 'OpenStack_Cfg'
|
||||||
|
}
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
active_zone_set = {}
|
||||||
|
zones_map = {}
|
||||||
|
try:
|
||||||
|
self.get_zone_info() # get the zone information of the switch
|
||||||
|
if self.active_cfg != '':
|
||||||
|
# get the zones list of the active_Cfg
|
||||||
|
zones_list = self.cfgs[self.active_cfg].split(";")
|
||||||
|
for n in zones_list:
|
||||||
|
# build the zones map
|
||||||
|
zones_map.update(
|
||||||
|
{n: self.zones[n].split(";")})
|
||||||
|
# Format map in the correct format
|
||||||
|
active_zone_set = {
|
||||||
|
"active_zone_config": self.active_cfg, "zones": zones_map}
|
||||||
|
return active_zone_set
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Failed getting active zone set from fabric %s.")
|
||||||
|
% six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def add_zones(self, add_zones_info, activate, active_zone_set=None):
|
||||||
|
"""Add zone configuration.
|
||||||
|
|
||||||
|
This method will add the zone configuration passed by user.
|
||||||
|
|
||||||
|
:param add_zones_info: Zone names mapped to members.
|
||||||
|
zone members are colon separated but case-insensitive
|
||||||
|
{ zonename1:[zonememeber1,zonemember2,...],
|
||||||
|
zonename2:[zonemember1, zonemember2,...]...}
|
||||||
|
e.g: {'openstack50060b0000c26604201900051ee8e329':
|
||||||
|
['50:06:0b:00:00:c2:66:04', '20:19:00:05:1e:e8:e3:29']
|
||||||
|
}R
|
||||||
|
:param activate: True will activate the zone config.
|
||||||
|
:param active_zone_set: Active zone set dict retrieved from
|
||||||
|
get_active_zone_set method
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
LOG.debug("Add zones - zones passed: %(zones)s.",
|
||||||
|
{'zones': add_zones_info})
|
||||||
|
cfg_name = zone_constant.CFG_NAME
|
||||||
|
cfgs = self.cfgs
|
||||||
|
zones = self.zones
|
||||||
|
alias = self.alias
|
||||||
|
qlps = self.qlps
|
||||||
|
ifas = self.ifas
|
||||||
|
active_cfg = self.active_cfg
|
||||||
|
# update the active_cfg, zones and cfgs map with new information
|
||||||
|
zones, cfgs, active_cfg = self.add_update_zones_cfgs(cfgs,
|
||||||
|
zones,
|
||||||
|
add_zones_info,
|
||||||
|
active_cfg,
|
||||||
|
cfg_name)
|
||||||
|
# Build the zonestring with updated maps
|
||||||
|
data = self.form_zone_string(cfgs,
|
||||||
|
active_cfg,
|
||||||
|
zones,
|
||||||
|
alias,
|
||||||
|
qlps,
|
||||||
|
ifas,
|
||||||
|
activate)
|
||||||
|
LOG.debug("Add zones: final zone string after applying "
|
||||||
|
"to the switch: %(zonestring)s", {'zonestring': data})
|
||||||
|
# Post the zone data to the switch
|
||||||
|
error_code, error_msg = self.post_zone_data(data)
|
||||||
|
if error_code != "0":
|
||||||
|
msg = (_("Applying the zones and cfgs to the switch failed "
|
||||||
|
"(error code=%(err_code)s error msg=%(err_msg)s.")
|
||||||
|
% {'err_code': error_code, 'err_msg': error_msg})
|
||||||
|
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def form_zone_string(self, cfgs, active_cfg,
|
||||||
|
zones, alias, qlps, ifas, activate):
|
||||||
|
"""Build the zone string in the required format.
|
||||||
|
|
||||||
|
:param cfgs: cfgs map
|
||||||
|
:param active_cfg: Active cfg string
|
||||||
|
:param zones: zones map
|
||||||
|
:param alias: alias map
|
||||||
|
:param qlps: qlps map
|
||||||
|
:param ifas: ifas map
|
||||||
|
:param activate: True will activate config.
|
||||||
|
:returns: zonestring in the required format
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
zoneString = zone_constant.ZONE_STRING_PREFIX
|
||||||
|
|
||||||
|
# based on the activate save only will be changed
|
||||||
|
saveonly = "false" if activate is True else "true"
|
||||||
|
|
||||||
|
# Form the zone string based on the dictionary of each items
|
||||||
|
for cfg in cfgs.keys():
|
||||||
|
zoneString += (zone_constant.CFG_DELIM +
|
||||||
|
cfg + " " + cfgs.get(cfg) + " ")
|
||||||
|
for zone in zones.keys():
|
||||||
|
zoneString += (zone_constant.ZONE_DELIM +
|
||||||
|
zone + " " + zones.get(zone) + " ")
|
||||||
|
for al in alias.keys():
|
||||||
|
zoneString += (zone_constant.ALIAS_DELIM +
|
||||||
|
al + " " + alias.get(al) + " ")
|
||||||
|
for qlp in qlps.keys():
|
||||||
|
zoneString += (zone_constant.QLP_DELIM +
|
||||||
|
qlp + " " + qlps.get(qlp) + " ")
|
||||||
|
for ifa in ifas.keys():
|
||||||
|
zoneString += (zone_constant.IFA_DELIM +
|
||||||
|
ifa + " " + ifas.get(ifa) + " ")
|
||||||
|
# append the active_cfg string only if it is not null and activate
|
||||||
|
# is true
|
||||||
|
if active_cfg != "" and activate:
|
||||||
|
zoneString += (zone_constant.ACTIVE_CFG_DELIM +
|
||||||
|
active_cfg + " null ")
|
||||||
|
# Build the final zone string
|
||||||
|
zoneString += zone_constant.ZONE_END_DELIM + saveonly
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Exception while forming the zone string: %s.")
|
||||||
|
% six.text_type(e))
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
return zoneString
|
||||||
|
|
||||||
|
def add_update_zones_cfgs(self, cfgs, zones, add_zones_info,
|
||||||
|
active_cfg, cfg_name):
|
||||||
|
"""Add or update the zones and cfgs map based on the new zones info.
|
||||||
|
|
||||||
|
This method will return the updated zones,cfgs and active_cfg
|
||||||
|
|
||||||
|
:param cfgs: Existing cfgs map
|
||||||
|
:param active_cfg: Existing Active cfg string
|
||||||
|
:param zones: Existing zones map
|
||||||
|
:param add_zones_info :Zones map to add
|
||||||
|
:param active_cfg :Existing active cfg
|
||||||
|
:param cfg_name : New cfg name
|
||||||
|
:returns: updated zones, zone configs map, and active_cfg
|
||||||
|
"""
|
||||||
|
cfg_string = ""
|
||||||
|
delimiter = ""
|
||||||
|
zones_in_active_cfg = ""
|
||||||
|
try:
|
||||||
|
if active_cfg:
|
||||||
|
zones_in_active_cfg = cfgs.get(active_cfg)
|
||||||
|
for zone_name, members in add_zones_info.items():
|
||||||
|
# if new zone is not active_cfg, build the cfg string with the
|
||||||
|
# new zones
|
||||||
|
if zone_name not in zones_in_active_cfg:
|
||||||
|
cfg_string += delimiter + zone_name
|
||||||
|
delimiter = ";"
|
||||||
|
# update the zone string
|
||||||
|
# if zone name already exists and dont have the new members
|
||||||
|
# already
|
||||||
|
if (zone_name in zones and set(members)
|
||||||
|
!= set(zones.get(zone_name).split(";"))):
|
||||||
|
# update the existing zone with new members
|
||||||
|
zones.update(
|
||||||
|
{zone_name: (";".join(members) +
|
||||||
|
";" + zones.get(zone_name))})
|
||||||
|
else:
|
||||||
|
# add a new zone with the members
|
||||||
|
zones.update({zone_name: ";".join(members)})
|
||||||
|
# update cfg string
|
||||||
|
if active_cfg:
|
||||||
|
if cfg_string:
|
||||||
|
# update the existing active cfg map with cfgs string
|
||||||
|
cfgs.update(
|
||||||
|
{active_cfg: cfg_string + ";" + cfgs.get(active_cfg)})
|
||||||
|
else:
|
||||||
|
# create new cfg and update that cfgs map with the new cfg
|
||||||
|
active_cfg = cfg_name
|
||||||
|
cfgs.update({cfg_name: cfg_string})
|
||||||
|
except Exception as e:
|
||||||
|
msg = (_("Error while updating the new zones and cfgs "
|
||||||
|
"in the zone string. Error %(description)s.")
|
||||||
|
% {'description': six.text_type(e)})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
return zones, cfgs, active_cfg
|
||||||
|
|
||||||
|
def get_nameserver_info(self):
|
||||||
|
"""Get name server data from fabric.
|
||||||
|
|
||||||
|
Return the connected node port wwn list(local
|
||||||
|
and remote) for the given switch fabric.
|
||||||
|
|
||||||
|
:returns: name server information.
|
||||||
|
"""
|
||||||
|
nsinfo = []
|
||||||
|
headers = {zone_constant.AUTH_HEADER: self.auth_header}
|
||||||
|
response = self.connect(zone_constant.GET_METHOD,
|
||||||
|
zone_constant.NS_PAGE,
|
||||||
|
header=headers) # GET request to nsinfo.html
|
||||||
|
parsed_raw_zoneinfo = self.get_parsed_data(
|
||||||
|
response,
|
||||||
|
zone_constant.NSINFO_BEGIN,
|
||||||
|
zone_constant.NSINFO_END).strip("\t\n\r")
|
||||||
|
# build the name server information in the correct format
|
||||||
|
for line in parsed_raw_zoneinfo.splitlines():
|
||||||
|
start_index = line.find(zone_constant.NS_DELIM) + 7
|
||||||
|
if start_index != -1:
|
||||||
|
nsinfo.extend([line[start_index:start_index + 23].strip()])
|
||||||
|
return nsinfo
|
||||||
|
|
||||||
|
def delete_update_zones_cfgs(
|
||||||
|
self, cfgs, zones,
|
||||||
|
delete_zones_info, active_cfg):
|
||||||
|
"""Add or update the zones and cfgs map based on the new zones info.
|
||||||
|
|
||||||
|
Return the updated zones, cfgs and active_cfg after deleting the
|
||||||
|
required items.
|
||||||
|
|
||||||
|
:param cfgs: Existing cfgs map
|
||||||
|
:param active_cfg: Existing Active cfg string
|
||||||
|
:param zones: Existing zones map
|
||||||
|
:param delete_zones_info :Zones map to add
|
||||||
|
:param active_cfg :Existing active cfg
|
||||||
|
:returns: updated zones, zone config sets, and active zone config
|
||||||
|
:raises: BrocadeZoningHttpException
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
delete_zones_info = delete_zones_info.split(";")
|
||||||
|
for zone in delete_zones_info:
|
||||||
|
# remove the zones from the zone map
|
||||||
|
zones.pop(zone)
|
||||||
|
# iterated all the cfgs, but need to check since in SSH only
|
||||||
|
# active cfg is iterated
|
||||||
|
for k, v in cfgs.items():
|
||||||
|
v = v.split(";")
|
||||||
|
if zone in v:
|
||||||
|
# remove the zone from the cfg string
|
||||||
|
v.remove(zone)
|
||||||
|
# if all the zones are removed, remove the cfg from the
|
||||||
|
# cfg map
|
||||||
|
if not v:
|
||||||
|
cfgs.pop(k)
|
||||||
|
# update the original cfg with the updated string
|
||||||
|
else:
|
||||||
|
cfgs[k] = ";".join(v)
|
||||||
|
|
||||||
|
# if all the zones are removed in the active_cfg, update it with
|
||||||
|
# empty string
|
||||||
|
if active_cfg not in cfgs:
|
||||||
|
active_cfg = ""
|
||||||
|
except KeyError as e:
|
||||||
|
msg = (_("Error while removing the zones and cfgs "
|
||||||
|
"in the zone string: %(description)s.")
|
||||||
|
% {'description': six.text_type(e)})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
return zones, cfgs, active_cfg
|
||||||
|
|
||||||
|
def delete_zones(self, delete_zones_info, activate, active_zone_set=None):
|
||||||
|
"""Delete zones from fabric.
|
||||||
|
|
||||||
|
Deletes zones in the active zone config.
|
||||||
|
|
||||||
|
:param zone_names: zoneNames separated by semicolon
|
||||||
|
:param activate: True/False
|
||||||
|
:param active_zone_set: the active zone set dict retrieved
|
||||||
|
from get_active_zone_set method
|
||||||
|
"""
|
||||||
|
cfgs = self.cfgs
|
||||||
|
zones = self.zones
|
||||||
|
alias = self.alias
|
||||||
|
qlps = self.qlps
|
||||||
|
ifas = self.ifas
|
||||||
|
active_cfg = self.active_cfg
|
||||||
|
# update the active_cfg, zones and cfgs map with required information
|
||||||
|
# being removed
|
||||||
|
zones, cfgs, active_cfg = self.delete_update_zones_cfgs(
|
||||||
|
cfgs,
|
||||||
|
zones,
|
||||||
|
delete_zones_info,
|
||||||
|
active_cfg)
|
||||||
|
# Build the zonestring with updated maps
|
||||||
|
data = self.form_zone_string(cfgs,
|
||||||
|
active_cfg,
|
||||||
|
zones,
|
||||||
|
alias,
|
||||||
|
qlps,
|
||||||
|
ifas,
|
||||||
|
activate)
|
||||||
|
LOG.debug("Delete zones: final zone string after applying "
|
||||||
|
"to the switch: %(zonestring)s", {'zonestring': data})
|
||||||
|
error_code, error_msg = self.post_zone_data(data)
|
||||||
|
if error_code != "0":
|
||||||
|
msg = (_("Applying the zones and cfgs to the switch failed "
|
||||||
|
"(error code=%(err_code)s error msg=%(err_msg)s.")
|
||||||
|
% {'err_code': error_code, 'err_msg': error_msg})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.BrocadeZoningHttpException(reason=msg)
|
||||||
|
|
||||||
|
def post_zone_data(self, data):
|
||||||
|
"""Send POST request to the switch with the payload.
|
||||||
|
|
||||||
|
:param data: payload to be sent to switch
|
||||||
|
"""
|
||||||
|
|
||||||
|
status = "progress"
|
||||||
|
parsed_data_txn = ""
|
||||||
|
headers = {zone_constant.AUTH_HEADER: self.auth_header}
|
||||||
|
|
||||||
|
LOG.debug("Requesting the switch with posting the zone string.")
|
||||||
|
# POST request to gzoneinfo with zonestring as payload
|
||||||
|
response = self.connect(zone_constant.POST_METHOD,
|
||||||
|
zone_constant.ZONE_PAGE,
|
||||||
|
data,
|
||||||
|
headers)
|
||||||
|
parsed_data = self.get_parsed_data(response,
|
||||||
|
zone_constant.ZONE_TX_BEGIN,
|
||||||
|
zone_constant.ZONE_TX_END)
|
||||||
|
transID = self.get_nvp_value(parsed_data,
|
||||||
|
zone_constant.ZONE_TX_ID)
|
||||||
|
transURL = zone_constant.ZONE_TRAN_STATUS.format(txnId=transID)
|
||||||
|
timeout = 360
|
||||||
|
sleep_time = 3
|
||||||
|
time_elapsed = 0
|
||||||
|
while(status != "done"):
|
||||||
|
txn_response = self.connect(
|
||||||
|
zone_constant.GET_METHOD, transURL, "", headers)
|
||||||
|
parsed_data_txn = self.get_parsed_data(txn_response,
|
||||||
|
zone_constant.ZONE_TX_BEGIN,
|
||||||
|
zone_constant.ZONE_TX_END)
|
||||||
|
status = self.get_nvp_value(parsed_data_txn,
|
||||||
|
zone_constant.ZONE_TX_STATUS)
|
||||||
|
time.sleep(sleep_time)
|
||||||
|
time_elapsed += sleep_time
|
||||||
|
if time_elapsed > timeout:
|
||||||
|
break
|
||||||
|
if status != "done":
|
||||||
|
errorCode = -1
|
||||||
|
errorMessage = ("Timed out, waiting for zone transaction on "
|
||||||
|
"the switch to complete")
|
||||||
|
else:
|
||||||
|
errorCode = self.get_nvp_value(parsed_data_txn,
|
||||||
|
zone_constant.ZONE_ERROR_CODE)
|
||||||
|
errorMessage = self.get_nvp_value(parsed_data_txn,
|
||||||
|
zone_constant.ZONE_ERROR_MSG)
|
||||||
|
return errorCode, errorMessage
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
"""Close session."""
|
||||||
|
self.session.close()
|
@ -1,8 +1,6 @@
|
|||||||
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
# (c) Copyright 2014 Brocade Communications Systems Inc.
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Copyright 2014 OpenStack Foundation
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
@ -44,3 +42,60 @@ CFG_SHOW_TRANS = 'cfgtransshow'
|
|||||||
CFG_ZONE_TRANS_ABORT = 'cfgtransabort'
|
CFG_ZONE_TRANS_ABORT = 'cfgtransabort'
|
||||||
NS_SHOW = 'nsshow'
|
NS_SHOW = 'nsshow'
|
||||||
NS_CAM_SHOW = 'nscamshow'
|
NS_CAM_SHOW = 'nscamshow'
|
||||||
|
|
||||||
|
"""
|
||||||
|
HTTPS connector constants
|
||||||
|
"""
|
||||||
|
AUTH_HEADER = "Authorization"
|
||||||
|
PROTOCOL_HTTPS = "HTTPS"
|
||||||
|
STATUS_OK = 200
|
||||||
|
SECINFO_PAGE = "/secinfo.html"
|
||||||
|
AUTHEN_PAGE = "/authenticate.html"
|
||||||
|
GET_METHOD = "GET"
|
||||||
|
POST_METHOD = "POST"
|
||||||
|
SECINFO_BEGIN = "--BEGIN SECINFO"
|
||||||
|
SECINFO_END = "--END SECINFO"
|
||||||
|
RANDOM = "RANDOM"
|
||||||
|
AUTH_STRING = "Custom_Basic " # Trailing space is required, do not remove
|
||||||
|
AUTHEN_BEGIN = "--BEGIN AUTHENTICATE"
|
||||||
|
AUTHEN_END = "--END AUTHENTICATE"
|
||||||
|
AUTHENTICATED = "authenticated"
|
||||||
|
SESSION_PAGE_ACTION = "/session.html?action=query"
|
||||||
|
SESSION_BEGIN = "--BEGIN SESSION"
|
||||||
|
SESSION_END = "--END SESSION"
|
||||||
|
SESSION_PAGE = "/session.html"
|
||||||
|
ZONEINFO_BEGIN = "--BEGIN ZONE INFO"
|
||||||
|
ZONEINFO_END = "--END ZONE INFO"
|
||||||
|
SWITCH_PAGE = "/switch.html"
|
||||||
|
SWITCHINFO_BEGIN = "--BEGIN SWITCH INFORMATION"
|
||||||
|
SWITCHINFO_END = "--END SWITCH INFORMATION"
|
||||||
|
FIRMWARE_VERSION = "swFWVersion"
|
||||||
|
VF_ENABLED = "vfEnabled"
|
||||||
|
MANAGEABLE_VF = "manageableLFList"
|
||||||
|
CHANGE_VF = ("Session=--BEGIN SESSION\n\taction=apply\n\tLFId= {vfid} "
|
||||||
|
"\b\t--END SESSION")
|
||||||
|
ZONE_TRAN_STATUS = "/gzoneinfo.htm?txnId={txnId}"
|
||||||
|
CFG_DELIM = "\x01"
|
||||||
|
ZONE_DELIM = "\x02"
|
||||||
|
ALIAS_DELIM = "\x03"
|
||||||
|
QLP_DELIM = "\x04"
|
||||||
|
ZONE_END_DELIM = "\x05&saveonly="
|
||||||
|
IFA_DELIM = "\x06"
|
||||||
|
ACTIVE_CFG_DELIM = "\x07"
|
||||||
|
DEFAULT_CFG = "d__efault__Cfg"
|
||||||
|
NS_PAGE = "/nsinfo.htm"
|
||||||
|
NSINFO_BEGIN = "--BEGIN NS INFO"
|
||||||
|
NSINFO_END = "--END NS INFO"
|
||||||
|
NS_DELIM = ";N ;"
|
||||||
|
ZONE_TX_BEGIN = "--BEGIN ZONE_TXN_INFO"
|
||||||
|
ZONE_TX_END = "--END ZONE_TXN_INFO"
|
||||||
|
ZONE_ERROR_CODE = "errorCode"
|
||||||
|
ZONE_PAGE = "/gzoneinfo.htm"
|
||||||
|
CFG_NAME = "openstack_cfg"
|
||||||
|
ZONE_STRING_PREFIX = "zonecfginfo="
|
||||||
|
ZONE_ERROR_MSG = "errorMessage"
|
||||||
|
ZONE_TX_ID = "txnId"
|
||||||
|
ZONE_TX_STATUS = "status"
|
||||||
|
SESSION_LF_ID = "sessionLFId"
|
||||||
|
HTTP = "http"
|
||||||
|
HTTPS = "https"
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- HTTP connector for the Cinder Brocade FC Zone plugin.
|
||||||
|
This connector allows for communication
|
||||||
|
between the Brocade FC zone plugin and the switch
|
||||||
|
to be over HTTP or HTTPs. To make use of this
|
||||||
|
connector, the user would add a configuration
|
||||||
|
setting in the fabric block for a Brocade switch
|
||||||
|
with the name as 'fc_southbound_protocol' with
|
||||||
|
a value as 'HTTP' or 'HTTPS'.
|
Loading…
x
Reference in New Issue
Block a user