Browse Source

Merged in alexpilotti/coriolis/auto_flavor (pull request #81)

Add automated flavor selection
Alessandro Pilotti 8 years ago
parent
commit
caec8dca0e

+ 36 - 2
coriolis/conductor/rpc/server.py

@@ -412,6 +412,13 @@ class ConductorServerEndpoint(object):
                 "A replica must have been executed succesfully in order "
                 "to be migrated")
 
+    def _get_provider_types(self, ctxt, endpoint):
+        provider_types = self.get_available_providers(ctxt).get(endpoint.type)
+        if provider_types is None:
+            raise exception.NotFound(
+                "No provider found for: %s" % endpoint.type)
+        return provider_types["types"]
+
     @replica_synchronized
     def deploy_replica_instances(self, ctxt, replica_id, clone_disks, force,
                                  skip_os_morphing=False):
@@ -419,6 +426,11 @@ class ConductorServerEndpoint(object):
         self._check_replica_running_executions(ctxt, replica)
         self._check_valid_replica_tasks_execution(replica, force)
 
+        destination_endpoint = self.get_endpoint(
+            ctxt, replica.destination_endpoint_id)
+        destination_provider_types = self._get_provider_types(
+            ctxt, destination_endpoint)
+
         for instance, info in replica.info.items():
             if not info.get("volumes_info"):
                 raise exception.InvalidReplicaState(
@@ -447,9 +459,19 @@ class ConductorServerEndpoint(object):
         execution.number = 1
 
         for instance in instances:
+            create_snapshot_task_depends_on = []
+
+            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)
+                create_snapshot_task_depends_on.append(
+                    get_optimal_flavor_task.id)
+
             create_snapshot_task = self._create_task(
                 instance, constants.TASK_TYPE_CREATE_REPLICA_DISK_SNAPSHOTS,
-                execution)
+                execution, depends_on=create_snapshot_task_depends_on)
 
             deploy_replica_task = self._create_task(
                 instance, constants.TASK_TYPE_DEPLOY_REPLICA_INSTANCE,
@@ -510,6 +532,9 @@ class ConductorServerEndpoint(object):
         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.origin_endpoint = origin_endpoint
@@ -527,9 +552,18 @@ class ConductorServerEndpoint(object):
             task_export = self._create_task(
                 instance, constants.TASK_TYPE_EXPORT_INSTANCE, execution)
 
+            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=[task_export.id])
+                next_task = get_optimal_flavor_task.id
+            else:
+                next_task = task_export.id
+
             task_import = self._create_task(
                 instance, constants.TASK_TYPE_IMPORT_INSTANCE,
-                execution, depends_on=[task_export.id])
+                execution, depends_on=[next_task])
 
             task_deploy_disk_copy_resources = self._create_task(
                 instance, constants.TASK_TYPE_DEPLOY_DISK_COPY_RESOURCES,

+ 2 - 0
coriolis/constants.py

@@ -44,6 +44,7 @@ TASK_TYPE_CLEANUP_FAILED_REPLICA_INSTANCE_DEPLOYMENT = (
 TASK_TYPE_CREATE_REPLICA_DISK_SNAPSHOTS = "CREATE_REPLICA_DISK_SNAPSHOTS"
 TASK_TYPE_DELETE_REPLICA_DISK_SNAPSHOTS = "DELETE_REPLICA_DISK_SNAPSHOTS"
 TASK_TYPE_RESTORE_REPLICA_DISK_SNAPSHOTS = "RESTORE_REPLICA_DISK_SNAPSHOTS"
+TASK_TYPE_GET_OPTIMAL_FLAVOR = "GET_OPTIMAL_FLAVOR"
 
 PROVIDER_TYPE_IMPORT = 1
 PROVIDER_TYPE_EXPORT = 2
@@ -53,6 +54,7 @@ PROVIDER_TYPE_ENDPOINT = 16
 PROVIDER_TYPE_ENDPOINT_INSTANCES = 32
 PROVIDER_TYPE_OS_MORPHING = 64
 PROVIDER_TYPE_ENDPOINT_NETWORKS = 128
+PROVIDER_TYPE_INSTANCE_FLAVOR = 256
 
 DISK_FORMAT_VMDK = 'vmdk'
 DISK_FORMAT_RAW = 'raw'

+ 7 - 0
coriolis/providers/base.py

@@ -207,6 +207,13 @@ class BaseReplicaExportProvider(BaseInstanceProvider):
         pass
 
 
+class BaseInstanceFlavorProvider(BaseProvider):
+    @abc.abstractmethod
+    def get_optimal_flavor(self, ctxt, connection_info, target_environment,
+                           export_info):
+        pass
+
+
 def get_os_morphing_tools_helper(conn, os_morphing_tools_clss,
                                  hypervisor_type, os_type, os_root_dir,
                                  os_root_dev, event_manager):

+ 2 - 1
coriolis/providers/factory.py

@@ -27,7 +27,8 @@ PROVIDER_TYPE_MAP = {
         base.BaseEndpointInstancesProvider,
     constants.PROVIDER_TYPE_ENDPOINT_NETWORKS:
         base.BaseEndpointNetworksProvider,
-    constants.PROVIDER_TYPE_OS_MORPHING: base.BaseImportInstanceProvider
+    constants.PROVIDER_TYPE_OS_MORPHING: base.BaseImportInstanceProvider,
+    constants.PROVIDER_TYPE_INSTANCE_FLAVOR: base.BaseInstanceFlavorProvider,
 }
 
 

+ 2 - 0
coriolis/tasks/factory.py

@@ -22,6 +22,8 @@ _TASKS_MAP = {
         migration_tasks.DeleteDiskCopyResources,
     constants.TASK_TYPE_CLEANUP_FAILED_IMPORT_INSTANCE:
         migration_tasks.CleanupFailedImportInstanceTask,
+    constants.TASK_TYPE_GET_OPTIMAL_FLAVOR:
+        migration_tasks.GetOptimalFlavorTask,
     constants.TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES:
         osmorphing_tasks.DeployOSMorphingResourcesTask,
     constants.TASK_TYPE_OS_MORPHING:

+ 31 - 2
coriolis/tasks/migration_tasks.py

@@ -2,6 +2,7 @@
 # All Rights Reserved.
 
 from coriolis import constants
+from coriolis import events
 from coriolis.providers import factory as providers_factory
 from coriolis import schemas
 from coriolis import exception
@@ -46,8 +47,10 @@ class ImportInstanceTask(base.TaskRunner):
         import_info = provider.import_instance(
             ctxt, connection_info, target_environment, instance, export_info)
 
-        task_info["instance_deployment_info"] = import_info[
-            "instance_deployment_info"]
+        if task_info.get("instance_deployment_info") is None:
+            task_info["instance_deployment_info"] = {}
+        task_info["instance_deployment_info"].update(import_info[
+            "instance_deployment_info"])
 
         task_info["origin_provider_type"] = constants.PROVIDER_TYPE_EXPORT
         task_info["destination_provider_type"] = constants.PROVIDER_TYPE_IMPORT
@@ -154,3 +157,29 @@ class CleanupFailedImportInstanceTask(base.TaskRunner):
             ctxt, connection_info, instance_deployment_info)
 
         return task_info
+
+
+class GetOptimalFlavorTask(base.TaskRunner):
+    def run(self, ctxt, instance, origin, destination, task_info,
+            event_handler):
+        provider = providers_factory.get_provider(
+            destination["type"], constants.PROVIDER_TYPE_INSTANCE_FLAVOR,
+            event_handler)
+
+        connection_info = base.get_connection_info(ctxt, destination)
+        target_environment = destination.get("target_environment") or {}
+        export_info = task_info["export_info"]
+
+        flavor = provider.get_optimal_flavor(
+            ctxt, connection_info, target_environment, export_info)
+
+        if task_info.get("instance_deployment_info") is None:
+            task_info["instance_deployment_info"] = {}
+        task_info["instance_deployment_info"]["selected_flavor"] = flavor
+
+        events.EventManager(event_handler).progress_update(
+            "Selected flavor: %s" % flavor)
+
+        task_info["retain_export_path"] = True
+
+        return task_info

+ 4 - 2
coriolis/tasks/replica_tasks.py

@@ -224,8 +224,10 @@ class DeployReplicaInstanceTask(base.TaskRunner):
             ctxt, connection_info, target_environment, instance,
             export_info, volumes_info, clone_disks)
 
-        task_info["instance_deployment_info"] = import_info[
-            "instance_deployment_info"]
+        if task_info.get("instance_deployment_info") is None:
+            task_info["instance_deployment_info"] = {}
+        task_info["instance_deployment_info"].update(import_info[
+            "instance_deployment_info"])
 
         task_info[
             "origin_provider_type"] = constants.PROVIDER_TYPE_REPLICA_EXPORT