diff --git a/cinder/exception.py b/cinder/exception.py index fbade5102e6..d50c5710177 100644 --- a/cinder/exception.py +++ b/cinder/exception.py @@ -1085,6 +1085,10 @@ class BrocadeZoningHttpException(CinderException): message = _("Brocade Fibre Channel Zoning HTTP error: %(reason)s") +class BrocadeZoningRestException(CinderException): + message = _("Brocade Fibre Channel Zoning REST error: %(reason)s") + + class CiscoZoningCliException(CinderException): message = _("Cisco Fibre Channel Zoning CLI error: %(reason)s") diff --git a/cinder/zonemanager/drivers/brocade/brcd_fabric_opts.py b/cinder/zonemanager/drivers/brocade/brcd_fabric_opts.py index 46e98dfbccf..55c3ba6311f 100644 --- a/cinder/zonemanager/drivers/brocade/brcd_fabric_opts.py +++ b/cinder/zonemanager/drivers/brocade/brcd_fabric_opts.py @@ -1,4 +1,4 @@ -# (c) Copyright 2014 Brocade Communications Systems Inc. +# (c) Copyright 2019 Brocade, a Broadcom Company # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -20,8 +20,8 @@ from cinder.volume import configuration brcd_zone_opts = [ cfg.StrOpt('fc_southbound_protocol', - default='HTTP', - choices=('SSH', 'HTTP', 'HTTPS'), + default='REST_HTTP', + choices=('SSH', 'HTTP', 'HTTPS', 'REST_HTTP', 'REST_HTTPS'), help='South bound connector for the fabric.'), cfg.StrOpt('fc_fabric_address', default='', diff --git a/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py b/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py index 02501c36c0d..75c671938e4 100644 --- a/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py +++ b/cinder/zonemanager/drivers/brocade/brcd_fc_san_lookup_service.py @@ -1,4 +1,4 @@ -# (c) Copyright 2016 Brocade Communications Systems Inc. +# (c) Copyright 2019 Brocade, a Broadcom Company # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -121,7 +121,7 @@ class BrcdFCSanLookupService(fc_service.FCSanLookupService): LOG.error("Failed collecting name server info from" " fabric %s", fabric_ip) except Exception as e: - msg = _("SSH connection failed " + msg = _("Connection failed " "for %(fabric)s with error: %(err)s" ) % {'fabric': fabric_ip, 'err': e} LOG.error(msg) diff --git a/cinder/zonemanager/drivers/brocade/brcd_fc_zone_client_cli.py b/cinder/zonemanager/drivers/brocade/brcd_fc_zone_client_cli.py index 14f88f6c39b..27266bc123c 100644 --- a/cinder/zonemanager/drivers/brocade/brcd_fc_zone_client_cli.py +++ b/cinder/zonemanager/drivers/brocade/brcd_fc_zone_client_cli.py @@ -1,4 +1,4 @@ -# (c) Copyright 2016 Brocade Communications Systems Inc. +# (c) Copyright 2019 Brocade, a Broadcom Company # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may diff --git a/cinder/zonemanager/drivers/brocade/brcd_fc_zone_connector_factory.py b/cinder/zonemanager/drivers/brocade/brcd_fc_zone_connector_factory.py index a6e7a8a6679..4e77eb3c27a 100644 --- a/cinder/zonemanager/drivers/brocade/brcd_fc_zone_connector_factory.py +++ b/cinder/zonemanager/drivers/brocade/brcd_fc_zone_connector_factory.py @@ -1,4 +1,4 @@ -# (c) Copyright 2015 Brocade Communications Systems Inc. +# (c) Copyright 2019 Brocade, a Broadcom Company # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -59,8 +59,20 @@ class BrcdFCZoneFactory(object): 'port': fabric_port, 'vf_id': fc_vfid}) - if sb_connector.lower() in (fc_zone_constants.HTTP, - fc_zone_constants.HTTPS): + if sb_connector.lower() in (fc_zone_constants.REST_HTTP, + fc_zone_constants.REST_HTTPS): + client = importutils.import_object( + "cinder.zonemanager.drivers.brocade." + "brcd_rest_fc_zone_client.BrcdRestFCZoneClient", + ipaddress=fabric_ip, + username=fabric_user, + password=fabric_pwd, + port=fabric_port, + vfid=fc_vfid, + protocol=sb_connector + ) + elif 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", diff --git a/cinder/zonemanager/drivers/brocade/brcd_fc_zone_driver.py b/cinder/zonemanager/drivers/brocade/brcd_fc_zone_driver.py index 69c9edf5fc5..c4529e3b663 100644 --- a/cinder/zonemanager/drivers/brocade/brcd_fc_zone_driver.py +++ b/cinder/zonemanager/drivers/brocade/brcd_fc_zone_driver.py @@ -1,4 +1,4 @@ -# (c) Copyright 2016 Brocade Communications Systems Inc. +# (c) Copyright 2019 Brocade, a Broadcom Company # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -27,6 +27,7 @@ add_connection and delete_connection interfaces. :zone_name_prefix: Used by: class: 'FCZoneDriver'. Defaults to 'openstack' """ +import string from oslo_concurrency import lockutils from oslo_config import cfg @@ -34,7 +35,6 @@ from oslo_log import log as logging from oslo_utils import excutils from oslo_utils import importutils import six -import string from cinder import exception from cinder.i18n import _ @@ -72,9 +72,10 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver): 1.3 - Added HTTP connector support 1.4 - Adds support to zone in Virtual Fabrics 1.5 - Initiator zoning updates through zoneadd/zoneremove + 1.6 - Add REST connector """ - VERSION = "1.5" + VERSION = "1.6" # ThirdPartySystems wiki page CI_WIKI_NAME = "Brocade_OpenStack_CI" @@ -226,7 +227,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver): LOG.debug("Zones updated successfully: %(updatemap)s", {'updatemap': zone_update_map}) except (exception.BrocadeZoningCliException, - exception.BrocadeZoningHttpException) as brocade_ex: + exception.BrocadeZoningHttpException, + exception.BrocadeZoningRestException) as brocade_ex: raise exception.FCZoneDriverException(brocade_ex) except Exception: msg = _("Failed to add or update zoning configuration.") @@ -373,7 +375,8 @@ class BrcdFCZoneDriver(fc_zone_driver.FCZoneDriver): zone_name_string, zone_activate, cfgmap_from_fabric) except (exception.BrocadeZoningCliException, - exception.BrocadeZoningHttpException) as brocade_ex: + exception.BrocadeZoningHttpException, + exception.BrocadeZoningRestException) as brocade_ex: raise exception.FCZoneDriverException(brocade_ex) except Exception: msg = _("Failed to update or delete zoning " diff --git a/cinder/zonemanager/drivers/brocade/brcd_http_fc_zone_client.py b/cinder/zonemanager/drivers/brocade/brcd_http_fc_zone_client.py index ea53350dd77..ca5cd33d85e 100644 --- a/cinder/zonemanager/drivers/brocade/brcd_http_fc_zone_client.py +++ b/cinder/zonemanager/drivers/brocade/brcd_http_fc_zone_client.py @@ -1,4 +1,4 @@ -# (c) Copyright 2016 Brocade Communications Systems Inc. +# (c) Copyright 2019 Brocade, a Broadcom Company # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -18,13 +18,14 @@ Brocade south bound connector to communicate with switch using HTTP or HTTPS protocol. """ -from oslo_log import log as logging -from oslo_serialization import base64 -from oslo_utils import encodeutils import requests import six import time +from oslo_log import log as logging +from oslo_serialization import base64 +from oslo_utils import encodeutils + from cinder import exception from cinder.i18n import _ import cinder.zonemanager.drivers.brocade.fc_zone_constants as zone_constant diff --git a/cinder/zonemanager/drivers/brocade/brcd_rest_fc_zone_client.py b/cinder/zonemanager/drivers/brocade/brcd_rest_fc_zone_client.py new file mode 100644 index 00000000000..af0722948e5 --- /dev/null +++ b/cinder/zonemanager/drivers/brocade/brcd_rest_fc_zone_client.py @@ -0,0 +1,412 @@ +# (c) Copyright 2019 Brocade, a Broadcom Company +# 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 +REST over HTTP or HTTPS protocol. +""" + +import json + +from oslo_log import log as logging +from oslo_serialization import base64 +import requests +import six + +from cinder import exception +from cinder.i18n import _ +from cinder.zonemanager.drivers.brocade import fc_zone_constants +from cinder.zonemanager.drivers.brocade import rest_constants + +LOG = logging.getLogger(__name__) + + +class BrcdRestFCZoneClient(object): + + def __init__(self, ipaddress, username, + password, port, vfid, protocol): + """Initializing the client with the parameters passed. + + :param ipaddress: IP Address of the device. + :param username: User id to login. + :param password: User password. + :param port: Device Communication port + :param vfid: Virtual Fabric ID. + :param protocol: Communication Protocol. + + """ + self.sw_ip = ipaddress + self.sw_user = username + self.sw_pwd = password + self.protocol = protocol + self.vfid = vfid + self.status_code = '' + self.session = None + self._login() + + def is_supported_firmware(self): + is_supported_firmware = False + fw_version = self._get_firmware_version() + ver = fw_version.split(".") + if len(ver[0]) > 1: + major_ver = ver[0] + ver[0] = major_ver[1] + if len(ver[2]) > 1: + patch_ver = ver[2] + ver[2] = patch_ver[0] + LOG.debug("Firmware version: %(version)s.", {'version': ver}) + if int(ver[0] + ver[1] + ver[2]) > 820: + is_supported_firmware = True + return is_supported_firmware + + def get_active_zone_set(self): + active_zone_set, checksum = self._get_effective_zone_set() + return active_zone_set + + def get_nameserver_info(self): + return self._get_name_server() + + def add_zones(self, add_zone_map, activate, active_zone_set=None): + self._add_zones(add_zone_map, activate) + + def update_zones(self, update_zone_map, activate, operation, + active_zone_set=None): + self._update_zones(update_zone_map, activate, operation) + + def delete_zones(self, zone_names_to_delete, activate, + active_zone_set=None): + self._delete_zones(zone_names_to_delete, activate) + + def cleanup(self): + self._logout() + + def _login(self): + if self.protocol == fc_zone_constants.REST_HTTPS: + self.protocol = fc_zone_constants.HTTPS + else: + self.protocol = fc_zone_constants.HTTP + if self.session is None: + self.session = requests.Session() + adapter = requests.adapters.HTTPAdapter(pool_connections=1, + pool_maxsize=1) + self.session.mount(self.protocol + '://', adapter) + credentials = base64.encode_as_text('%s:%s' % (self.sw_user, + self.sw_pwd)).replace('\n', '') + self.session.headers = {rest_constants.USER_AGENT: + rest_constants.ZONE_DRIVER, + rest_constants.ACCEPT: rest_constants.YANG, + rest_constants.AUTHORIZATION: + "Basic %s" % credentials} + response = self.session.post(self._build_url(rest_constants.LOGIN)) + if response.status_code == 200: + auth = response.headers.get('Authorization') + LOG.info("REST login success, setting auth: %s", auth) + self.session.headers = {rest_constants.USER_AGENT: + rest_constants.ZONE_DRIVER, + rest_constants.ACCEPT: rest_constants.YANG, + rest_constants.CONTENT_TYPE: + rest_constants.YANG, + rest_constants.AUTHORIZATION: auth} + else: + msg = (_("REST login failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + return response.status_code + + def _logout(self): + response = self.session.post(self._build_url(rest_constants.LOGOUT)) + if response.status_code == 204: + LOG.info("REST logout success") + else: + msg = (_("REST logout failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + + def _get_firmware_version(self): + response = self.session.get(self._build_url(rest_constants.GET_SWITCH)) + firmware_version = '' + if response.status_code == 200: + data = response.json() + json_response = data[rest_constants.RESPONSE] + switch = json_response[rest_constants.SWITCH] + firmware_version = switch[rest_constants.FIRMWARE_VERSION] + LOG.info("REST firmware version: %s", firmware_version) + else: + msg = (_("REST get switch fw version failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + return firmware_version + + def _get_name_server(self): + port_names = [] + url = self._build_url(rest_constants.GET_NAMESERVER) + response = self.session.get(url) + if response.status_code == 200: + data = response.json() + json_response = data[rest_constants.RESPONSE] + nsinfos = json_response[rest_constants.FC_NAME_SERVER] + i = 0 + for nsinfo in nsinfos: + port_names.append(nsinfos[i][rest_constants.PORT_NAME]) + i = i + 1 + else: + msg = (_("REST get NS info failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + return port_names + + def _get_effective_zone_set(self): + active_zone_set = {} + zones_map = {} + url = self._build_url(rest_constants.GET_ACTIVE_ZONE_CFG) + response = self.session.get(url) + checksum = '' + active_cfg_name = '' + if response.status_code == 200: + data = response.json() + json_response = data[rest_constants.RESPONSE] + effective_cfg = json_response[rest_constants.EFFECTIVE_CFG] + checksum = effective_cfg[rest_constants.CHECKSUM] + try: + active_cfg_name = effective_cfg[rest_constants.CFG_NAME] + zones = effective_cfg[rest_constants.ENABLED_ZONE] + if type(zones) is list: + for i, zone in enumerate(zones): + zones_map.update({zones[i][rest_constants.ZONE_NAME]: + zones[i][rest_constants.MEMBER_ENTRY] + [rest_constants.ENTRY_NAME]}) + else: + zones_map.update({zones[rest_constants.ZONE_NAME]: + zones[rest_constants.MEMBER_ENTRY] + [rest_constants.ENTRY_NAME]}) + except Exception: + active_cfg_name = '' + LOG.info("REST get effective zoneset success: " + "active cfg: %(cfg_name)s, checksum: %(chksum)s", + {'cfg_name': active_cfg_name, 'chksum': checksum}) + else: + msg = (_("REST get effective zoneset failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + active_zone_set = {"active_zone_config": active_cfg_name, + "zones": zones_map} + return active_zone_set, checksum + + def _add_zones(self, add_zone_map, activate): + active_zone_set, checksum = self._get_effective_zone_set() + # if activate, get the zones already configured in the active cfg + if activate: + zones_in_active_cfg = active_zone_set.get("zones") + # for each new zone, create a zone entry in defined zone db + for zone_name, members in add_zone_map.items(): + if zone_name not in zones_in_active_cfg: + body = {rest_constants.MEMBER_ENTRY: + {rest_constants.ENTRY_NAME: + add_zone_map.get(zone_name)}} + json_str = json.dumps(body) + url = self._build_url(rest_constants.POST_ZONE + zone_name) + response = self.session.post(url, data=json_str) + if response.status_code == 201: + LOG.info("REST create zone success: %s", zone_name) + else: + msg = (_("REST create zone failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + # update the cfg with the new zones + active_cfg_name = active_zone_set.get("active_zone_config") + active_zones = active_zone_set.get("zones") + active_zone_names = active_zones.keys() + active_zone_names.extend(add_zone_map.keys()) + body = {rest_constants.MEMBER_ZONE: + {rest_constants.ZONE_NAME: active_zone_names}} + json_str = json.dumps(body) + if active_cfg_name == '': + active_cfg_name = fc_zone_constants.CFG_NAME + url = self._build_url(rest_constants.POST_CFG + active_cfg_name) + response = self.session.post(url, data=json_str) + if response.status_code == 201: + LOG.info("REST cfg create success: %s", active_cfg_name) + self._save_and_activate_cfg(checksum, activate, + active_cfg_name) + else: + msg = (_("REST cfg create failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + else: + url = self._build_url(rest_constants.PATCH_CFG + active_cfg_name) + response = self.session.patch(url, data=json_str) + # if update successful, save the configuration changes + if response.status_code == 204: + LOG.info("REST cfg update success: %s", active_cfg_name) + self._save_and_activate_cfg(checksum, activate, + active_cfg_name) + else: + msg = (_("REST cfg update failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + + def _update_zones(self, update_zone_map, activate, operation): + active_zone_set, checksum = self._get_effective_zone_set() + active_cfg_name = active_zone_set.get("active_zone_config") + active_zones = active_zone_set.get("zones") + # for each zone, update the zone members in defined zone db + for zone_name, members in update_zone_map.items(): + current_members = active_zones.get(zone_name) + if operation == "ADD": + new_members = set(members).difference(set(current_members)) + if new_members: + update_zone_map.update({zone_name: new_members}) + elif operation == "REMOVE": + new_members = set(current_members).difference(set(members)) + if new_members: + update_zone_map.update({zone_name: new_members}) + # for each zone to be updated, make REST PATCH call to update + for zone in update_zone_map.keys(): + body = {rest_constants.MEMBER_ENTRY: + {rest_constants.ENTRY_NAME: update_zone_map.get(zone)}} + json_str = json.dumps(body) + url = self._build_url(rest_constants.POST_ZONE + zone) + response = self.session.patch(url, data=json_str) + if response.status_code == 204: + LOG.info("REST zone update success: %s", zone) + else: + msg = (_("REST zone update failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + # save and activate the config changes + self._save_and_activate_cfg(checksum, activate, active_cfg_name) + + def _delete_zones(self, zone_names_to_delete, activate): + zone_names_to_delete = zone_names_to_delete.split(";") + active_zone_set, checksum = self._get_effective_zone_set() + # for each zone name, make REST DELETE call + for zone in zone_names_to_delete: + url = self._build_url(rest_constants.DELETE_ZONE + zone) + response = self.session.delete(url) + if response.status_code == 204: + LOG.info("REST delete zone success: %s", zone) + else: + msg = (_("REST delete zone failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + # update the cfg removing the deleted zones + active_cfg_name = active_zone_set.get("active_zone_config") + active_zones = active_zone_set.get("zones") + active_zone_names = active_zones.keys() + if len(active_zone_names) == len(zone_names_to_delete): + # disable the cfg + url = self._build_url(rest_constants.PATCH_CFG_DISABLE) + body = {"checksum": checksum} + json_str = json.dumps(body) + response = self.session.patch(url, data=json_str) + if response.status_code == 204: + LOG.info("REST cfg disable success") + else: + msg = (_("REST cfg disable failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + # delete the cfg + url = self._build_url(rest_constants.DELETE_CFG + active_cfg_name) + response = self.session.delete(url) + if response.status_code == 204: + LOG.info("REST cfg delete success: %s", active_cfg_name) + else: + msg = (_("REST cfg delete failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + checksum = self._get_checksum() + self._save_and_activate_cfg(checksum, False, active_cfg_name) + else: + # update the cfg by removing the deleted zones + zone_names_in_cfg = list(set(active_zone_names) + .difference(set(zone_names_to_delete))) + body = {rest_constants.MEMBER_ZONE: + {rest_constants.ZONE_NAME: zone_names_in_cfg}} + json_str = json.dumps(body) + url = self._build_url(rest_constants.PATCH_CFG + active_cfg_name) + response = self.session.patch(url, data=json_str) + # if update successful, save the configuration changes + if response.status_code == 204: + LOG.info("REST cfg update success: %s", active_cfg_name) + self._save_and_activate_cfg(checksum, activate, + active_cfg_name) + else: + msg = (_("REST cfg update failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + + def _save_and_activate_cfg(self, checksum, activate, active_cfg_name): + body = {"checksum": checksum} + json_str = json.dumps(body) + url = self._build_url(rest_constants.PATCH_CFG_SAVE) + response = self.session.patch(url, data=json_str) + if response.status_code == 204: + LOG.info("REST cfg save success") + else: + msg = (_("REST cfg save failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + # if activate=true, then enable the cfg changes to effective cfg + if activate: + checksum = self._get_checksum() + body = {"checksum": checksum} + json_str = json.dumps(body) + url = self._build_url(rest_constants.PATCH_CFG_ENABLE + + active_cfg_name) + response = self.session.patch(url, data=json_str) + if response.status_code == 204: + LOG.info("REST cfg activate success: %s", active_cfg_name) + else: + msg = (_("REST cfg activate failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + + def _get_checksum(self): + url = self._build_url(rest_constants.GET_CHECKSUM) + response = self.session.get(url) + checksum = '' + if response.status_code == 200: + data = response.json() + json_response = data[rest_constants.RESPONSE] + effective_cfg = json_response[rest_constants.EFFECTIVE_CFG] + checksum = effective_cfg[rest_constants.CHECKSUM] + LOG.info("REST get checksum success: %s", checksum) + else: + msg = (_("REST get checksum failed: %s") + % six.text_type(response.text)) + LOG.error(msg) + raise exception.BrocadeZoningRestException(reason=msg) + return checksum + + def _build_url(self, path): + url = '%s://%s%s' % (self.protocol, self.sw_ip, path) + if self.vfid is not None: + url = '%s?vf-id=%s' % (url, self.vfid) + return url diff --git a/cinder/zonemanager/drivers/brocade/fc_zone_constants.py b/cinder/zonemanager/drivers/brocade/fc_zone_constants.py index 8af6333ea5b..1c781a39233 100644 --- a/cinder/zonemanager/drivers/brocade/fc_zone_constants.py +++ b/cinder/zonemanager/drivers/brocade/fc_zone_constants.py @@ -1,4 +1,4 @@ -# (c) Copyright 2016 Brocade Communications Systems Inc. +# (c) Copyright 2019 Brocade, a Broadcom Company # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -102,3 +102,5 @@ ZONE_TX_STATUS = "status" SESSION_LF_ID = "sessionLFId" HTTP = "http" HTTPS = "https" +REST_HTTP = "rest_http" +REST_HTTPS = "rest_https" diff --git a/cinder/zonemanager/drivers/brocade/rest_constants.py b/cinder/zonemanager/drivers/brocade/rest_constants.py new file mode 100644 index 00000000000..862b828bdea --- /dev/null +++ b/cinder/zonemanager/drivers/brocade/rest_constants.py @@ -0,0 +1,59 @@ +# (c) Copyright 2019 Brocade, a Broadcom Company +# 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. +# + +YANG = "application/yang-data+json" +ACCEPT = "Accept" +CONTENT_TYPE = "Content-Type" +AUTHORIZATION = "Authorization" +USER_AGENT = "User-Agent" +ZONE_DRIVER = "OpenStack Zone Driver" +LOGIN = "/rest/login" +LOGOUT = "/rest/logout" +NAME_SERVER = "/rest/running/brocade-name-server" +ZONING = "/rest/running/zoning" +DEFINED_CFG = "/defined-configuration" +EFFECTIVE_CFG = "/effective-configuration" +GET_SWITCH = "/rest/running/switch/fibrechannel-switch" +GET_NAMESERVER = NAME_SERVER + "/fibrechannel-name-server" +GET_DEFINED_ZONE_CFG = ZONING + DEFINED_CFG +GET_ACTIVE_ZONE_CFG = ZONING + EFFECTIVE_CFG +GET_CHECKSUM = ZONING + EFFECTIVE_CFG + "/checksum" +POST_ZONE = ZONING + DEFINED_CFG + "/zone/zone-name/" +POST_CFG = ZONING + DEFINED_CFG + "/cfg/cfg-name/" +PATCH_CFG = ZONING + DEFINED_CFG + "/cfg/cfg-name/" +PATCH_CFG_SAVE = ZONING + EFFECTIVE_CFG + "/cfg-action/1" +PATCH_CFG_DISABLE = ZONING + EFFECTIVE_CFG + "/cfg-action/2" +PATCH_CFG_ENABLE = ZONING + EFFECTIVE_CFG + "/cfg-name/" +DELETE_ZONE = POST_ZONE +DELETE_CFG = POST_CFG +RESPONSE = "Response" +SWITCH = "fibrechannel-switch" +FIRMWARE_VERSION = "firmware-version" +FC_NAME_SERVER = "fibrechannel-name-server" +PORT_NAME = "port-name" +DEFINED_CFG = "defined-configuration" +CFG = "cfg" +CFG_NAME = "cfg-name" +MEMBER_ZONE = "member-zone" +ZONE_NAME = "zone-name" +ZONE = "zone" +MEMBER_ENTRY = "member-entry" +ENTRY_NAME = "entry-name" +ALIAS = "alias" +ALIAS_ENTRY_NAME = "alias-entry-name" +EFFECTIVE_CFG = "effective-configuration" +CHECKSUM = "checksum" +ENABLED_ZONE = "enabled-zone" diff --git a/doc/source/configuration/block-storage/fc-zoning.rst b/doc/source/configuration/block-storage/fc-zoning.rst index 8f3f9cffe30..5f01c56d037 100644 --- a/doc/source/configuration/block-storage/fc-zoning.rst +++ b/doc/source/configuration/block-storage/fc-zoning.rst @@ -75,9 +75,17 @@ Configure SAN fabric parameters under a section matching the name used in To define a fabric group for a switch which has Virtual Fabrics enabled, include the ``fc_virtual_fabric_id`` configuration option - and ``fc_southbound_protocol`` configuration option set to ``HTTP`` - or ``HTTPS`` in the fabric group. Zoning on VF enabled fabric using - ``SSH`` southbound protocol is not supported. + and ``fc_southbound_protocol`` configuration option set to ``HTTP``, + ``HTTPS``, ``REST_HTTP`` or ``REST_HTTPS`` in the fabric group. + Zoning on VF enabled fabric using ``SSH`` southbound protocol is + not supported. + +.. note:: + + On switches running Fabric OS v8.2.1 or greater, the use of the + REST interface is recommended for southbound communication. Set + the ``fc_southbound_protocol`` configuration option to ``REST_HTTP`` + or ``REST_HTTPS`` in the fabric group. System requirements -------------------