Răsfoiți Sursa

Remove `/migrations` API path and update unit tests accordingly

Daniel Vincze 1 an în urmă
părinte
comite
fa5674e93a

+ 3 - 3
coriolis/api/v1/deployment_actions.py

@@ -1,13 +1,13 @@
 # Copyright 2024 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from webob import exc
+
 from coriolis.api import wsgi as api_wsgi
-from coriolis import exception
 from coriolis.deployments import api
+from coriolis import exception
 from coriolis.policies import deployments as deployment_policies
 
-from webob import exc
-
 
 class DeploymentActionsController(api_wsgi.Controller):
     def __init__(self):

+ 9 - 11
coriolis/api/v1/deployments.py

@@ -1,19 +1,18 @@
 # Copyright 2024 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_config import cfg as conf
+from oslo_log import log as logging
+from webob import exc
+
 from coriolis.api.v1 import utils as api_utils
 from coriolis.api.v1.views import deployment_view
 from coriolis.api import wsgi as api_wsgi
+from coriolis.deployments import api
 from coriolis.endpoints import api as endpoints_api
 from coriolis import exception
-from coriolis.deployments import api
 from coriolis.policies import deployments as deployment_policies
 
-from oslo_config import cfg as conf
-from oslo_log import log as logging
-from webob import exc
-
-
 DEPLOYMENTS_API_OPTS = [
     conf.BoolOpt("include_task_info_in_deployments_api",
                  default=False,
@@ -70,9 +69,9 @@ class DeploymentsController(api_wsgi.Controller):
 
         if not replica_id:
             raise exc.HTTPBadRequest(
-                explanation=f"Missing 'replica_id' field from deployment "
-                            f"body. A deployment can be created strictly "
-                            f"based on an existing Replica.")
+                explanation="Missing 'replica_id' field from deployment "
+                            "body. A deployment can be created strictly "
+                            "based on an existing Replica.")
 
         clone_disks = deployment.get("clone_disks", True)
         force = deployment.get("force", False)
@@ -89,14 +88,13 @@ class DeploymentsController(api_wsgi.Controller):
             instance_osmorphing_minion_pool_mappings,
             user_scripts)
 
-
     def create(self, req, body):
         context = req.environ['coriolis.context']
         context.can(deployment_policies.get_deployments_policy_label("create"))
 
         (replica_id, force, clone_disks, skip_os_morphing,
          instance_osmorphing_minion_pool_mappings,
-          user_scripts) = self._validate_deployment_input(
+         user_scripts) = self._validate_deployment_input(
             context, body)
 
         # NOTE: destination environment for replica should have been

+ 0 - 33
coriolis/api/v1/migration_actions.py

@@ -1,33 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis.api import wsgi as api_wsgi
-from coriolis import exception
-from coriolis.migrations import api
-from coriolis.policies import migrations as migration_policies
-
-from webob import exc
-
-
-class MigrationActionsController(api_wsgi.Controller):
-    def __init__(self):
-        self._migration_api = api.API()
-        super(MigrationActionsController, self).__init__()
-
-    @api_wsgi.action('cancel')
-    def _cancel(self, req, id, body):
-        context = req.environ['coriolis.context']
-        context.can(migration_policies.get_migrations_policy_label("cancel"))
-        try:
-            force = (body["cancel"] or {}).get("force", False)
-
-            self._migration_api.cancel(context, id, force)
-            raise exc.HTTPNoContent()
-        except exception.NotFound as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-        except exception.InvalidParameterValue as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-
-
-def create_resource():
-    return api_wsgi.Resource(MigrationActionsController())

+ 0 - 189
coriolis/api/v1/migrations.py

@@ -1,189 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis.api.v1 import utils as api_utils
-from coriolis.api.v1.views import migration_view
-from coriolis.api import wsgi as api_wsgi
-from coriolis.endpoints import api as endpoints_api
-from coriolis import exception
-from coriolis.migrations import api
-from coriolis.policies import migrations as migration_policies
-
-from oslo_config import cfg as conf
-from oslo_log import log as logging
-from webob import exc
-
-
-MIGRATIONS_API_OPTS = [
-    conf.BoolOpt("include_task_info_in_migrations_api",
-                 default=False,
-                 help="Whether or not to expose the internal 'info' field of "
-                      "a Migration as part of a `GET` request.")]
-
-CONF = conf.CONF
-CONF.register_opts(MIGRATIONS_API_OPTS, 'api')
-
-LOG = logging.getLogger(__name__)
-
-
-class MigrationController(api_wsgi.Controller):
-    def __init__(self):
-        self._migration_api = api.API()
-        self._endpoints_api = endpoints_api.API()
-        super(MigrationController, self).__init__()
-
-    def show(self, req, id):
-        context = req.environ["coriolis.context"]
-        context.can(migration_policies.get_migrations_policy_label("show"))
-        migration = self._migration_api.get_migration(
-            context, id,
-            include_task_info=CONF.api.include_task_info_in_migrations_api)
-        if not migration:
-            raise exc.HTTPNotFound()
-
-        return migration_view.single(migration)
-
-    def _list(self, req):
-        show_deleted = api_utils._get_show_deleted(
-            req.GET.get("show_deleted", None))
-        context = req.environ["coriolis.context"]
-        context.show_deleted = show_deleted
-        context.can(migration_policies.get_migrations_policy_label("list"))
-        return migration_view.collection(
-            self._migration_api.get_migrations(
-                context,
-                include_tasks=CONF.api.include_task_info_in_migrations_api,
-                include_task_info=CONF.api.include_task_info_in_migrations_api
-            ))
-
-    def index(self, req):
-        return self._list(req)
-
-    def detail(self, req):
-        return self._list(req)
-
-    @api_utils.format_keyerror_message(resource='migration', method='create')
-    def _validate_migration_input(self, context, body):
-        migration = body["migration"]
-        origin_endpoint_id = migration["origin_endpoint_id"]
-        destination_endpoint_id = migration["destination_endpoint_id"]
-        origin_minion_pool_id = migration.get('origin_minion_pool_id')
-        destination_minion_pool_id = migration.get(
-            'destination_minion_pool_id')
-        instance_osmorphing_minion_pool_mappings = migration.get(
-            'instance_osmorphing_minion_pool_mappings', {})
-        instances = api_utils.validate_instances_list_for_transfer(
-            migration.get('instances'))
-        extras = [
-            instance
-            for instance in instance_osmorphing_minion_pool_mappings
-            if instance not in instances]
-        if extras:
-            raise ValueError(
-                "One or more instance OSMorphing pool mappings were "
-                "provided for instances (%s) which are not part of the "
-                "migration's declared instances (%s)" % (extras, instances))
-
-        notes = migration.get("notes")
-        skip_os_morphing = migration.get("skip_os_morphing", False)
-        shutdown_instances = migration.get(
-            "shutdown_instances", False)
-        replication_count = int(migration.get("replication_count", 2))
-        if replication_count not in range(1, 11):
-            raise ValueError(
-                "'replication_count' must be an integer between 1 and 10."
-                " Got: %s" % replication_count)
-
-        source_environment = migration.get("source_environment", {})
-        self._endpoints_api.validate_source_environment(
-            context, origin_endpoint_id, source_environment)
-
-        network_map = migration.get("network_map", {})
-        api_utils.validate_network_map(network_map)
-
-        # TODO(aznashwan): until the provider plugin interface is updated
-        # to have separate 'network_map' and 'storage_mappings' fields,
-        # we add them as part of the destination environment:
-        destination_environment = migration.get(
-            "destination_environment", {})
-        destination_environment['network_map'] = network_map
-        self._endpoints_api.validate_target_environment(
-            context, destination_endpoint_id, destination_environment)
-
-        storage_mappings = migration.get("storage_mappings", {})
-        api_utils.validate_storage_mappings(storage_mappings)
-        # NOTE(aznashwan): we validate the destination environment for the
-        # import provider before appending the 'storage_mappings' parameter
-        # for plugins with strict property name checks which do not yet
-        # support storage mapping features:
-        destination_environment['storage_mappings'] = storage_mappings
-
-        return (origin_endpoint_id, destination_endpoint_id,
-                origin_minion_pool_id, destination_minion_pool_id,
-                instance_osmorphing_minion_pool_mappings, source_environment,
-                destination_environment, instances, notes,
-                skip_os_morphing, replication_count,
-                shutdown_instances, network_map, storage_mappings)
-
-    def create(self, req, body):
-        migration_body = body.get("migration", {})
-        context = req.environ['coriolis.context']
-        context.can(migration_policies.get_migrations_policy_label("create"))
-        user_scripts = migration_body.get('user_scripts', {})
-        api_utils.validate_user_scripts(user_scripts)
-        user_scripts = api_utils.normalize_user_scripts(
-            user_scripts, migration_body.get("instances", []))
-        replica_id = migration_body.get("replica_id")
-        if replica_id:
-            clone_disks = migration_body.get("clone_disks", True)
-            force = migration_body.get("force", False)
-            skip_os_morphing = migration_body.get("skip_os_morphing", False)
-            instance_osmorphing_minion_pool_mappings = migration_body.get(
-                'instance_osmorphing_minion_pool_mappings', {})
-
-            # NOTE: destination environment for replica should have been
-            # validated upon its creation.
-            migration = self._migration_api.deploy_replica_instances(
-                context, replica_id, instance_osmorphing_minion_pool_mappings,
-                clone_disks, force, skip_os_morphing,
-                user_scripts=user_scripts)
-        else:
-            (origin_endpoint_id,
-             destination_endpoint_id,
-             origin_minion_pool_id,
-             destination_minion_pool_id,
-             instance_osmorphing_minion_pool_mappings,
-             source_environment,
-             destination_environment,
-             instances,
-             notes,
-             skip_os_morphing,
-             replication_count,
-             shutdown_instances,
-             network_map,
-             storage_mappings) = self._validate_migration_input(
-                 context, body)
-            migration = self._migration_api.migrate_instances(
-                context, origin_endpoint_id, destination_endpoint_id,
-                origin_minion_pool_id, destination_minion_pool_id,
-                instance_osmorphing_minion_pool_mappings,
-                source_environment, destination_environment, instances,
-                network_map, storage_mappings, replication_count,
-                shutdown_instances, notes=notes,
-                skip_os_morphing=skip_os_morphing,
-                user_scripts=user_scripts)
-
-        return migration_view.single(migration)
-
-    def delete(self, req, id):
-        context = req.environ['coriolis.context']
-        context.can(migration_policies.get_migrations_policy_label("delete"))
-        try:
-            self._migration_api.delete(context, id)
-            raise exc.HTTPNoContent()
-        except exception.NotFound as ex:
-            raise exc.HTTPNotFound(explanation=ex.msg)
-
-
-def create_resource():
-    return api_wsgi.Resource(MigrationController())

+ 1 - 1
coriolis/api/v1/replicas.py

@@ -6,8 +6,8 @@ from coriolis.api.v1.views import replica_tasks_execution_view
 from coriolis.api.v1.views import replica_view
 from coriolis.api import wsgi as api_wsgi
 from coriolis import constants
-from coriolis import exception
 from coriolis.endpoints import api as endpoints_api
+from coriolis import exception
 from coriolis.policies import replicas as replica_policies
 from coriolis.replicas import api
 

+ 3 - 20
coriolis/api/v1/router.py

@@ -4,9 +4,9 @@
 from oslo_log import log as logging
 
 from coriolis import api
-from coriolis.api.v1 import diagnostics
-from coriolis.api.v1 import deployments
 from coriolis.api.v1 import deployment_actions
+from coriolis.api.v1 import deployments
+from coriolis.api.v1 import diagnostics
 from coriolis.api.v1 import endpoint_actions
 from coriolis.api.v1 import endpoint_destination_minion_pool_options
 from coriolis.api.v1 import endpoint_destination_options
@@ -16,8 +16,6 @@ from coriolis.api.v1 import endpoint_source_minion_pool_options
 from coriolis.api.v1 import endpoint_source_options
 from coriolis.api.v1 import endpoint_storage
 from coriolis.api.v1 import endpoints
-from coriolis.api.v1 import migration_actions
-from coriolis.api.v1 import migrations
 from coriolis.api.v1 import minion_pool_actions
 from coriolis.api.v1 import minion_pools
 from coriolis.api.v1 import provider_schemas
@@ -141,21 +139,6 @@ class APIRouter(api.APIRouter):
                         'providers/{platform_name}/schemas/{provider_type}',
                         controller=self.resources['provider_schemas'])
 
-        self.resources['migrations'] = migrations.create_resource()
-        mapper.resource('migration', 'migrations',
-                        controller=self.resources['migrations'],
-                        collection={'detail': 'GET'},
-                        member={'action': 'POST'})
-
-        migration_actions_resource = migration_actions.create_resource()
-        self.resources['migration_actions'] = migration_actions_resource
-        migration_path = '/{project_id}/migrations/{id}'
-        mapper.connect('migration_actions',
-                       migration_path + '/actions',
-                       controller=self.resources['migration_actions'],
-                       action='action',
-                       conditions={'method': 'POST'})
-
         self.resources['deployments'] = deployments.create_resource()
         mapper.resource('deployment', 'deployments',
                         controller=self.resources['deployments'],
@@ -164,7 +147,7 @@ class APIRouter(api.APIRouter):
 
         deployments_actions_resource = deployment_actions.create_resource()
         self.resources['deployment_actions'] = deployments_actions_resource
-        deployment_path  = '/{project_id}/deployments/{id}'
+        deployment_path = '/{project_id}/deployments/{id}'
         mapper.connect('deployment_actions',
                        deployment_path + '/actions',
                        controller=self.resources['deployment_actions'],

+ 2 - 49
coriolis/conductor/rpc/client.py

@@ -9,7 +9,6 @@ from coriolis import constants
 from coriolis import events
 from coriolis import rpc
 
-
 VERSION = "1.0"
 LOG = logging.getLogger(__name__)
 
@@ -206,17 +205,6 @@ class ConductorClient(rpc.BaseRPCClient):
         return self._call(
             ctxt, 'delete_replica_disks', replica_id=replica_id)
 
-    def get_migrations(self, ctxt, include_tasks=False,
-                       include_task_info=False):
-        return self._call(
-            ctxt, 'get_migrations', include_tasks=include_tasks,
-            include_task_info=include_task_info)
-
-    def get_migration(self, ctxt, migration_id, include_task_info=False):
-        return self._call(
-            ctxt, 'get_migration', migration_id=migration_id,
-            include_task_info=include_task_info)
-
     def get_deployments(self, ctxt, include_tasks=False,
                         include_task_info=False):
         return self._call(
@@ -228,34 +216,6 @@ class ConductorClient(rpc.BaseRPCClient):
             ctxt, 'get_deployment', deployment_id=deployment_id,
             include_task_info=include_task_info)
 
-    def migrate_instances(self, ctxt, origin_endpoint_id,
-                          destination_endpoint_id, origin_minion_pool_id,
-                          destination_minion_pool_id,
-                          instance_osmorphing_minion_pool_mappings,
-                          source_environment, destination_environment,
-                          instances, network_map, storage_mappings,
-                          replication_count, shutdown_instances=False,
-                          notes=None, skip_os_morphing=False,
-                          user_scripts=None):
-        return self._call(
-            ctxt, 'migrate_instances',
-            origin_endpoint_id=origin_endpoint_id,
-            destination_endpoint_id=destination_endpoint_id,
-            origin_minion_pool_id=origin_minion_pool_id,
-            destination_minion_pool_id=destination_minion_pool_id,
-            instance_osmorphing_minion_pool_mappings=(
-                instance_osmorphing_minion_pool_mappings),
-            destination_environment=destination_environment,
-            instances=instances,
-            notes=notes,
-            replication_count=replication_count,
-            shutdown_instances=shutdown_instances,
-            skip_os_morphing=skip_os_morphing,
-            network_map=network_map,
-            storage_mappings=storage_mappings,
-            source_environment=source_environment,
-            user_scripts=user_scripts)
-
     def deploy_replica_instances(
             self, ctxt, replica_id,
             instance_osmorphing_minion_pool_mappings=None, clone_disks=False,
@@ -268,21 +228,14 @@ class ConductorClient(rpc.BaseRPCClient):
             skip_os_morphing=skip_os_morphing,
             user_scripts=user_scripts)
 
-    def delete_migration(self, ctxt, migration_id):
-        self._call(
-            ctxt, 'delete_migration', migration_id=migration_id)
-
-    def cancel_migration(self, ctxt, migration_id, force):
-        self._call(
-            ctxt, 'cancel_migration', migration_id=migration_id, force=force)
-
     def delete_deployment(self, ctxt, deployment_id):
         self._call(
             ctxt, 'delete_deployment', deployment_id=deployment_id)
 
     def cancel_deployment(self, ctxt, deployment_id, force):
         self._call(
-            ctxt, 'cancel_deployment', deployment_id=deployment_id, force=force)
+            ctxt, 'cancel_deployment', deployment_id=deployment_id,
+            force=force)
 
     def set_task_host(self, ctxt, task_id, host):
         self._call(

+ 7 - 412
coriolis/conductor/rpc/server.py

@@ -366,12 +366,13 @@ class ConductorServerEndpoint(object):
                     "reservation.")
             LOG.debug(
                 f"Reservation with ID '{reservation_id}' for transfer "
-                f"transfer action '{action_id}' was already marked as fulfilled")
+                f"transfer action '{action_id}' was already marked as "
+                f"fulfilled")
         else:
             self._licensing_client.mark_reservation_fulfilled(reservation_id)
             LOG.debug(
-                f"Successfully marked reservation with ID '{reservation_id}' for "
-                f"transfer action '{action_id}' as fulfilled")
+                f"Successfully marked reservation with ID '{reservation_id}' "
+                f"for transfer action '{action_id}' as fulfilled")
 
     def _check_reservation_for_replica(self, replica):
         scenario = replica.scenario
@@ -1324,13 +1325,6 @@ class ConductorServerEndpoint(object):
                 "Replica with ID '%s' not found." % replica_id)
         return replica
 
-    def get_migrations(self, ctxt, include_tasks,
-                       include_task_info=False):
-        return db_api.get_migrations(
-            ctxt, include_tasks,
-            include_task_info=include_task_info,
-            to_dict=True)
-
     @migration_synchronized
     def get_migration(self, ctxt, migration_id, include_task_info=False):
         return self._get_migration(
@@ -1840,398 +1834,6 @@ class ConductorServerEndpoint(object):
             ctxt, execution,
             constants.EXECUTION_STATUS_ERROR_ALLOCATING_MINIONS)
 
-    def migrate_instances(
-            self, ctxt, origin_endpoint_id, destination_endpoint_id,
-            origin_minion_pool_id, destination_minion_pool_id,
-            instance_osmorphing_minion_pool_mappings, source_environment,
-            destination_environment, instances, network_map, storage_mappings,
-            replication_count, shutdown_instances=False, notes=None,
-            skip_os_morphing=False, user_scripts=None):
-        origin_endpoint = self.get_endpoint(ctxt, origin_endpoint_id)
-        destination_endpoint = self.get_endpoint(
-            ctxt, destination_endpoint_id)
-        self._check_endpoints(ctxt, origin_endpoint, destination_endpoint)
-
-        destination_provider_types = self._get_provider_types(
-            ctxt, destination_endpoint)
-
-        migration = models.Migration()
-        migration.id = str(uuid.uuid4())
-        migration.base_id = migration.id
-        migration.origin_endpoint_id = origin_endpoint_id
-        migration.destination_endpoint_id = destination_endpoint_id
-        migration.destination_environment = destination_environment
-        migration.source_environment = source_environment
-        migration.network_map = network_map
-        migration.storage_mappings = storage_mappings
-        migration.last_execution_status = constants.EXECUTION_STATUS_UNEXECUTED
-        execution = models.TasksExecution()
-        execution.status = constants.EXECUTION_STATUS_UNEXECUTED
-        execution.number = 1
-        execution.type = constants.EXECUTION_TYPE_MIGRATION
-        migration.executions = [execution]
-        migration.instances = instances
-        migration.info = {}
-        migration.user_scripts = user_scripts or {}
-        migration.notes = notes
-        migration.shutdown_instances = shutdown_instances
-        migration.replication_count = replication_count
-        migration.origin_minion_pool_id = origin_minion_pool_id
-        migration.destination_minion_pool_id = destination_minion_pool_id
-        if instance_osmorphing_minion_pool_mappings is None:
-            instance_osmorphing_minion_pool_mappings = {}
-        migration.instance_osmorphing_minion_pool_mappings = (
-            instance_osmorphing_minion_pool_mappings)
-
-        self._create_reservation_for_replica(migration)
-
-        self._check_minion_pools_for_action(ctxt, migration)
-
-        for instance in instances:
-            migration.info[instance] = {
-                "volumes_info": [],
-                "source_environment": source_environment,
-                "target_environment": destination_environment,
-                "user_scripts": self._get_instance_scripts(
-                    user_scripts, instance),
-                # NOTE: we must explicitly set this in each VM's info
-                # to prevent the Replica disks from being cloned:
-                "clone_disks": False}
-            # TODO(aznashwan): have these passed separately to the relevant
-            # provider methods (they're currently passed directly inside
-            # dest-env by the API service when accepting the call)
-            # "network_map": network_map,
-            # "storage_mappings": storage_mappings,
-
-            get_instance_info_task = self._create_task(
-                instance,
-                constants.TASK_TYPE_GET_INSTANCE_INFO,
-                execution)
-
-            validate_migration_source_inputs_task = self._create_task(
-                instance,
-                constants.TASK_TYPE_VALIDATE_MIGRATION_SOURCE_INPUTS,
-                execution)
-
-            validate_migration_destination_inputs_task = self._create_task(
-                instance,
-                constants.TASK_TYPE_VALIDATE_MIGRATION_DESTINATION_INPUTS,
-                execution,
-                depends_on=[get_instance_info_task.id])
-
-            migration_resources_task_ids = []
-            validate_origin_minion_task = None
-            deploy_migration_source_resources_task = None
-            migration_resources_task_deps = [
-                get_instance_info_task.id,
-                validate_migration_source_inputs_task.id]
-            if migration.origin_minion_pool_id:
-                # NOTE: these values are required for the
-                # _check_execution_tasks_sanity call but
-                # will be populated later when the pool
-                # allocations actually happen:
-                migration.info[instance].update({
-                    "origin_minion_machine_id": None,
-                    "origin_minion_provider_properties": None,
-                    "origin_minion_connection_info": None})
-                validate_origin_minion_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_VALIDATE_SOURCE_MINION_POOL_COMPATIBILITY,  # noqa: E501
-                    execution,
-                    depends_on=migration_resources_task_deps)
-                migration_resources_task_ids.append(
-                    validate_origin_minion_task.id)
-            else:
-                deploy_migration_source_resources_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_DEPLOY_MIGRATION_SOURCE_RESOURCES,
-                    execution, depends_on=migration_resources_task_deps)
-                migration_resources_task_ids.append(
-                    deploy_migration_source_resources_task.id)
-
-            create_instance_disks_task = self._create_task(
-                instance, constants.TASK_TYPE_CREATE_INSTANCE_DISKS,
-                execution, depends_on=[
-                    validate_migration_source_inputs_task.id,
-                    validate_migration_destination_inputs_task.id])
-
-            validate_destination_minion_task = None
-            attach_destination_minion_disks_task = None
-            deploy_migration_target_resources_task = None
-            if migration.destination_minion_pool_id:
-                # NOTE: these values are required for the
-                # _check_execution_tasks_sanity call but
-                # will be populated later when the pool
-                # allocations actually happen:
-                migration.info[instance].update({
-                    "destination_minion_machine_id": None,
-                    "destination_minion_provider_properties": None,
-                    "destination_minion_connection_info": None,
-                    "destination_minion_backup_writer_connection_info": None})
-                ttyp = (
-                    constants.TASK_TYPE_VALIDATE_DESTINATION_MINION_POOL_COMPATIBILITY)  # noqa: E501
-                validate_destination_minion_task = self._create_task(
-                    instance, ttyp, execution, depends_on=[
-                        validate_migration_destination_inputs_task.id])
-
-                attach_destination_minion_disks_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_ATTACH_VOLUMES_TO_DESTINATION_MINION,
-                    execution, depends_on=[
-                        validate_destination_minion_task.id,
-                        create_instance_disks_task.id])
-                migration_resources_task_ids.append(
-                    attach_destination_minion_disks_task.id)
-            else:
-                deploy_migration_target_resources_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_DEPLOY_MIGRATION_TARGET_RESOURCES,
-                    execution, depends_on=[create_instance_disks_task.id])
-                migration_resources_task_ids.append(
-                    deploy_migration_target_resources_task.id)
-
-            validate_osmorphing_minion_task = None
-            if not skip_os_morphing and (
-                    instance in instance_osmorphing_minion_pool_mappings):
-                # NOTE: these values are required for the
-                # _check_execution_tasks_sanity call but
-                # will be populated later when the pool
-                # allocations actually happen:
-                migration.info[instance].update({
-                    "osmorphing_minion_machine_id": None,
-                    "osmorphing_minion_provider_properties": None,
-                    "osmorphing_minion_connection_info": None})
-                validate_osmorphing_minion_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_VALIDATE_OSMORPHING_MINION_POOL_COMPATIBILITY,  # noqa: E501
-                    execution, depends_on=[
-                        validate_migration_destination_inputs_task.id])
-                migration_resources_task_ids.append(
-                    validate_osmorphing_minion_task.id)
-
-            last_sync_task = None
-            first_sync_task = None
-            for i in range(migration.replication_count):
-                # insert SHUTDOWN_INSTANCES task before the last sync:
-                if i == (migration.replication_count - 1) and (
-                        migration.shutdown_instances):
-                    shutdown_deps = migration_resources_task_ids
-                    if last_sync_task:
-                        shutdown_deps = [last_sync_task.id]
-                    last_sync_task = self._create_task(
-                        instance, constants.TASK_TYPE_SHUTDOWN_INSTANCE,
-                        execution, depends_on=shutdown_deps)
-
-                replication_deps = migration_resources_task_ids
-                if last_sync_task:
-                    replication_deps = [last_sync_task.id]
-
-                last_sync_task = self._create_task(
-                    instance, constants.TASK_TYPE_REPLICATE_DISKS,
-                    execution, depends_on=replication_deps)
-                if not first_sync_task:
-                    first_sync_task = last_sync_task
-
-            release_origin_minion_task = None
-            delete_source_resources_task = None
-            source_resource_cleanup_task = None
-            if migration.origin_minion_pool_id:
-                release_origin_minion_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_RELEASE_SOURCE_MINION,  # noqa: E501
-                    execution,
-                    depends_on=[
-                        validate_origin_minion_task.id,
-                        last_sync_task.id],
-                    on_error=True)
-                source_resource_cleanup_task = release_origin_minion_task
-            else:
-                delete_source_resources_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_DELETE_MIGRATION_SOURCE_RESOURCES,
-                    execution, depends_on=[
-                        deploy_migration_source_resources_task.id,
-                        last_sync_task.id],
-                    on_error=True)
-                source_resource_cleanup_task = delete_source_resources_task
-
-            cleanup_source_storage_task = self._create_task(
-                instance, constants.TASK_TYPE_CLEANUP_INSTANCE_SOURCE_STORAGE,
-                execution, depends_on=[
-                    first_sync_task.id,
-                    source_resource_cleanup_task.id],
-                on_error=True)
-
-            target_resources_cleanup_task = None
-            if migration.destination_minion_pool_id:
-                detach_volumes_from_destination_minion_task = (
-                    self._create_task(
-                        instance,
-                        constants.TASK_TYPE_DETACH_VOLUMES_FROM_DESTINATION_MINION,  # noqa: E501
-                        execution,
-                        depends_on=[
-                            attach_destination_minion_disks_task.id,
-                            last_sync_task.id],
-                        on_error=True))
-
-                release_destination_minion_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_RELEASE_DESTINATION_MINION,
-                    execution, depends_on=[
-                        validate_destination_minion_task.id,
-                        detach_volumes_from_destination_minion_task.id],
-                    on_error=True)
-                target_resources_cleanup_task = release_destination_minion_task
-            else:
-                delete_destination_resources_task = self._create_task(
-                    instance,
-                    constants.TASK_TYPE_DELETE_MIGRATION_TARGET_RESOURCES,
-                    execution, depends_on=[
-                        deploy_migration_target_resources_task.id,
-                        last_sync_task.id],
-                    on_error=True)
-                target_resources_cleanup_task = (
-                    delete_destination_resources_task)
-
-            deploy_instance_task = self._create_task(
-                instance, constants.TASK_TYPE_DEPLOY_INSTANCE_RESOURCES,
-                execution, depends_on=[
-                    last_sync_task.id,
-                    target_resources_cleanup_task.id])
-
-            depends_on = [deploy_instance_task.id]
-            osmorphing_resources_cleanup_task = None
-            if not skip_os_morphing:
-                task_deploy_os_morphing_resources = None
-                task_delete_os_morphing_resources = None
-                attach_osmorphing_minion_volumes_task = None
-                last_osmorphing_resources_deployment_task = None
-                if instance in (
-                        migration.instance_osmorphing_minion_pool_mappings):
-                    osmorphing_vol_attachment_deps = [
-                        validate_osmorphing_minion_task.id]
-                    osmorphing_vol_attachment_deps.extend(depends_on)
-                    attach_osmorphing_minion_volumes_task = self._create_task(
-                        instance,
-                        constants.TASK_TYPE_ATTACH_VOLUMES_TO_OSMORPHING_MINION,  # noqa: E501
-                        execution, depends_on=osmorphing_vol_attachment_deps)
-                    last_osmorphing_resources_deployment_task = (
-                        attach_osmorphing_minion_volumes_task)
-
-                    collect_osmorphing_info_task = self._create_task(
-                        instance,
-                        constants.TASK_TYPE_COLLECT_OSMORPHING_INFO,
-                        execution,
-                        depends_on=[attach_osmorphing_minion_volumes_task.id])
-                    last_osmorphing_resources_deployment_task = (
-                        collect_osmorphing_info_task)
-                else:
-                    task_deploy_os_morphing_resources = self._create_task(
-                        instance,
-                        constants.TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES,
-                        execution, depends_on=depends_on)
-                    last_osmorphing_resources_deployment_task = (
-                        task_deploy_os_morphing_resources)
-
-                task_osmorphing = self._create_task(
-                    instance, constants.TASK_TYPE_OS_MORPHING,
-                    execution, depends_on=[
-                        last_osmorphing_resources_deployment_task.id])
-
-                depends_on = [task_osmorphing.id]
-
-                if instance in (
-                        migration.instance_osmorphing_minion_pool_mappings):
-                    detach_osmorphing_minion_volumes_task = self._create_task(
-                        instance,
-                        constants.TASK_TYPE_DETACH_VOLUMES_FROM_OSMORPHING_MINION,  # noqa: E501
-                        execution, depends_on=[
-                            attach_osmorphing_minion_volumes_task.id,
-                            task_osmorphing.id],
-                        on_error=True)
-
-                    release_osmorphing_minion_task = self._create_task(
-                        instance,
-                        constants.TASK_TYPE_RELEASE_OSMORPHING_MINION,
-                        execution, depends_on=[
-                            validate_osmorphing_minion_task.id,
-                            detach_osmorphing_minion_volumes_task.id],
-                        on_error=True)
-                    depends_on.append(release_osmorphing_minion_task.id)
-                    osmorphing_resources_cleanup_task = (
-                        release_osmorphing_minion_task)
-                else:
-                    task_delete_os_morphing_resources = (
-                        self._create_task(
-                            instance, constants.TASK_TYPE_DELETE_OS_MORPHING_RESOURCES,  # noqa: E501
-                            execution, depends_on=[
-                                task_deploy_os_morphing_resources.id,
-                                task_osmorphing.id],
-                            on_error=True))
-
-                    depends_on.append(task_delete_os_morphing_resources.id)
-                    osmorphing_resources_cleanup_task = (
-                        task_delete_os_morphing_resources)
-
-            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=depends_on)
-                depends_on = [get_optimal_flavor_task.id]
-
-            finalize_deployment_task = self._create_task(
-                instance,
-                constants.TASK_TYPE_FINALIZE_INSTANCE_DEPLOYMENT,
-                execution, depends_on=depends_on)
-
-            cleanup_failed_deployment_task = self._create_task(
-                instance,
-                constants.TASK_TYPE_CLEANUP_FAILED_INSTANCE_DEPLOYMENT,
-                execution, depends_on=[
-                    deploy_instance_task.id,
-                    finalize_deployment_task.id],
-                on_error_only=True)
-
-            cleanup_deps = [
-                create_instance_disks_task.id,
-                cleanup_source_storage_task.id,
-                target_resources_cleanup_task.id,
-                cleanup_failed_deployment_task.id]
-            if osmorphing_resources_cleanup_task:
-                cleanup_deps.append(osmorphing_resources_cleanup_task.id)
-            self._create_task(
-                instance, constants.TASK_TYPE_CLEANUP_INSTANCE_TARGET_STORAGE,
-                execution, depends_on=cleanup_deps,
-                on_error_only=True)
-
-        self._check_execution_tasks_sanity(execution, migration.info)
-        db_api.add_migration(ctxt, migration)
-        LOG.info("Migration added to DB: %s", migration.id)
-
-        uses_minion_pools = any([
-            migration.origin_minion_pool_id,
-            migration.destination_minion_pool_id,
-            migration.instance_osmorphing_minion_pool_mappings])
-        if uses_minion_pools:
-            # NOTE: we lock on the migration ID to ensure the minion
-            # allocation confirmations don't come in too early:
-            with lockutils.lock(
-                    constants.MIGRATION_LOCK_NAME_FORMAT % migration.id,
-                    external=True):
-                (self._minion_manager_client
-                    .allocate_minion_machines_for_migration(
-                        ctxt, migration, include_transfer_minions=True,
-                        include_osmorphing_minions=not skip_os_morphing)
-                 )
-                self._set_tasks_execution_status(
-                    ctxt, execution,
-                    constants.EXECUTION_STATUS_AWAITING_MINION_ALLOCATIONS)
-        else:
-            self._begin_tasks(ctxt, migration, execution)
-
-        return self.get_migration(ctxt, migration.id)
-
     def _get_migration(self, ctxt, migration_id, include_task_info=False,
                        to_dict=False):
         migration = db_api.get_migration(
@@ -2251,10 +1853,6 @@ class ConductorServerEndpoint(object):
                 "'%s' state." % (migration_id, execution.status))
         db_api.delete_migration(ctxt, migration_id)
 
-    @migration_synchronized
-    def delete_migration(self, ctxt, migration_id):
-        self._delete_migration(ctxt, migration_id)
-
     @deployment_synchronized
     def delete_deployment(self, ctxt, deployment_id):
         self._delete_migration(ctxt, deployment_id)
@@ -2280,10 +1878,6 @@ class ConductorServerEndpoint(object):
                 external=True):
             self._cancel_tasks_execution(ctxt, execution, force=force)
 
-    @migration_synchronized
-    def cancel_migration(self, ctxt, migration_id, force):
-        self._cancel_migration(ctxt, migration_id, force)
-
     @deployment_synchronized
     def cancel_deployment(self, ctxt, deployment_id, force):
         self._cancel_migration(ctxt, deployment_id, force)
@@ -2495,11 +2089,12 @@ class ConductorServerEndpoint(object):
             transfer_action = self._get_replica(
                 ctxt, execution.action_id, include_task_info=False)
 
-        if transfer_action.scenario == constants.REPLICA_SCENARIO_REPLICA and (
+        scenario = transfer_action.scenario
+        if scenario == constants.REPLICA_SCENARIO_REPLICA and (
                 execution.type == constants.EXECUTION_TYPE_REPLICA_EXECUTION):
             self._check_mark_reservation_fulfilled(
                 transfer_action, must_unfulfilled=False)
-        elif transfer_action.scenario == constants.REPLICA_SCENARIO_LIVE_MIGRATION and (
+        elif scenario == constants.REPLICA_SCENARIO_LIVE_MIGRATION and (
                 execution.type == constants.EXECUTION_TYPE_REPLICA_DEPLOY):
             self._check_mark_reservation_fulfilled(
                 transfer_action, must_unfulfilled=False)

+ 1 - 2
coriolis/db/api.py

@@ -15,7 +15,6 @@ from sqlalchemy import orm
 from sqlalchemy.sql import null
 
 from coriolis.db.sqlalchemy import models
-from coriolis import constants
 from coriolis import exception
 from coriolis import utils
 
@@ -548,7 +547,7 @@ def get_migrations(context,
         q = q.options(orm.undefer('info'))
 
     if replica_migrations_only:
-        q.filter(models.Migration.replica_id != None)
+        q.filter(models.Migration.replica_id is not None)
 
     args = {}
     if is_user_context(context):

+ 1 - 1
coriolis/licensing/client.py

@@ -44,7 +44,7 @@ class LicensingClient(object):
                 "instantiate licensing client.")
             return None
         allow_untrusted = os.environ.get(
-            "LICENSING_SERVER_ALLOW_UNTRUSTED", None) != None
+            "LICENSING_SERVER_ALLOW_UNTRUSTED", None) is not None
         client = cls(
             base_url, appliance_id=None, allow_untrusted=allow_untrusted)
         appliance_ids = client.get_appliances()

+ 0 - 0
coriolis/migrations/__init__.py


+ 0 - 54
coriolis/migrations/api.py

@@ -1,54 +0,0 @@
-# Copyright 2016 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from coriolis.conductor.rpc import client as rpc_client
-
-
-class API(object):
-    def __init__(self):
-        self._rpc_client = rpc_client.ConductorClient()
-
-    def migrate_instances(self, ctxt, origin_endpoint_id,
-                          destination_endpoint_id, origin_minion_pool_id,
-                          destination_minion_pool_id,
-                          instance_osmorphing_minion_pool_mappings,
-                          source_environment, destination_environment,
-                          instances, network_map, storage_mappings,
-                          replication_count,
-                          shutdown_instances, notes=None,
-                          skip_os_morphing=False, user_scripts=None):
-        return self._rpc_client.migrate_instances(
-            ctxt, origin_endpoint_id, destination_endpoint_id,
-            origin_minion_pool_id, destination_minion_pool_id,
-            instance_osmorphing_minion_pool_mappings, source_environment,
-            destination_environment, instances, network_map,
-            storage_mappings, replication_count,
-            shutdown_instances=shutdown_instances,
-            notes=notes, skip_os_morphing=skip_os_morphing,
-            user_scripts=user_scripts)
-
-    def deploy_replica_instances(self, ctxt, replica_id,
-                                 instance_osmorphing_minion_pool_mappings,
-                                 clone_disks=False, force=False,
-                                 skip_os_morphing=False, user_scripts=None):
-        return self._rpc_client.deploy_replica_instances(
-            ctxt, replica_id, instance_osmorphing_minion_pool_mappings=(
-                instance_osmorphing_minion_pool_mappings),
-            clone_disks=clone_disks, force=force,
-            skip_os_morphing=skip_os_morphing,
-            user_scripts=user_scripts)
-
-    def delete(self, ctxt, migration_id):
-        self._rpc_client.delete_migration(ctxt, migration_id)
-
-    def cancel(self, ctxt, migration_id, force):
-        self._rpc_client.cancel_migration(ctxt, migration_id, force)
-
-    def get_migrations(self, ctxt, include_tasks=False,
-                       include_task_info=False):
-        return self._rpc_client.get_migrations(
-            ctxt, include_tasks, include_task_info=include_task_info)
-
-    def get_migration(self, ctxt, migration_id, include_task_info=False):
-        return self._rpc_client.get_migration(
-            ctxt, migration_id, include_task_info=include_task_info)

+ 0 - 101
coriolis/migrations/manager.py

@@ -1,101 +0,0 @@
-# Copyright 2017 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-import gc
-import sys
-
-import eventlet
-from oslo_log import log as logging
-from oslo_utils import units
-
-from coriolis import events
-from coriolis.providers import backup_writers
-from coriolis import qemu_reader
-from coriolis import utils
-
-LOG = logging.getLogger(__name__)
-
-
-def _copy_volume(volume, disk_image_reader, backup_writer, event_manager):
-    disk_id = volume["disk_id"]
-    # for now we assume it is a local file
-    path = volume["disk_image_uri"]
-    skip_zeroes = volume.get("zeroed", False)
-
-    with backup_writer.open("", disk_id) as writer:
-        with disk_image_reader.open(path) as reader:
-            disk_size = reader.disk_size
-
-            perc_step = event_manager.add_percentage_step(
-                "Copying data of disk %s" % disk_id, disk_size)
-
-            offset = 0
-            max_block_size = 10 * units.Mi  # 10 MB
-
-            while offset < disk_size:
-                allocated, zero_block, block_size = reader.get_block_status(
-                    offset, max_block_size)
-                if not allocated or zero_block and skip_zeroes:
-                    if not allocated:
-                        LOG.debug(
-                            "Unallocated block detected: %s", block_size)
-                    else:
-                        LOG.debug("Skipping zero block: %s", block_size)
-                    offset += block_size
-                    writer.seek(offset)
-                else:
-                    buf = reader.read(offset, block_size)
-                    writer.write(buf)
-                    offset += len(buf)
-                    buf = None
-                    gc.collect()
-
-                event_manager.set_percentage_step(
-                    perc_step, offset)
-
-
-def _copy_wrapper(job_args):
-    disk_id = job_args[0].get("disk_id")
-    try:
-        return _copy_volume(*job_args), disk_id, False
-    except BaseException:
-        return sys.exc_info(), disk_id, True
-
-
-def copy_disk_data(target_conn_info, volumes_info, event_handler):
-    # TODO(gsamfira): the disk image should be an URI that can either be local
-    # (file://) or remote (https://, ftp://, smb://, nfs:// etc).
-    # This must happen if we are to implement multi-worker scenarios.
-    # In such cases, it is not guaranteed that the disk sync task
-    # will be started on the same node onto which the import
-    # happened. It may also be conceivable, that wherever the disk
-    # image ends up, we might be able to directly expose it using
-    # NFS, iSCSI or any other network protocol. In which case,
-    # we can skip downloading it locally just to sync it.
-
-    event_manager = events.EventManager(event_handler)
-
-    ip = target_conn_info["ip"]
-    port = target_conn_info.get("port", 22)
-    username = target_conn_info["username"]
-    pkey = target_conn_info.get("pkey")
-    password = target_conn_info.get("password")
-    event_manager.progress_update("Waiting for connectivity on %s:%s" % (
-        ip, port))
-    utils.wait_for_port_connectivity(ip, port)
-    backup_writer = backup_writers.SSHBackupWriter(
-        ip, port, username, pkey, password, volumes_info)
-    disk_image_reader = qemu_reader.QEMUDiskImageReader()
-
-    pool = eventlet.greenpool.GreenPool()
-    job_data = [(vol, disk_image_reader, backup_writer, event_manager)
-                for vol in volumes_info]
-    for result, disk_id, error in pool.imap(_copy_wrapper, job_data):
-        # TODO(gsamfira): There is no use in letting the other disks finish
-        # sync-ing as we don't save the state of the disk sync anywhere (yet).
-        # When/If we ever do add this info to the database, keep track of
-        # failures, and allow any other paralel sync to finish
-        if error:
-            event_manager.progress_update(
-                "Volume \"%s\" failed to sync" % disk_id)
-            raise result[0](result[1]).with_traceback(result[2])

+ 0 - 0
coriolis/tests/api/v1/__init__py


+ 2 - 1
coriolis/tests/api/v1/data/replicas_validate_create_body.yml

@@ -19,6 +19,7 @@
         storage_mappings: "mock_storage_mappings"
   exception_raised: False
   expected_result:
+    - replica
     - mock_origin_endpoint_id
     - mock_destination_endpoint_id
     - mock_source_environment
@@ -52,5 +53,5 @@
         user_scripts: "mock_user_scripts"
         storage_mappings: "mock_storage_mappings"
   exception_raised: "One or more instance OSMorphing pool mappings were"
-  expected_result: 
+  expected_result:
 

+ 0 - 114
coriolis/tests/api/v1/test_migration_actions.py

@@ -1,114 +0,0 @@
-# Copyright 2023 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from unittest import mock
-
-from webob import exc
-
-from coriolis.api.v1 import migration_actions
-from coriolis import exception
-from coriolis.migrations import api
-from coriolis.tests import test_base
-from coriolis.tests import testutils
-
-
-class MigrationActionsControllerTestCase(test_base.CoriolisBaseTestCase):
-    """Test suite for the Coriolis Migration Actions v1 API"""
-
-    def setUp(self):
-        super(MigrationActionsControllerTestCase, self).setUp()
-        self.migration_actions = migration_actions.MigrationActionsController()
-
-    @mock.patch.object(api.API, 'cancel')
-    def test__cancel(
-        self,
-        mock_cancel,
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-        mock_body = {
-            'cancel': {
-                'force': False
-            }
-        }
-
-        self.assertRaises(
-            exc.HTTPNoContent,
-            testutils.get_wrapped_function(self.migration_actions._cancel),
-            mock_req,
-            id,
-            mock_body
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:cancel")
-        mock_cancel.assert_called_once_with(mock_context, id, False)
-
-    @mock.patch.object(api.API, 'cancel')
-    def test__cancel_empty(
-        self,
-        mock_cancel,
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-        mock_body = {'cancel': {}}
-
-        self.assertRaises(
-            exc.HTTPNoContent,
-            testutils.get_wrapped_function(self.migration_actions._cancel),
-            mock_req,
-            id,
-            mock_body
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:cancel")
-        mock_cancel.assert_called_once_with(mock_context, id, False)
-
-    @mock.patch.object(api.API, 'cancel')
-    def test__cancel_not_found(
-        self,
-        mock_cancel,
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-        mock_body = {'cancel': {}}
-        mock_cancel.side_effect = exception.NotFound()
-
-        self.assertRaises(
-            exc.HTTPNotFound,
-            testutils.get_wrapped_function(self.migration_actions._cancel),
-            mock_req,
-            id,
-            mock_body
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:cancel")
-        mock_cancel.assert_called_once_with(mock_context, id, False)
-
-    @mock.patch.object(api.API, 'cancel')
-    def test__cancel_invalid_parameter_value(
-        self,
-        mock_cancel,
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-        mock_body = {'cancel': {}}
-        mock_cancel.side_effect = exception.InvalidParameterValue("err")
-
-        self.assertRaises(
-            exc.HTTPNotFound,
-            testutils.get_wrapped_function(self.migration_actions._cancel),
-            mock_req,
-            id,
-            mock_body
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:cancel")
-        mock_cancel.assert_called_once_with(mock_context, id, False)

+ 0 - 260
coriolis/tests/api/v1/test_migrations.py

@@ -1,260 +0,0 @@
-# Copyright 2023 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from unittest import mock
-from webob import exc
-
-import ddt
-
-from coriolis.api.v1 import migrations
-from coriolis.api.v1 import utils as api_utils
-from coriolis.api.v1.views import migration_view
-from coriolis.endpoints import api as endpoints_api
-from coriolis import exception
-from coriolis.migrations import api
-from coriolis.tests import test_base
-from coriolis.tests import testutils
-
-
-@ddt.ddt
-class MigrationControllerTestCase(test_base.CoriolisBaseTestCase):
-    """Test suite for the Coriolis Migrations v1 API"""
-
-    def setUp(self):
-        super(MigrationControllerTestCase, self).setUp()
-        self.migrations = migrations.MigrationController()
-
-    @mock.patch.object(migration_view, 'single')
-    @mock.patch.object(api.API, 'get_migration')
-    @mock.patch('coriolis.api.v1.migrations.CONF')
-    def test_show(
-        self,
-        mock_conf,
-        mock_get_migration,
-        mock_single
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-        mock_conf.api.include_task_info_in_migrations_api = False
-
-        result = self.migrations.show(mock_req, id)
-
-        self.assertEqual(
-            mock_single.return_value,
-            result
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:show")
-        mock_get_migration.assert_called_once_with(
-            mock_context, id, include_task_info=False
-        )
-        mock_single.assert_called_once_with(mock_get_migration.return_value)
-
-    @mock.patch.object(api.API, 'get_migration')
-    @mock.patch('coriolis.api.v1.migrations.CONF')
-    def test_show_no_migration(
-        self,
-        mock_conf,
-        mock_get_migration
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-        mock_conf.api.include_task_info_in_migrations_api = False
-        mock_get_migration.return_value = None
-
-        self.assertRaises(
-            exc.HTTPNotFound,
-            self.migrations.show,
-            mock_req,
-            id
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:show")
-        mock_get_migration.assert_called_once_with(
-            mock_context, id, include_task_info=False
-        )
-
-    @mock.patch.object(migration_view, 'collection')
-    @mock.patch.object(api.API, 'get_migrations')
-    @mock.patch.object(api_utils, '_get_show_deleted')
-    @mock.patch('coriolis.api.v1.migrations.CONF')
-    def test__list(
-        self,
-        mock_conf,
-        mock__get_show_deleted,
-        mock_get_migrations,
-        mock_collection
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        mock_conf.api.include_task_info_in_migrations_api = False
-
-        result = self.migrations._list(mock_req)
-
-        self.assertEqual(
-            mock_collection.return_value,
-            result
-        )
-        self.assertEqual(
-            mock_context.show_deleted,
-            mock__get_show_deleted.return_value
-        )
-
-        mock__get_show_deleted.assert_called_once_with(
-            mock_req.GET.get.return_value)
-        mock_context.can.assert_called_once_with("migration:migrations:list")
-        mock_get_migrations.assert_called_once_with(
-            mock_context,
-            include_tasks=False,
-            include_task_info=False
-        )
-
-    @mock.patch.object(api_utils, 'validate_storage_mappings')
-    @mock.patch.object(endpoints_api.API, 'validate_target_environment')
-    @mock.patch.object(api_utils, 'validate_network_map')
-    @mock.patch.object(endpoints_api.API, 'validate_source_environment')
-    @mock.patch.object(api_utils, 'validate_instances_list_for_transfer')
-    @ddt.file_data('data/migration_validate_input.yml')
-    @ddt.unpack
-    def test__validate_migration_input(
-            self,
-            mock_validate_instances_list_for_transfer,
-            mock_validate_source_environment,
-            mock_validate_network_map,
-            mock_validate_target_environment,
-            mock_validate_storage_mappings,
-            config,
-            raises_value_error,
-    ):
-        mock_context = mock.Mock()
-        mock_validate_instances_list_for_transfer.return_value = \
-            config['migration']['instances']
-
-        if raises_value_error:
-            self.assertRaises(
-                ValueError,
-                testutils.get_wrapped_function(
-                    self.migrations._validate_migration_input),
-                self.migrations,
-                context=mock_context,
-                body=config
-            )
-            mock_validate_instances_list_for_transfer.assert_called_once()
-        else:
-            testutils.get_wrapped_function(
-                self.migrations._validate_migration_input)(
-                    self.migrations,
-                    context=mock_context,  # type: ignore
-                    body=config,  # type: ignore
-            )
-            mock_validate_source_environment.assert_called_once_with(
-                mock_context,
-                config['migration']['origin_endpoint_id'],
-                config['migration']['source_environment']
-            )
-            mock_validate_network_map.assert_called_once_with(
-                config['migration']['network_map']
-            )
-            mock_validate_target_environment.assert_called_once_with(
-                mock_context,
-                config['migration']['destination_endpoint_id'],
-                config['migration']['destination_environment']
-            )
-            mock_validate_storage_mappings.assert_called_once_with(
-                config['migration']['storage_mappings']
-            )
-            mock_validate_instances_list_for_transfer.assert_called_once_with(
-                config['migration']['instances'],
-            )
-
-    @mock.patch.object(migration_view, 'single')
-    @mock.patch.object(migrations.MigrationController,
-                       '_validate_migration_input')
-    @mock.patch.object(api_utils, 'normalize_user_scripts')
-    @mock.patch.object(api_utils, 'validate_user_scripts')
-    @ddt.file_data('data/migration_create.yml')
-    @ddt.unpack
-    def test_create(
-        self,
-        mock_validate_user_scripts,
-        mock_normalize_user_scripts,
-        mock__validate_migration_input,
-        mock_single,
-        config,
-        expected_api_method,
-        validation_expected,
-    ):
-        with mock.patch.object(api.API,
-                               expected_api_method) as mock_api_method:
-            mock_req = mock.Mock()
-            mock_context = mock.Mock()
-            mock_req.environ = {'coriolis.context': mock_context}
-            mock__validate_migration_input.return_value = \
-                (mock.sentinel.value,) * 14
-
-            result = self.migrations.create(mock_req, config)
-
-            self.assertEqual(
-                mock_single.return_value,
-                result
-            )
-
-            mock_context.can.assert_called_once_with(
-                "migration:migrations:create")
-            mock_validate_user_scripts.assert_called_once_with(
-                config['migration']['user_scripts'])
-            mock_normalize_user_scripts.assert_called_once_with(
-                config['migration']['user_scripts'],
-                config['migration']['instances']
-            )
-            if validation_expected:
-                mock__validate_migration_input.assert_called_once_with(
-                    mock_context, config)
-            mock_api_method.assert_called_once()
-            mock_single.assert_called_once_with(mock_api_method.return_value)
-
-    @mock.patch.object(api.API, 'delete')
-    def test_delete(
-        self,
-        mock_delete
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-
-        self.assertRaises(
-            exc.HTTPNoContent,
-            self.migrations.delete,
-            mock_req,
-            id
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:delete")
-        mock_delete.assert_called_once_with(mock_context, id)
-
-    @mock.patch.object(api.API, 'delete')
-    def test_delete_not_found(
-        self,
-        mock_delete
-    ):
-        mock_req = mock.Mock()
-        mock_context = mock.Mock()
-        mock_req.environ = {'coriolis.context': mock_context}
-        id = mock.sentinel.id
-        mock_delete.side_effect = exception.NotFound()
-
-        self.assertRaises(
-            exc.HTTPNotFound,
-            self.migrations.delete,
-            mock_req,
-            id
-        )
-
-        mock_context.can.assert_called_once_with("migration:migrations:delete")
-        mock_delete.assert_called_once_with(mock_context, id)

+ 1 - 1
coriolis/tests/api/v1/test_replicas.py

@@ -200,7 +200,7 @@ class ReplicaControllerTestCase(test_base.CoriolisBaseTestCase):
         mock_context = mock.Mock()
         mock_req.environ = {'coriolis.context': mock_context}
         mock_body = {}
-        mock_validate_create_body.return_value = (mock.sentinel.value,) * 12
+        mock_validate_create_body.return_value = (mock.sentinel.value,) * 13
 
         result = self.replicas.create(mock_req, mock_body)
 

+ 21 - 22
coriolis/tests/api/v1/test_router.py

@@ -3,6 +3,8 @@
 
 from unittest import mock
 
+from coriolis.api.v1 import deployment_actions
+from coriolis.api.v1 import deployments
 from coriolis.api.v1 import diagnostics
 from coriolis.api.v1 import endpoint_actions
 from coriolis.api.v1 import endpoint_destination_minion_pool_options
@@ -13,8 +15,6 @@ from coriolis.api.v1 import endpoint_source_minion_pool_options
 from coriolis.api.v1 import endpoint_source_options
 from coriolis.api.v1 import endpoint_storage
 from coriolis.api.v1 import endpoints
-from coriolis.api.v1 import migration_actions
-from coriolis.api.v1 import migrations
 from coriolis.api.v1 import minion_pool_actions
 from coriolis.api.v1 import minion_pools
 from coriolis.api.v1 import provider_schemas
@@ -37,14 +37,14 @@ class APIRouterTestCase(test_base.CoriolisBaseTestCase):
         super(APIRouterTestCase, self).setUp()
         self.router = router.APIRouter()
 
+    @mock.patch.object(deployments, 'create_resource')
+    @mock.patch.object(deployment_actions, 'create_resource')
     @mock.patch.object(diagnostics, 'create_resource')
     @mock.patch.object(replica_schedules, 'create_resource')
     @mock.patch.object(replica_tasks_execution_actions, 'create_resource')
     @mock.patch.object(replica_tasks_executions, 'create_resource')
     @mock.patch.object(replica_actions, 'create_resource')
     @mock.patch.object(replicas, 'create_resource')
-    @mock.patch.object(migration_actions, 'create_resource')
-    @mock.patch.object(migrations, 'create_resource')
     @mock.patch.object(provider_schemas, 'create_resource')
     @mock.patch.object(endpoint_source_options, 'create_resource')
     @mock.patch.object(endpoint_destination_options, 'create_resource')
@@ -78,14 +78,14 @@ class APIRouterTestCase(test_base.CoriolisBaseTestCase):
         mock_endpoint_destination_options_create_resource,
         mock_endpoint_source_options_create_resource,
         mock_provider_schemas_create_resource,
-        mock_migrations_create_resource,
-        mock_migration_actions_create_resource,
         mock_replicas_create_resource,
         mock_replica_actions_create_resource,
         mock_replica_tasks_executions_create_resource,
         mock_replica_tasks_execution_actions_create_resource,
         mock_replica_schedules_create_resource,
         mock_diagnostics_create_resource,
+        mock_deployment_actions_create_resource,
+        mock_deployments_create_resource
     ):
         ext_mgr = mock.sentinel.ext_mgr
         mapper = mock.Mock()
@@ -160,12 +160,6 @@ class APIRouterTestCase(test_base.CoriolisBaseTestCase):
                 'providers/{platform_name}/schemas/{provider_type}',
                 controller=mock_provider_schemas_create_resource.return_value,
             ),
-            mock.call(
-                'migration', 'migrations',
-                controller=mock_migrations_create_resource.return_value,
-                collection={'detail': 'GET'},
-                member={'action': 'POST'}
-            ),
             mock.call(
                 'replica', 'replicas',
                 controller=mock_replicas_create_resource.return_value,
@@ -192,6 +186,12 @@ class APIRouterTestCase(test_base.CoriolisBaseTestCase):
                 'diagnostics', 'diagnostics',
                 controller=mock_diagnostics_create_resource.return_value,
             ),
+            mock.call(
+                'deployment', 'deployments',
+                controller=mock_deployments_create_resource.return_value,
+                collection={'detail': 'GET'},
+                member={'action': 'POST'}
+            ),
         ]
 
         connect_calls = [
@@ -211,14 +211,6 @@ class APIRouterTestCase(test_base.CoriolisBaseTestCase):
                 action='action',
                 conditions={'method': 'POST'}
             ),
-            mock.call(
-                'migration_actions',
-                '/{project_id}/migrations/{id}/actions',
-                controller=
-                mock_migration_actions_create_resource.return_value,
-                action='action',
-                conditions={'method': 'POST'}
-            ),
             mock.call(
                 'replica_actions',
                 '/{project_id}/replicas/{id}/actions',
@@ -235,10 +227,17 @@ class APIRouterTestCase(test_base.CoriolisBaseTestCase):
                 action='action',
                 conditions={'method': 'POST'}
             ),
+            mock.call(
+                'deployment_actions', '/{project_id}/deployments/{id}/actions',
+                controller=(
+                    mock_deployment_actions_create_resource.return_value),
+                action='action',
+                conditions={"method": "POST"}
+            ),
         ]
 
         self.router._setup_routes(mapper, ext_mgr)
 
         mapper.redirect.assert_called_once_with("", "/")
-        mapper.resource.assert_has_calls(resource_calls)
-        mapper.connect.assert_has_calls(connect_calls)
+        mapper.resource.assert_has_calls(resource_calls, any_order=True)
+        mapper.connect.assert_has_calls(connect_calls, any_order=True)

+ 1 - 42
coriolis/tests/conductor/rpc/test_client.py

@@ -7,8 +7,8 @@ from coriolis.conductor.rpc import client
 from coriolis import constants
 from coriolis.tests import test_base
 
-
 INSTANCE_ARGS = {
+    "replica_scenario": "mock_replica_scenario",
     "origin_endpoint_id": "mock_origin_endpoint_id",
     "destination_endpoint_id": "mock_destination_endpoint_id",
     "origin_minion_pool_id": "mock_origin_minion_pool_id",
@@ -223,34 +223,6 @@ class ConductorClientTestCase(test_base.CoriolisRPCClientTestCase):
         }
         self._test(self.client.delete_replica_disks, args)
 
-    def test_get_migrations(self):
-        args = {
-            "include_tasks": False,
-            "include_task_info": False,
-        }
-        self._test(self.client.get_migrations, args)
-
-    def test_get_migration(self):
-        args = {
-            "migration_id": "mock_migration_id",
-            "include_task_info": False,
-        }
-        self._test(self.client.get_migration, args)
-
-    def test_migrate_instances(self):
-        args = {
-            **INSTANCE_ARGS,
-            "replication_count": 1,
-            "shutdown_instances": False,
-            "skip_os_morphing": False
-        }
-        new_args = {
-            "notes": None,
-            "user_scripts": None
-        }
-        args.update(new_args)
-        self._test(self.client.migrate_instances, args)
-
     def test_deploy_replica_instances(self):
         args = {
             "replica_id": "mock_replica_id",
@@ -262,19 +234,6 @@ class ConductorClientTestCase(test_base.CoriolisRPCClientTestCase):
         }
         self._test(self.client.deploy_replica_instances, args)
 
-    def test_delete_migration(self):
-        args = {
-            "migration_id": "mock_migration_id"
-        }
-        self._test(self.client.delete_migration, args)
-
-    def test_cancel_migration(self):
-        args = {
-            "migration_id": "mock_migration_id",
-            "force": "mock_force"
-        }
-        self._test(self.client.cancel_migration, args)
-
     def test_set_task_host(self):
         args = {
             "task_id": "mock_task_id",

+ 12 - 550
coriolis/tests/conductor/rpc/test_server.py

@@ -17,7 +17,6 @@ from coriolis.db import api as db_api
 from coriolis.db.sqlalchemy import models
 from coriolis import exception
 from coriolis import keystone
-from coriolis.licensing import client as licensing_client
 from coriolis import schemas
 from coriolis.tests import test_base
 from coriolis.tests import testutils
@@ -136,136 +135,6 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             transfer_action.reservation_id
         )
 
-    def test_check_create_reservation_for_transfer(self):
-        transfer_action = mock.Mock()
-        transfer_action.instances = ['instance_1', 'instance_2']
-        transfer_type = mock.sentinel.transfer_type
-        self._licensing_client.add_reservation.return_value = {
-            'id': mock.sentinel.id
-        }
-        self.server._check_create_reservation_for_transfer(
-            transfer_action, transfer_type)
-        self._licensing_client.add_reservation.assert_called_once_with(
-            mock.sentinel.transfer_type,
-            2
-        )
-        self.assertEqual(
-            transfer_action.reservation_id,
-            mock.sentinel.id
-        )
-
-    def test_check_create_reservation_for_transfer_no_licensing_client(self):
-        transfer_action = mock.Mock()
-        transfer_type = mock.sentinel.transfer_type
-        self.server._licensing_client = None
-        with self.assertLogs(
-            'coriolis.conductor.rpc.server', level=logging.WARNING):
-            self.server._check_create_reservation_for_transfer(
-                transfer_action, transfer_type)
-
-    def test_check_reservation_for_transfer(self):
-        transfer_action = mock.Mock()
-        transfer_action.reservation_id = mock.sentinel.reservation_id
-        reservation_type = mock.sentinel.reservation_type
-        self._licensing_client.check_refresh_reservation.return_value = {
-            'id': mock.sentinel.reservation_id}
-        self.server._check_reservation_for_transfer(
-            transfer_action, reservation_type)
-        (self._licensing_client.check_refresh_reservation.
-            assert_called_once_with)(
-                mock.sentinel.reservation_id)
-
-    def test_check_reservation_for_transfer_no_licensing_client(
-        self
-    ):
-        transfer_action = mock.Mock()
-        reservation_type = mock.sentinel.reservation_type
-        self.server._licensing_client = None
-        with self.assertLogs(
-            'coriolis.conductor.rpc.server', level=logging.WARNING):
-            self.server._check_reservation_for_transfer(
-                transfer_action, reservation_type)
-
-    @mock.patch.object(server.ConductorServerEndpoint,
-                       '_check_create_reservation_for_transfer')
-    def test_check_reservation_for_transfer_no_reservation_id(
-        self,
-        mock_check_create_reservation_for_transfer
-    ):
-        transfer_action = mock.Mock()
-        transfer_action.reservation_id = None
-        reservation_type = mock.sentinel.reservation_type
-        self.server._check_reservation_for_transfer(
-            transfer_action, reservation_type)
-        self._licensing_client.check_refresh_reservation.assert_not_called()
-        mock_check_create_reservation_for_transfer.assert_called_once_with(
-            transfer_action, reservation_type
-        )
-
-    @mock.patch.object(server.ConductorServerEndpoint,
-                       '_check_create_reservation_for_transfer')
-    def test_check_reservation_for_transfer_exc_code_404(
-        self,
-        mock_check_create_reservation_for_transfer
-    ):
-        transfer_action = mock.Mock()
-        transfer_action.reservation_id = mock.sentinel.reservation_id
-        reservation_type = mock.sentinel.reservation_type
-        ex = CoriolisTestException()
-        ex.code = 404
-        self._licensing_client.check_refresh_reservation.side_effect = ex
-        self.server._check_reservation_for_transfer(
-            transfer_action, reservation_type)
-        (self._licensing_client.check_refresh_reservation
-            .assert_called_once_with)(
-                mock.sentinel.reservation_id)
-        mock_check_create_reservation_for_transfer.assert_called_once_with(
-            transfer_action, reservation_type
-        )
-
-    @mock.patch.object(server.ConductorServerEndpoint,
-                       '_check_create_reservation_for_transfer')
-    def test_check_reservation_for_transfer_exc_code_409(
-        self,
-        mock_check_create_reservation_for_transfer
-    ):
-        transfer_action = mock.Mock()
-        transfer_action.reservation_id = mock.sentinel.reservation_id
-        reservation_type = mock.sentinel.reservation_type
-        ex = CoriolisTestException()
-        ex.code = 409
-        self._licensing_client.check_refresh_reservation.side_effect = ex
-        self.server._check_reservation_for_transfer(
-            transfer_action, reservation_type)
-        (self._licensing_client.check_refresh_reservation
-            .assert_called_once_with)(
-                mock.sentinel.reservation_id)
-        mock_check_create_reservation_for_transfer.assert_called_once_with(
-            transfer_action, reservation_type
-        )
-
-    @mock.patch.object(server.ConductorServerEndpoint,
-                       '_check_create_reservation_for_transfer')
-    def test_check_reservation_for_transfer_exc_code_not_excepted(
-        self,
-        mock_check_create_reservation_for_transfer
-    ):
-        transfer_action = mock.Mock()
-        transfer_action.reservation_id = mock.sentinel.reservation_id
-        reservation_type = mock.sentinel.reservation_type
-        ex = CoriolisTestException()
-        self._licensing_client.check_refresh_reservation.side_effect = ex
-        self.assertRaises(
-            CoriolisTestException,
-            self.server._check_reservation_for_transfer,
-            transfer_action,
-            reservation_type
-        )
-        (self._licensing_client.check_refresh_reservation
-            .assert_called_once_with)(
-                mock.sentinel.reservation_id)
-        mock_check_create_reservation_for_transfer.assert_not_called()
-
     @mock.patch.object(server.ConductorServerEndpoint, "get_endpoint")
     @mock.patch.object(db_api, "delete_endpoint")
     @mock.patch.object(db_api, "update_endpoint")
@@ -1343,7 +1212,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
     )
     @mock.patch.object(
         server.ConductorServerEndpoint,
-        "_check_reservation_for_transfer"
+        "_check_reservation_for_replica"
     )
     @mock.patch.object(
         server.ConductorServerEndpoint,
@@ -1422,10 +1291,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             mock.sentinel.replica_id,
             include_task_info=True,
         )
-        mock_check_reservation.assert_called_once_with(
-            mock_replica,
-            licensing_client.RESERVATION_TYPE_REPLICA
-        )
+        mock_check_reservation.assert_called_once_with(mock_replica)
         mock_check_replica_running_executions.assert_called_once_with(
             mock.sentinel.context, mock_replica)
         mock_check_minion_pools_for_action.assert_called_once_with(
@@ -2033,7 +1899,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
     @mock.patch.object(server.ConductorServerEndpoint, 'get_replica')
     @mock.patch.object(db_api, 'add_replica')
     @mock.patch.object(server.ConductorServerEndpoint,
-                       '_check_create_reservation_for_transfer')
+                       '_create_reservation_for_replica')
     @mock.patch.object(server.ConductorServerEndpoint,
                        '_check_minion_pools_for_action')
     @mock.patch.object(models, 'Replica')
@@ -2045,7 +1911,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
         mock_check_endpoints,
         mock_replica,
         mock_check_minion_pools_for_action,
-        mock_check_create_reservation_for_transfer,
+        mock_create_reservation_for_replica,
         mock_add_replica,
         mock_get_replica
     ):
@@ -2054,6 +1920,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
         mock_replica.return_value = mock.Mock()
         result = self.server.create_instances_replica(
             mock.sentinel.context,
+            constants.REPLICA_SCENARIO_REPLICA,
             mock.sentinel.origin_endpoint_id,
             mock.sentinel.destination_endpoint_id,
             mock.sentinel.origin_minion_pool_id,
@@ -2111,10 +1978,8 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
         )
         mock_check_minion_pools_for_action.assert_called_once_with(
             mock.sentinel.context, mock_replica.return_value)
-        mock_check_create_reservation_for_transfer.assert_called_once_with(
-            mock_replica.return_value,
-            licensing_client.RESERVATION_TYPE_REPLICA
-        )
+        mock_create_reservation_for_replica.assert_called_once_with(
+            mock_replica.return_value)
         mock_add_replica.assert_called_once_with(
             mock.sentinel.context, mock_replica.return_value)
         mock_get_replica.assert_called_once_with(
@@ -2157,24 +2022,6 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             to_dict=False
         )
 
-    @mock.patch.object(db_api, 'get_migrations')
-    def test_get_migrations(self, mock_get_migrations):
-        result = self.server.get_migrations(
-            mock.sentinel.context,
-            mock.sentinel.migration_id,
-            include_task_info=False
-        )
-        self.assertEqual(
-            mock_get_migrations.return_value,
-            result
-        )
-        mock_get_migrations.assert_called_once_with(
-            mock.sentinel.context,
-            mock.sentinel.migration_id,
-            include_task_info=False,
-            to_dict=True
-        )
-
     @mock.patch.object(server.ConductorServerEndpoint, '_get_migration')
     def test_get_migration(self, mock_get_migration):
         result = testutils.get_wrapped_function(self.server.get_migration)(
@@ -2374,7 +2221,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
     )
     @mock.patch.object(
         server.ConductorServerEndpoint,
-        '_check_reservation_for_transfer'
+        '_check_reservation_for_replica'
     )
     @mock.patch.object(
         server.ConductorServerEndpoint,
@@ -2452,7 +2299,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             mock_get_endpoint,
             mock_check_valid_replica_tasks_execution,
             mock_check_replica_running_executions,
-            mock_check_reservation_for_transfer,
+            mock_check_reservation_for_replica,
             mock_get_replica,
             config,
             expected_tasks,
@@ -2515,10 +2362,8 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             mock.sentinel.replica_id,
             include_task_info=True,
         )
-        mock_check_reservation_for_transfer.assert_called_once_with(
-            mock_get_replica.return_value,
-            licensing_client.RESERVATION_TYPE_REPLICA
-        )
+        mock_check_reservation_for_replica.assert_called_once_with(
+            mock_get_replica.return_value)
         mock_check_replica_running_executions.assert_called_once_with(
             mock.sentinel.context,
             mock_get_replica.return_value
@@ -3295,289 +3140,6 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
         mock_cancel_tasks_execution.assert_not_called()
         mock_set_tasks_execution_status.assert_not_called()
 
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "get_endpoint"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_check_endpoints"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_get_provider_types"
-    )
-    @mock.patch.object(models, "Migration")
-    @mock.patch.object(uuid, "uuid4")
-    @mock.patch.object(models, "TasksExecution")
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_check_create_reservation_for_transfer"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_check_minion_pools_for_action"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_get_instance_scripts"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_create_task"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_check_execution_tasks_sanity"
-    )
-    @mock.patch.object(
-        db_api,
-        "add_migration"
-    )
-    @mock.patch.object(
-        lockutils,
-        "lock"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_minion_manager_client"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_set_tasks_execution_status"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "_begin_tasks"
-    )
-    @mock.patch.object(
-        server.ConductorServerEndpoint,
-        "get_migration"
-    )
-    @ddt.file_data("data/migrate_instances_config.yml")
-    @ddt.unpack
-    def test_migrate_instances(
-            self,
-            mock_get_migration,
-            mock_begin_tasks,
-            mock_set_tasks_execution_status,
-            mock_minion_manager_client,
-            mock_lock,
-            mock_add_migration,
-            mock_check_execution_tasks_sanity,
-            mock_create_task,
-            mock_get_instance_scripts,
-            mock_check_minion_pools_for_action,
-            mock_check_create_reservation_for_transfer,
-            mock_tasks_execution,
-            mock_uuid4,
-            mock_migration,
-            mock_get_provider_types,
-            mock_check_endpoints,
-            mock_get_endpoint,
-            config,
-            expected_tasks,
-    ):
-        has_origin_minion_pool = config.get(
-            'has_origin_minion_pool', False
-        )
-        has_destination_minion_pool = config.get(
-            'has_destination_minion_pool', False
-        )
-        has_os_morphing_pool = config.get(
-            'has_os_morphing_pool', False
-        )
-        shutdown_instances = config.get('shutdown_instances', False)
-        skip_os_morphing = config.get('skip_os_morphing', True)
-        get_optimal_flavor = config.get('get_optimal_flavor', False)
-
-        if get_optimal_flavor:
-            mock_get_provider_types.return_value = [
-                constants.PROVIDER_TYPE_INSTANCE_FLAVOR
-            ]
-
-        instances = [
-            mock.sentinel.instance_1,
-            mock.sentinel.instance_2,
-        ]
-        instance_osmorphing_minion_pool_mappings = {}
-        if has_os_morphing_pool:
-            instance_osmorphing_minion_pool_mappings = {
-                mock.sentinel.instance_1: mock.sentinel.minion_pool_1,
-                mock.sentinel.instance_2: mock.sentinel.minion_pool_2,
-            }
-
-        replication_count = 2
-
-        def create_task_side_effect(
-                instance,
-                task_type,
-                execution,
-                depends_on=None,
-                on_error=False,
-                on_error_only=False
-        ):
-            return mock.Mock(
-                id=task_type,
-                type=task_type,
-                instance=instance,
-                execution=execution,
-                depends_on=depends_on,
-                on_error=on_error,
-                on_error_only=on_error_only,
-            )
-
-        mock_create_task.side_effect = create_task_side_effect
-
-        migration = self.server.migrate_instances(
-            mock.sentinel.context,
-            mock.sentinel.origin_endpoint_id,
-            mock.sentinel.destination_endpoint_id,
-            has_origin_minion_pool
-            and mock.sentinel.origin_minion_pool_id,
-            has_destination_minion_pool
-            and mock.sentinel.destination_minion_pool_id,
-            instance_osmorphing_minion_pool_mappings,
-            mock.sentinel.source_environment,
-            mock.sentinel.destination_environment,
-            instances,
-            mock.sentinel.network_map,
-            mock.sentinel.storage_mappings,
-            replication_count,
-            shutdown_instances=shutdown_instances,
-            notes=mock.sentinel.notes,
-            skip_os_morphing=skip_os_morphing,
-            user_scripts=mock.sentinel.user_scripts,
-        )
-
-        mock_get_endpoint.assert_has_calls([
-            mock.call(
-                mock.sentinel.context,
-                mock.sentinel.origin_endpoint_id,
-            ),
-            mock.call(
-                mock.sentinel.context,
-                mock.sentinel.destination_endpoint_id,
-            ),
-        ])
-
-        mock_check_endpoints.assert_called_once_with(
-            mock.sentinel.context,
-            mock_get_endpoint.return_value,
-            mock_get_endpoint.return_value,
-        )
-
-        self.assertEqual(
-            mock_migration.return_value.last_execution_status,
-            constants.EXECUTION_STATUS_UNEXECUTED,
-        )
-        self.assertEqual(
-            mock_tasks_execution.return_value.status,
-            constants.EXECUTION_STATUS_UNEXECUTED,
-        )
-        self.assertEqual(
-            mock_tasks_execution.return_value.type,
-            constants.EXECUTION_TYPE_MIGRATION,
-        )
-
-        mock_check_create_reservation_for_transfer.assert_called_once_with(
-            mock_migration.return_value,
-            licensing_client.RESERVATION_TYPE_MIGRATION,
-        )
-
-        mock_check_minion_pools_for_action.assert_called_once_with(
-            mock.sentinel.context,
-            mock_migration.return_value,
-        )
-
-        for instance in instances:
-            mock_get_instance_scripts.assert_any_call(
-                mock.sentinel.user_scripts,
-                instance,
-            )
-            mock_create_task.assert_has_calls([
-                mock.call(
-                    instance,
-                    constants.TASK_TYPE_GET_INSTANCE_INFO,
-                    mock_tasks_execution.return_value,
-                ),
-                mock.call(
-                    instance,
-                    constants.TASK_TYPE_VALIDATE_MIGRATION_SOURCE_INPUTS,
-                    mock_tasks_execution.return_value,
-                ),
-                mock.call(
-                    instance,
-                    constants.TASK_TYPE_VALIDATE_MIGRATION_DESTINATION_INPUTS,
-                    mock_tasks_execution.return_value,
-                    depends_on=[constants.TASK_TYPE_GET_INSTANCE_INFO]
-                ),
-            ])
-
-            # tasks defined in the yaml config
-            for task in expected_tasks:
-                kwargs = {}
-                if 'on_error' in task:
-                    kwargs = {'on_error': task['on_error']}
-                if 'on_error_only' in task:
-                    kwargs = {'on_error_only': task['on_error_only']}
-                mock_create_task.assert_has_calls([
-                    mock.call(
-                        instance,
-                        task['type'],
-                        mock_tasks_execution.return_value,
-                        depends_on=task['depends_on'],
-                        **kwargs,
-                    )
-                ])
-
-        mock_check_execution_tasks_sanity.assert_called_once_with(
-            mock_tasks_execution.return_value,
-            mock_migration.return_value.info,
-        )
-
-        mock_add_migration.assert_called_once_with(
-            mock.sentinel.context,
-            mock_migration.return_value,
-        )
-
-        if any([
-            has_origin_minion_pool,
-            has_destination_minion_pool,
-            has_os_morphing_pool,
-        ]):
-            mock_lock.assert_any_call(
-                constants.MIGRATION_LOCK_NAME_FORMAT
-                % mock_migration.return_value.id,
-                external=True,
-            )
-            mock_minion_manager_client\
-                .allocate_minion_machines_for_migration\
-                .assert_called_once_with(
-                    mock.sentinel.context,
-                    mock_migration.return_value,
-                    include_transfer_minions=True,
-                    include_osmorphing_minions=not skip_os_morphing,
-                )
-            mock_set_tasks_execution_status.assert_called_once_with(
-                mock.sentinel.context,
-                mock_tasks_execution.return_value,
-                constants.EXECUTION_STATUS_AWAITING_MINION_ALLOCATIONS
-            )
-        else:
-            mock_begin_tasks.assert_called_once_with(
-                mock.sentinel.context,
-                mock_migration.return_value,
-                mock_tasks_execution.return_value,
-            )
-
-        mock_get_migration.assert_called_once_with(
-            mock.sentinel.context,
-            mock_migration.return_value.id,
-        )
-
-        self.assertEqual(migration, mock_get_migration.return_value)
-
     @mock.patch.object(db_api, 'get_tasks_execution')
     @mock.patch.object(
         server.ConductorServerEndpoint,
@@ -3725,106 +3287,6 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
             to_dict=False
         )
 
-    @mock.patch.object(db_api, 'delete_migration')
-    @mock.patch.object(server.ConductorServerEndpoint, '_get_migration')
-    def test_delete_migration(
-        self,
-        mock_get_migration,
-        mock_delete_migration
-    ):
-        migration = mock.Mock()
-        execution = mock.Mock()
-        execution.status = constants.EXECUTION_STATUS_COMPLETED
-        migration.executions = [execution]
-        mock_get_migration.return_value = migration
-
-        testutils.get_wrapped_function(self.server.delete_migration)(
-            self.server,
-            mock.sentinel.context,
-            mock.sentinel.migration_id
-        )
-
-        mock_get_migration.assert_called_once_with(
-            mock.sentinel.context,
-            mock.sentinel.migration_id
-        )
-        mock_delete_migration.assert_called_once_with(
-            mock.sentinel.context,
-            mock.sentinel.migration_id
-        )
-        mock_get_migration.reset_mock()
-        mock_delete_migration.reset_mock()
-        execution.status = constants.EXECUTION_STATUS_RUNNING
-
-        self.assertRaises(
-            exception.InvalidMigrationState,
-            testutils.get_wrapped_function(self.server.delete_migration),
-            self.server,
-            mock.sentinel.context,
-            mock.sentinel.migration_id
-        )
-
-        mock_get_migration.assert_called_once_with(
-            mock.sentinel.context,
-            mock.sentinel.migration_id
-        )
-        mock_delete_migration.assert_not_called()
-
-    @mock.patch.object(server.ConductorServerEndpoint,
-                       '_cancel_tasks_execution')
-    @mock.patch.object(lockutils, 'lock')
-    @mock.patch.object(server.ConductorServerEndpoint, '_get_migration')
-    @ddt.file_data("data/cancel_migration_config.yml")
-    @ddt.unpack
-    def test_cancel_migration(
-        self,
-        mock_get_migration,
-        mock_lock,
-        mock_cancel_tasks_execution,
-        config,
-        raises_exception
-    ):
-        migration = mock.Mock()
-        migration.executions = []
-        statuses = config.get('execution_statuses', [])
-        for status in statuses:
-            execution = mock.Mock()
-            execution.status = getattr(constants, status)
-            migration.executions.append(execution)
-        mock_get_migration.return_value = migration
-        force = config.get('force', False)
-
-        if raises_exception:
-            self.assertRaises(
-                exception.InvalidMigrationState,
-                testutils.get_wrapped_function(self.server.cancel_migration),
-                self.server,
-                mock.sentinel.context,
-                mock.sentinel.migration_id,
-                force=force
-            )
-        else:
-            testutils.get_wrapped_function(self.server.cancel_migration)(
-                self.server,
-                mock.sentinel.context,
-                mock.sentinel.migration_id,
-                force=force
-            )
-            mock_lock.assert_called_once_with(
-                constants.EXECUTION_LOCK_NAME_FORMAT % execution.id,
-                external=True
-            )
-            mock_cancel_tasks_execution.assert_called_once_with(
-                mock.sentinel.context,
-                execution,
-                force=force
-            )
-
-        mock_get_migration.assert_called_once_with(
-            mock.sentinel.context,
-            mock.sentinel.migration_id
-        )
-
     @mock.patch.object(db_api, 'get_tasks_execution')
     @mock.patch.object(
         server.ConductorServerEndpoint,
@@ -3946,7 +3408,7 @@ class ConductorServerEndpointTestCase(test_base.CoriolisBaseTestCase):
         )
         mock_delete_trust.assert_not_called()
         mock_get_action.assert_called_once_with(
-            context, mock_set_execution_status.return_value.action_id)
+            context, execution.action_id)
         mock_deallocate_minion_machines_for_action.assert_called_once_with(
             context, mock_get_action.return_value)
 

+ 0 - 0
coriolis/tests/migrations/__init__.py


+ 0 - 93
coriolis/tests/migrations/test_api.py

@@ -1,93 +0,0 @@
-# Copyright 2024 Cloudbase Solutions Srl
-# All Rights Reserved.
-
-from unittest import mock
-
-from coriolis.migrations import api as migrations_module
-from coriolis.tests import test_base
-
-
-class APITestCase(test_base.CoriolisBaseTestCase):
-    """Test suite for the Coriolis Migrations API."""
-
-    def setUp(self):
-        super(APITestCase, self).setUp()
-        self.api = migrations_module.API()
-        self.rpc_client = mock.MagicMock()
-        self.api._rpc_client = self.rpc_client
-        self.ctxt = mock.sentinel.ctxt
-        self.migration_id = mock.sentinel.migration_id
-
-    def test_migrate_instances(self):
-        origin_endpoint_id = mock.sentinel.origin_endpoint_id
-        destination_endpoint_id = mock.sentinel.destination_endpoint_id
-        origin_minion_pool_id = mock.sentinel.origin_minion_pool_id
-        destination_minion_pool_id = mock.sentinel.destination_minion_pool_id
-        instance_osmorphing_minion_pool_mappings = (
-            mock.sentinel.instance_osmorphing_minion_pool_mappings)
-        source_environment = mock.sentinel.source_environment
-        destination_environment = mock.sentinel.destination_environment
-        instances = mock.sentinel.instances
-        network_map = mock.sentinel.network_map
-        storage_mappings = mock.sentinel.storage_mappings
-        replication_count = mock.sentinel.replication_count
-        shutdown_instances = mock.sentinel.shutdown_instances
-
-        result = self.api.migrate_instances(
-            self.ctxt, origin_endpoint_id, destination_endpoint_id,
-            origin_minion_pool_id, destination_minion_pool_id,
-            instance_osmorphing_minion_pool_mappings, source_environment,
-            destination_environment, instances, network_map, storage_mappings,
-            replication_count, shutdown_instances)
-        self.rpc_client.migrate_instances.assert_called_once_with(
-            self.ctxt, origin_endpoint_id, destination_endpoint_id,
-            origin_minion_pool_id, destination_minion_pool_id,
-            instance_osmorphing_minion_pool_mappings, source_environment,
-            destination_environment, instances, network_map, storage_mappings,
-            replication_count, shutdown_instances=shutdown_instances,
-            notes=None, skip_os_morphing=False, user_scripts=None)
-        self.assertEqual(result,
-                         self.rpc_client.migrate_instances.return_value)
-
-    def test_deploy_replica_instances(self):
-        replica_id = mock.sentinel.replica_id
-        instance_osmorphing_minion_pool_mappings = (
-            mock.sentinel.instance_osmorphing_minion_pool_mappings)
-
-        result = self.api.deploy_replica_instances(
-            self.ctxt, replica_id, instance_osmorphing_minion_pool_mappings)
-
-        self.rpc_client.deploy_replica_instances.assert_called_once_with(
-            self.ctxt, replica_id,
-            instance_osmorphing_minion_pool_mappings=(
-                instance_osmorphing_minion_pool_mappings),
-            clone_disks=False, force=False, skip_os_morphing=False,
-            user_scripts=None)
-        self.assertEqual(result,
-                         self.rpc_client.deploy_replica_instances.return_value)
-
-    def test_delete(self):
-        self.api.delete(self.ctxt, self.migration_id)
-        self.rpc_client.delete_migration.assert_called_once_with(
-            self.ctxt, self.migration_id)
-
-    def test_cancel(self):
-        self.api.cancel(self.ctxt, self.migration_id, True)
-        self.rpc_client.cancel_migration.assert_called_once_with(
-            self.ctxt, self.migration_id, True)
-
-    def test_get_migrations(self):
-        result = self.api.get_migrations(self.ctxt, include_tasks=False,
-                                         include_task_info=False)
-
-        self.rpc_client.get_migrations.assert_called_once_with(
-            self.ctxt, False, include_task_info=False)
-        self.assertEqual(result, self.rpc_client.get_migrations.return_value)
-
-    def test_get_migration(self):
-        result = self.api.get_migration(self.ctxt, self.migration_id,
-                                        include_task_info=False)
-
-        self.rpc_client.get_migration.assert_called_once_with(
-            self.ctxt, self.migration_id, include_task_info=False)
-        self.assertEqual(result, self.rpc_client.get_migration.return_value)

+ 4 - 2
coriolis/tests/replicas/test_api.py

@@ -32,13 +32,15 @@ class APITestCase(test_base.CoriolisBaseTestCase):
         storage_mappings = mock.sentinel.storage_mappings
 
         result = self.api.create(
-            self.ctxt, origin_endpoint_id, destination_endpoint_id,
+            self.ctxt, mock.sentinel.replica_scenario,
+            origin_endpoint_id, destination_endpoint_id,
             origin_minion_pool_id, destination_minion_pool_id,
             instance_osmorphing_minion_pool_mappings, source_environment,
             destination_environment, instances, network_map, storage_mappings)
 
         self.rpc_client.create_instances_replica.assert_called_once_with(
-            self.ctxt, origin_endpoint_id, destination_endpoint_id,
+            self.ctxt, mock.sentinel.replica_scenario,
+            origin_endpoint_id, destination_endpoint_id,
             origin_minion_pool_id, destination_minion_pool_id,
             instance_osmorphing_minion_pool_mappings, source_environment,
             destination_environment, instances, network_map, storage_mappings,