Răsfoiți Sursa

Adds providers API

Alessandro Pilotti 9 ani în urmă
părinte
comite
4f53dbf835

+ 23 - 0
coriolis/api/v1/provider_schemas.py

@@ -0,0 +1,23 @@
+# Copyright 2016 Cloudbase Solutions Srl
+# All Rights Reserved.
+
+from oslo_log import log as logging
+
+from coriolis.api import wsgi as api_wsgi
+from coriolis.providers import api
+
+LOG = logging.getLogger(__name__)
+
+
+class ProviderSchemasController(api_wsgi.Controller):
+    def __init__(self):
+        self._provider_api = api.API()
+        super(ProviderSchemasController, self).__init__()
+
+    def index(self, req, platform_name, provider_type):
+        return {"schemas": self._provider_api.get_provider_schemas(
+            req.environ["coriolis.context"], platform_name, provider_type)}
+
+
+def create_resource():
+    return api_wsgi.Resource(ProviderSchemasController())

+ 23 - 0
coriolis/api/v1/providers.py

@@ -0,0 +1,23 @@
+# Copyright 2016 Cloudbase Solutions Srl
+# All Rights Reserved.
+
+from oslo_log import log as logging
+
+from coriolis.api import wsgi as api_wsgi
+from coriolis.providers import api
+
+LOG = logging.getLogger(__name__)
+
+
+class ProviderController(api_wsgi.Controller):
+    def __init__(self):
+        self._provider_api = api.API()
+        super(ProviderController, self).__init__()
+
+    def index(self, req):
+        return {"providers": self._provider_api.get_available_providers(
+            req.environ['coriolis.context'])}
+
+
+def create_resource():
+    return api_wsgi.Resource(ProviderController())

+ 12 - 0
coriolis/api/v1/router.py

@@ -9,6 +9,8 @@ from coriolis.api.v1 import endpoints
 from coriolis.api.v1 import endpoint_instances
 from coriolis.api.v1 import migrations
 from coriolis.api.v1 import migration_actions
+from coriolis.api.v1 import provider_schemas
+from coriolis.api.v1 import providers
 from coriolis.api.v1 import replica_actions
 from coriolis.api.v1 import replica_tasks_executions
 from coriolis.api.v1 import replica_tasks_execution_actions
@@ -31,6 +33,10 @@ class APIRouter(api.APIRouter):
     def _setup_routes(self, mapper, ext_mgr):
         mapper.redirect("", "/")
 
+        self.resources['providers'] = providers.create_resource()
+        mapper.resource('provider', 'providers',
+                        controller=self.resources['providers'])
+
         self.resources['endpoints'] = endpoints.create_resource()
         mapper.resource('endpoint', 'endpoints',
                         controller=self.resources['endpoints'],
@@ -51,6 +57,12 @@ class APIRouter(api.APIRouter):
         mapper.resource('instance', 'endpoints/{endpoint_id}/instances',
                         controller=self.resources['endpoint_instances'])
 
+        self.resources['provider_schemas'] = \
+            provider_schemas.create_resource()
+        mapper.resource('provider_schemas',
+                        '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'],

+ 10 - 0
coriolis/conductor/rpc/client.py

@@ -45,6 +45,16 @@ class ConductorClient(object):
             ctxt, 'validate_endpoint_connection',
             endpoint_id=endpoint_id)
 
+    def get_available_providers(self, ctxt):
+        return self._client.call(
+            ctxt, 'get_available_providers')
+
+    def get_provider_schemas(self, ctxt, platform_name, provider_type):
+        return self._client.call(
+            ctxt, 'get_provider_schemas',
+            platform_name=platform_name,
+            provider_type=provider_type)
+
     def execute_replica_tasks(self, ctxt, replica_id,
                               shutdown_instances=False):
         return self._client.call(

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

@@ -113,6 +113,13 @@ class ConductorServerEndpoint(object):
         return self._rpc_worker_client.validate_endpoint_connection(
             ctxt, endpoint.type, endpoint.connection_info)
 
+    def get_available_providers(self, ctxt):
+        return self._rpc_worker_client.get_available_providers(ctxt)
+
+    def get_provider_schemas(self, ctxt, platform_name, provider_type):
+        return self._rpc_worker_client.get_provider_schemas(
+            ctxt, platform_name, provider_type)
+
     @staticmethod
     def _create_task(instance, task_type, execution, depends_on=None,
                      on_error=False):

+ 16 - 0
coriolis/providers/api.py

@@ -0,0 +1,16 @@
+# 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 get_available_providers(self, ctxt):
+        return self._rpc_client.get_available_providers(ctxt)
+
+    def get_provider_schemas(self, ctxt, platform_name, provider_type):
+        return self._rpc_client.get_provider_schemas(
+            ctxt, platform_name, int(provider_type))

+ 8 - 18
coriolis/providers/base.py

@@ -7,7 +7,6 @@ import itertools
 from oslo_log import log as logging
 
 from coriolis import exception
-from coriolis import schemas
 
 LOG = logging.getLogger(__name__)
 
@@ -34,6 +33,10 @@ class BaseEndpointProvider(BaseProvider):
         """
         pass
 
+    @abc.abstractmethod
+    def get_connection_info_schema(self):
+        pass
+
 
 class BaseInstanceProvider(BaseProvider):
     __metaclass__ = abc.ABCMeta
@@ -45,6 +48,10 @@ class BaseInstanceProvider(BaseProvider):
 class BaseImportInstanceProvider(BaseInstanceProvider):
     __metaclass__ = abc.ABCMeta
 
+    @abc.abstractmethod
+    def get_target_environment_schema(self):
+        pass
+
     def _get_destination_instance_name(self, export_info, instance_name):
         dest_instance_name = export_info.get("name", instance_name)
         LOG.debug('Destination instance name for "%(instance_name)s": '
@@ -57,23 +64,6 @@ class BaseImportInstanceProvider(BaseInstanceProvider):
 class BaseImportProvider(BaseImportInstanceProvider):
     __metaclass__ = abc.ABCMeta
 
-    @property
-    def target_environment_schema(self):
-        raise NotImplementedError("Missing target environment schema.")
-
-    @abc.abstractmethod
-    def validate_target_environment(self, target_environment):
-        """ Checks the provided target environment info and raises an exception
-        if it is invalid.
-        """
-        try:
-            schemas.validate_value(
-                target_environment, self.target_environment_schema)
-        except Exception as ex:
-            raise Exception(
-                "Error validating provider '%s' target environment: %s" % (
-                    self.platform, str(ex))) from ex
-
     @abc.abstractmethod
     def import_instance(self, ctxt, connection_info, target_environment,
                         instance_name, export_info):

+ 17 - 0
coriolis/providers/factory.py

@@ -26,6 +26,23 @@ PROVIDER_TYPE_MAP = {
 }
 
 
+def get_available_providers():
+    providers = {}
+    for provider in CONF.providers:
+        cls = utils.load_class(provider)
+        for provider_type, provider_class in PROVIDER_TYPE_MAP.items():
+            provider_data = providers.get(cls.platform, {})
+
+            provider_types = provider_data.get("types", [])
+            if (provider_class in cls.__bases__ and
+                    provider_type not in provider_types):
+                provider_types.append(provider_type)
+
+            provider_data["types"] = sorted(provider_types)
+            providers[cls.platform] = provider_data
+    return providers
+
+
 def get_provider(platform_name, provider_type, event_handler):
     for provider in CONF.providers:
         cls = utils.load_class(provider)

+ 10 - 0
coriolis/worker/rpc/client.py

@@ -47,3 +47,13 @@ class WorkerClient(object):
             ctxt, 'validate_endpoint_connection',
             endpoint_type=endpoint_type,
             connection_info=connection_info)
+
+    def get_available_providers(self, ctxt):
+        return self._client.call(
+            ctxt, 'get_available_providers')
+
+    def get_provider_schemas(self, ctxt, platform_name, provider_type):
+        return self._client.call(
+            ctxt, 'get_provider_schemas',
+            platform_name=platform_name,
+            provider_type=provider_type)

+ 21 - 0
coriolis/worker/rpc/server.py

@@ -17,6 +17,7 @@ from coriolis.conductor.rpc import client as rpc_conductor_client
 from coriolis import constants
 from coriolis import events
 from coriolis import exception
+from coriolis.providers import base as providers_base
 from coriolis.providers import factory as providers_factory
 from coriolis import schemas
 from coriolis.tasks import factory as task_runners_factory
@@ -184,6 +185,9 @@ class WorkerServerEndpoint(object):
 
         return instances_info
 
+    def get_available_providers(self, ctxt):
+        return providers_factory.get_available_providers()
+
     def validate_endpoint_connection(self, ctxt, endpoint_type,
                                      connection_info):
         provider = providers_factory.get_provider(
@@ -202,6 +206,23 @@ class WorkerServerEndpoint(object):
 
         return (is_valid, message)
 
+    def get_provider_schemas(self, ctxt, platform_name, provider_type):
+        provider = providers_factory.get_provider(
+            platform_name, provider_type, None)
+
+        schemas = {}
+
+        if provider_type == constants.PROVIDER_TYPE_ENDPOINT:
+            schema = provider.get_connection_info_schema()
+            schemas["connection_info_schema"] = schema
+
+        if provider_type in [constants.PROVIDER_TYPE_IMPORT,
+                             constants.PROVIDER_TYPE_REPLICA_IMPORT]:
+            schema = provider.get_target_environment_schema()
+            schemas["destination_environment_schema"] = schema
+
+        return schemas
+
 
 def _get_task_export_path(task_id, create=False):
     export_path = os.path.join(CONF.worker.export_base_path, task_id)