Explorar o código

Provider loading refactoring

Alessandro Pilotti %!s(int64=9) %!d(string=hai) anos
pai
achega
33955b1fd6

+ 2 - 0
coriolis/constants.py

@@ -32,6 +32,8 @@ TASK_TYPE_RESTORE_REPLICA_DISK_SNAPSHOTS = "RESTORE_REPLICA_DISK_SNAPSHOTS"
 
 PROVIDER_TYPE_IMPORT = 1
 PROVIDER_TYPE_EXPORT = 2
+PROVIDER_TYPE_REPLICA_IMPORT = 4
+PROVIDER_TYPE_REPLICA_EXPORT = 8
 
 DISK_FORMAT_VMDK = 'vmdk'
 DISK_FORMAT_RAW = 'raw'

+ 1 - 0
coriolis/providers/azure/__init__.py

@@ -155,6 +155,7 @@ AzureWorkerInstance = collections.namedtuple(
 
 class ImportProvider(BaseImportProvider):
     """ Provides import capabilities. """
+    platform = constants.PLATFORM_AZURE_RM
 
     connection_info_schema = schemas.get_schema(
         __name__, schemas.PROVIDER_CONNECTION_INFO_SCHEMA_NAME)

+ 21 - 17
coriolis/providers/factory.py

@@ -3,28 +3,32 @@
 
 from coriolis import constants
 from coriolis import exception
-from coriolis.providers import azure
-from coriolis.providers import openstack
-from coriolis.providers import vmware_vsphere
+from coriolis.providers import base
+from coriolis import utils
 
-
-EXPORT_PROVIDERS = {
-    constants.PLATFORM_VMWARE_VSPHERE: vmware_vsphere.ExportProvider,
-    constants.PLATFORM_OPENSTACK: openstack.ExportProvider
+PROVIDERS = {
+    "coriolis.providers.azure.ImportProvider",
+    "coriolis.providers.openstack.ExportProvider",
+    "coriolis.providers.openstack.ImportProvider",
+    "coriolis.providers.vmware_vsphere.ExportProvider",
 }
 
-IMPORT_PROVIDERS = {
-    constants.PLATFORM_OPENSTACK: openstack.ImportProvider,
-    constants.PLATFORM_AZURE_RM: azure.ImportProvider
+
+PROVIDER_TYPE_MAP = {
+    constants.PROVIDER_TYPE_EXPORT: base.BaseExportProvider,
+    constants.PROVIDER_TYPE_REPLICA_EXPORT: base.BaseReplicaExportProvider,
+    constants.PROVIDER_TYPE_IMPORT: base.BaseImportProvider,
+    constants.PROVIDER_TYPE_REPLICA_IMPORT: base.BaseReplicaImportProvider,
 }
 
 
 def get_provider(platform_name, provider_type, event_handler):
-    if provider_type == constants.PROVIDER_TYPE_EXPORT:
-        cls = EXPORT_PROVIDERS.get(platform_name)
-    elif provider_type == constants.PROVIDER_TYPE_IMPORT:
-        cls = IMPORT_PROVIDERS.get(platform_name)
+    for provider in PROVIDERS:
+        cls = utils.load_class(provider)
+        if (cls.platform == platform_name and
+                PROVIDER_TYPE_MAP[provider_type] in cls.__bases__):
+            return cls(event_handler)
 
-    if not cls:
-        raise exception.NotFound("Provider not found: %s" % platform_name)
-    return cls(event_handler)
+    raise exception.NotFound(
+        "Provider not found for: %(platform_name)s, %(provider_type)s" %
+        {"platform_name": platform_name, "provider_type": provider_type})

+ 5 - 0
coriolis/providers/openstack/__init__.py

@@ -320,6 +320,8 @@ class _MigrationResources(object):
 
 class ImportProvider(base.BaseReplicaImportProvider):
 
+    platform = constants.PLATFORM_OPENSTACK
+
     connection_info_schema = schemas.get_schema(
         __name__, schemas.PROVIDER_CONNECTION_INFO_SCHEMA_NAME)
 
@@ -1099,6 +1101,9 @@ class ImportProvider(base.BaseReplicaImportProvider):
 
 
 class ExportProvider(base.BaseExportProvider):
+
+    platform = constants.PLATFORM_OPENSTACK
+
     _OS_DISTRO_MAP = {
         'windows': constants.OS_TYPE_WINDOWS,
         'freebsd': constants.OS_TYPE_BSD,

+ 2 - 0
coriolis/providers/vmware_vsphere/__init__.py

@@ -198,6 +198,8 @@ class _SSHBackupWriter(_BaseBackupWriter):
 
 class ExportProvider(base.BaseReplicaExportProvider):
 
+    platform = constants.PLATFORM_VMWARE_VSPHERE
+
     connection_info_schema = schemas.get_schema(
         __name__, schemas.PROVIDER_CONNECTION_INFO_SCHEMA_NAME)
 

+ 26 - 13
coriolis/tasks/replica_tasks.py

@@ -53,7 +53,8 @@ class GetInstanceInfoTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            origin["type"], constants.PROVIDER_TYPE_EXPORT, event_handler)
+            origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, origin)
 
         export_info = provider.get_replica_instance_info(
@@ -71,7 +72,8 @@ class ShutdownInstanceTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            origin["type"], constants.PROVIDER_TYPE_EXPORT, event_handler)
+            origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, origin)
 
         provider.shutdown_instance(ctxt, connection_info, instance)
@@ -83,7 +85,8 @@ class ReplicateDisksTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            origin["type"], constants.PROVIDER_TYPE_EXPORT, event_handler)
+            origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, origin)
 
         volumes_info = _get_volumes_info(task_info)
@@ -112,7 +115,8 @@ class DeployReplicaDisksTask(base.TaskRunner):
         export_info = task_info["export_info"]
 
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = task_info.get("volumes_info") or []
@@ -130,7 +134,8 @@ class DeleteReplicaDisksTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = _get_volumes_info(task_info)
@@ -147,7 +152,8 @@ class DeployReplicaSourceResourcesTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            origin["type"], constants.PROVIDER_TYPE_EXPORT, event_handler)
+            origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, origin)
 
         replica_resources_info = provider.deploy_replica_source_resources(
@@ -166,7 +172,8 @@ class DeleteReplicaSourceResourcesTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            origin["type"], constants.PROVIDER_TYPE_EXPORT, event_handler)
+            origin["type"], constants.PROVIDER_TYPE_REPLICA_EXPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, origin)
 
         migr_resources = task_info.get("migr_source_resources")
@@ -187,7 +194,8 @@ class DeployReplicaTargetResourcesTask(base.TaskRunner):
         target_environment = destination.get("target_environment") or {}
 
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = _get_volumes_info(task_info)
@@ -210,7 +218,8 @@ class DeleteReplicaTargetResourcesTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         migr_resources = task_info.get("migr_target_resources")
@@ -232,7 +241,8 @@ class DeployReplicaInstanceTask(base.TaskRunner):
         export_info = task_info["export_info"]
 
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = _get_volumes_info(task_info)
@@ -250,7 +260,8 @@ class CreateReplicaDiskSnapshotsTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = _get_volumes_info(task_info)
@@ -267,7 +278,8 @@ class DeleteReplicaDiskSnapshotsTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = _get_volumes_info(task_info)
@@ -284,7 +296,8 @@ class RestoreReplicaDiskSnapshotsTask(base.TaskRunner):
     def run(self, ctxt, instance, origin, destination, task_info,
             event_handler):
         provider = providers_factory.get_provider(
-            destination["type"], constants.PROVIDER_TYPE_IMPORT, event_handler)
+            destination["type"], constants.PROVIDER_TYPE_REPLICA_IMPORT,
+            event_handler)
         connection_info = base.get_connection_info(ctxt, destination)
 
         volumes_info = _get_volumes_info(task_info)

+ 7 - 0
coriolis/utils.py

@@ -314,3 +314,10 @@ def topological_graph_sorting(items, id="id", depends_on="depends_on",
         raise ValueError("The graph contains cycles")
 
     return l
+
+
+def load_class(class_path):
+    LOG.debug('Loading class \'%s\'' % class_path)
+    parts = class_path.rsplit('.', 1)
+    module = __import__(parts[0], fromlist=parts[1])
+    return getattr(module, parts[1])