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' } """ zone_set = {} zone = {} zone_member = None zone_name = None switch_data = None zone_set_name = None try: switch_data = self._get_switch_info( [ZoneConstant.GET_ACTIVE_ZONE_CFG]) except exception.BrocadeZoningCliException: with excutils.save_and_reraise_exception(): LOG.error(_("Failed getting active zone set " "from fabric %s"), self.switch_ip) try: for line in switch_data: line_split = re.split('\\t', line) if len(line_split) > 2: line_split = [x.replace( '\n', '') for x in line_split] line_split = [x.replace( ' ', '') for x in line_split] if ZoneConstant.CFG_ZONESET in line_split: zone_set_name = line_split[1] continue if line_split[1]: zone_name = line_split[1] zone[zone_name] = list() if line_split[2]: zone_member = line_split[2] if zone_member: zone_member_list = zone.get(zone_name) zone_member_list.append(zone_member) zone_set[ZoneConstant.CFG_ZONES] = zone zone_set[ZoneConstant.ACTIVE_ZONE_CONFIG] = zone_set_name except Exception as ex: # Incase of parsing error here, it should be malformed cli output. msg = _("Malformed zone configuration: (switch=%(switch)s " "zone_config=%(zone_config)s)." ) % {'switch': self.switch_ip, 'zone_config': switch_data} LOG.error(msg) LOG.exception(ex) raise exception.FCZoneDriverException(reason=msg) switch_data = None return zone_set
def delete_connection(self, fabric, initiator_target_map, host_name=None, storage_system=None): """Concrete implementation of delete_connection. Based on zoning policy and state of each I-T pair, list of zones are created for deletion. The zones are either updated deleted based on the policy and attach/detach state of each I-T pair. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.info("BrcdFCZoneDriver - Delete connection for fabric " "%(fabric)s for I-T map: %(i_t_map)s", {'fabric': fabric, 'i_t_map': initiator_target_map}) zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'zoning_policy') zone_name_prefix = self.fabric_configs[fabric].safe_get( 'zone_name_prefix') zone_activate = self.fabric_configs[fabric].safe_get( 'zone_activate') if zoning_policy_fab: zoning_policy = zoning_policy_fab LOG.info("Zoning policy for fabric %(policy)s", {'policy': zoning_policy}) conn = self._get_southbound_client(fabric) cfgmap_from_fabric = self._get_active_zone_set(conn) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # Based on zoning policy, get zone member list and push changes to # fabric. This operation could result in an update for zone config # with new member list or deleting zones from active cfg. LOG.debug("zone config from Fabric: %(cfgmap)s", {'cfgmap': cfgmap_from_fabric}) for initiator_key in initiator_target_map.keys(): initiator = initiator_key.lower() formatted_initiator = utils.get_formatted_wwn(initiator) zone_map = {} zones_to_delete = [] t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': # In this case, zone needs to be deleted. for t in t_list: target = t.lower() zone_name = driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS) LOG.debug("Zone name to delete: %(zonename)s", {'zonename': zone_name}) if len(zone_names) > 0 and (zone_name in zone_names): # delete zone. LOG.debug("Added zone to delete to list: %(zonename)s", {'zonename': zone_name}) zones_to_delete.append(zone_name) elif zoning_policy == 'initiator': zone_members = [formatted_initiator] for t in t_list: target = t.lower() zone_members.append(utils.get_formatted_wwn(target)) zone_name = driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS) if (zone_names and (zone_name in zone_names)): # Check to see if there are other zone members # in the zone besides the initiator and # the targets being removed. filtered_members = filter( lambda x: x not in zone_members, cfgmap_from_fabric['zones'][zone_name]) # If there are other zone members, proceed with # zone update to remove the targets. Otherwise, # delete the zone. if filtered_members: zone_members.remove(formatted_initiator) # Verify that the zone members in target list # are listed in zone definition. If not, remove # the zone members from the list of members # to remove, otherwise switch will return error. zm_list = cfgmap_from_fabric['zones'][zone_name] for t in t_list: formatted_target = utils.get_formatted_wwn(t) if formatted_target not in zm_list: zone_members.remove(formatted_target) if zone_members: LOG.debug("Zone members to remove: " "%(members)s", {'members': zone_members}) zone_map[zone_name] = zone_members else: zones_to_delete.append(zone_name) else: LOG.warning("Zoning policy not recognized: %(policy)s", {'policy': zoning_policy}) LOG.debug("Zone map to update: %(zonemap)s", {'zonemap': zone_map}) LOG.debug("Zone list to delete: %(zones)s", {'zones': zones_to_delete}) try: # Update zone membership. if zone_map: conn.update_zones(zone_map, zone_activate, fc_zone_constants.ZONE_REMOVE, cfgmap_from_fabric) # Delete zones if zones_to_delete: zone_name_string = '' num_zones = len(zones_to_delete) for i in range(0, num_zones): if i == 0: zone_name_string = ( '%s%s' % ( zone_name_string, zones_to_delete[i])) else: zone_name_string = '%s;%s' % ( zone_name_string, zones_to_delete[i]) conn.delete_zones( zone_name_string, zone_activate, cfgmap_from_fabric) except (exception.BrocadeZoningCliException, exception.BrocadeZoningHttpException, exception.BrocadeZoningRestException) as brocade_ex: raise exception.FCZoneDriverException(brocade_ex) except Exception: msg = _("Failed to update or delete zoning " "configuration.") LOG.exception(msg) raise exception.FCZoneDriverException(msg) finally: conn.cleanup()
def get_san_context(self, target_wwn_list): """Lookup SAN context for visible end devices. Look up each SAN configured and return a map of SAN (fabric IP) to list of target WWNs visible to the fabric. """ formatted_target_list = [] fabric_map = {} fc_fabric_names = self.configuration.fc_fabric_names fabrics = [x.strip() for x in fc_fabric_names.split(',')] LOG.debug("Fabric List: %(fabrics)s", {'fabrics': fabrics}) LOG.debug("Target WWN list: %(targetwwns)s", {'targetwwns': target_wwn_list}) if len(fabrics) > 0: for t in target_wwn_list: formatted_target_list.append(utils.get_formatted_wwn(t)) LOG.debug("Formatted target WWN list: %(targetlist)s", {'targetlist': formatted_target_list}) for fabric_name in fabrics: conn = self._get_southbound_client(fabric_name) # Get name server data from fabric and get the targets # logged in. nsinfo = None try: nsinfo = conn.get_nameserver_info() LOG.debug("Name server info from fabric: %(nsinfo)s", {'nsinfo': nsinfo}) except (exception.BrocadeZoningCliException, exception.BrocadeZoningHttpException): if not conn.is_supported_firmware(): msg = _("Unsupported firmware on switch %s. Make sure " "switch is running firmware v6.4 or higher" ) % conn.switch_ip LOG.exception(msg) raise exception.FCZoneDriverException(msg) with excutils.save_and_reraise_exception(): LOG.exception("Error getting name server info.") except Exception: msg = _("Failed to get name server info.") LOG.exception(msg) raise exception.FCZoneDriverException(msg) finally: conn.cleanup() visible_targets = filter( lambda x: x in formatted_target_list, nsinfo) if visible_targets: LOG.info("Filtered targets for SAN is: %(targets)s", {'targets': visible_targets}) # getting rid of the ':' before returning for idx, elem in enumerate(visible_targets): visible_targets[idx] = str( visible_targets[idx]).replace(':', '') fabric_map[fabric_name] = visible_targets else: LOG.debug("No targets found in the nameserver " "for fabric: %(fabric)s", {'fabric': fabric_name}) LOG.debug("Return SAN context output: %(fabricmap)s", {'fabricmap': fabric_map}) return fabric_map
def delete_connection(self, fabric, initiator_target_map): """Concrete implementation of delete_connection. Based on zoning policy and state of each I-T pair, list of zones are created for deletion. The zones are either updated deleted based on the policy and attach/detach state of each I-T pair. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.debug("Delete connection for fabric:%s", fabric) LOG.info(_("BrcdFCZoneDriver - Delete connection for I-T map: %s"), initiator_target_map) zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'zoning_policy') if zoning_policy_fab: zoning_policy = zoning_policy_fab LOG.info(_("Zoning policy for fabric %s"), zoning_policy) conn = self._get_cli_client(fabric) cfgmap_from_fabric = self._get_active_zone_set(conn) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # Based on zoning policy, get zone member list and push changes to # fabric. This operation could result in an update for zone config # with new member list or deleting zones from active cfg. LOG.debug("zone config from Fabric: %s", cfgmap_from_fabric) for initiator_key in initiator_target_map.keys(): initiator = initiator_key.lower() formatted_initiator = self.get_formatted_wwn(initiator) zone_map = {} zones_to_delete = [] t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': # In this case, zone needs to be deleted. for t in t_list: target = t.lower() zone_name = ( self.configuration.zone_name_prefix + initiator.replace(':', '') + target.replace(':', '')) LOG.debug("Zone name to del: %s", zone_name) if len(zone_names) > 0 and (zone_name in zone_names): # delete zone. LOG.debug("Added zone to delete to " "list: %s", zone_name) zones_to_delete.append(zone_name) elif zoning_policy == 'initiator': zone_members = [formatted_initiator] for t in t_list: target = t.lower() zone_members.append(self.get_formatted_wwn(target)) zone_name = self.configuration.zone_name_prefix \ + initiator.replace(':', '') if (zone_names and (zone_name in zone_names)): filtered_members = filter( lambda x: x not in zone_members, cfgmap_from_fabric['zones'][zone_name]) # The assumption here is that initiator is always there # in the zone as it is 'initiator' policy. We find the # filtered list and if it is non-empty, add initiator # to it and update zone if filtered list is empty, we # remove that zone. LOG.debug("Zone delete - I mode: " "filtered targets:%s", filtered_members) if filtered_members: filtered_members.append(formatted_initiator) LOG.debug("Filtered zone members to " "update: %s", filtered_members) zone_map[zone_name] = filtered_members LOG.debug("Filtered zone Map to " "update: %s", zone_map) else: zones_to_delete.append(zone_name) else: LOG.info(_("Zoning Policy: %s, not " "recognized"), zoning_policy) LOG.debug("Final Zone map to update: %s", zone_map) LOG.debug("Final Zone list to delete: %s", zones_to_delete) try: # Update zone membership. if zone_map: conn.add_zones( zone_map, self.configuration.zone_activate, cfgmap_from_fabric) # Delete zones ~sk. if zones_to_delete: zone_name_string = '' num_zones = len(zones_to_delete) for i in range(0, num_zones): if i == 0: zone_name_string = ( '%s%s' % ( zone_name_string, zones_to_delete[i])) else: zone_name_string = '%s%s%s' % ( zone_name_string, ';', zones_to_delete[i]) conn.delete_zones( zone_name_string, self.configuration.zone_activate, cfgmap_from_fabric) conn.cleanup() except Exception as e: LOG.error(e) msg = _("Failed to update or delete zoning configuration") raise exception.FCZoneDriverException(msg)
def add_connection(self, fabric, initiator_target_map, host_name=None, storage_system=None): """Concrete implementation of add_connection. Based on zoning policy and state of each I-T pair, list of zone members are created and pushed to the fabric to add zones. The new zones created or zones updated are activated based on isActivate flag set in cinder.conf returned by volume driver after attach operation. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.info("BrcdFCZoneDriver - Add connection for fabric " "%(fabric)s for I-T map: %(i_t_map)s", {'fabric': fabric, 'i_t_map': initiator_target_map}) zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'zoning_policy') zone_name_prefix = self.fabric_configs[fabric].safe_get( 'zone_name_prefix') zone_activate = self.fabric_configs[fabric].safe_get( 'zone_activate') if zoning_policy_fab: zoning_policy = zoning_policy_fab LOG.info("Zoning policy for Fabric %(policy)s", {'policy': zoning_policy}) if (zoning_policy != 'initiator' and zoning_policy != 'initiator-target'): LOG.info("Zoning policy is not valid, " "no zoning will be performed.") return client = self._get_southbound_client(fabric) cfgmap_from_fabric = self._get_active_zone_set(client) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # based on zoning policy, create zone member list and # push changes to fabric. for initiator_key in initiator_target_map.keys(): zone_map = {} zone_update_map = {} initiator = initiator_key.lower() target_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': for target in target_list: zone_members = [utils.get_formatted_wwn(initiator), utils.get_formatted_wwn(target)] zone_name = driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS) if (len(cfgmap_from_fabric) == 0 or ( zone_name not in zone_names)): zone_map[zone_name] = zone_members else: # This is I-T zoning, skip if zone already exists. LOG.info("Zone exists in I-T mode. Skipping " "zone creation for %(zonename)s", {'zonename': zone_name}) elif zoning_policy == 'initiator': zone_members = [utils.get_formatted_wwn(initiator)] for target in target_list: zone_members.append(utils.get_formatted_wwn(target)) zone_name = driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS) # If zone exists, then do a zoneadd to update # the zone members in the existing zone. Otherwise, # do a zonecreate to create a new zone. if len(zone_names) > 0 and (zone_name in zone_names): # Verify that the target WWNs are not already members # of the existing zone. If so, remove them from the # list of members to add, otherwise error will be # returned from the switch. for t in target_list: if t in cfgmap_from_fabric['zones'][zone_name]: zone_members.remove(utils.get_formatted_wwn(t)) if zone_members: zone_update_map[zone_name] = zone_members else: zone_map[zone_name] = zone_members LOG.info("Zone map to create: %(zonemap)s", {'zonemap': zone_map}) LOG.info("Zone map to update: %(zone_update_map)s", {'zone_update_map': zone_update_map}) try: if zone_map: client.add_zones(zone_map, zone_activate, cfgmap_from_fabric) LOG.debug("Zones created successfully: %(zonemap)s", {'zonemap': zone_map}) if zone_update_map: client.update_zones(zone_update_map, zone_activate, fc_zone_constants.ZONE_ADD, cfgmap_from_fabric) LOG.debug("Zones updated successfully: %(updatemap)s", {'updatemap': zone_update_map}) except (exception.BrocadeZoningCliException, exception.BrocadeZoningHttpException, exception.BrocadeZoningRestException) as brocade_ex: raise exception.FCZoneDriverException(brocade_ex) except Exception: msg = _("Failed to add or update zoning configuration.") LOG.exception(msg) raise exception.FCZoneDriverException(msg) finally: client.cleanup()
def get_san_context(self, target_wwn_list): """Lookup SAN context for visible end devices. Look up each SAN configured and return a map of SAN (fabric IP) to list of target WWNs visible to the fabric. """ formatted_target_list = [] fabric_map = {} fabrics = [ x.strip() for x in self.configuration.fc_fabric_names.split(',') ] LOG.debug("Fabric List: %s", fabrics) LOG.debug("Target wwn List: %s", target_wwn_list) if len(fabrics) > 0: for t in target_wwn_list: formatted_target_list.append( zm_utils.get_formatted_wwn(t.lower())) LOG.debug("Formatted Target wwn List: %s", formatted_target_list) for fabric_name in fabrics: fabric_ip = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_address') fabric_user = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_user') fabric_pwd = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_password') fabric_port = self.fabric_configs[fabric_name].safe_get( 'cisco_fc_fabric_port') zoning_vsan = self.fabric_configs[fabric_name].safe_get( 'cisco_zoning_vsan') # Get name server data from fabric and get the targets # logged in. nsinfo = None try: conn = importutils.import_object( self.configuration.cisco_sb_connector, ipaddress=fabric_ip, username=fabric_user, password=fabric_pwd, port=fabric_port, vsan=zoning_vsan) nsinfo = conn.get_nameserver_info() LOG.debug("show fcns database info from fabric: %s", nsinfo) conn.cleanup() except c_exception.CiscoZoningCliException: with excutils.save_and_reraise_exception(): LOG.exception("Error getting show fcns database info.") except Exception: msg = _("Failed to get show fcns database info.") LOG.exception(msg) raise exception.FCZoneDriverException(msg) visible_targets = filter(lambda x: x in formatted_target_list, nsinfo) if visible_targets: LOG.info("Filtered targets for SAN is: %s", {fabric_name: visible_targets}) # getting rid of the ':' before returning for idx, elem in enumerate(visible_targets): visible_targets[idx] = six.text_type( visible_targets[idx]).replace(':', '') fabric_map[fabric_name] = visible_targets else: LOG.debug("No targets are in the fcns info for SAN %s", fabric_name) LOG.debug("Return SAN context output: %s", fabric_map) return fabric_map
def add_connection(self, fabric, initiator_target_map): """Concrete implementation of add_connection. Based on zoning policy and state of each I-T pair, list of zone members are created and pushed to the fabric to add zones. The new zones created or zones updated are activated based on isActivate flag set in cinder.conf returned by volume driver after attach operation. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.debug("Add connection for Fabric:%s", fabric) LOG.info(_("BrcdFCZoneDriver - Add connection " "for I-T map: %s"), initiator_target_map) zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'zoning_policy') if zoning_policy_fab: zoning_policy = zoning_policy_fab LOG.info(_("Zoning policy for Fabric %s"), zoning_policy) cli_client = self._get_cli_client(fabric) cfgmap_from_fabric = self._get_active_zone_set(cli_client) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # based on zoning policy, create zone member list and # push changes to fabric. for initiator_key in initiator_target_map.keys(): zone_map = {} initiator = initiator_key.lower() t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': for t in t_list: target = t.lower() zone_members = [self.get_formatted_wwn(initiator), self.get_formatted_wwn(target)] zone_name = (self.configuration.zone_name_prefix + initiator.replace(':', '') + target.replace(':', '')) if ( len(cfgmap_from_fabric) == 0 or ( zone_name not in zone_names)): zone_map[zone_name] = zone_members else: # This is I-T zoning, skip if zone already exists. LOG.info(_("Zone exists in I-T mode. " "Skipping zone creation %s"), zone_name) elif zoning_policy == 'initiator': zone_members = [self.get_formatted_wwn(initiator)] for t in t_list: target = t.lower() zone_members.append(self.get_formatted_wwn(target)) zone_name = self.configuration.zone_name_prefix \ + initiator.replace(':', '') if len(zone_names) > 0 and (zone_name in zone_names): zone_members = zone_members + filter( lambda x: x not in zone_members, cfgmap_from_fabric['zones'][zone_name]) zone_map[zone_name] = zone_members else: msg = _("Zoning Policy: %s, not " "recognized") % zoning_policy LOG.error(msg) raise exception.FCZoneDriverException(msg) LOG.info(_("Zone map to add: %s"), zone_map) if len(zone_map) > 0: try: cli_client.add_zones( zone_map, self.configuration.zone_activate, cfgmap_from_fabric) cli_client.cleanup() except exception.BrocadeZoningCliException as brocade_ex: raise exception.FCZoneDriverException(brocade_ex) except Exception as e: LOG.error(e) msg = _("Failed to add zoning configuration %s") % e raise exception.FCZoneDriverException(msg) LOG.debug("Zones added successfully: %s", zone_map)
def add_connection(self, fabric, initiator_target_map, host_name=None, storage_system=None): """Concrete implementation of add_connection. Based on zoning policy and state of each I-T pair, list of zone members are created and pushed to the fabric to add zones. The new zones created or zones updated are activated based on isActivate flag set in cinder.conf returned by volume driver after attach operation. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.debug("Add connection for Fabric: %s", fabric) LOG.info("CiscoFCZoneDriver - Add connection " "for I-T map: %s", initiator_target_map) fabric_ip = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_address') fabric_user = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_user') fabric_pwd = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_password') fabric_port = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_port') zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'cisco_zoning_policy') if zoning_policy_fab: zoning_policy = zoning_policy_fab zone_name_prefix = self.fabric_configs[fabric].safe_get( 'cisco_zone_name_prefix') if not zone_name_prefix: zone_name_prefix = self.configuration.cisco_zone_name_prefix zoning_vsan = self.fabric_configs[fabric].safe_get('cisco_zoning_vsan') LOG.info("Zoning policy for Fabric %s", zoning_policy) statusmap_from_fabric = self.get_zoning_status(fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) if statusmap_from_fabric.get('session') == 'none': cfgmap_from_fabric = self.get_active_zone_set( fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # based on zoning policy, create zone member list and # push changes to fabric. for initiator_key in initiator_target_map.keys(): zone_map = {} zone_update_map = {} initiator = initiator_key.lower() t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': for t in t_list: target = t.lower() zone_members = [ zm_utils.get_formatted_wwn(initiator), zm_utils.get_formatted_wwn(target) ] zone_name = (driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS)) if (len(cfgmap_from_fabric) == 0 or (zone_name not in zone_names)): zone_map[zone_name] = zone_members else: # This is I-T zoning, skip if zone exists. LOG.info( "Zone exists in I-T mode. " "Skipping zone creation %s", zone_name) elif zoning_policy == 'initiator': zone_members = [zm_utils.get_formatted_wwn(initiator)] for t in t_list: target = t.lower() zone_members.append(zm_utils.get_formatted_wwn(target)) zone_name = (driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS)) # If zone exists, then perform an update_zone and add # new members into existing zone. if zone_name and (zone_name in zone_names): zone_members = filter( lambda x: x not in cfgmap_from_fabric['zones'][ zone_name], zone_members) if zone_members: zone_update_map[zone_name] = zone_members else: zone_map[zone_name] = zone_members else: msg = _("Zoning Policy: %s, not" " recognized") % zoning_policy LOG.error(msg) raise exception.FCZoneDriverException(msg) LOG.info("Zone map to add: %(zone_map)s", {'zone_map': zone_map}) LOG.info("Zone map to update add: %(zone_update_map)s", {'zone_update_map': zone_update_map}) if zone_map or zone_update_map: conn = None try: conn = importutils.import_object( self.configuration.cisco_sb_connector, ipaddress=fabric_ip, username=fabric_user, password=fabric_pwd, port=fabric_port, vsan=zoning_vsan) if zone_map: conn.add_zones(zone_map, self.configuration.cisco_zone_activate, zoning_vsan, cfgmap_from_fabric, statusmap_from_fabric) if zone_update_map: conn.update_zones( zone_update_map, self.configuration.cisco_zone_activate, zoning_vsan, ZoneConstant.ZONE_ADD, cfgmap_from_fabric, statusmap_from_fabric) conn.cleanup() except c_exception.CiscoZoningCliException as cisco_ex: msg = _("Exception: %s") % six.text_type(cisco_ex) raise exception.FCZoneDriverException(msg) except Exception: msg = _("Failed to add zoning configuration.") LOG.exception(msg) raise exception.FCZoneDriverException(msg) LOG.debug("Zones added successfully: %s", zone_map) else: LOG.debug("Zones already exist - Initiator Target Map: %s", initiator_target_map) else: LOG.debug("Zoning session exists VSAN: %s", zoning_vsan)
def delete_connection(self, fabric, initiator_target_map, host_name=None, storage_system=None): """Concrete implementation of delete_connection. Based on zoning policy and state of each I-T pair, list of zones are created for deletion. The zones are either updated deleted based on the policy and attach/detach state of each I-T pair. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.debug("Delete connection for fabric: %s", fabric) LOG.info("CiscoFCZoneDriver - Delete connection for I-T map: %s", initiator_target_map) fabric_ip = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_address') fabric_user = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_user') fabric_pwd = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_password') fabric_port = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_port') zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'cisco_zoning_policy') zone_name_prefix = self.fabric_configs[fabric].safe_get( 'cisco_zone_name_prefix') if not zone_name_prefix: zone_name_prefix = self.configuration.cisco_zone_name_prefix if zoning_policy_fab: zoning_policy = zoning_policy_fab zoning_vsan = self.fabric_configs[fabric].safe_get('cisco_zoning_vsan') LOG.info("Zoning policy for fabric %s", zoning_policy) statusmap_from_fabric = self.get_zoning_status(fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) if statusmap_from_fabric.get('session') == 'none': cfgmap_from_fabric = self.get_active_zone_set( fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # Based on zoning policy, get zone member list and push # changes to fabric. This operation could result in an update # for zone config with new member list or deleting zones from # active cfg. LOG.debug("zone config from Fabric: %s", cfgmap_from_fabric) for initiator_key in initiator_target_map.keys(): initiator = initiator_key.lower() formatted_initiator = zm_utils.get_formatted_wwn(initiator) zone_update_map = {} zones_to_delete = [] t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': # In this case, zone needs to be deleted. for t in t_list: target = t.lower() zone_name = (driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS)) LOG.debug("Zone name to del: %s", zone_name) if (len(zone_names) > 0 and (zone_name in zone_names)): # delete zone. LOG.debug("Added zone to delete to list: %s", zone_name) zones_to_delete.append(zone_name) elif zoning_policy == 'initiator': zone_members = [formatted_initiator] for t in t_list: target = t.lower() zone_members.append(zm_utils.get_formatted_wwn(target)) zone_name = driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS) # Check if there are zone members leftover after removal if (zone_names and (zone_name in zone_names)): filtered_members = filter( lambda x: x not in zone_members, cfgmap_from_fabric['zones'][zone_name]) # The assumption here is that initiator is always # there in the zone as it is 'initiator' policy. # If filtered list is empty, we remove that zone. # If there are other members leftover, then perform # update_zone to remove targets LOG.debug("Zone delete - I mode: filtered targets: %s", filtered_members) if filtered_members: remove_members = filter( lambda x: x in cfgmap_from_fabric['zones'][ zone_name], zone_members) if remove_members: # Do not want to remove the initiator remove_members.remove(formatted_initiator) LOG.debug("Zone members to remove: %s", remove_members) zone_update_map[zone_name] = remove_members LOG.debug("Filtered zone Map to update: %s", zone_update_map) else: zones_to_delete.append(zone_name) else: LOG.info("Zoning Policy: %s, not recognized", zoning_policy) LOG.debug("Zone map to remove update: %s", zone_update_map) LOG.debug("Final Zone list to delete: %s", zones_to_delete) conn = None try: conn = importutils.import_object( self.configuration.cisco_sb_connector, ipaddress=fabric_ip, username=fabric_user, password=fabric_pwd, port=fabric_port, vsan=zoning_vsan) # Update zone membership. if zone_update_map: conn.update_zones( zone_update_map, self.configuration.cisco_zone_activate, zoning_vsan, ZoneConstant.ZONE_REMOVE, cfgmap_from_fabric, statusmap_from_fabric) # Delete zones ~sk. if zones_to_delete: zone_name_string = '' num_zones = len(zones_to_delete) for i in range(0, num_zones): if i == 0: zone_name_string = ( '%s%s' % (zone_name_string, zones_to_delete[i])) else: zone_name_string = ('%s%s%s' % (zone_name_string, ';', zones_to_delete[i])) conn.delete_zones( zone_name_string, self.configuration.cisco_zone_activate, zoning_vsan, cfgmap_from_fabric, statusmap_from_fabric) conn.cleanup() except Exception: msg = _("Failed to update or delete zoning configuration") LOG.exception(msg) raise exception.FCZoneDriverException(msg) LOG.debug("Zones deleted successfully: %s", zone_update_map) else: LOG.debug("Zoning session exists VSAN: %s", zoning_vsan)
def get_san_context(self, target_wwn_list): """Lookup SAN context for visible end devices. Look up each SAN configured and return a map of SAN (fabric IP) to list of target WWNs visible to the fabric. """ # TODO(Santhosh Kolathur): consider refactoring to use lookup service. formatted_target_list = [] fabric_map = {} fc_fabric_names = self.configuration.fc_fabric_names fabrics = [x.strip() for x in fc_fabric_names.split(',')] LOG.debug("Fabric List: %s", fabrics) LOG.debug("Target wwn List: %s", target_wwn_list) if len(fabrics) > 0: for t in target_wwn_list: formatted_target_list.append(self.get_formatted_wwn(t.lower())) LOG.debug("Formatted Target wwn List:" " %s", formatted_target_list) for fabric_name in fabrics: fabric_ip = self.fabric_configs[fabric_name].safe_get( 'fc_fabric_address') fabric_user = self.fabric_configs[fabric_name].safe_get( 'fc_fabric_user') fabric_pwd = self.fabric_configs[fabric_name].safe_get( 'fc_fabric_password') fabric_port = self.fabric_configs[fabric_name].safe_get( 'fc_fabric_port') conn = None try: conn = importutils.import_object( self.configuration.brcd_sb_connector, ipaddress=fabric_ip, username=fabric_user, password=fabric_pwd, port=fabric_port) if not conn.is_supported_firmware(): msg = _("Unsupported firmware on switch %s. Make sure " "switch is running firmware v6.4 or higher" ) % fabric_ip LOG.error(msg) raise exception.FCZoneDriverException(msg) except exception.BrocadeZoningCliException as brocade_ex: raise exception.FCZoneDriverException(brocade_ex) except Exception as e: LOG.error(e) msg = _("Failed to get SAN context %s") % e raise exception.FCZoneDriverException(msg) # Get name server data from fabric and get the targets # logged in. nsinfo = None try: nsinfo = conn.get_nameserver_info() LOG.debug("name server info from fabric:%s", nsinfo) conn.cleanup() except exception.BrocadeZoningCliException as ex: with excutils.save_and_reraise_exception(): LOG.error(_("Error getting name server " "info: %s"), ex) except Exception as e: msg = (_("Failed to get name server info:%s") % e) LOG.error(msg) raise exception.FCZoneDriverException(msg) visible_targets = filter( lambda x: x in formatted_target_list, nsinfo) if visible_targets: LOG.info(_("Filtered targets for SAN is: %s"), {fabric_name: visible_targets}) # getting rid of the ':' before returning for idx, elem in enumerate(visible_targets): visible_targets[idx] = str( visible_targets[idx]).replace(':', '') fabric_map[fabric_name] = visible_targets else: LOG.debug("No targets are in the nameserver for SAN %s", fabric_name) LOG.debug("Return SAN context output:%s", fabric_map) return fabric_map
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 .. code-block:: python { 'zones': {'openstack50060b0000c26604201900051ee8e329': ['50060b0000c26604', '201900051ee8e329'] }, 'active_zone_config': 'OpenStack_Cfg' } """ zone_set = {} zone = {} zone_member = None zone_name = None switch_data = None zone_set_name = None try: switch_data = self._get_switch_info([ ZoneConstant.GET_ACTIVE_ZONE_CFG, self.fabric_vsan, ' | no-more' ]) except exception.CiscoZoningCliException: with excutils.save_and_reraise_exception(): LOG.error("Failed getting active zone set " "from fabric %s", self.switch_ip) try: for line in switch_data: # Split on non-word characters, line_split = re.split('[\s\[\]]+', line) if ZoneConstant.CFG_ZONESET in line_split: # zoneset name [name] vsan [vsan] zone_set_name = \ line_split[line_split.index(ZoneConstant.CFG_ZONESET) + 2] continue if ZoneConstant.CFG_ZONE in line_split: # zone name [name] vsan [vsan] zone_name = \ line_split[line_split.index(ZoneConstant.CFG_ZONE) + 2] zone[zone_name] = list() continue if ZoneConstant.CFG_ZONE_MEMBER in line_split: # Examples: # pwwn c0:50:76:05:15:9f:00:12 # * fcid 0x1e01c0 [pwwn 50:05:07:68:02:20:48:04] [V7K_N1P2] zone_member = \ line_split[ line_split.index(ZoneConstant.CFG_ZONE_MEMBER) + 1] zone_member_list = zone.get(zone_name) zone_member_list.append(zone_member) zone_set[ZoneConstant.CFG_ZONES] = zone zone_set[ZoneConstant.ACTIVE_ZONE_CONFIG] = zone_set_name except Exception as ex: # In case of parsing error here, it should be malformed cli output. msg = _("Malformed zone configuration: (switch=%(switch)s " "zone_config=%(zone_config)s).") % { 'switch': self.switch_ip, 'zone_config': switch_data } LOG.error(msg) exc_msg = _("Exception: %s") % six.text_type(ex) LOG.error(exc_msg) raise exception.FCZoneDriverException(reason=msg) return zone_set
def delete_connection(self, fabric, initiator_target_map): """Concrete implementation of delete_connection. Based on zoning policy and state of each I-T pair, list of zones are created for deletion. The zones are either updated deleted based on the policy and attach/detach state of each I-T pair. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.debug("Delete connection for fabric:%s", fabric) LOG.info(_LI("CiscoFCZoneDriver - Delete connection for I-T map: %s"), initiator_target_map) fabric_ip = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_address') fabric_user = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_user') fabric_pwd = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_password') fabric_port = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_port') zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'cisco_zoning_policy') if zoning_policy_fab: zoning_policy = zoning_policy_fab zoning_vsan = self.fabric_configs[fabric].safe_get('cisco_zoning_vsan') LOG.info(_LI("Zoning policy for fabric %s"), zoning_policy) statusmap_from_fabric = self.get_zoning_status(fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) if statusmap_from_fabric.get('session') == 'none': cfgmap_from_fabric = self.get_active_zone_set( fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # Based on zoning policy, get zone member list and push # changes to fabric. This operation could result in an update # for zone config with new member list or deleting zones from # active cfg. LOG.debug("zone config from Fabric: %s", cfgmap_from_fabric) for initiator_key in initiator_target_map.keys(): initiator = initiator_key.lower() formatted_initiator = get_formatted_wwn(initiator) zone_map = {} zones_to_delete = [] t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': # In this case, zone needs to be deleted. for t in t_list: target = t.lower() zone_name = ( self.configuration.cisco_zone_name_prefix + initiator.replace(':', '') + target.replace(':', '')) LOG.debug("Zone name to del: %s", zone_name) if (len(zone_names) > 0 and (zone_name in zone_names)): # delete zone. LOG.debug("Added zone to delete to list: %s", zone_name) zones_to_delete.append(zone_name) elif zoning_policy == 'initiator': zone_members = [formatted_initiator] for t in t_list: target = t.lower() zone_members.append(get_formatted_wwn(target)) zone_name = self.configuration.cisco_zone_name_prefix \ + initiator.replace(':', '') if (zone_names and (zone_name in zone_names)): filtered_members = filter( lambda x: x not in zone_members, cfgmap_from_fabric['zones'][zone_name]) # The assumption here is that initiator is always # there in the zone as it is 'initiator' policy. # We find the filtered list and if it is non-empty, # add initiator to it and update zone if filtered # list is empty, we remove that zone. LOG.debug("Zone delete - I mode: filtered targets:%s", filtered_members) if filtered_members: filtered_members.append(formatted_initiator) LOG.debug("Filtered zone members to update: %s", filtered_members) zone_map[zone_name] = filtered_members LOG.debug("Filtered zone Map to update: %s", zone_map) else: zones_to_delete.append(zone_name) else: LOG.info(_LI("Zoning Policy: %s, not recognized"), zoning_policy) LOG.debug("Final Zone map to update: %s", zone_map) LOG.debug("Final Zone list to delete: %s", zones_to_delete) conn = None try: conn = importutils.import_object( self.configuration.cisco_sb_connector, ipaddress=fabric_ip, username=fabric_user, password=fabric_pwd, port=fabric_port, vsan=zoning_vsan) # Update zone membership. if zone_map: conn.add_zones(zone_map, self.configuration.cisco_zone_activate, zoning_vsan, cfgmap_from_fabric, statusmap_from_fabric) # Delete zones ~sk. if zones_to_delete: zone_name_string = '' num_zones = len(zones_to_delete) for i in range(0, num_zones): if i == 0: zone_name_string = ( '%s%s' % (zone_name_string, zones_to_delete[i])) else: zone_name_string = ('%s%s%s' % (zone_name_string, ';', zones_to_delete[i])) conn.delete_zones( zone_name_string, self.configuration.cisco_zone_activate, zoning_vsan, cfgmap_from_fabric, statusmap_from_fabric) conn.cleanup() except Exception as e: msg = _("Exception: %s") % six.text_type(e) LOG.error(msg) msg = _("Failed to update or delete zoning configuration") raise exception.FCZoneDriverException(msg) LOG.debug("Zones deleted successfully: %s", zone_map) else: LOG.debug("Zoning session exists VSAN: %s", zoning_vsan)
def add_connection(self, fabric, initiator_target_map): """Concrete implementation of add_connection. Based on zoning policy and state of each I-T pair, list of zone members are created and pushed to the fabric to add zones. The new zones created or zones updated are activated based on isActivate flag set in cinder.conf returned by volume driver after attach operation. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.debug("Add connection for Fabric:%s", fabric) LOG.info(_LI("CiscoFCZoneDriver - Add connection " "for I-T map: %s"), initiator_target_map) fabric_ip = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_address') fabric_user = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_user') fabric_pwd = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_password') fabric_port = self.fabric_configs[fabric].safe_get( 'cisco_fc_fabric_port') zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'cisco_zoning_policy') if zoning_policy_fab: zoning_policy = zoning_policy_fab zoning_vsan = self.fabric_configs[fabric].safe_get('cisco_zoning_vsan') LOG.info(_LI("Zoning policy for Fabric %s"), zoning_policy) statusmap_from_fabric = self.get_zoning_status(fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) if statusmap_from_fabric.get('session') == 'none': cfgmap_from_fabric = self.get_active_zone_set( fabric_ip, fabric_user, fabric_pwd, fabric_port, zoning_vsan) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # based on zoning policy, create zone member list and # push changes to fabric. for initiator_key in initiator_target_map.keys(): zone_map = {} initiator = initiator_key.lower() t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': for t in t_list: target = t.lower() zone_members = [ get_formatted_wwn(initiator), get_formatted_wwn(target) ] zone_name = ( self.configuration.cisco_zone_name_prefix + initiator.replace(':', '') + target.replace(':', '')) if (len(cfgmap_from_fabric) == 0 or (zone_name not in zone_names)): zone_map[zone_name] = zone_members else: # This is I-T zoning, skip if zone exists. LOG.info( _LI("Zone exists in I-T mode. " "Skipping zone creation %s"), zone_name) elif zoning_policy == 'initiator': zone_members = [get_formatted_wwn(initiator)] for t in t_list: target = t.lower() zone_members.append(get_formatted_wwn(target)) zone_name = self.configuration.cisco_zone_name_prefix \ + initiator.replace(':', '') if len(zone_names) > 0 and (zone_name in zone_names): zone_members = zone_members + filter( lambda x: x not in zone_members, cfgmap_from_fabric['zones'][zone_name]) zone_map[zone_name] = zone_members else: msg = _("Zoning Policy: %s, not" " recognized") % zoning_policy LOG.error(msg) raise exception.FCZoneDriverException(msg) LOG.info(_LI("Zone map to add: %s"), zone_map) if len(zone_map) > 0: conn = None try: conn = importutils.import_object( self.configuration.cisco_sb_connector, ipaddress=fabric_ip, username=fabric_user, password=fabric_pwd, port=fabric_port, vsan=zoning_vsan) conn.add_zones(zone_map, self.configuration.cisco_zone_activate, zoning_vsan, cfgmap_from_fabric, statusmap_from_fabric) conn.cleanup() except exception.CiscoZoningCliException as cisco_ex: msg = _("Exception: %s") % six.text_type(cisco_ex) raise exception.FCZoneDriverException(msg) except Exception as e: LOG.error(_LE("Exception: %s") % six.text_type(e)) msg = (_("Failed to add zoning configuration %s") % six.text_type(e)) raise exception.FCZoneDriverException(msg) LOG.debug("Zones added successfully: %s", zone_map) else: LOG.debug("Zoning session exists VSAN: %s", zoning_vsan)
def delete_connection(self, fabric, initiator_target_map, host_name=None, storage_system=None): """Concrete implementation of delete_connection. Based on zoning policy and state of each I-T pair, list of zones are created for deletion. The zones are either updated deleted based on the policy and attach/detach state of each I-T pair. :param fabric: Fabric name from cinder.conf file :param initiator_target_map: Mapping of initiator to list of targets """ LOG.info(_LI("BrcdFCZoneDriver - Delete connection for fabric " "%(fabric)s for I-T map: %(i_t_map)s"), {'fabric': fabric, 'i_t_map': initiator_target_map}) zoning_policy = self.configuration.zoning_policy zoning_policy_fab = self.fabric_configs[fabric].safe_get( 'zoning_policy') zone_name_prefix = self.fabric_configs[fabric].safe_get( 'zone_name_prefix') zone_activate = self.fabric_configs[fabric].safe_get( 'zone_activate') if zoning_policy_fab: zoning_policy = zoning_policy_fab LOG.info(_LI("Zoning policy for fabric %(policy)s"), {'policy': zoning_policy}) conn = self._get_southbound_client(fabric) cfgmap_from_fabric = self._get_active_zone_set(conn) zone_names = [] if cfgmap_from_fabric.get('zones'): zone_names = cfgmap_from_fabric['zones'].keys() # Based on zoning policy, get zone member list and push changes to # fabric. This operation could result in an update for zone config # with new member list or deleting zones from active cfg. LOG.debug("zone config from Fabric: %(cfgmap)s", {'cfgmap': cfgmap_from_fabric}) for initiator_key in initiator_target_map.keys(): initiator = initiator_key.lower() formatted_initiator = utils.get_formatted_wwn(initiator) zone_map = {} zones_to_delete = [] t_list = initiator_target_map[initiator_key] if zoning_policy == 'initiator-target': # In this case, zone needs to be deleted. for t in t_list: target = t.lower() zone_name = driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS) LOG.debug("Zone name to delete: %(zonename)s", {'zonename': zone_name}) if len(zone_names) > 0 and (zone_name in zone_names): # delete zone. LOG.debug("Added zone to delete to list: %(zonename)s", {'zonename': zone_name}) zones_to_delete.append(zone_name) elif zoning_policy == 'initiator': zone_members = [formatted_initiator] for t in t_list: target = t.lower() zone_members.append(utils.get_formatted_wwn(target)) zone_name = driver_utils.get_friendly_zone_name( zoning_policy, initiator, target, host_name, storage_system, zone_name_prefix, SUPPORTED_CHARS) if (zone_names and (zone_name in zone_names)): filtered_members = filter( lambda x: x not in zone_members, cfgmap_from_fabric['zones'][zone_name]) # The assumption here is that initiator is always there # in the zone as it is 'initiator' policy. We find the # filtered list and if it is non-empty, add initiator # to it and update zone if filtered list is empty, we # remove that zone. LOG.debug("Zone delete - initiator mode: " "filtered targets: %(targets)s", {'targets': filtered_members}) if filtered_members: filtered_members.append(formatted_initiator) LOG.debug("Filtered zone members to update: " "%(members)s", {'members': filtered_members}) zone_map[zone_name] = filtered_members LOG.debug("Filtered zone map to update: %(zonemap)s", {'zonemap': zone_map}) else: zones_to_delete.append(zone_name) else: LOG.warning(_LW("Zoning policy not recognized: %(policy)s"), {'policy': zoning_policy}) LOG.debug("Final zone map to update: %(zonemap)s", {'zonemap': zone_map}) LOG.debug("Final zone list to delete: %(zones)s", {'zones': zones_to_delete}) try: # Update zone membership. if zone_map: conn.add_zones( zone_map, zone_activate, cfgmap_from_fabric) # Delete zones ~sk. if zones_to_delete: zone_name_string = '' num_zones = len(zones_to_delete) for i in range(0, num_zones): if i == 0: zone_name_string = ( '%s%s' % ( zone_name_string, zones_to_delete[i])) else: zone_name_string = '%s;%s' % ( zone_name_string, zones_to_delete[i]) conn.delete_zones( zone_name_string, zone_activate, cfgmap_from_fabric) conn.cleanup() except (exception.BrocadeZoningCliException, exception.BrocadeZoningHttpException) as brocade_ex: raise exception.FCZoneDriverException(brocade_ex) except Exception: msg = _("Failed to update or delete zoning " "configuration.") LOG.exception(msg) raise exception.FCZoneDriverException(msg)