def update_consistencygroup(self, context, group,
                                add_volumes, remove_volumes):
        LOG.info(_LI("Update Consistency Group: %(group)s. "
                     "This adds or removes volumes from a CG."),
                 {'group': group['id']})

        metrogroup_id = self.check_consistencygroup_need_to_stop(group)
        if not metrogroup_id:
            msg = _("The CG does not exist on array.")
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)

        # Deal with add volumes to CG
        for volume in add_volumes:
            metadata = huawei_utils.get_lun_metadata(volume)
            if not metadata.get('hypermetro'):
                err_msg = _("Volume %s is not in hypermetro pair.") % volume.id
                LOG.error(err_msg)
                raise exception.VolumeBackendAPIException(data=err_msg)

            lun_name = huawei_utils.encode_name(volume.id)
            hypermetro = self.client.get_hypermetro_by_lun_name(lun_name)
            if not hypermetro:
                err_msg = _("Volume %s is not in hypermetro pair.") % volume.id
                LOG.error(err_msg)
                raise exception.VolumeBackendAPIException(data=err_msg)

            metro_id = hypermetro['ID']
            if not self._check_metro_in_cg(metro_id, metrogroup_id):
                self.check_metro_need_to_stop(metro_id)
                self.client.add_metro_to_metrogroup(metrogroup_id,
                                                    metro_id)
                self._ensure_hypermetro_added_to_cg(
                    metro_id, metrogroup_id)

        # Deal with remove volumes from CG
        for volume in remove_volumes:
            metadata = huawei_utils.get_lun_metadata(volume)
            if not metadata.get('hypermetro'):
                continue

            lun_name = huawei_utils.encode_name(volume.id)
            hypermetro = self.client.get_hypermetro_by_lun_name(lun_name)
            if not hypermetro:
                continue

            metro_id = hypermetro['ID']
            if self._check_metro_in_cg(metro_id, metrogroup_id):
                self.check_metro_need_to_stop(metro_id)
                self.client.remove_metro_from_metrogroup(metrogroup_id,
                                                         metro_id)
                self._ensure_hypermetro_removed_from_cg(
                    metro_id, metrogroup_id)
                self.client.sync_hypermetro(metro_id)

        new_group_info = self.client.get_metrogroup_by_id(metrogroup_id)
        is_empty = new_group_info["ISEMPTY"]
        if is_empty == 'false':
            self.client.sync_metrogroup(metrogroup_id)
Exemple #2
0
    def update_consistencygroup(self, context, group, add_volumes,
                                remove_volumes):
        LOG.info(
            _LI("Update Consistency Group: %(group)s. "
                "This adds or removes volumes from a CG."),
            {'group': group['id']})
        model_update = {}
        model_update['status'] = group['status']
        metrogroup_id = self.check_consistencygroup_need_to_stop(group)
        if metrogroup_id:
            # Deal with add volumes to CG
            for volume in add_volumes:
                metadata = huawei_utils.get_lun_metadata(volume)
                metro_id = metadata.get('hypermetro_id')
                if metro_id and self.client.check_hypermetro_exist(metro_id):
                    if not self._check_metro_in_cg(metro_id, metrogroup_id):
                        self.check_metro_need_to_stop(metro_id)
                        self.client.add_metro_to_metrogroup(
                            metrogroup_id, metro_id)
                        self._ensure_hypermetro_added_to_cg(
                            metro_id, metrogroup_id)
                else:
                    err_msg = _("Hypermetro pair doesn't exist on array.")
                    LOG.error(err_msg)
                    raise exception.VolumeBackendAPIException(data=err_msg)

            # Deal with remove volumes from CG
            for volume in remove_volumes:
                metadata = huawei_utils.get_lun_metadata(volume)
                metro_id = metadata.get('hypermetro_id')
                if metro_id and self.client.check_hypermetro_exist(metro_id):
                    if self._check_metro_in_cg(metro_id, metrogroup_id):
                        self.check_metro_need_to_stop(metro_id)
                        self.client.remove_metro_from_metrogroup(
                            metrogroup_id, metro_id)
                        self._ensure_hypermetro_removed_from_cg(
                            metro_id, metrogroup_id)
                        self.client.sync_hypermetro(metro_id)
                else:
                    err_msg = _("Hypermetro pair doesn't exist on array.")
                    LOG.error(err_msg)
                    raise exception.VolumeBackendAPIException(data=err_msg)

            new_group_info = self.client.get_metrogroup_by_id(metrogroup_id)
            is_empty = new_group_info["ISEMPTY"]
            if is_empty == 'false':
                self.client.sync_metrogroup(metrogroup_id)

        # if CG not exist on array
        else:
            msg = _("The CG does not exist on array.")
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)
    def delete_consistencygroup(self, context, group, volumes):
        LOG.info(_LI("Delete Consistency Group: %(group)s."),
                 {'group': group['id']})
        metrogroup_id = self.check_consistencygroup_need_to_stop(group)
        if not metrogroup_id:
            return

        # Remove pair from metrogroup.
        for volume in volumes:
            metadata = huawei_utils.get_lun_metadata(volume)
            if not metadata.get('hypermetro'):
                continue

            lun_name = huawei_utils.encode_name(volume.id)
            hypermetro = self.client.get_hypermetro_by_lun_name(lun_name)
            if not hypermetro:
                continue

            metro_id = hypermetro['ID']
            if self._check_metro_in_cg(metro_id, metrogroup_id):
                self.client.remove_metro_from_metrogroup(
                    metrogroup_id, metro_id)

        # Delete metrogroup.
        self.client.delete_metrogroup(metrogroup_id)
    def failover(self, volumes):
        """Failover volumes back to secondary array.

        Split the replication pairs and make the secondary LUNs R&W.
        """
        volumes_update = []
        cgid_list = set()
        replicacg = ReplicaCG(self.local_client, self.rmt_client, self.conf)
        for v in volumes:
            v_update = {}
            v_update['volume_id'] = v.id
            drv_data = get_replication_driver_data(v)
            pair_id = drv_data.get('pair_id')
            if not pair_id:
                LOG.warning(_LW("No pair id in volume %s."), v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            rmt_lun_id = drv_data.get('rmt_lun_id')
            if not rmt_lun_id:
                LOG.warning(_LW("No remote lun id in volume %s."), v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            replica_info = self.rmt_op.get_replica_info(pair_id)
            consisgroup_id = replica_info.get('CGID')
            if consisgroup_id:
                if consisgroup_id not in cgid_list:
                    replicacg.failover(consisgroup_id)
                    cgid_list.add(consisgroup_id)
            else:
                self.rmt_driver.failover(pair_id)

            local_metadata = huawei_utils.get_lun_metadata(v)
            new_drv_data = to_string({
                'pair_id':
                pair_id,
                'huawei_sn':
                local_metadata.get('huawei_sn'),
                'rmt_lun_id':
                local_metadata.get('huawei_lun_id'),
                'rmt_lun_wwn':
                local_metadata.get('huawei_lun_wwn')
            })
            location = huawei_utils.to_string(
                huawei_lun_id=rmt_lun_id,
                huawei_sn=drv_data.get('huawei_sn'),
                huawei_lun_wwn=drv_data.get('rmt_lun_wwn'))

            v_update['updates'] = {
                'provider_location': location,
                'replication_status': 'failed-over',
                'replication_driver_data': new_drv_data
            }
            volumes_update.append(v_update)

        return volumes_update
    def failback(self, volumes):
        """Failover volumes back to primary backend.

        The main steps:
        1. Switch the role of replication pairs.
        2. Copy the second LUN data back to primary LUN.
        3. Split replication pairs.
        4. Switch the role of replication pairs.
        5. Enable replications.
        """
        volumes_update = []
        for v in volumes:
            v_update = {}
            v_update['volume_id'] = v.id
            drv_data = get_replication_driver_data(v)
            pair_id = drv_data.get('pair_id')
            if not pair_id:
                LOG.warning("No pair id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            rmt_lun_id = drv_data.get('rmt_lun_id')
            if not rmt_lun_id:
                LOG.warning("No remote lun id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            # Switch replication pair role, and start synchronize.
            self.local_driver.enable(pair_id)

            # Wait for synchronize complete.
            self.local_driver.wait_replica_ready(pair_id)

            # Split replication pair again
            self.rmt_driver.failover(pair_id)

            # Switch replication pair role, and start synchronize.
            self.rmt_driver.enable(pair_id)

            local_metadata = huawei_utils.get_lun_metadata(v)
            new_drv_data = to_string(
                {'pair_id': pair_id,
                 'rmt_lun_id': local_metadata.get('huawei_lun_id'),
                 'rmt_lun_wwn': local_metadata.get('huawei_lun_wwn')})
            location = huawei_utils.to_string(
                huawei_lun_id=rmt_lun_id,
                huawei_lun_wwn=drv_data.get('rmt_lun_wwn'))

            v_update['updates'] = {'provider_location': location,
                                   'replication_status': 'available',
                                   'replication_driver_data': new_drv_data}
            volumes_update.append(v_update)

        return volumes_update
    def delete_hypermetro(self, volume):
        """Delete hypermetro."""
        metadata = huawei_utils.get_lun_metadata(volume)
        metro_id = metadata['hypermetro_id']
        remote_lun_id = metadata['remote_lun_id']

        if metro_id:
            self.check_metro_need_to_stop(volume)

            # Delete hypermetro
            self.client.delete_hypermetro(metro_id)

        # Delete remote lun.
        if remote_lun_id and self.rmt_client.check_lun_exist(remote_lun_id):
            self.rmt_client.delete_lun(remote_lun_id)
Exemple #7
0
    def delete_hypermetro(self, volume):
        """Delete hypermetro."""
        metadata = huawei_utils.get_lun_metadata(volume)
        metro_id = metadata['hypermetro_id']
        remote_lun_id = metadata['remote_lun_id']

        if metro_id:
            self.check_metro_need_to_stop(volume)

            # Delete hypermetro
            self.client.delete_hypermetro(metro_id)

        # Delete remote lun.
        if remote_lun_id and self.rmt_client.check_lun_exist(remote_lun_id):
            self.rmt_client.delete_lun(remote_lun_id)
Exemple #8
0
    def check_metro_need_to_stop(self, volume):
        metadata = huawei_utils.get_lun_metadata(volume)
        metro_id = metadata['hypermetro_id']
        metro_existed = self.client.check_hypermetro_exist(metro_id)

        if metro_existed:
            metro_info = self.client.get_hypermetro_by_id(metro_id)
            metro_health_status = metro_info['HEALTHSTATUS']
            metro_running_status = metro_info['RUNNINGSTATUS']

            if (metro_health_status == constants.HEALTH_NORMAL
                    and (metro_running_status == constants.RUNNING_NORMAL
                         or metro_running_status == constants.RUNNING_SYNC)):
                self.client.stop_hypermetro(metro_id)

        return metro_id
    def delete_hypermetro(self, volume, metadata=None):
        """Delete hypermetro."""
        if not metadata:
            metadata = huawei_utils.get_lun_metadata(volume)

        metro_id = metadata.get('hypermetro_id')
        remote_lun_id = metadata.get('remote_lun_id')

        # Delete hypermetro.
        if metro_id and self.client.check_hypermetro_exist(metro_id):
            self.check_metro_need_to_stop(metro_id)
            self.client.delete_hypermetro(metro_id)

        # Delete remote lun.
        if remote_lun_id and self.rmt_client.check_lun_exist(remote_lun_id):
            self.rmt_client.delete_lun(remote_lun_id)
    def check_metro_need_to_stop(self, volume):
        metadata = huawei_utils.get_lun_metadata(volume)
        metro_id = metadata['hypermetro_id']
        metro_existed = self.client.check_hypermetro_exist(metro_id)

        if metro_existed:
            metro_info = self.client.get_hypermetro_by_id(metro_id)
            metro_health_status = metro_info['HEALTHSTATUS']
            metro_running_status = metro_info['RUNNINGSTATUS']

            if (metro_health_status == constants.HEALTH_NORMAL and
                (metro_running_status == constants.RUNNING_NORMAL or
                    metro_running_status == constants.RUNNING_SYNC)):
                self.client.stop_hypermetro(metro_id)

        return metro_id
    def failover(self, volumes):
        """Failover volumes back to secondary array.

        Split the replication pairs and make the secondary LUNs R&W.
        """
        volumes_update = []
        for v in volumes:
            v_update = {}
            v_update['volume_id'] = v.id
            drv_data = get_replication_driver_data(v)
            pair_id = drv_data.get('pair_id')
            if not pair_id:
                LOG.warning("No pair id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            rmt_lun_id = drv_data.get('rmt_lun_id')
            if not rmt_lun_id:
                LOG.warning("No remote lun id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            self.rmt_driver.failover(pair_id)

            local_metadata = huawei_utils.get_lun_metadata(v)
            new_drv_data = to_string({
                'pair_id':
                pair_id,
                'rmt_lun_id':
                local_metadata.get('huawei_lun_id'),
                'rmt_lun_wwn':
                local_metadata.get('huawei_lun_wwn')
            })
            location = huawei_utils.to_string(
                huawei_lun_id=rmt_lun_id,
                huawei_lun_wwn=drv_data.get('rmt_lun_wwn'))

            v_update['updates'] = {
                'provider_location': location,
                'replication_status': 'failed-over',
                'replication_driver_data': new_drv_data
            }
            volumes_update.append(v_update)

        return volumes_update
    def failover(self, volumes):
        """Failover volumes back to secondary array.

        Split the replication pairs and make the secondary LUNs R&W.
        """
        volumes_update = []
        for v in volumes:
            v_update = {}
            v_update['volume_id'] = v.id
            drv_data = get_replication_driver_data(v)
            pair_id = drv_data.get('pair_id')
            if not pair_id:
                LOG.warning("No pair id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            rmt_lun_id = drv_data.get('rmt_lun_id')
            if not rmt_lun_id:
                LOG.warning("No remote lun id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            self.rmt_driver.failover(pair_id)

            local_metadata = huawei_utils.get_lun_metadata(v)
            new_drv_data = to_string(
                {'pair_id': pair_id,
                 'rmt_lun_id': local_metadata.get('huawei_lun_id'),
                 'rmt_lun_wwn': local_metadata.get('huawei_lun_wwn')})
            location = huawei_utils.to_string(
                huawei_lun_id=rmt_lun_id,
                huawei_lun_wwn=drv_data.get('rmt_lun_wwn'))

            v_update['updates'] = {'provider_location': location,
                                   'replication_status': 'failed-over',
                                   'replication_driver_data': new_drv_data}
            volumes_update.append(v_update)

        return volumes_update
Exemple #13
0
    def disconnect_volume_fc(self, volume, connector):
        """Delete map between a volume and a host for FC."""
        wwns = connector['wwpns']
        metadata = huawei_utils.get_lun_metadata(volume)
        lun_id = metadata.get('remote_lun_id')
        host_name = connector['host']
        lungroup_id = None

        LOG.info(
            _LI('terminate_connection_fc: volume: %(id)s, '
                'wwpns: %(wwns)s, '
                'lun_id: %(lunid)s.'),
            {
                'id': volume.id,
                'wwns': wwns,
                'lunid': lun_id
            },
        )

        hostid = huawei_utils.get_host_id(self.rmt_client, host_name)
        if hostid:
            mapping_view_name = constants.MAPPING_VIEW_PREFIX + hostid
            view_id = self.rmt_client.find_mapping_view(mapping_view_name)
            if view_id:
                lungroup_id = self.rmt_client.find_lungroup_from_map(view_id)

        if lun_id and self.rmt_client.check_lun_exist(lun_id):
            if lungroup_id:
                lungroup_ids = self.rmt_client.get_lungroupids_by_lunid(lun_id)
                if lungroup_id in lungroup_ids:
                    self.rmt_client.remove_lun_from_lungroup(
                        lungroup_id, lun_id)
                else:
                    LOG.warning(
                        _LW("Lun is not in lungroup. "
                            "Lun id: %(lun_id)s, "
                            "lungroup id: %(lungroup_id)s"), {
                                "lun_id": lun_id,
                                "lungroup_id": lungroup_id
                            })
    def delete_consistencygroup(self, context, group, volumes):
        LOG.info("Delete Consistency Group: %(group)s.",
                 {'group': group['id']})
        metrogroup_id = self.check_consistencygroup_need_to_stop(group)
        if metrogroup_id:
            # Remove pair from metrogroup.
            for volume in volumes:
                metadata = huawei_utils.get_lun_metadata(volume)
                metro_id = metadata.get('hypermetro_id')
                if metro_id and self.client.check_hypermetro_exist(metro_id):
                    if self._check_metro_in_cg(metro_id, metrogroup_id):
                        self.client.remove_metro_from_metrogroup(
                            metrogroup_id, metro_id)
                else:
                    err = (
                        _("Hypermetro pair %(id)s doesn't exist on array.") % {
                            'id': metro_id
                        })
                    LOG.warning(err)

            # Delete metrogroup.
            self.client.delete_metrogroup(metrogroup_id)
    def failback(self, volumes):
        """Failover volumes back to primary backend.

        The main steps:
        1. Switch the role of replication pairs.
        2. Copy the second LUN data back to primary LUN.
        3. Split replication pairs.
        4. Switch the role of replication pairs.
        5. Enable replications.
        """
        volumes_update = []
        for v in volumes:
            v_update = {}
            v_update['volume_id'] = v.id
            drv_data = get_replication_driver_data(v)
            pair_id = drv_data.get('pair_id')
            if not pair_id:
                LOG.warning("No pair id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            rmt_lun_id = drv_data.get('rmt_lun_id')
            if not rmt_lun_id:
                LOG.warning("No remote lun id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            # Switch replication pair role, and start synchronize.
            self.local_driver.enable(pair_id)

            # Wait for synchronize complete.
            self.local_driver.wait_replica_ready(pair_id)

            # Split replication pair again
            self.rmt_driver.failover(pair_id)

            # Switch replication pair role, and start synchronize.
            self.rmt_driver.enable(pair_id)

            local_metadata = huawei_utils.get_lun_metadata(v)
            new_drv_data = to_string({
                'pair_id':
                pair_id,
                'rmt_lun_id':
                local_metadata.get('huawei_lun_id'),
                'rmt_lun_wwn':
                local_metadata.get('huawei_lun_wwn')
            })
            location = huawei_utils.to_string(
                huawei_lun_id=rmt_lun_id,
                huawei_lun_wwn=drv_data.get('rmt_lun_wwn'))

            v_update['updates'] = {
                'provider_location': location,
                'replication_status': 'available',
                'replication_driver_data': new_drv_data
            }
            volumes_update.append(v_update)

        return volumes_update
    def connect_volume_fc(self, volume, connector):
        """Create map between a volume and a host for FC."""
        wwns = connector['wwpns']
        LOG.info(
            'initialize_connection_fc, initiator: %(wwpns)s, '
            'volume id: %(id)s.',
            {'wwpns': wwns,
             'id': volume.id})

        metadata = huawei_utils.get_lun_metadata(volume)
        lun_id = metadata.get('remote_lun_id')
        if lun_id is None:
            msg = _("Can't get volume id. Volume name: %s.") % volume.id
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)

        original_host_name = connector['host']
        host_id = self.client.add_host_with_check(original_host_name)

        # Create hostgroup if not exist.
        host_id = self.rmt_client.add_host_with_check(original_host_name)

        online_wwns_in_host = (
            self.rmt_client.get_host_online_fc_initiators(host_id))
        online_free_wwns = self.rmt_client.get_online_free_wwns()
        for wwn in wwns:
            if (wwn not in online_wwns_in_host
                    and wwn not in online_free_wwns):
                wwns_in_host = (
                    self.rmt_client.get_host_fc_initiators(host_id))
                iqns_in_host = (
                    self.rmt_client.get_host_iscsi_initiators(host_id))
                if not (wwns_in_host or iqns_in_host):
                    self.rmt_client.remove_host(host_id)

                msg = _('Can not add FC port to host.')
                LOG.error(msg)
                raise exception.VolumeBackendAPIException(data=msg)

        for wwn in wwns:
            if wwn in online_free_wwns:
                self.rmt_client.add_fc_port_to_host(host_id, wwn)

        (tgt_port_wwns, init_targ_map) = (
            self.rmt_client.get_init_targ_map(wwns))

        # Add host into hostgroup.
        hostgroup_id = self.rmt_client.add_host_to_hostgroup(host_id)
        map_info = self.rmt_client.do_mapping(lun_id, hostgroup_id, host_id,
                                              hypermetro_lun=True)
        if not map_info:
            msg = _('Map info is None due to array version '
                    'not supporting hypermetro.')
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)

        host_lun_id = self.rmt_client.get_host_lun_id(host_id, lun_id)

        # Return FC properties.
        fc_info = {'driver_volume_type': 'fibre_channel',
                   'data': {'target_lun': int(host_lun_id),
                            'target_discovered': True,
                            'target_wwn': tgt_port_wwns,
                            'volume_id': volume.id,
                            'initiator_target_map': init_targ_map,
                            'map_info': map_info},
                   }

        LOG.info('Remote return FC info is: %s.', fc_info)

        return fc_info
    def disconnect_volume_fc(self, volume, connector):
        """Delete map between a volume and a host for FC."""
        wwns = connector['wwpns']
        metadata = huawei_utils.get_lun_metadata(volume)
        lun_id = metadata.get('remote_lun_id')
        host_name = connector['host']
        left_lunnum = -1
        lungroup_id = None
        view_id = None

        LOG.info('terminate_connection_fc: volume: %(id)s, '
                 'wwpns: %(wwns)s, '
                 'lun_id: %(lunid)s.',
                 {'id': volume.id,
                  'wwns': wwns,
                  'lunid': lun_id},)

        hostid = huawei_utils.get_host_id(self.rmt_client, host_name)
        if hostid:
            mapping_view_name = constants.MAPPING_VIEW_PREFIX + hostid
            view_id = self.rmt_client.find_mapping_view(
                mapping_view_name)
            if view_id:
                lungroup_id = self.rmt_client.find_lungroup_from_map(
                    view_id)

        if lun_id and self.rmt_client.check_lun_exist(lun_id):
            if lungroup_id:
                lungroup_ids = self.rmt_client.get_lungroupids_by_lunid(
                    lun_id)
                if lungroup_id in lungroup_ids:
                    self.rmt_client.remove_lun_from_lungroup(
                        lungroup_id, lun_id)
                else:
                    LOG.warning("Lun is not in lungroup. "
                                "Lun id: %(lun_id)s, "
                                "lungroup id: %(lungroup_id)s",
                                {"lun_id": lun_id,
                                 "lungroup_id": lungroup_id})

        (tgt_port_wwns, init_targ_map) = (
            self.rmt_client.get_init_targ_map(wwns))

        hostid = huawei_utils.get_host_id(self.rmt_client, host_name)
        if hostid:
            mapping_view_name = constants.MAPPING_VIEW_PREFIX + hostid
            view_id = self.rmt_client.find_mapping_view(
                mapping_view_name)
            if view_id:
                lungroup_id = self.rmt_client.find_lungroup_from_map(
                    view_id)
        if lungroup_id:
            left_lunnum = self.rmt_client.get_obj_count_from_lungroup(
                lungroup_id)

        if int(left_lunnum) > 0:
            info = {'driver_volume_type': 'fibre_channel',
                    'data': {}}
        else:
            info = {'driver_volume_type': 'fibre_channel',
                    'data': {'target_wwn': tgt_port_wwns,
                             'initiator_target_map': init_targ_map}, }

        return info
    def disconnect_volume_fc(self, volume, connector):
        """Delete map between a volume and a host for FC."""
        wwns = connector['wwpns']
        metadata = huawei_utils.get_lun_metadata(volume)
        lun_id = metadata.get('remote_lun_id')
        host_name = connector['host']
        left_lunnum = -1
        lungroup_id = None
        view_id = None

        LOG.info(
            'terminate_connection_fc: volume: %(id)s, '
            'wwpns: %(wwns)s, '
            'lun_id: %(lunid)s.',
            {
                'id': volume.id,
                'wwns': wwns,
                'lunid': lun_id
            },
        )

        hostid = huawei_utils.get_host_id(self.rmt_client, host_name)
        if hostid:
            mapping_view_name = constants.MAPPING_VIEW_PREFIX + hostid
            view_id = self.rmt_client.find_mapping_view(mapping_view_name)
            if view_id:
                lungroup_id = self.rmt_client.find_lungroup_from_map(view_id)

        if lun_id and self.rmt_client.check_lun_exist(lun_id):
            if lungroup_id:
                lungroup_ids = self.rmt_client.get_lungroupids_by_lunid(lun_id)
                if lungroup_id in lungroup_ids:
                    self.rmt_client.remove_lun_from_lungroup(
                        lungroup_id, lun_id)
                else:
                    LOG.warning(
                        "Lun is not in lungroup. "
                        "Lun id: %(lun_id)s, "
                        "lungroup id: %(lungroup_id)s", {
                            "lun_id": lun_id,
                            "lungroup_id": lungroup_id
                        })

        (tgt_port_wwns,
         init_targ_map) = (self.rmt_client.get_init_targ_map(wwns))

        hostid = huawei_utils.get_host_id(self.rmt_client, host_name)
        if hostid:
            mapping_view_name = constants.MAPPING_VIEW_PREFIX + hostid
            view_id = self.rmt_client.find_mapping_view(mapping_view_name)
            if view_id:
                lungroup_id = self.rmt_client.find_lungroup_from_map(view_id)
        if lungroup_id:
            left_lunnum = self.rmt_client.get_obj_count_from_lungroup(
                lungroup_id)

        if int(left_lunnum) > 0:
            info = {'driver_volume_type': 'fibre_channel', 'data': {}}
        else:
            info = {
                'driver_volume_type': 'fibre_channel',
                'data': {
                    'target_wwn': tgt_port_wwns,
                    'initiator_target_map': init_targ_map
                },
            }

        return info
    def connect_volume_fc(self, volume, connector):
        """Create map between a volume and a host for FC."""
        wwns = connector['wwpns']
        LOG.info(
            'initialize_connection_fc, initiator: %(wwpns)s,'
            'volume id: %(id)s.', {
                'wwpns': wwns,
                'id': volume.id
            })

        metadata = huawei_utils.get_lun_metadata(volume)
        lun_id = metadata.get('remote_lun_id')
        if lun_id is None:
            msg = _("Can't get volume id. Volume name: %s.") % volume.id
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)

        original_host_name = connector['host']
        host_id = self.client.add_host_with_check(original_host_name)

        # Create hostgroup if not exist.
        host_id = self.rmt_client.add_host_with_check(original_host_name)

        online_wwns_in_host = (
            self.rmt_client.get_host_online_fc_initiators(host_id))
        online_free_wwns = self.rmt_client.get_online_free_wwns()
        fc_initiators_on_array = self.rmt_client.get_fc_initiator_on_array()
        wwns = [i for i in wwns if i in fc_initiators_on_array]
        for wwn in wwns:
            if (wwn not in online_wwns_in_host
                    and wwn not in online_free_wwns):
                wwns_in_host = (
                    self.rmt_client.get_host_fc_initiators(host_id))
                iqns_in_host = (
                    self.rmt_client.get_host_iscsi_initiators(host_id))
                if not (wwns_in_host or iqns_in_host):
                    self.rmt_client.remove_host(host_id)

                msg = _('Can not add FC port to host.')
                LOG.error(msg)
                raise exception.VolumeBackendAPIException(data=msg)

        for wwn in wwns:
            self.rmt_client.ensure_fc_initiator_added(wwn, host_id)

        (tgt_port_wwns,
         init_targ_map) = (self.rmt_client.get_init_targ_map(wwns))

        # Add host into hostgroup.
        hostgroup_id = self.rmt_client.add_host_to_hostgroup(host_id)
        map_info = self.rmt_client.do_mapping(lun_id,
                                              hostgroup_id,
                                              host_id,
                                              hypermetro_lun=True)
        if not map_info:
            msg = _('Map info is None due to array version '
                    'not supporting hypermetro.')
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)

        host_lun_id = self.rmt_client.get_host_lun_id(host_id, lun_id)

        # Return FC properties.
        fc_info = {
            'driver_volume_type': 'fibre_channel',
            'data': {
                'target_lun': int(host_lun_id),
                'target_discovered': True,
                'target_wwn': tgt_port_wwns,
                'volume_id': volume.id,
                'initiator_target_map': init_targ_map,
                'map_info': map_info
            },
        }

        LOG.info('Remote return FC info is: %s.', fc_info)

        return fc_info
Exemple #20
0
    def failback(self, volumes):
        """Failover volumes back to primary backend.

        The main steps:
        1. Switch the role of replication pairs.
        2. Copy the second LUN data back to primary LUN.
        3. Split replication pairs.
        4. Switch the role of replication pairs.
        5. Enable replications.
        """
        running_status_set = (constants.REPLICA_RUNNING_STATUS_NORMAL,
                              constants.REPLICA_RUNNING_STATUS_SPLIT,
                              constants.REPLICA_RUNNING_STATUS_ERRUPTED)

        volumes_update = []
        cgid_list = set()
        replicacg = ReplicaCG(self.local_client, self.rmt_client, self.conf)
        for v in volumes:
            drv_data = get_replication_driver_data(v)
            pair_id = drv_data.get('pair_id')
            if not pair_id:
                self._pre_fail_check(v, running_status_set)

        for v in volumes:
            v_update = {}
            v_update['volume_id'] = v.id
            drv_data = get_replication_driver_data(v)
            pair_id = drv_data.get('pair_id')
            if not pair_id:
                # Failback check running status only.
                LOG.warning("No pair id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            rmt_lun_id = drv_data.get('rmt_lun_id')
            if not rmt_lun_id:
                LOG.warning("No remote lun id in volume %s.", v.id)
                v_update['updates'] = {'replication_status': 'error'}
                volumes_update.append(v_update)
                continue

            replica_info = self.local_op.get_replica_info(pair_id)
            consisgroup_id = replica_info.get('CGID')
            if consisgroup_id:
                if consisgroup_id not in cgid_list:
                    replicacg.failback(consisgroup_id)
                    cgid_list.add(consisgroup_id)
            else:
                # Switch replication pair role, and start synchronize.
                self.local_driver.enable(pair_id)

                # Wait for synchronize complete.
                self.local_driver.wait_replica_ready(pair_id)

                # Split replication pair again
                self.rmt_driver.failover(pair_id)

                # Switch replication pair role, and start synchronize.
                self.rmt_driver.enable(pair_id)

            local_metadata = huawei_utils.get_lun_metadata(v)
            new_drv_data = to_string({
                'pair_id':
                pair_id,
                'huawei_sn':
                local_metadata.get('huawei_sn'),
                'rmt_lun_id':
                local_metadata.get('huawei_lun_id'),
                'rmt_lun_wwn':
                local_metadata.get('huawei_lun_wwn')
            })
            location = huawei_utils.to_string(
                huawei_lun_id=rmt_lun_id,
                huawei_sn=drv_data.get('huawei_sn'),
                huawei_lun_wwn=drv_data.get('rmt_lun_wwn'))

            v_update['updates'] = {
                'provider_location': location,
                'replication_status': 'available',
                'replication_driver_data': new_drv_data
            }
            volumes_update.append(v_update)

        return volumes_update
Exemple #21
0
    def terminate_connection(self, volume, connector, **kwargs):
        """Delete map between a volume and a host."""
        lun_id, lun_type = self.get_lun_id_and_type(volume)
        wwns = connector['wwpns']
        host_name = connector['host']
        left_lunnum = -1
        lungroup_id = None
        view_id = None
        LOG.info(
            'terminate_connection: wwpns: %(wwns)s, '
            'LUN ID: %(lun_id)s.', {
                'wwns': wwns,
                'lun_id': lun_id
            })

        host_id = huawei_utils.get_host_id(self.client, host_name)
        if host_id:
            mapping_view_name = constants.MAPPING_VIEW_PREFIX + host_id
            view_id = self.client.find_mapping_view(mapping_view_name)
            if view_id:
                lungroup_id = self.client.find_lungroup_from_map(view_id)

        if lun_id and lungroup_id:
            lungroup_ids = self.client.get_lungroupids_by_lunid(
                lun_id, lun_type)
            if lungroup_id in lungroup_ids:
                self.client.remove_lun_from_lungroup(lungroup_id, lun_id,
                                                     lun_type)
            else:
                LOG.warning(
                    "LUN is not in lungroup. "
                    "LUN ID: %(lun_id)s. "
                    "Lungroup id: %(lungroup_id)s.", {
                        "lun_id": lun_id,
                        "lungroup_id": lungroup_id
                    })

        else:
            LOG.warning("Can't find lun on the array.")
        if lungroup_id:
            left_lunnum = self.client.get_obj_count_from_lungroup(lungroup_id)
        if int(left_lunnum) > 0:
            fc_info = {'driver_volume_type': 'fibre_channel', 'data': {}}
        else:
            fc_info, portg_id = self._delete_zone_and_remove_fc_initiators(
                wwns, host_id)
            if lungroup_id:
                if view_id and self.client.lungroup_associated(
                        view_id, lungroup_id):
                    self.client.delete_lungroup_mapping_view(
                        view_id, lungroup_id)
                self.client.delete_lungroup(lungroup_id)
            if portg_id:
                if view_id and self.client.is_portgroup_associated_to_view(
                        view_id, portg_id):
                    self.client.delete_portgroup_mapping_view(
                        view_id, portg_id)
                    self.client.delete_portgroup(portg_id)

            if host_id:
                hostgroup_name = constants.HOSTGROUP_PREFIX + host_id
                hostgroup_id = self.client.find_hostgroup(hostgroup_name)
                if hostgroup_id:
                    if view_id and self.client.hostgroup_associated(
                            view_id, hostgroup_id):
                        self.client.delete_hostgoup_mapping_view(
                            view_id, hostgroup_id)
                    self.client.remove_host_from_hostgroup(
                        hostgroup_id, host_id)
                    self.client.delete_hostgroup(hostgroup_id)

                if not self.client.check_fc_initiators_exist_in_host(host_id):
                    self.client.remove_host(host_id)

            if view_id:
                self.client.delete_mapping_view(view_id)

        # Deal with hypermetro connection.
        metadata = huawei_utils.get_lun_metadata(volume)
        LOG.info("Detach Volume, metadata is: %s.", metadata)

        if metadata.get('hypermetro_id'):
            hyperm = hypermetro.HuaweiHyperMetro(self.client, self.rmt_client,
                                                 self.configuration)
            hyperm.disconnect_volume_fc(volume, connector)

        LOG.info("terminate_connection, return data is: %s.", fc_info)

        # This only does something if and only if the initiator_target_map
        # exists in fc_info
        fczm_utils.remove_fc_zone(fc_info)
        return fc_info
Exemple #22
0
    def initialize_connection(self, volume, connector):
        lun_id, lun_type = self.get_lun_id_and_type(volume)
        wwns = connector['wwpns']
        LOG.info(
            'initialize_connection, initiator: %(wwpns)s,'
            ' LUN ID: %(lun_id)s.',
            {
                'wwpns': wwns,
                'lun_id': lun_id
            },
        )

        portg_id = None
        host_id = self.client.add_host_with_check(connector['host'])

        if not self.fcsan:
            self.fcsan = fczm_utils.create_lookup_service()

        if self.fcsan:
            # Use FC switch.
            zone_helper = fc_zone_helper.FCZoneHelper(self.fcsan, self.client)
            try:
                (tgt_port_wwns, portg_id,
                 init_targ_map) = (zone_helper.build_ini_targ_map(
                     wwns, host_id, lun_id, lun_type))
            except Exception as err:
                self.remove_host_with_check(host_id)
                msg = _('build_ini_targ_map fails. %s') % err
                raise exception.VolumeBackendAPIException(data=msg)

            for ini in init_targ_map:
                self.client.ensure_fc_initiator_added(ini, host_id)
        else:
            # Not use FC switch.
            online_wwns_in_host = (
                self.client.get_host_online_fc_initiators(host_id))
            online_free_wwns = self.client.get_online_free_wwns()
            fc_initiators_on_array = self.client.get_fc_initiator_on_array()
            wwns = [i for i in wwns if i in fc_initiators_on_array]

            for wwn in wwns:
                if (wwn not in online_wwns_in_host
                        and wwn not in online_free_wwns):
                    wwns_in_host = (
                        self.client.get_host_fc_initiators(host_id))
                    iqns_in_host = (
                        self.client.get_host_iscsi_initiators(host_id))
                    if not (wwns_in_host or iqns_in_host or self.client.
                            is_host_associated_to_hostgroup(host_id)):
                        self.client.remove_host(host_id)

                    msg = _('No FC initiator can be added to host.')
                    LOG.error(msg)
                    raise exception.VolumeBackendAPIException(data=msg)

            for wwn in wwns:
                if wwn in online_free_wwns:
                    self.client.add_fc_port_to_host(host_id, wwn)

            (tgt_port_wwns,
             init_targ_map) = (self.client.get_init_targ_map(wwns))

        # Add host into hostgroup.
        hostgroup_id = self.client.add_host_to_hostgroup(host_id)

        metadata = huawei_utils.get_lun_metadata(volume)
        LOG.info("initialize_connection, metadata is: %s.", metadata)
        hypermetro_lun = metadata.get('hypermetro_id') is not None

        map_info = self.client.do_mapping(lun_id, hostgroup_id, host_id,
                                          portg_id, lun_type, hypermetro_lun)
        host_lun_id = self.client.get_host_lun_id(host_id, lun_id, lun_type)

        # Return FC properties.
        fc_info = {
            'driver_volume_type': 'fibre_channel',
            'data': {
                'target_lun': int(host_lun_id),
                'target_discovered': True,
                'target_wwn': tgt_port_wwns,
                'volume_id': volume.id,
                'initiator_target_map': init_targ_map,
                'map_info': map_info
            },
        }

        # Deal with hypermetro connection.
        if hypermetro_lun:
            loc_tgt_wwn = fc_info['data']['target_wwn']
            local_ini_tgt_map = fc_info['data']['initiator_target_map']
            hyperm = hypermetro.HuaweiHyperMetro(self.client, self.rmt_client,
                                                 self.configuration)
            rmt_fc_info = hyperm.connect_volume_fc(volume, connector)

            rmt_tgt_wwn = rmt_fc_info['data']['target_wwn']
            rmt_ini_tgt_map = rmt_fc_info['data']['initiator_target_map']
            fc_info['data']['target_wwn'] = (loc_tgt_wwn + rmt_tgt_wwn)
            wwns = connector['wwpns']
            for wwn in wwns:
                if (wwn in local_ini_tgt_map and wwn in rmt_ini_tgt_map):
                    fc_info['data']['initiator_target_map'][wwn].extend(
                        rmt_ini_tgt_map[wwn])

                elif (wwn not in local_ini_tgt_map and wwn in rmt_ini_tgt_map):
                    fc_info['data']['initiator_target_map'][wwn] = (
                        rmt_ini_tgt_map[wwn])
                # else, do nothing

            loc_map_info = fc_info['data']['map_info']
            rmt_map_info = rmt_fc_info['data']['map_info']
            same_host_id = self._get_same_hostid(loc_map_info, rmt_map_info)

            self.client.change_hostlun_id(loc_map_info, same_host_id)
            hyperm.rmt_client.change_hostlun_id(rmt_map_info, same_host_id)

            fc_info['data']['target_lun'] = same_host_id
            hyperm.rmt_client.logout()

        fczm_utils.add_fc_zone(fc_info)
        LOG.info("Return FC info is: %s.", fc_info)
        return fc_info