def delete_replica_disks(self, ctxt, replica_id): replica = self._get_replica(ctxt, replica_id) self._check_replica_running_executions(ctxt, replica) execution = models.TasksExecution() execution.id = str(uuid.uuid4()) execution.status = constants.EXECUTION_STATUS_RUNNING execution.action = replica has_tasks = False for instance in replica.instances: if (instance in replica.info and "volumes_info" in replica.info[instance]): self._create_task(instance, constants.TASK_TYPE_DELETE_REPLICA_DISKS, execution) has_tasks = True if not has_tasks: raise exception.InvalidReplicaState( "This replica does not have volumes information for any " "instance. Ensure that the replica has been executed " "successfully priorly") db_api.add_replica_tasks_execution(ctxt, execution) LOG.info("Replica tasks execution created: %s", execution.id) self._begin_tasks(ctxt, execution, replica.info) return self.get_replica_tasks_execution(ctxt, replica_id, execution.id)
def _check_running_replica_migrations(ctxt, replica_id): migrations = db_api.get_replica_migrations(ctxt, replica_id) if [ m.id for m in migrations if m.executions[0].status == constants.EXECUTION_STATUS_RUNNING ]: raise exception.InvalidReplicaState( "This replica is currently being migrated")
def cancel_replica_tasks_execution(self, ctxt, replica_id, execution_id, force): execution = self._get_replica_tasks_execution(ctxt, replica_id, execution_id) if execution.status != constants.EXECUTION_STATUS_RUNNING: raise exception.InvalidReplicaState( "The replica tasks execution is not running") self._cancel_tasks_execution(ctxt, execution, force)
def _check_valid_replica_tasks_execution(replica, force=False): sorted_executions = sorted(replica.executions, key=lambda e: e.number, reverse=True) if (force and sorted_executions[0].status != constants.EXECUTION_STATUS_COMPLETED): raise exception.InvalidReplicaState( "The last replica tasks execution was not successful. " "Perform a forced migration if you wish to perform a " "migration without a successful last replica execution") elif not [ e for e in sorted_executions if e.status == constants.EXECUTION_STATUS_COMPLETED ]: raise exception.InvalidReplicaState( "A replica must have been executed succesfully in order " "to be migrated")
def deploy_replica_instances(self, ctxt, replica_id, clone_disks, force, skip_os_morphing=False): replica = self._get_replica(ctxt, replica_id) self._check_replica_running_executions(ctxt, replica) self._check_valid_replica_tasks_execution(replica, force) destination_endpoint = self.get_endpoint( ctxt, replica.destination_endpoint_id) destination_provider_types = self._get_provider_types( ctxt, destination_endpoint) for instance, info in replica.info.items(): if not info.get("volumes_info"): raise exception.InvalidReplicaState( "The replica doesn't contain volumes information for " "instance: %s. If replicated disks are deleted, the " "replica needs to be executed anew before a migration can " "occur" % instance) instances = replica.instances migration = models.Migration() migration.id = str(uuid.uuid4()) migration.origin_endpoint_id = replica.origin_endpoint_id migration.destination_endpoint_id = replica.destination_endpoint_id migration.destination_environment = replica.destination_environment migration.source_environment = replica.source_environment migration.network_map = replica.network_map migration.storage_mappings = replica.storage_mappings migration.instances = instances migration.replica = replica migration.info = replica.info for instance in instances: migration.info[instance]["clone_disks"] = clone_disks execution = models.TasksExecution() migration.executions = [execution] execution.status = constants.EXECUTION_STATUS_RUNNING execution.number = 1 for instance in instances: validate_replica_desployment_inputs_task = self._create_task( instance, constants.TASK_TYPE_VALIDATE_REPLICA_DEPLOYMENT_INPUTS, execution) create_snapshot_task_depends_on = [ validate_replica_desployment_inputs_task.id ] if (constants.PROVIDER_TYPE_INSTANCE_FLAVOR in destination_provider_types): get_optimal_flavor_task = self._create_task( instance, constants.TASK_TYPE_GET_OPTIMAL_FLAVOR, execution, depends_on=[validate_replica_desployment_inputs_task.id]) create_snapshot_task_depends_on.append( get_optimal_flavor_task.id) create_snapshot_task = self._create_task( instance, constants.TASK_TYPE_CREATE_REPLICA_DISK_SNAPSHOTS, execution, depends_on=create_snapshot_task_depends_on) deploy_replica_task = self._create_task( instance, constants.TASK_TYPE_DEPLOY_REPLICA_INSTANCE, execution, [create_snapshot_task.id]) if not skip_os_morphing: task_deploy_os_morphing_resources = self._create_task( instance, constants.TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES, execution, depends_on=[deploy_replica_task.id]) task_osmorphing = self._create_task( instance, constants.TASK_TYPE_OS_MORPHING, execution, depends_on=[task_deploy_os_morphing_resources.id]) task_delete_os_morphing_resources = self._create_task( instance, constants.TASK_TYPE_DELETE_OS_MORPHING_RESOURCES, execution, depends_on=[task_osmorphing.id], on_error=True) next_task = task_delete_os_morphing_resources else: next_task = deploy_replica_task finalize_deployment_task = self._create_task( instance, constants.TASK_TYPE_FINALIZE_REPLICA_INSTANCE_DEPLOYMENT, execution, depends_on=[next_task.id]) self._create_task( instance, constants.TASK_TYPE_DELETE_REPLICA_DISK_SNAPSHOTS, execution, depends_on=[finalize_deployment_task.id], on_error=clone_disks) cleanup_deployment_task = self._create_task( instance, constants.TASK_TYPE_CLEANUP_FAILED_REPLICA_INSTANCE_DEPLOYMENT, execution, on_error=True) if not clone_disks: self._create_task( instance, constants.TASK_TYPE_RESTORE_REPLICA_DISK_SNAPSHOTS, execution, depends_on=[cleanup_deployment_task.id], on_error=True) db_api.add_migration(ctxt, migration) LOG.info("Migration created: %s", migration.id) self._begin_tasks(ctxt, execution, migration.info) return self.get_migration(ctxt, migration.id)