Ejemplo n.º 1
0
    def _copy_volume_to_volume(self, dest_volume_name, 
                                        dest_volume_size,
                                        dest_volume_id,
                                        source_volume_name, 
                                        source_volume_size,
                                        source_volume_id,
                                        created = False, 
                                        source_attached = False,
                                        dest_attached = False):
        """
        """

        def _attach_disks_to_vm():
            for detached_disk in detached_disks:
                self._vcloud_client.attach_disk_to_vm(detached_disk['vapp_name'], detached_disk['disk_ref'])

        def _delete_volumes():
            for created_volume in created_volumes:
                self._vcloud_client.delete_volume(created_volume)

        def _delete_vapp():
            self._vcloud_client.delete_vapp(clone_vapp_name)

        def _detach_disks_to_vm():
            for attached_disk_name in attached_disk_names:
                result, disk_ref = self._vcloud_client.get_disk_ref(attached_disk_name)
                if result:
                    self._vcloud_client.detach_disk_from_vm(clone_vapp_name, disk_ref)

        def _power_off_vapp():
            self._vcloud_client.power_off_vapp(clone_vapp_name)

        LOG.debug('copy volume to volume: dest: %s ID %s %s GB source: %s id: %s %s GB',
                    dest_volume_name, dest_volume_id, dest_volume_size,
                    source_volume_name, source_volume_id, source_volume_size)

        detached_disks = []
        created_volumes = []
        attached_disk_names =[]
        undo_mgr = util.UndoManager()

        try:

            if not created and dest_attached:
                msg = _('only created destination volume can be attached')
                LOG.error(msg)
                raise exception.CinderException(msg)

            result, source_disk_ref = self._vcloud_client.get_disk_ref(source_volume_name)
            if not result:
                msg = _('source volume %s cannot found') % source_volume_name
                LOG.error(msg)
                raise exception.CinderException(msg)

            if source_attached:
                source_vapp_name = self._vcloud_client.get_disk_attached_vapp(source_volume_name)
                source_vapp = self._vcloud_client._get_vcloud_vapp(source_vapp_name)
                if self._vcloud_client._get_status_first_vm(source_vapp) != constants.VM_POWER_OFF_STATUS:
                    msg = "when source volume is attached, the vm must be in power off state"
                    LOG.info(msg)
                    raise exception.CinderException(msg)

                self._vcloud_client.detach_disk_from_vm(source_vapp_name, source_disk_ref)

                source_detached_disk = {}
                source_detached_disk['vapp_name'] = source_vapp_name
                source_detached_disk['disk_ref'] = source_disk_ref
                detached_disks.append(source_detached_disk)
                undo_mgr.undo_with(_attach_disks_to_vm)
                LOG.debug("source volume %s has been detached from vapp %s", source_volume_name, source_vapp_name)

            if not created:
                self._vcloud_client.create_volume(dest_volume_name, dest_volume_size)
                created_volumes.append(dest_volume_name)
                undo_mgr.undo_with(_delete_volumes)
                LOG.debug("dst volume %s(%s GB) has been created", dest_volume_name, dest_volume_size)

            result, dest_disk_ref = self._vcloud_client.get_disk_ref(dest_volume_name)
            if not result:
                msg = _('dest volume %s cannot found') % dest_volume_name
                LOG.error(msg)
                raise exception.CinderException(msg)

            if dest_attached:
                dest_vapp_name = self._vcloud_client.get_disk_attached_vapp(dest_volume_name)
                dest_vapp = self._vcloud_client._get_vcloud_vapp(dest_vapp_name)
                if self._vcloud_client._get_status_first_vm(dest_vapp) != constants.VM_POWER_OFF_STATUS:
                    msg = "when dest volume is attached, the vm must be in power off state"
                    LOG.info(msg)
                    raise exception.CinderException(msg)

                self._vcloud_client.detach_disk_from_vm(dest_vapp_name, dest_disk_ref)

                dest_detached_disk = {}
                dest_detached_disk['vapp_name'] = dest_vapp_name
                dest_detached_disk['disk_ref'] = dest_disk_ref
                detached_disks.append(dest_detached_disk)
                if undo_mgr.count_func(_attach_disks_to_vm) == 0:
                    undo_mgr.undo_with(_attach_disks_to_vm)
                LOG.debug("dst volume %s has been detached from vapp %s", dest_volume_name, dest_vapp_name)

            #NOTE(nkapotoxin): create vapp with vapptemplate
            network_names = [CONF.vcloud.provider_tunnel_network_name, CONF.vcloud.provider_base_network_name]
            network_configs = self._vcloud_client.get_network_configs(network_names)

            # create vapp
            clone_vapp_name = 'server@%s' % dest_volume_name
            clone_vapp = self._vcloud_client.create_vapp(clone_vapp_name, CONF.vcloud.base_image_id, network_configs)

            undo_mgr.undo_with(_delete_vapp)
            LOG.debug("Create clone vapp %s successful" % clone_vapp_name)

            # generate the network_connection
            network_connections = self._vcloud_client.get_network_connections(clone_vapp, network_names)

            # update network
            self._vcloud_client.update_vms_connections(clone_vapp, network_connections)

            # update vm specification
            #self._vcloud_client.modify_vm_cpu(clone_vapp, instance.get_flavor().vcpus)
            #self._vcloud_client.modify_vm_memory(clone_vapp, instance.get_flavor().memory_mb)
            LOG.debug("Config vapp %s successful" % clone_vapp_name)

            local_disk_name = 'Local@%s' % clone_vapp_name[len('server@'):]

            self._vcloud_client.create_volume(local_disk_name, 1)
            created_volumes.append(local_disk_name)
            if undo_mgr.count_func(_delete_volumes) == 0:
                undo_mgr.undo_with(_delete_volumes)
            LOG.debug("Create Local disk %s for vapp %s successful", local_disk_name, clone_vapp_name)

            result, local_disk_ref = self._vcloud_client.get_disk_ref(local_disk_name)
            self._vcloud_client.attach_disk_to_vm(clone_vapp_name, local_disk_ref)
            attached_disk_names.append(local_disk_name)
            undo_mgr.undo_with(_detach_disks_to_vm)
            LOG.debug("attach local disk %s to vapp %s successful", local_disk_name, clone_vapp_name)

            # power on it
            self._vcloud_client.power_on_vapp(clone_vapp_name)
            undo_mgr.undo_with(_power_off_vapp)

            vapp_ip = self.get_vapp_ip(clone_vapp_name)
            client = Client(vapp_ip, CONF.vcloud.hybrid_service_port)
            self._wait_hybrid_service_up(vapp_ip, CONF.vcloud.hybrid_service_port)
            LOG.debug("vapp %s(ip: %s) hybrid service has been up", clone_vapp_name, vapp_ip)

            odevs = set(client.list_volume()['devices'])
            if self._vcloud_client.attach_disk_to_vm(clone_vapp_name, source_disk_ref):
                attached_disk_names.append(source_volume_name)
                LOG.debug("Volume %s attached to: %s",source_volume_name, clone_vapp_name)

            ndevs = set(client.list_volume()['devices'])
            devs = ndevs - odevs
            for dev in devs:
                client.attach_volume(source_volume_id, dev, constants.DEV1)

            odevs = set(client.list_volume()['devices'])
            if self._vcloud_client.attach_disk_to_vm(clone_vapp_name, dest_disk_ref):
                attached_disk_names.append(dest_volume_name)
                LOG.debug("Volume %s attached to: %s", dest_volume_name, clone_vapp_name)

            ndevs = set(client.list_volume()['devices'])
            devs = ndevs - odevs
            for dev in devs:
                client.attach_volume(dest_volume_id, dev, constants.DEV2)

            LOG.debug('begin time of copy vloume(size %s GB) is %s', source_volume_size, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

            dest_volume = {}
            dest_volume['id'] = dest_volume_id
            dest_volume['size'] = dest_volume_size
            src_volume = {}
            src_volume['id'] = source_volume_id
            src_volume['size'] = source_volume_size

            task = client.clone_volume(dest_volume, src_volume)
            while task['code'] == client_constants.TASK_DOING:
                eventlet.greenthread.sleep(30)
                task = client.query_task(task)

            if task['code'] != client_constants.TASK_SUCCESS:
                LOG.error(task['message'])
                raise exception.CinderException(task['message'])
            else:
                LOG.debug('end time of copy vloume is %s', time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))

            undo_mgr.cancel_undo(_power_off_vapp)
            self._vcloud_client.power_off_vapp(clone_vapp_name)

            attached_disk_names.remove(source_volume_name)
            self._vcloud_client.detach_disk_from_vm(clone_vapp_name, source_disk_ref)
            if source_attached:
                detached_disks.remove(source_detached_disk)
                self._vcloud_client.attach_disk_to_vm(source_vapp_name, source_disk_ref)

            attached_disk_names.remove(local_disk_name)
            self._vcloud_client.detach_disk_from_vm(clone_vapp_name, local_disk_ref)

            attached_disk_names.remove(dest_volume_name)
            self._vcloud_client.detach_disk_from_vm(clone_vapp_name, dest_disk_ref)
            if dest_attached:
                detached_disks.remove(dest_detached_disk)
                self._vcloud_client.attach_disk_to_vm(dest_vapp_name, dest_disk_ref)

            undo_mgr.cancel_undo(_delete_vapp)
            self._vcloud_client.delete_vapp(clone_vapp_name)

            created_volumes.remove(local_disk_name)
            self._vcloud_client.delete_volume(local_disk_name)

            return True
        except Exception as e:
            msg = _("Failed to copy volume to volume reason %s, rolling back") % e
            LOG.error(msg)
            undo_mgr.rollback_and_reraise(msg=msg)
            return False