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
def copy_volume_to_image(self, context, volume, image_service, image_meta): """Creates glance image from 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) undo_mgr = util.UndoManager() attached_disk_names = [] try: LOG.info('begin time of copy_volume_to_image is %s' % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))) container_format = image_meta.get('container_format') if container_format in VGW_URLS: # attach the volume to vgw vm disk_ref, vapp_name = self._attach_volume_to_vgw(volume) try: # use ssh client connect to vgw_host and copy image file to volume self._copy_volume_to_file_to_vgw(image_meta) finally: self._vcloud_client.detach_disk_from_vm(vapp_name, disk_ref) # create an empty file to glance with image_utils.temporary_file() as tmp: image_utils.upload_volume(context, image_service, image_meta, tmp) elif container_format == constants.HYBRID_VM: volume_name = volume['display_name'] vcloud_volume_name = self._get_vcloud_volume_name(volume['id'], volume_name) result,disk_ref = self._vcloud_client.get_disk_ref(vcloud_volume_name) if not result: msg = 'can not find volume %s in vcloud!' % vcloud_volume_name LOG.error(msg) raise exception.CinderException(msg) if volume['volume_attachment']: msg = 'copy volume to image not support attached volume!' LOG.error(msg) raise exception.CinderException(msg) #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' % image_meta['id'] 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) if self._vcloud_client.attach_disk_to_vm(clone_vapp_name, disk_ref): attached_disk_names.append(vcloud_volume_name) undo_mgr.undo_with(_detach_disks_to_vm) LOG.debug("Volume %s attached to: %s", vcloud_volume_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) LOG.debug('begin time of create image is %s' % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) task = client.create_image(image_meta['name'], image_meta['id']) while task['code'] == client_constants.TASK_DOING: eventlet.greenthread.sleep(10) 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 create image is %s' % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) image_info = client.image_info(image_meta['name'], image_meta['id']) if not image_info: LOG.error('cannot get image info') raise exception.CinderException('cannot get image info') LOG.debug('begin time of image_utils upload_volume %s' % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) with image_utils.temporary_file() as tmp: with fileutils.file_open(tmp, 'wb+') as f: f.truncate(image_info['size']) image_utils.upload_volume(context, image_service, image_meta, tmp, volume_format=image_meta['disk_format']) LOG.debug('end time of image_utils upload_volume %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(vcloud_volume_name) self._vcloud_client.detach_disk_from_vm(clone_vapp_name, disk_ref) undo_mgr.cancel_undo(_delete_vapp) self._vcloud_client.delete_vapp(clone_vapp_name) LOG.info('end time of copy_volume_to_image is %s' % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))) except Exception as e: msg = _("Failed to copy volume to image reason %s, rolling back") % e LOG.error(msg) undo_mgr.rollback_and_reraise(msg=msg)
def _wait_hybrid_service_up(self, server_ip, port = '7127'): client = Client(server_ip, port = port) return client.get_version()