def _task_process(ctxt, task_id, task_type, origin, destination, instance, task_info, mp_q, mp_log_q): try: _setup_task_process(mp_log_q) task_runner = task_runners_factory.get_task_runner_class(task_type)() event_handler = _ConductorProviderEventHandler(ctxt, task_id) LOG.debug( "Executing task: %(task_id)s, type: %(task_type)s, " "origin: %(origin)s, destination: %(destination)s, " "instance: %(instance)s, task_info: %(task_info)s", { "task_id": task_id, "task_type": task_type, "origin": origin, "destination": destination, "instance": instance, "task_info": utils.sanitize_task_info(task_info) }) task_result = task_runner.run(ctxt, instance, origin, destination, task_info, event_handler) # mq_p.put() doesn't raise if new_task_info is not serializable utils.is_serializable(task_result) mp_q.put(task_result) except Exception as ex: mp_q.put(str(ex)) LOG.exception(ex) finally: # Signal the log event handler that there are no more events mp_log_q.put(None)
def exec_task(self, ctxt, task_id, task_type, origin, destination, instance, task_info): try: task_result = self._exec_task_process(ctxt, task_id, task_type, origin, destination, instance, task_info) LOG.info("Output of completed %s task with ID %s: %s", task_type, task_id, utils.sanitize_task_info(task_result)) self._rpc_conductor_client.task_completed(ctxt, task_id, task_result) except exception.TaskProcessCanceledException as ex: LOG.debug( "Task with ID '%s' appears to have been cancelled. " "Confirming cancellation to Conductor now. Error was: %s", task_id, utils.get_exception_details()) LOG.exception(ex) self._rpc_conductor_client.confirm_task_cancellation( ctxt, task_id, str(ex)) except exception.NoSuitableWorkerServiceError as ex: LOG.warn( "A conductor-side scheduling error has occurred following the " "completion of task '%s'. Ignoring. Error was: %s", task_id, utils.get_exception_details()) except Exception as ex: LOG.debug( "Task with ID '%s' has error'd out. Reporting error to " "Conductor now. Error was: %s", task_id, utils.get_exception_details()) LOG.exception(ex) self._rpc_conductor_client.set_task_error(ctxt, task_id, str(ex))
def _run(self, ctxt, instance, origin, destination, task_info, event_handler): event_manager = events.EventManager(event_handler) if not task_info.get("volumes_info"): LOG.debug("No volumes_info present. Skipping disk deletion.") event_manager.progress_update( "No previous volumes information present, nothing to delete") return {'volumes_info': []} provider = providers_factory.get_provider( destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT, event_handler) connection_info = base.get_connection_info(ctxt, destination) volumes_info = _get_volumes_info(task_info) target_environment = task_info['target_environment'] volumes_info = provider.delete_replica_disks(ctxt, connection_info, target_environment, volumes_info) if volumes_info: LOG.warn( "'volumes_info' should have been void after disk " "deletion task but it is: %s" % (utils.sanitize_task_info({'volumes_info': volumes_info}))) return {'volumes_info': []}
def _check_ensure_volumes_info_ordering(export_info, volumes_info): """ Returns a new list of volumes_info, ensuring that the order of the disks in 'volumes_info' is consistent with the order that the disks appear in 'export_info[devices][disks]' """ instance = export_info.get('instance_name', export_info.get('name', export_info['id'])) ordered_volumes_info = [] for disk in export_info['devices']['disks']: disk_id = disk['id'] matching_volumes = [ vol for vol in volumes_info if vol['disk_id'] == disk_id ] if not matching_volumes: raise exception.InvalidActionTasksExecutionState( "Could not find source disk '%s' (ID '%s') in Replica " "volumes info: %s" % (disk, disk_id, volumes_info)) elif len(matching_volumes) > 1: raise exception.InvalidActionTasksExecutionState( "Multiple disks with ID '%s' foind in Replica " "volumes info: %s" % (disk_id, volumes_info)) ordered_volumes_info.append(matching_volumes[0]) vol_info_cpy = utils.sanitize_task_info({ "volumes_info": volumes_info }).get("volumes_info", []) ordered_vol_info_cpy = utils.sanitize_task_info({ "volumes_info": ordered_volumes_info }).get("volumes_info", []) LOG.debug("volumes_info returned by provider for instance " "'%s': %s", instance, vol_info_cpy) LOG.debug("volumes_info for instance '%s' after " "reordering: %s", instance, ordered_vol_info_cpy) return ordered_volumes_info
def run(self, ctxt, instance, origin, destination, task_info, event_handler): """ Runs the task with the given params and returns a dict with the results. NOTE: This should NOT modify the existing task_info in any way. """ missing_info_props = [ prop for prop in self.get_required_task_info_properties() if prop not in task_info ] if missing_info_props: raise exception.CoriolisException( "Task type '%s' asked to run on task info with " "missing properties: %s" % (self.__class__, missing_info_props)) result = self._run(ctxt, instance, origin, destination, task_info, event_handler) if type(result) is not dict: raise exception.CoriolisException( "Task type '%s' returned result of type %s " "instead of a dict: %s" % (self.__class__, type(result), result)) missing_returns = [ prop for prop in self.get_returned_task_info_properties() if prop not in result.keys() ] if missing_returns: raise exception.CoriolisException( "Task type '%s' failed to return the following " "declared return values in its result: %s. " "Result was: %s" % (self.__class__, missing_returns, utils.sanitize_task_info(result))) undeclared_returns = [ prop for prop in result.keys() if prop not in self.get_returned_task_info_properties() ] if undeclared_returns: raise exception.CoriolisException( "Task type '%s' returned the following undeclared " "keys in its result: %s" % (self.__class__, undeclared_returns)) return result
def exec_task(self, ctxt, task_id, task_type, origin, destination, instance, task_info): try: task_result = self._exec_task_process(ctxt, task_id, task_type, origin, destination, instance, task_info) LOG.info("Output of completed %s task with ID %s: %s", task_type, task_id, utils.sanitize_task_info(task_result)) self._rpc_conductor_client.task_completed(ctxt, task_id, task_result) except exception.TaskProcessCanceledException as ex: LOG.exception(ex) self._rpc_conductor_client.confirm_task_cancellation( ctxt, task_id, str(ex)) except Exception as ex: LOG.exception(ex) self._rpc_conductor_client.set_task_error(ctxt, task_id, str(ex))
def _run(self, ctxt, instance, origin, destination, task_info, event_handler): if not task_info.get("volumes_info"): LOG.debug("No volumes_info present. Skipping disk deletion.") return {'volumes_info': []} provider = providers_factory.get_provider( destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT, event_handler) connection_info = base.get_connection_info(ctxt, destination) volumes_info = _get_volumes_info(task_info) # TODO (aznashwan): add target_env options to `delete_replica_disks`: volumes_info = provider.delete_replica_disks(ctxt, connection_info, volumes_info) if volumes_info: LOG.warn( "'volumes_info' should have been void after disk " "deletion task but it is: %s" % (utils.sanitize_task_info({'volumes_info': volumes_info}))) return {'volumes_info': []}