def _handle_volume_for_svm_after_clone(self, context, server_resource, resources): bdms = server_resource['properties'].get('block_device_mapping_v2', []) vgw_id = server_resource.get('extra_properties', {}).get('gw_id') for bdm in bdms: volume_key = bdm.get('volume_id', {}).get('get_resource') boot_index = bdm.get('boot_index') device_name = bdm.get('device_name') volume_res = resources.get(volume_key) try: if volume_res.get('extra_properties', {}).get('is_deacidized'): volume_id = volume_res.get('extra_properties', {}) \ .get('id') vgw_url = volume_res.get('extra_properties', {}) \ .get('gw_url') sys_clone = volume_res.get('extra_properties', {}) \ .get('sys_clone') copy_data = volume_res.get('extra_properties', {}). \ get('copy_data') if (boot_index in ['0', 0] and not sys_clone) or \ not copy_data: continue vgw_ip = vgw_url.split(':')[0] client = birdiegatewayclient.get_birdiegateway_client( vgw_ip, str(CONF.v2vgateway_api_listen_port)) if boot_index not in ['0', 0] or sys_clone: client.vservices._force_umount_disk( "/opt/" + volume_id) # if provider cloud can not detcah volume in active status if not CONF.is_active_detach_volume: resouce_common = common.ResourceCommon() self.compute_api.stop_server(context, vgw_id) resouce_common._await_instance_status(context, vgw_id, 'SHUTOFF') self.compute_api.detach_volume(context, vgw_id, volume_id) self._wait_for_volume_status(context, volume_id, vgw_id, 'available') server_id = server_resource.get('extra_properties', {}) \ .get('id') self.compute_api.attach_volume(context, server_id, volume_id, device_name) self._wait_for_volume_status(context, volume_id, server_id, 'in-use') if not CONF.is_active_detach_volume: self.compute_api.start_server(context, vgw_id) resouce_common._await_instance_status(context, vgw_id, 'ACTIVE') except Exception as e: LOG.error(_LE('Error from handle volume of vm after' ' clone.' 'Error=%(e)s'), {'e': e})
def _handle_dep_volume_after_clone(self, context, resource): volume_id = resource.get('extra_properties', {}).get('id') if not resource.get('extra_properties', {}).get('copy_data'): return if resource.get('extra_properties', {}).get('is_deacidized'): extra_properties = resource.get('extra_properties', {}) vgw_id = extra_properties.get('gw_id') if vgw_id: try: mount_point = resource.get('extra_properties', {}) \ .get('mount_point') if mount_point: vgw_url = resource.get('extra_properties', {}) \ .get('gw_url') vgw_ip = vgw_url.split(':')[0] client = birdiegatewayclient.get_birdiegateway_client( vgw_ip, str(CONF.v2vgateway_api_listen_port)) client.vservices._force_umount_disk("/opt/" + volume_id) # if provider cloud can not detach volume in active status if not CONF.is_active_detach_volume: resouce_common = common.ResourceCommon() self.compute_api.stop_server(context, vgw_id) resouce_common._await_instance_status( context, vgw_id, 'SHUTOFF') self.compute_api.detach_volume(context, vgw_id, volume_id) self._wait_for_volume_status(context, volume_id, vgw_id, 'available') if not CONF.is_active_detach_volume: self.compute_api.start_server(context, vgw_id) resouce_common._await_instance_status( context, vgw_id, 'ACTIVE') except Exception as e: LOG.error( _LE('Error from handle volume of ' 'vm after clone. Error=%(e)s'), {'e': e})
def __init__(self, *args, **kwargs): """Load configuration options and connect to the hypervisor.""" self.clone_driver = importutils.import_object(CONF.volume_clone_driver) self.resource_common = common.ResourceCommon() self.plan_api = plan_api.PlanAPI()
def start_volume_clone(self, context, resource_name, template, trans_data_wait_fun=None, volume_wait_fun=None, set_plan_state=None): resources = template.get('resources') volume_res = resources.get(resource_name) volume_id = volume_res.get('id') plan_id = template.get('plan_id', None) ext_properties = volume_res.get('extra_properties', None) d_copy = ext_properties.get('copy_data', True) if ext_properties \ else True if not d_copy: plan_state = 'DATA_TRANS_FINISHED' set_plan_state(context, plan_id, plan_state, plan_status.STATE_MAP) return resource_names = resource_name.split('.') if len(resource_names) >= 1: if resource_names[0].startswith('stack'): self._copy_stack_volume(context, resource_name, template, plan_id, trans_data_wait_fun, volume_wait_fun, set_plan_state) return # 1. check instance which dependences this volume in template or not # if instance exists in template do not execute copy data step is_attached = self._check_volume_attach_instance(resource_name, template) if is_attached: LOG.debug('Volume clone driver: volume %(id)s, name %(name)s', {'id': volume_id, 'name': resource_name}) # update plan status plan_state = 'DATA_TRANS_FINISHED' set_plan_state(context, plan_id, plan_state, plan_status.STATE_MAP) return # 2. if volume is system volume and does not clone, skip copy data step if ext_properties: sys_clone = ext_properties.get('sys_clone', False) boot_index = ext_properties.get('boot_index', 1) else: sys_clone = False boot_index = 1 if not sys_clone and boot_index in ['0', 0]: plan_state = 'DATA_TRANS_FINISHED' set_plan_state(context, plan_id, plan_state, plan_status.STATE_MAP) return # 3. get volume info try: volume_info = self.cinder_api.get(context, volume_id) except Exception as e: LOG.error("Clone volume driver get volume %(id)s error: %(error)s", {'id': volume_id, 'error': e}) raise exception.VolumeNotFound() volume_status = volume_info['status'] v_shareable = volume_info.get('shareable', False) volume_az = volume_info.get('availability_zone') need_set_shareable = False if volume_status == 'in-use' and not v_shareable: need_set_shareable = True # 3. attach volume to gateway vm vgw_id, vgw_ip = utils.get_next_vgw(volume_az) LOG.debug('Clone volume driver vgw info: id: %(id)s,ip: %(ip)s', {'id': vgw_id, 'ip': vgw_ip}) des_dev_name = None try: client = birdiegatewayclient.get_birdiegateway_client( vgw_ip, str(CONF.v2vgateway_api_listen_port) ) disks = set(client.vservices.get_disk_name().get('dev_name')) if CONF.is_provide_device_name: if need_set_shareable: self.cinder_api.set_volume_shareable(context, volume_id, True) self.compute_api.attach_volume(context, vgw_id, volume_id, None) # des_dev_name = attach_resp._info.get('device') self._wait_for_shareable_volume_status(context, volume_id, vgw_id, 'in-use') else: self.compute_api.attach_volume(context, vgw_id, volume_id, None) if volume_wait_fun: volume_wait_fun(context, volume_id, 'in-use') # des_dev_name = attach_resp._info.get('device') n_disks = set(client.vservices.get_disk_name().get('dev_name')) diff_disk = n_disks - disks des_dev_name = list(diff_disk)[0] if len(diff_disk) >= 1 \ else None LOG.debug("dev_name = %s", des_dev_name) else: des_dev_name = self._attach_volume_for_device_name( context, need_set_shareable, vgw_id, volume_id, volume_wait_fun, client) LOG.debug("dev_name = %s", des_dev_name) except Exception as e: LOG.error('Volume clone error: attach volume failed:%(id)s,%(e)s', {'id': volume_id, 'e': e}) raise exception.VolumeNotAttach(volume_id=volume_id, seconds=120, attempts=5) # 5. copy data try: result = self._copy_volume_data(context, resource_name, vgw_ip, vgw_id, template, des_dev_name) des_gw_ip = result.get('des_ip') des_port = result.get('des_port') task_ids = result.get('copy_tasks') if trans_data_wait_fun: trans_data_wait_fun(context, des_gw_ip, des_port, task_ids, plan_status.STATE_MAP, plan_id) except Exception as e: LOG.error('Volume clone error: copy data failed:%(id)s,%(e)s', {'id': volume_id, 'e': e}) raise finally: try: # if protocol is ftp, we should unmount volume in gateway vm data_trans_protocol = CONF.data_transformer_procotol if 'ftp' == data_trans_protocol: client = birdiegatewayclient.get_birdiegateway_client( vgw_ip, str(CONF.v2vgateway_api_listen_port) ) client.vservices._force_umount_disk("/opt/" + volume_id) # if provider cloud can not detach volume in active status if not CONF.is_active_detach_volume: resouce_common = common.ResourceCommon() self.compute_api.stop_server(context, vgw_id) resouce_common._await_instance_status(context, vgw_id, 'SHUTOFF') # 5. detach volume self.compute_api.detach_volume(context, vgw_id, volume_id) if need_set_shareable: self._wait_for_shareable_volume_status(context, volume_id, vgw_id, 'available') self.cinder_api.set_volume_shareable(context, volume_id, False) else: if volume_wait_fun: volume_wait_fun(context, volume_id, 'available') if not CONF.is_active_detach_volume: self.compute_api.start_server(context, vgw_id) resouce_common._await_instance_status(context, vgw_id, 'ACTIVE') except Exception as e: LOG.error('Volume clone error: detach failed:%(id)s,%(e)s', {'id': volume_id, 'e': e})
def _copy_stack_volume(self, context, resource_name, template, plan_id, trans_data_wait_fun=None, volume_wait_fun=None, set_plan_state=None): resources = template.get('resources') volume_res = resources.get(resource_name) ext_properties = volume_res.get('extra_properties', None) if ext_properties: sys_clone = ext_properties.get('sys_clone', False) boot_index = ext_properties.get('boot_index', 1) else: sys_clone = False boot_index = 1 if not sys_clone and boot_index in ['0', 0]: plan_state = 'DATA_TRANS_FINISHED' set_plan_state(context, plan_id, plan_state, plan_status.STATE_MAP) return volume_id = volume_res.get('id') try: volume_info = self.cinder_api.get(context, volume_id) except Exception as e: LOG.error("Clone volume driver get volume %(id)s error: %(error)s", {'id': volume_id, 'error': e}) raise exception.VolumeNotFound() volume_status = volume_info['status'] v_shareable = volume_info.get('shareable', False) volume_az = volume_info.get('availability_zone') volume_attachments = volume_info.get('attachments', []) if volume_status == 'in-use' and not v_shareable: for attachment in volume_attachments: server_id = attachment.get('server_id') if not CONF.is_active_detach_volume: resouce_common = common.ResourceCommon() self.compute_api.stop_server(context, server_id) resouce_common._await_instance_status(context, server_id, 'SHUTOFF') self.compute_api.detach_volume(context, server_id, volume_id) if volume_wait_fun: volume_wait_fun(context, volume_id, 'available') vgw_id, vgw_ip = utils.get_next_vgw(volume_az) LOG.debug('Clone volume driver vgw info: id: %(id)s,ip: %(ip)s', {'id': vgw_id, 'ip': vgw_ip}) des_dev_name = None try: client = birdiegatewayclient.get_birdiegateway_client( vgw_ip, str(CONF.v2vgateway_api_listen_port) ) disks = set(client.vservices.get_disk_name().get('dev_name')) self.compute_api.attach_volume(context, vgw_id, volume_id, None) if volume_wait_fun: volume_wait_fun(context, volume_id, 'in-use') n_disks = set(client.vservices.get_disk_name().get('dev_name')) diff_disk = n_disks - disks des_dev_name = list(diff_disk)[0] if len(diff_disk) >= 1 else None LOG.debug("dev_name = %s", des_dev_name) except Exception as e: LOG.error('Volume clone error: attach volume failed:%(id)s,%(e)s', {'id': volume_id, 'e': e}) raise exception.VolumeNotAttach(volume_id=volume_id, seconds=120, attempts=5) # 5. copy data try: result = self._copy_volume_data(context, resource_name, vgw_ip, vgw_id, template, des_dev_name) des_gw_ip = result.get('des_ip') des_port = result.get('des_port') task_ids = result.get('copy_tasks') if trans_data_wait_fun: trans_data_wait_fun(context, des_gw_ip, des_port, task_ids, plan_status.STATE_MAP, plan_id) except Exception as e: LOG.error('Volume clone error: copy data failed:%(id)s,%(e)s', {'id': volume_id, 'e': e}) raise finally: try: # if protocol is ftp, we should unmount volume in gateway vm data_trans_protocol = CONF.data_transformer_procotol if 'ftp' == data_trans_protocol: client = birdiegatewayclient.get_birdiegateway_client( vgw_ip, str(CONF.v2vgateway_api_listen_port) ) client.vservices._force_umount_disk("/opt/" + volume_id) # if provider cloud can not detach volume in active status if not CONF.is_active_detach_volume: resouce_common = common.ResourceCommon() self.compute_api.stop_server(context, vgw_id) resouce_common._await_instance_status(context, vgw_id, 'SHUTOFF') # 5. detach volume self.compute_api.detach_volume(context, vgw_id, volume_id) if volume_wait_fun: volume_wait_fun(context, volume_id, 'available') if not CONF.is_active_detach_volume: self.compute_api.start_server(context, vgw_id) resouce_common._await_instance_status(context, vgw_id, 'ACTIVE') for attachment in volume_attachments: server_id = attachment.get('server_id') self.compute_api.attach_volume(context, server_id, volume_id, None) if volume_wait_fun: volume_wait_fun(context, volume_id, 'in-use') except Exception as e: LOG.error('Volume clone error: detach failed:%(id)s,%(e)s', {'id': volume_id, 'e': e})
def setUp(self): super(ResourceCommonTestCase, self).setUp() self.context = context.RequestContext('fake', 'fake', is_admin=False) self.manager = resource_comm.ResourceCommon()