Alessandro Pilotti 9 лет назад
Родитель
Сommit
3358235f99

+ 8 - 4
coriolis/api/v1/migrations.py

@@ -43,9 +43,11 @@ class MigrationController(api_wsgi.Controller):
             destination_environment = migration.get("destination_environment")
             instances = migration["instances"]
             notes = migration.get("notes")
+            skip_os_morphing = migration.get("skip_os_morphing", False)
 
             return (origin_endpoint_id, destination_endpoint_id,
-                    destination_environment, instances, notes)
+                    destination_environment, instances, notes,
+                    skip_os_morphing)
         except Exception as ex:
             LOG.exception(ex)
             if hasattr(ex, "message"):
@@ -63,19 +65,21 @@ class MigrationController(api_wsgi.Controller):
         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)
 
             migration = self._migration_api.deploy_replica_instances(
-                context, replica_id, clone_disks, force)
+                context, replica_id, clone_disks, force, skip_os_morphing)
         else:
             (origin_endpoint_id,
              destination_endpoint_id,
              destination_environment,
              instances,
-             notes) = self._validate_migration_input(
+             notes,
+             skip_os_morphing) = self._validate_migration_input(
                 migration_body)
             migration = self._migration_api.migrate_instances(
                 context, origin_endpoint_id, destination_endpoint_id,
-                destination_environment, instances, notes)
+                destination_environment, instances, notes, skip_os_morphing)
 
         return migration_view.single(req, migration)
 

+ 6 - 4
coriolis/conductor/rpc/client.py

@@ -123,20 +123,22 @@ class ConductorClient(object):
 
     def migrate_instances(self, ctxt, origin_endpoint_id,
                           destination_endpoint_id, destination_environment,
-                          instances, notes=None):
+                          instances, notes=None, skip_os_morphing=False):
         return self._client.call(
             ctxt, 'migrate_instances',
             origin_endpoint_id=origin_endpoint_id,
             destination_endpoint_id=destination_endpoint_id,
             destination_environment=destination_environment,
             instances=instances,
-            notes=notes)
+            notes=notes,
+            skip_os_morphing=skip_os_morphing)
 
     def deploy_replica_instances(self, ctxt, replica_id, clone_disks=False,
-                                 force=False):
+                                 force=False, skip_os_morphing=False):
         return self._client.call(
             ctxt, 'deploy_replica_instances', replica_id=replica_id,
-            clone_disks=clone_disks, force=force)
+            clone_disks=clone_disks, force=force,
+            skip_os_morphing=skip_os_morphing)
 
     def delete_migration(self, ctxt, migration_id):
         self._client.call(

+ 41 - 10
coriolis/conductor/rpc/server.py

@@ -396,7 +396,8 @@ class ConductorServerEndpoint(object):
                 "to be migrated")
 
     @replica_synchronized
-    def deploy_replica_instances(self, ctxt, replica_id, clone_disks, force):
+    def deploy_replica_instances(self, ctxt, replica_id, clone_disks, force,
+                                 skip_os_morphing=False):
         replica = self._get_replica(ctxt, replica_id)
         self._check_replica_running_executions(ctxt, replica)
         self._check_valid_replica_tasks_execution(replica, force)
@@ -437,14 +438,29 @@ class ConductorServerEndpoint(object):
                 instance, constants.TASK_TYPE_DEPLOY_REPLICA_INSTANCE,
                 execution, [create_snapshot_task.id])
 
-            osmorphing_task = self._create_task(
-                instance, constants.TASK_TYPE_OS_MORPHING,
-                execution, depends_on=[deploy_replica_task.id])
+            if not skip_os_morphing:
+                task_deploy_os_morphing_resources = self._create_task(
+                    instance, constants.TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES,
+                    execution, depends_on=[deploy_replica_task.id])
+
+                task_osmorphing = self._create_task(
+                    instance, constants.TASK_TYPE_OS_MORPHING,
+                    execution, depends_on=[
+                        task_deploy_os_morphing_resources.id])
+
+                task_delete_os_morphing_resources = self._create_task(
+                    instance, constants.TASK_TYPE_DELETE_OS_MORPHING_RESOURCES,
+                    execution, depends_on=[task_osmorphing.id],
+                    on_error=True)
+
+                next_task = task_delete_os_morphing_resources
+            else:
+                next_task = deploy_replica_task
 
             finalize_deployment_task = self._create_task(
                 instance,
                 constants.TASK_TYPE_FINALIZE_REPLICA_INSTANCE_DEPLOYMENT,
-                execution, depends_on=[osmorphing_task.id])
+                execution, depends_on=[next_task.id])
 
             self._create_task(
                 instance, constants.TASK_TYPE_DELETE_REPLICA_DISK_SNAPSHOTS,
@@ -472,7 +488,7 @@ class ConductorServerEndpoint(object):
 
     def migrate_instances(self, ctxt, origin_endpoint_id,
                           destination_endpoint_id, destination_environment,
-                          instances, notes=None):
+                          instances, skip_os_morphing=False, notes=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)
@@ -498,13 +514,28 @@ class ConductorServerEndpoint(object):
                 instance, constants.TASK_TYPE_IMPORT_INSTANCE,
                 execution, depends_on=[task_export.id])
 
-            task_osmorphing = self._create_task(
-                instance, constants.TASK_TYPE_OS_MORPHING,
-                execution, depends_on=[task_import.id])
+            if not skip_os_morphing:
+                task_deploy_os_morphing_resources = self._create_task(
+                    instance, constants.TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES,
+                    execution, depends_on=[task_import.id])
+
+                task_osmorphing = self._create_task(
+                    instance, constants.TASK_TYPE_OS_MORPHING,
+                    execution, depends_on=[
+                        task_deploy_os_morphing_resources.id])
+
+                task_delete_os_morphing_resources = self._create_task(
+                    instance, constants.TASK_TYPE_DELETE_OS_MORPHING_RESOURCES,
+                    execution, depends_on=[task_osmorphing.id],
+                    on_error=True)
+
+                next_task = task_delete_os_morphing_resources
+            else:
+                next_task = task_import
 
             self._create_task(
                 instance, constants.TASK_TYPE_FINALIZE_IMPORT_INSTANCE,
-                execution, depends_on=[task_osmorphing.id])
+                execution, depends_on=[next_task.id])
 
             self._create_task(
                 instance,

+ 4 - 0
coriolis/constants.py

@@ -17,7 +17,10 @@ TASK_TYPE_IMPORT_INSTANCE = "IMPORT_INSTANCE"
 TASK_TYPE_FINALIZE_IMPORT_INSTANCE = "FINALIZE_IMPORT_INSTANCE"
 TASK_TYPE_CLEANUP_FAILED_IMPORT_INSTANCE = "CLEANUP_FAILED_IMPORT_INSTANCE"
 
+TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES = "DEPLOY_OS_MORPHING_RESOURCES"
 TASK_TYPE_OS_MORPHING = "OS_MORPHING"
+TASK_TYPE_DELETE_OS_MORPHING_RESOURCES = "DELETE_OS_MORPHING_RESOURCES"
+
 
 TASK_TYPE_GET_INSTANCE_INFO = "GET_INSTANCE_INFO"
 TASK_TYPE_DEPLOY_REPLICA_DISKS = "DEPLOY_REPLICA_DISKS"
@@ -42,6 +45,7 @@ PROVIDER_TYPE_EXPORT = 2
 PROVIDER_TYPE_REPLICA_IMPORT = 4
 PROVIDER_TYPE_REPLICA_EXPORT = 8
 PROVIDER_TYPE_ENDPOINT = 16
+PROVIDER_TYPE_OS_MORPHING = 32
 
 DISK_FORMAT_VMDK = 'vmdk'
 DISK_FORMAT_RAW = 'raw'

+ 4 - 4
coriolis/migrations/api.py

@@ -10,15 +10,15 @@ class API(object):
 
     def migrate_instances(self, ctxt, origin_endpoint_id,
                           destination_endpoint_id, destination_environment,
-                          instances, notes=None):
+                          instances, notes=None, skip_os_morphing=False):
         return self._rpc_client.migrate_instances(
             ctxt, origin_endpoint_id, destination_endpoint_id,
-            destination_environment, instances, notes)
+            destination_environment, instances, notes, skip_os_morphing)
 
     def deploy_replica_instances(self, ctxt, replica_id, clone_disks=False,
-                                 force=False):
+                                 force=False, skip_os_morphing=False):
         return self._rpc_client.deploy_replica_instances(
-            ctxt, replica_id, clone_disks, force)
+            ctxt, replica_id, clone_disks, force, skip_os_morphing)
 
     def delete(self, ctxt, migration_id):
         self._rpc_client.delete_migration(ctxt, migration_id)

+ 10 - 0
coriolis/providers/base.py

@@ -60,6 +60,16 @@ class BaseImportInstanceProvider(BaseInstanceProvider):
                    "dest_instance_name": dest_instance_name})
         return dest_instance_name
 
+    @abc.abstractmethod
+    def deploy_os_morphing_resources(self, ctxt, connection_info,
+                                     instance_deployment_info):
+        pass
+
+    @abc.abstractmethod
+    def delete_os_morphing_resources(self, ctxt, connection_info,
+                                     os_morphing_resources):
+        pass
+
 
 class BaseImportProvider(BaseImportInstanceProvider):
     __metaclass__ = abc.ABCMeta

+ 1 - 0
coriolis/providers/factory.py

@@ -23,6 +23,7 @@ PROVIDER_TYPE_MAP = {
     constants.PROVIDER_TYPE_IMPORT: base.BaseImportProvider,
     constants.PROVIDER_TYPE_REPLICA_IMPORT: base.BaseReplicaImportProvider,
     constants.PROVIDER_TYPE_ENDPOINT: base.BaseEndpointProvider,
+    constants.PROVIDER_TYPE_OS_MORPHING: base.BaseOSMorphingProvider,
 }
 
 

+ 3 - 3
coriolis/schemas.py

@@ -23,7 +23,7 @@ PROVIDER_TARGET_ENVIRONMENT_SCHEMA_NAME = "target_environment_schema.json"
 
 _CORIOLIS_VM_EXPORT_INFO_SCHEMA_NAME = "vm_export_info_schema.json"
 _CORIOLIS_VM_INSTANCE_INFO_SCHEMA_NAME = "vm_instance_info_schema.json"
-_CORIOLIS_VM_IMPORT_INFO_SCHEMA_NAME = "vm_import_info_schema.json"
+_CORIOLIS_OS_MORPHING_RES_SCHEMA_NAME = "os_morphing_resources_schema.json"
 
 
 def get_schema(package_name, schema_name,
@@ -71,8 +71,8 @@ def validate_string(json_string, schema):
 CORIOLIS_VM_EXPORT_INFO_SCHEMA = get_schema(
     __name__, _CORIOLIS_VM_EXPORT_INFO_SCHEMA_NAME)
 
-CORIOLIS_VM_IMPORT_INFO_SCHEMA = get_schema(
-    __name__, _CORIOLIS_VM_IMPORT_INFO_SCHEMA_NAME)
+CORIOLIS_OS_MORPHING_RESOURCES_SCHEMA = get_schema(
+    __name__, _CORIOLIS_OS_MORPHING_RES_SCHEMA_NAME)
 
 CORIOLIS_VM_INSTANCE_INFO_SCHEMA = get_schema(
     __name__, _CORIOLIS_VM_INSTANCE_INFO_SCHEMA_NAME)

+ 1 - 4
coriolis/schemas/vm_import_info_schema.json → coriolis/schemas/os_morphing_resources_schema.json

@@ -2,9 +2,6 @@
   "$schema": "http://cloudbase.it/coriolis/schemas/import_info#",
   "type": "object",
   "properties": {
-    "instance_deployment_info": {
-      "type": "object"
-    },
     "osmorphing_connection_info": {
       "type": "object",
       "properties": {
@@ -59,7 +56,7 @@
       "additionalProperties": true
     }
   },
-  "required": ["instance_deployment_info", "osmorphing_connection_info", "osmorphing_info"],
+  "required": ["osmorphing_connection_info", "osmorphing_info"],
   "definitions": {
     "nullableString": {
       "oneOf": [{

+ 4 - 0
coriolis/tasks/factory.py

@@ -16,8 +16,12 @@ _TASKS_MAP = {
         migration_tasks.FinalizeImportInstanceTask,
     constants.TASK_TYPE_CLEANUP_FAILED_IMPORT_INSTANCE:
         migration_tasks.CleanupFailedImportInstanceTask,
+    constants.TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES:
+        osmorphing_tasks.DeployOSMorphingResourcesTask,
     constants.TASK_TYPE_OS_MORPHING:
         osmorphing_tasks.OSMorphingTask,
+    constants.TASK_TYPE_DELETE_OS_MORPHING_RESOURCES:
+        osmorphing_tasks.DeleteOSMorphingResourcesTask,
     constants.TASK_TYPE_GET_INSTANCE_INFO:
         replica_tasks.GetInstanceInfoTask,
     constants.TASK_TYPE_REPLICATE_DISKS:

+ 0 - 6
coriolis/tasks/migration_tasks.py

@@ -46,12 +46,6 @@ class ImportInstanceTask(base.TaskRunner):
 
         task_info["instance_deployment_info"] = import_info[
             "instance_deployment_info"]
-        task_info["osmorphing_info"] = import_info.get("osmorphing_info", {})
-        task_info["osmorphing_connection_info"] = base.marshal_migr_conn_info(
-            import_info["osmorphing_connection_info"])
-
-        schemas.validate_value(
-            task_info, schemas.CORIOLIS_VM_IMPORT_INFO_SCHEMA)
 
         task_info["origin_provider_type"] = constants.PROVIDER_TYPE_EXPORT
         task_info["destination_provider_type"] = constants.PROVIDER_TYPE_IMPORT

+ 41 - 0
coriolis/tasks/osmorphing_tasks.py

@@ -1,8 +1,10 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from coriolis import constants
 from coriolis.osmorphing import manager as osmorphing_manager
 from coriolis.providers import factory as providers_factory
+from coriolis import schemas
 from coriolis.tasks import base
 
 
@@ -31,3 +33,42 @@ class OSMorphingTask(base.TaskRunner):
             event_handler)
 
         return task_info
+
+
+class DeployOSMorphingResourcesTask(base.TaskRunner):
+    def run(self, ctxt, instance, origin, destination, task_info,
+            event_handler):
+        provider = providers_factory.get_provider(
+            destination["type"], constants.PROVIDER_TYPE_OS_MORPHING,
+            event_handler)
+        connection_info = base.get_connection_info(ctxt, destination)
+        instance_deployment_info = task_info["instance_deployment_info"]
+
+        import_info = provider.deploy_os_morphing_resources(
+            ctxt, connection_info, instance_deployment_info)
+
+        task_info["os_morphing_resources"] = import_info.get(
+            "os_morphing_resources")
+        task_info["osmorphing_info"] = import_info.get("osmorphing_info", {})
+        task_info["osmorphing_connection_info"] = base.marshal_migr_conn_info(
+            import_info["osmorphing_connection_info"])
+
+        schemas.validate_value(
+            task_info, schemas.CORIOLIS_OS_MORPHING_RESOURCES_SCHEMA)
+
+        return task_info
+
+
+class DeleteOSMorphingResourcesTask(base.TaskRunner):
+    def run(self, ctxt, instance, origin, destination, task_info,
+            event_handler):
+        provider = providers_factory.get_provider(
+            destination["type"], constants.PROVIDER_TYPE_OS_MORPHING,
+            event_handler)
+        connection_info = base.get_connection_info(ctxt, destination)
+        os_morphing_resources = task_info.get("os_morphing_resources")
+
+        provider.delete_os_morphing_resources(
+            ctxt, connection_info, os_morphing_resources)
+
+        return task_info

+ 0 - 3
coriolis/tasks/replica_tasks.py

@@ -226,9 +226,6 @@ class DeployReplicaInstanceTask(base.TaskRunner):
 
         task_info["instance_deployment_info"] = import_info[
             "instance_deployment_info"]
-        task_info["osmorphing_info"] = import_info.get("osmorphing_info", {})
-        task_info["osmorphing_connection_info"] = base.marshal_migr_conn_info(
-            import_info["osmorphing_connection_info"])
 
         task_info[
             "origin_provider_type"] = constants.PROVIDER_TYPE_REPLICA_EXPORT