Просмотр исходного кода

Format the code with ruff + flake8

Fabian Fulga 1 неделя назад
Родитель
Сommit
1c7bf33254
100 измененных файлов с 3491 добавлено и 2625 удалено
  1. 3 7
      coriolis/api-refs/source/conf.py
  2. 22 23
      coriolis/api/__init__.py
  3. 3 3
      coriolis/api/common.py
  4. 21 16
      coriolis/api/middleware/auth.py
  5. 15 13
      coriolis/api/middleware/fault.py
  6. 1 1
      coriolis/api/v1/deployment_actions.py
  7. 44 26
      coriolis/api/v1/deployments.py
  8. 5 8
      coriolis/api/v1/diagnostics.py
  9. 8 11
      coriolis/api/v1/endpoint_actions.py
  10. 13 12
      coriolis/api/v1/endpoint_destination_minion_pool_options.py
  11. 10 8
      coriolis/api/v1/endpoint_destination_options.py
  12. 19 13
      coriolis/api/v1/endpoint_instances.py
  13. 6 6
      coriolis/api/v1/endpoint_inventory.py
  14. 7 8
      coriolis/api/v1/endpoint_networks.py
  15. 12 10
      coriolis/api/v1/endpoint_source_minion_pool_options.py
  16. 10 8
      coriolis/api/v1/endpoint_source_options.py
  17. 7 8
      coriolis/api/v1/endpoint_storage.py
  18. 28 21
      coriolis/api/v1/endpoints.py
  19. 11 17
      coriolis/api/v1/minion_pool_actions.py
  20. 140 92
      coriolis/api/v1/minion_pools.py
  21. 5 2
      coriolis/api/v1/provider_schemas.py
  22. 3 4
      coriolis/api/v1/providers.py
  23. 17 14
      coriolis/api/v1/regions.py
  24. 188 137
      coriolis/api/v1/router.py
  25. 25 16
      coriolis/api/v1/services.py
  26. 7 7
      coriolis/api/v1/transfer_actions.py
  27. 38 42
      coriolis/api/v1/transfer_schedules.py
  28. 3 5
      coriolis/api/v1/transfer_tasks_execution_actions.py
  29. 29 23
      coriolis/api/v1/transfer_tasks_executions.py
  30. 160 115
      coriolis/api/v1/transfers.py
  31. 68 54
      coriolis/api/v1/utils.py
  32. 3 3
      coriolis/api/v1/views/deployment_view.py
  33. 6 9
      coriolis/api/v1/views/endpoint_options_view.py
  34. 2 4
      coriolis/api/v1/views/endpoint_resources_view.py
  35. 2 4
      coriolis/api/v1/views/endpoint_view.py
  36. 6 6
      coriolis/api/v1/views/minion_pool_view.py
  37. 3 6
      coriolis/api/v1/views/region_view.py
  38. 2 4
      coriolis/api/v1/views/service_view.py
  39. 1 2
      coriolis/api/v1/views/transfer_schedule_view.py
  40. 7 9
      coriolis/api/v1/views/transfer_tasks_execution_view.py
  41. 2 2
      coriolis/api/v1/views/transfer_view.py
  42. 3 2
      coriolis/api/v1/views/utils.py
  43. 111 89
      coriolis/api/wsgi.py
  44. 4 6
      coriolis/cache.py
  45. 9 8
      coriolis/cmd/api.py
  46. 11 8
      coriolis/cmd/conductor.py
  47. 2 3
      coriolis/cmd/db_sync.py
  48. 11 8
      coriolis/cmd/deployer_manager.py
  49. 12 10
      coriolis/cmd/minion_manager.py
  50. 12 10
      coriolis/cmd/scheduler.py
  51. 6 8
      coriolis/cmd/transfer_cron.py
  52. 12 8
      coriolis/cmd/worker.py
  53. 403 240
      coriolis/conductor/rpc/client.py
  54. 352 214
      coriolis/conductor/rpc/server.py
  55. 40 17
      coriolis/conductor/rpc/utils.py
  56. 5 3
      coriolis/conf.py
  57. 61 60
      coriolis/constants.py
  58. 40 23
      coriolis/context.py
  59. 46 35
      coriolis/cron/cron.py
  60. 34 30
      coriolis/data_transfer.py
  61. 306 240
      coriolis/db/api.py
  62. 1 2
      coriolis/db/sqlalchemy/alembic/env.py
  63. 89 62
      coriolis/db/sqlalchemy/alembic/versions/001_initial.py
  64. 21 11
      coriolis/db/sqlalchemy/alembic/versions/002_adds_endpoints.py
  65. 2 3
      coriolis/db/sqlalchemy/alembic/versions/003_adds_notes.py
  66. 18 11
      coriolis/db/sqlalchemy/alembic/versions/004_adds_replica_schedules.py
  67. 3 2
      coriolis/db/sqlalchemy/alembic/versions/005_adds_transfer_result.py
  68. 2 3
      coriolis/db/sqlalchemy/alembic/versions/006_adds_network_map.py
  69. 3 2
      coriolis/db/sqlalchemy/alembic/versions/007_adds_storage_mappings.py
  70. 3 2
      coriolis/db/sqlalchemy/alembic/versions/008_adds_source_environment.py
  71. 1 2
      coriolis/db/sqlalchemy/alembic/versions/009_migrate_info_to_blob.py
  72. 3 2
      coriolis/db/sqlalchemy/alembic/versions/010_adds_reservation_id.py
  73. 2 3
      coriolis/db/sqlalchemy/alembic/versions/011_adds_execution_type.py
  74. 8 5
      coriolis/db/sqlalchemy/alembic/versions/012_adds_migration_sync_fields.py
  75. 3 2
      coriolis/db/sqlalchemy/alembic/versions/013_adds_task_index.py
  76. 50 34
      coriolis/db/sqlalchemy/alembic/versions/014_adds_worker_service_regions.py
  77. 6 3
      coriolis/db/sqlalchemy/alembic/versions/015_adds_action_last_execution_status.py
  78. 135 101
      coriolis/db/sqlalchemy/alembic/versions/016_adds_minion_vm_pools.py
  79. 2 3
      coriolis/db/sqlalchemy/alembic/versions/017_adds_user_scripts_column.py
  80. 13 7
      coriolis/db/sqlalchemy/alembic/versions/018_adds_task_progress_idices.py
  81. 3 3
      coriolis/db/sqlalchemy/alembic/versions/019_add_replica_scenario_field.py
  82. 25 17
      coriolis/db/sqlalchemy/alembic/versions/020_rename_tables.py
  83. 11 5
      coriolis/db/sqlalchemy/alembic/versions/021_add_deployment_defaults.py
  84. 6 3
      coriolis/db/sqlalchemy/alembic/versions/022_adds_auto_deploy_column.py
  85. 3 5
      coriolis/db/sqlalchemy/alembic/versions/023_add_deployer_id.py
  86. 7 5
      coriolis/db/sqlalchemy/alembic/versions/024_add_clustered_to_base_transfer_action.py
  87. 3 2
      coriolis/db/sqlalchemy/api.py
  88. 11 8
      coriolis/db/sqlalchemy/migration.py
  89. 279 268
      coriolis/db/sqlalchemy/models.py
  90. 2 5
      coriolis/db/sqlalchemy/types.py
  91. 15 14
      coriolis/deployer_manager/rpc/client.py
  92. 47 39
      coriolis/deployer_manager/rpc/server.py
  93. 39 17
      coriolis/deployments/api.py
  94. 1 1
      coriolis/diagnostics/api.py
  95. 20 13
      coriolis/endpoint_options/api.py
  96. 27 14
      coriolis/endpoint_resources/api.py
  97. 26 21
      coriolis/endpoints/api.py
  98. 46 38
      coriolis/events.py
  99. 45 41
      coriolis/exception.py
  100. 68 45
      coriolis/keystone.py

+ 3 - 7
coriolis/api-refs/source/conf.py

@@ -1,15 +1,11 @@
-
-extensions = [
-    'openstackdocstheme',
-    'os_api_ref'
-]
+extensions = ['openstackdocstheme', 'os_api_ref']
 
 source_suffix = '.rst'
 
 master_doc = 'index'
 
-project = u'Coriolis API Reference'
-copyright = u'2018-present, Cloudbase Solutions S.R.L'
+project = 'Coriolis API Reference'
+copyright = '2018-present, Cloudbase Solutions S.R.L'
 
 repository_name = 'cloudbase/coriolis'
 bug_project = 'coriolis'

+ 22 - 23
coriolis/api/__init__.py

@@ -18,16 +18,14 @@
 WSGI middleware for OpenStack API controllers.
 """
 
-from paste import urlmap
 import routes
-
 from oslo_log import log as logging
 from oslo_service import wsgi as base_wsgi
+from paste import urlmap
 
-from coriolis.api import wsgi
 from coriolis import exception
-from coriolis.i18n import _, _LW  # noqa
-
+from coriolis.api import wsgi
+from coriolis.i18n import _LW, _  # noqa
 
 LOG = logging.getLogger(__name__)
 
@@ -61,16 +59,13 @@ class ProjectMapper(APIMapper):
             parent_resource = kwargs['parent_resource']
             p_collection = parent_resource['collection_name']
             p_member = parent_resource['member_name']
-            kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection,
-                                                                p_member)
-        routes.Mapper.resource(self,
-                               member_name,
-                               collection_name,
-                               **kwargs)
+            kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection, p_member)
+        routes.Mapper.resource(self, member_name, collection_name, **kwargs)
 
 
 class APIRouter(base_wsgi.Router):
     """Routes requests on the API to the appropriate controller and method."""
+
     ExtensionManager = None  # override in subclasses
 
     @classmethod
@@ -83,7 +78,8 @@ class APIRouter(base_wsgi.Router):
                 ext_mgr = self.ExtensionManager()
             else:
                 raise exception.CoriolisException(
-                    _("Must specify an ExtensionManager class"))
+                    _("Must specify an ExtensionManager class")
+                )
 
         mapper = ProjectMapper()
         self.resources = {}
@@ -94,15 +90,15 @@ class APIRouter(base_wsgi.Router):
 
     def _setup_ext_routes(self, mapper, ext_mgr):
         for resource in ext_mgr.get_resources():
-            LOG.debug('Extended resource: %s',
-                      resource.collection)
+            LOG.debug('Extended resource: %s', resource.collection)
 
             wsgi_resource = wsgi.Resource(resource.controller)
             self.resources[resource.collection] = wsgi_resource
             kargs = dict(
                 controller=wsgi_resource,
                 collection=resource.collection_actions,
-                member=resource.member_actions)
+                member=resource.member_actions,
+            )
 
             if resource.parent:
                 kargs['parent_resource'] = resource.parent
@@ -118,16 +114,19 @@ class APIRouter(base_wsgi.Router):
             controller = extension.controller
 
             if collection not in self.resources:
-                LOG.warning(_LW('Extension %(ext_name)s: Cannot extend '
-                                'resource %(collection)s: No such resource'),
-                            {'ext_name': extension.extension.name,
-                             'collection': collection})
+                LOG.warning(
+                    _LW(
+                        'Extension %(ext_name)s: Cannot extend '
+                        'resource %(collection)s: No such resource'
+                    ),
+                    {'ext_name': extension.extension.name, 'collection': collection},
+                )
                 continue
 
-            LOG.debug('Extension %(ext_name)s extending resource: '
-                      '%(collection)s',
-                      {'ext_name': extension.extension.name,
-                       'collection': collection})
+            LOG.debug(
+                'Extension %(ext_name)s extending resource: %(collection)s',
+                {'ext_name': extension.extension.name, 'collection': collection},
+            )
 
             resource = self.resources[collection]
             resource.register_actions(controller)

+ 3 - 3
coriolis/api/common.py

@@ -12,9 +12,9 @@ def get_paging_params(req):
     return marker, limit
 
 
-def get_sort_params(req,
-                    default_keys=('created_at', 'id'),
-                    default_dirs=('desc', 'desc')):
+def get_sort_params(
+    req, default_keys=('created_at', 'id'), default_dirs=('desc', 'desc')
+):
     """Retrieves sort keys/directions parameters.
 
     Processes the parameters to create a list of sort keys and sort directions

+ 21 - 16
coriolis/api/middleware/auth.py

@@ -1,13 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+import webob
 from oslo_log import log as logging
 from oslo_middleware import request_id
 from oslo_serialization import jsonutils
-import webob
 
-from coriolis.api import wsgi
 from coriolis import context
+from coriolis.api import wsgi
 from coriolis.i18n import _
 
 LOG = logging.getLogger(__name__)
@@ -23,14 +23,16 @@ class CoriolisKeystoneContext(wsgi.Middleware):
             return req.headers['X_TENANT']
         else:
             raise webob.exc.HTTPBadRequest(
-                explanation=_("No 'X_TENANT_ID' or 'X_TENANT' passed."))
+                explanation=_("No 'X_TENANT_ID' or 'X_TENANT' passed.")
+            )
 
     def _get_user(self, req):
         user = req.headers.get('X_USER')
         user = req.headers.get('X_USER_ID', user)
         if user is None:
             raise webob.exc.HTTPUnauthorized(
-                explanation=_("Neither X_USER_ID nor X_USER found in request"))
+                explanation=_("Neither X_USER_ID nor X_USER found in request")
+            )
         return user
 
     @webob.dec.wsgify(RequestClass=wsgi.Request)
@@ -64,18 +66,21 @@ class CoriolisKeystoneContext(wsgi.Middleware):
                 service_catalog = jsonutils.loads(catalog_header)
             except ValueError:
                 raise webob.exc.HTTPInternalServerError(
-                    explanation=_('Invalid service catalog json.'))
-
-        ctx = context.RequestContext(user,
-                                     project_id,
-                                     project_name=project_name,
-                                     project_domain_name=project_domain_name,
-                                     user_domain_name=user_domain_name,
-                                     roles=roles,
-                                     auth_token=auth_token,
-                                     remote_address=remote_address,
-                                     service_catalog=service_catalog,
-                                     request_id=req_id)
+                    explanation=_('Invalid service catalog json.')
+                )
+
+        ctx = context.RequestContext(
+            user,
+            project_id,
+            project_name=project_name,
+            project_domain_name=project_domain_name,
+            user_domain_name=user_domain_name,
+            roles=roles,
+            auth_token=auth_token,
+            remote_address=remote_address,
+            service_catalog=service_catalog,
+            request_id=req_id,
+        )
 
         req.environ['coriolis.context'] = ctx
         return self.application

+ 15 - 13
coriolis/api/middleware/fault.py

@@ -14,16 +14,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log as logging
 import six
 import webob.dec
 import webob.exc
+from oslo_log import log as logging
 
+from coriolis import exception, utils
 from coriolis.api import wsgi
-from coriolis import exception
-from coriolis.i18n import _, _LE, _LI  # noqa
-from coriolis import utils
-
+from coriolis.i18n import _LE, _LI, _  # noqa
 
 LOG = logging.getLogger(__name__)
 
@@ -39,12 +37,14 @@ class FaultWrapper(wsgi.Middleware):
             for clazz in utils.walk_class_hierarchy(webob.exc.HTTPError):
                 FaultWrapper._status_to_type[clazz.code] = clazz
         return FaultWrapper._status_to_type.get(
-            status, webob.exc.HTTPInternalServerError)()
+            status, webob.exc.HTTPInternalServerError
+        )()
 
     def _error(self, inner, req):
-        LOG.exception(_LE("Caught error: %(type)s %(error)s"),
-                      {'type': type(inner),
-                       'error': inner})
+        LOG.exception(
+            _LE("Caught error: %(type)s %(error)s"),
+            {'type': type(inner), 'error': inner},
+        )
         safe = getattr(inner, 'safe', False)
         headers = getattr(inner, 'headers', None)
         status = getattr(inner, 'code', 500)
@@ -57,10 +57,12 @@ class FaultWrapper(wsgi.Middleware):
         if headers:
             outer.headers = headers
         if safe:
-            msg = (inner.msg if isinstance(inner, exception.CoriolisException)
-                   else six.text_type(inner))
-            params = {'exception': inner.__class__.__name__,
-                      'explanation': msg}
+            msg = (
+                inner.msg
+                if isinstance(inner, exception.CoriolisException)
+                else six.text_type(inner)
+            )
+            params = {'exception': inner.__class__.__name__, 'explanation': msg}
             outer.explanation = _('%(exception)s: %(explanation)s') % params
         return wsgi.Fault(outer)
 

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

@@ -3,9 +3,9 @@
 
 from webob import exc
 
+from coriolis import exception
 from coriolis.api import wsgi as api_wsgi
 from coriolis.deployments import api
-from coriolis import exception
 from coriolis.policies import deployments as deployment_policies
 
 

+ 44 - 26
coriolis/api/v1/deployments.py

@@ -4,17 +4,15 @@
 from oslo_log import log as logging
 from webob import exc
 
+from coriolis import constants, exception
 from coriolis.api import common
+from coriolis.api import wsgi as api_wsgi
 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 import constants
 from coriolis.deployments import api
 from coriolis.endpoints import api as endpoints_api
-from coriolis import exception
 from coriolis.policies import deployments as deployment_policies
 
-
 LOG = logging.getLogger(__name__)
 
 
@@ -28,10 +26,11 @@ class DeploymentsController(api_wsgi.Controller):
         context = req.environ["coriolis.context"]
         context.can(deployment_policies.get_deployments_policy_label("show"))
         include_task_info = api_utils.get_bool_url_arg(
-            req, "include_task_info", default=False)
+            req, "include_task_info", default=False
+        )
         deployment = self._deployment_api.get_deployment(
-            context, id,
-            include_task_info=include_task_info)
+            context, id, include_task_info=include_task_info
+        )
         if not deployment:
             raise exc.HTTPNotFound()
 
@@ -45,18 +44,19 @@ class DeploymentsController(api_wsgi.Controller):
         if status is not None:
             if status not in constants.ALL_EXECUTION_STATUSES:
                 raise exc.HTTPBadRequest(
-                    explanation=f"Unknown deployment status: {status}")
+                    explanation=f"Unknown deployment status: {status}"
+                )
             filters["status"] = status
         return filters
 
     def _list(self, req):
-        show_deleted = api_utils.get_bool_url_arg(
-            req, "show_deleted", default=False)
+        show_deleted = api_utils.get_bool_url_arg(req, "show_deleted", default=False)
         context = req.environ["coriolis.context"]
         context.show_deleted = show_deleted
         context.can(deployment_policies.get_deployments_policy_label("list"))
         include_task_info = api_utils.get_bool_url_arg(
-            req, "include_task_info", default=False)
+            req, "include_task_info", default=False
+        )
 
         marker, limit = common.get_paging_params(req)
         sort_keys, sort_dirs = common.get_sort_params(req)
@@ -67,10 +67,13 @@ class DeploymentsController(api_wsgi.Controller):
                 context,
                 include_tasks=include_task_info,
                 include_task_info=include_task_info,
-                marker=marker, limit=limit,
-                sort_keys=sort_keys, sort_dirs=sort_dirs,
+                marker=marker,
+                limit=limit,
+                sort_keys=sort_keys,
+                sort_dirs=sort_dirs,
                 filters=filters,
-            ))
+            )
+        )
 
     def index(self, req):
         return self._list(req)
@@ -87,36 +90,51 @@ class DeploymentsController(api_wsgi.Controller):
         if not transfer_id:
             raise exc.HTTPBadRequest(
                 explanation="Missing 'transfer_id' field from deployment "
-                            "body. A deployment can be created strictly "
-                            "based on an existing Transfer.")
+                "body. A deployment can be created strictly "
+                "based on an existing Transfer."
+            )
 
         clone_disks = deployment.get("clone_disks", True)
         force = deployment.get("force", False)
         skip_os_morphing = deployment.get("skip_os_morphing", False)
         instance_osmorphing_minion_pool_mappings = deployment.get(
-            'instance_osmorphing_minion_pool_mappings', {})
+            'instance_osmorphing_minion_pool_mappings', {}
+        )
         user_scripts = deployment.get('user_scripts', {})
         api_utils.validate_user_scripts(user_scripts)
         return (
-            transfer_id, force, clone_disks, skip_os_morphing,
+            transfer_id,
+            force,
+            clone_disks,
+            skip_os_morphing,
             instance_osmorphing_minion_pool_mappings,
-            user_scripts)
+            user_scripts,
+        )
 
     def create(self, req, body):
         context = req.environ['coriolis.context']
         context.can(deployment_policies.get_deployments_policy_label("create"))
 
-        (transfer_id, force, clone_disks, skip_os_morphing,
-         instance_osmorphing_minion_pool_mappings,
-         user_scripts) = self._validate_deployment_input(
-            context, body)
+        (
+            transfer_id,
+            force,
+            clone_disks,
+            skip_os_morphing,
+            instance_osmorphing_minion_pool_mappings,
+            user_scripts,
+        ) = self._validate_deployment_input(context, body)
 
         # NOTE: destination environment for transfer should have been
         # validated upon its creation.
         deployment = self._deployment_api.deploy_transfer_instances(
-            context, transfer_id, instance_osmorphing_minion_pool_mappings,
-            clone_disks, force, skip_os_morphing,
-            user_scripts=user_scripts)
+            context,
+            transfer_id,
+            instance_osmorphing_minion_pool_mappings,
+            clone_disks,
+            force,
+            skip_os_morphing,
+            user_scripts=user_scripts,
+        )
 
         return deployment_view.single(deployment)
 

+ 5 - 8
coriolis/api/v1/diagnostics.py

@@ -1,14 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import diagnostic_view
+import logging
+
 from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import diagnostic_view
 from coriolis.diagnostics import api
 from coriolis.policies import diagnostics
 
-import logging
-
-
 LOG = logging.getLogger(__name__)
 
 
@@ -19,11 +18,9 @@ class DiagnosticsController(api_wsgi.Controller):
 
     def index(self, req):
         context = req.environ['coriolis.context']
-        context.can(
-            diagnostics.get_diagnostics_policy_label("get"))
+        context.can(diagnostics.get_diagnostics_policy_label("get"))
 
-        return diagnostic_view.collection(
-            self._diag_api.get(context))
+        return diagnostic_view.collection(self._diag_api.get(context))
 
 
 def create_resource():

+ 8 - 11
coriolis/api/v1/endpoint_actions.py

@@ -1,13 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from webob import exc
+
+from coriolis import exception
 from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoints import api
-from coriolis import exception
 from coriolis.policies import endpoints as endpoint_policies
 
-from webob import exc
-
 
 class EndpointActionsController(api_wsgi.Controller):
     def __init__(self):
@@ -17,15 +17,12 @@ class EndpointActionsController(api_wsgi.Controller):
     @api_wsgi.action('validate-connection')
     def _validate_connection(self, req, id, body):
         context = req.environ['coriolis.context']
-        context.can("%s:validate_connection" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can(
+            "%s:validate_connection" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX)
+        )
         try:
-            is_valid, message = self._endpoint_api.validate_connection(
-                context, id)
-            return {
-                "validate-connection":
-                    {"valid": is_valid, "message": message}
-            }
+            is_valid, message = self._endpoint_api.validate_connection(context, id)
+            return {"validate-connection": {"valid": is_valid, "message": message}}
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
         except exception.InvalidParameterValue as ex:

+ 13 - 12
coriolis/api/v1/endpoint_destination_minion_pool_options.py

@@ -1,14 +1,13 @@
 # Copyright 2020 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import endpoint_options_view
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import endpoint_options_view
 from coriolis.endpoint_options import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
-
 
 LOG = logging.getLogger(__name__)
 
@@ -20,8 +19,10 @@ class EndpointDestinationMinionPoolOptionsController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:list_destination_minion_pool_options" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can(
+            "%s:list_destination_minion_pool_options"
+            % (endpoint_policies.ENDPOINTS_POLICY_PREFIX)
+        )
 
         env = req.GET.get("env")
         if env is not None:
@@ -35,11 +36,11 @@ class EndpointDestinationMinionPoolOptionsController(api_wsgi.Controller):
         else:
             options = {}
 
-        return (endpoint_options_view.
-                destination_minion_pool_options_collection)(
-            (self._minion_pool_options_api.
-             get_endpoint_destination_minion_pool_options)(
-                context, endpoint_id, env=env, option_names=options))
+        return (endpoint_options_view.destination_minion_pool_options_collection)(
+            (
+                self._minion_pool_options_api.get_endpoint_destination_minion_pool_options
+            )(context, endpoint_id, env=env, option_names=options)
+        )
 
 
 def create_resource():

+ 10 - 8
coriolis/api/v1/endpoint_destination_options.py

@@ -1,14 +1,13 @@
 # Copyright 2018 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import endpoint_options_view
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import endpoint_options_view
 from coriolis.endpoint_options import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
-
 
 LOG = logging.getLogger(__name__)
 
@@ -20,8 +19,9 @@ class EndpointDestinationOptionsController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:list_destination_options" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can(
+            "%s:list_destination_options" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX)
+        )
 
         env = req.GET.get("env")
         if env is not None:
@@ -37,7 +37,9 @@ class EndpointDestinationOptionsController(api_wsgi.Controller):
 
         return endpoint_options_view.destination_options_collection(
             self._destination_options_api.get_endpoint_destination_options(
-                context, endpoint_id, env=env, option_names=options))
+                context, endpoint_id, env=env, option_names=options
+            )
+        )
 
 
 def create_resource():

+ 19 - 13
coriolis/api/v1/endpoint_instances.py

@@ -1,15 +1,15 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import common
+from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1 import utils as api_utils
 from coriolis.api.v1.views import endpoint_resources_view
-from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoint_resources import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
 
 LOG = logging.getLogger(__name__)
 
@@ -21,12 +21,10 @@ class EndpointInstanceController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:list_instances" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can("%s:list_instances" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX))
         marker, limit = common.get_paging_params(req)
         instance_name_pattern = req.GET.get("name")
-        refresh = api_utils.get_bool_url_arg(
-            req, "refresh", default=False)
+        refresh = api_utils.get_bool_url_arg(req, "refresh", default=False)
 
         env = req.GET.get("env")
         if env is not None:
@@ -36,13 +34,19 @@ class EndpointInstanceController(api_wsgi.Controller):
 
         return endpoint_resources_view.instances_collection(
             self._instance_api.get_endpoint_instances(
-                context, endpoint_id, env, marker, limit,
-                instance_name_pattern, refresh=refresh))
+                context,
+                endpoint_id,
+                env,
+                marker,
+                limit,
+                instance_name_pattern,
+                refresh=refresh,
+            )
+        )
 
     def show(self, req, endpoint_id, id):
         context = req.environ['coriolis.context']
-        context.can("%s:get_instance" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can("%s:get_instance" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX))
 
         # WSGI does not allow encoded / chars (%2F) in the url
         # See e.g.: https://github.com/pallets/flask/issues/900
@@ -56,7 +60,9 @@ class EndpointInstanceController(api_wsgi.Controller):
 
         return endpoint_resources_view.instance_single(
             self._instance_api.get_endpoint_instance(
-                req.environ['coriolis.context'], endpoint_id, env, id))
+                req.environ['coriolis.context'], endpoint_id, env, id
+            )
+        )
 
 
 def create_resource():

+ 6 - 6
coriolis/api/v1/endpoint_inventory.py

@@ -1,12 +1,12 @@
 # Copyright 2026 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoint_resources import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
 
 LOG = logging.getLogger(__name__)
 
@@ -20,8 +20,7 @@ class EndpointInventoryController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:export_inventory" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can("%s:export_inventory" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX))
 
         env = req.GET.get("env")
         if env is not None:
@@ -30,7 +29,8 @@ class EndpointInventoryController(api_wsgi.Controller):
             env = {}
 
         csv_content = self._endpoint_resources_api.get_endpoint_inventory_csv(
-            context, endpoint_id, env)
+            context, endpoint_id, env
+        )
 
         return api_wsgi.ResponseObject(csv_content)
 

+ 7 - 8
coriolis/api/v1/endpoint_networks.py

@@ -1,13 +1,13 @@
 # Copyright 2017 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import endpoint_resources_view
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import endpoint_resources_view
 from coriolis.endpoint_resources import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
 
 LOG = logging.getLogger(__name__)
 
@@ -19,8 +19,7 @@ class EndpointNetworkController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:list_networks" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can("%s:list_networks" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX))
         env = req.GET.get("env")
         if env is not None:
             env = utils.decode_base64_param(env, is_json=True)
@@ -28,8 +27,8 @@ class EndpointNetworkController(api_wsgi.Controller):
             env = {}
 
         return endpoint_resources_view.networks_collection(
-            self._network_api.get_endpoint_networks(
-                context, endpoint_id, env))
+            self._network_api.get_endpoint_networks(context, endpoint_id, env)
+        )
 
 
 def create_resource():

+ 12 - 10
coriolis/api/v1/endpoint_source_minion_pool_options.py

@@ -1,14 +1,13 @@
 # Copyright 2020 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import endpoint_options_view
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import endpoint_options_view
 from coriolis.endpoint_options import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
-
 
 LOG = logging.getLogger(__name__)
 
@@ -20,8 +19,10 @@ class EndpointSourceMinionPoolOptionsController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:list_source_minion_pool_options" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can(
+            "%s:list_source_minion_pool_options"
+            % (endpoint_policies.ENDPOINTS_POLICY_PREFIX)
+        )
 
         env = req.GET.get("env")
         if env is not None:
@@ -36,9 +37,10 @@ class EndpointSourceMinionPoolOptionsController(api_wsgi.Controller):
             options = {}
 
         return endpoint_options_view.source_minion_pool_options_collection(
-            (self._minion_pool_options_api.
-             get_endpoint_source_minion_pool_options)(
-                context, endpoint_id, env=env, option_names=options))
+            (self._minion_pool_options_api.get_endpoint_source_minion_pool_options)(
+                context, endpoint_id, env=env, option_names=options
+            )
+        )
 
 
 def create_resource():

+ 10 - 8
coriolis/api/v1/endpoint_source_options.py

@@ -1,14 +1,13 @@
 # Copyright 2019 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import endpoint_options_view
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import endpoint_options_view
 from coriolis.endpoint_options import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
-
 
 LOG = logging.getLogger(__name__)
 
@@ -20,8 +19,9 @@ class EndpointSourceOptionsController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:list_source_options" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can(
+            "%s:list_source_options" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX)
+        )
 
         env = req.GET.get("env")
         if env is not None:
@@ -37,7 +37,9 @@ class EndpointSourceOptionsController(api_wsgi.Controller):
 
         return endpoint_options_view.source_options_collection(
             self._source_options_api.get_endpoint_source_options(
-                context, endpoint_id, env=env, option_names=options))
+                context, endpoint_id, env=env, option_names=options
+            )
+        )
 
 
 def create_resource():

+ 7 - 8
coriolis/api/v1/endpoint_storage.py

@@ -1,13 +1,13 @@
 # Copyright 2018 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import endpoint_resources_view
+from oslo_log import log as logging
+
+from coriolis import utils
 from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import endpoint_resources_view
 from coriolis.endpoint_resources import api
 from coriolis.policies import endpoints as endpoint_policies
-from coriolis import utils
-
-from oslo_log import log as logging
 
 LOG = logging.getLogger(__name__)
 
@@ -19,8 +19,7 @@ class EndpointStorageController(api_wsgi.Controller):
 
     def index(self, req, endpoint_id):
         context = req.environ['coriolis.context']
-        context.can("%s:list_storage" % (
-            endpoint_policies.ENDPOINTS_POLICY_PREFIX))
+        context.can("%s:list_storage" % (endpoint_policies.ENDPOINTS_POLICY_PREFIX))
         env = req.GET.get("env")
         if env is not None:
             env = utils.decode_base64_param(env, is_json=True)
@@ -28,8 +27,8 @@ class EndpointStorageController(api_wsgi.Controller):
             env = {}
 
         return endpoint_resources_view.storage_collection(
-            self._storage_api.get_endpoint_storage(
-                context, endpoint_id, env))
+            self._storage_api.get_endpoint_storage(context, endpoint_id, env)
+        )
 
 
 def create_resource():

+ 28 - 21
coriolis/api/v1/endpoints.py

@@ -1,17 +1,16 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+from webob import exc
+
+from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1 import utils as api_utils
 from coriolis.api.v1.views import endpoint_view
-from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoints import api
-from coriolis import exception
 from coriolis.policies import endpoints as endpoint_policies
 
-from oslo_log import log as logging
-from webob import exc
-
-
 LOG = logging.getLogger(__name__)
 
 
@@ -32,8 +31,7 @@ class EndpointController(api_wsgi.Controller):
     def index(self, req):
         context = req.environ["coriolis.context"]
         context.can(endpoint_policies.get_endpoints_policy_label("list"))
-        return endpoint_view.collection(
-            self._endpoint_api.get_endpoints(context))
+        return endpoint_view.collection(self._endpoint_api.get_endpoints(context))
 
     @api_utils.format_keyerror_message(resource='endpoint', method='create')
     def _validate_create_body(self, body):
@@ -43,34 +41,43 @@ class EndpointController(api_wsgi.Controller):
         endpoint_type = endpoint["type"]
         connection_info = endpoint["connection_info"]
         mapped_regions = endpoint.get("mapped_regions", [])
-        return (
-            name, endpoint_type, description, connection_info,
-            mapped_regions)
+        return (name, endpoint_type, description, connection_info, mapped_regions)
 
     def create(self, req, body):
         context = req.environ["coriolis.context"]
         context.can(endpoint_policies.get_endpoints_policy_label("create"))
-        (name, endpoint_type, description,
-         connection_info, mapped_regions) = self._validate_create_body(body)
-        return endpoint_view.single(self._endpoint_api.create(
-            context, name, endpoint_type, description, connection_info,
-            mapped_regions))
+        (name, endpoint_type, description, connection_info, mapped_regions) = (
+            self._validate_create_body(body)
+        )
+        return endpoint_view.single(
+            self._endpoint_api.create(
+                context,
+                name,
+                endpoint_type,
+                description,
+                connection_info,
+                mapped_regions,
+            )
+        )
 
     @api_utils.format_keyerror_message(resource='endpoint', method='update')
     def _validate_update_body(self, body):
         endpoint = body["endpoint"]
         return {
             k: endpoint[k]
-            for k in endpoint.keys() & {
-                "name", "description", "connection_info",
-                "mapped_regions"}}
+            for k in endpoint.keys()
+            & {"name", "description", "connection_info", "mapped_regions"}
+        }
 
     def update(self, req, id, body):
         context = req.environ["coriolis.context"]
         context.can(endpoint_policies.get_endpoints_policy_label("update"))
         updated_values = self._validate_update_body(body)
-        return endpoint_view.single(self._endpoint_api.update(
-            req.environ['coriolis.context'], id, updated_values))
+        return endpoint_view.single(
+            self._endpoint_api.update(
+                req.environ['coriolis.context'], id, updated_values
+            )
+        )
 
     def delete(self, req, id):
         context = req.environ["coriolis.context"]

+ 11 - 17
coriolis/api/v1/minion_pool_actions.py

@@ -3,9 +3,9 @@
 
 from webob import exc
 
-from coriolis.api.v1.views import minion_pool_view
-from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import minion_pool_view
 from coriolis.minion_pools import api
 from coriolis.policies import minion_pools as minion_pool_policies
 
@@ -18,13 +18,11 @@ class MinionPoolActionsController(api_wsgi.Controller):
     @api_wsgi.action('allocate')
     def _allocate_pool(self, req, id, body):
         context = req.environ['coriolis.context']
-        context.can(
-            minion_pool_policies.get_minion_pools_policy_label(
-                "allocate"))
+        context.can(minion_pool_policies.get_minion_pools_policy_label("allocate"))
         try:
             return minion_pool_view.single(
-                self.minion_pool_api.allocate_minion_pool(
-                    context, id))
+                self.minion_pool_api.allocate_minion_pool(context, id)
+            )
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
         except exception.InvalidParameterValue as ex:
@@ -33,13 +31,11 @@ class MinionPoolActionsController(api_wsgi.Controller):
     @api_wsgi.action('refresh')
     def _refresh_pool(self, req, id, body):
         context = req.environ['coriolis.context']
-        context.can(
-            minion_pool_policies.get_minion_pools_policy_label(
-                "refresh"))
+        context.can(minion_pool_policies.get_minion_pools_policy_label("refresh"))
         try:
             return minion_pool_view.single(
-                self.minion_pool_api.refresh_minion_pool(
-                    context, id))
+                self.minion_pool_api.refresh_minion_pool(context, id)
+            )
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
         except exception.InvalidParameterValue as ex:
@@ -48,14 +44,12 @@ class MinionPoolActionsController(api_wsgi.Controller):
     @api_wsgi.action('deallocate')
     def _deallocate_pool(self, req, id, body):
         context = req.environ['coriolis.context']
-        context.can(
-            minion_pool_policies.get_minion_pools_policy_label(
-                "deallocate"))
+        context.can(minion_pool_policies.get_minion_pools_policy_label("deallocate"))
         force = (body["deallocate"] or {}).get("force", False)
         try:
             return minion_pool_view.single(
-                self.minion_pool_api.deallocate_minion_pool(
-                    context, id, force=force))
+                self.minion_pool_api.deallocate_minion_pool(context, id, force=force)
+            )
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
         except exception.InvalidParameterValue as ex:

+ 140 - 92
coriolis/api/v1/minion_pools.py

@@ -1,18 +1,17 @@
 # Copyright 2020 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+from webob import exc
+
+from coriolis import constants, exception
+from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1 import utils as api_utils
 from coriolis.api.v1.views import minion_pool_view
-from coriolis.api import wsgi as api_wsgi
-from coriolis import constants
 from coriolis.endpoints import api as endpoints_api
-from coriolis import exception
 from coriolis.minion_pools import api
 from coriolis.policies import minion_pools as pools_policies
 
-from oslo_log import log as logging
-from webob import exc
-
 LOG = logging.getLogger(__name__)
 
 
@@ -35,46 +34,54 @@ class MinionPoolController(api_wsgi.Controller):
         context = req.environ["coriolis.context"]
         context.can(pools_policies.get_minion_pools_policy_label("list"))
         return minion_pool_view.collection(
-            self._minion_pool_api.get_minion_pools(context))
+            self._minion_pool_api.get_minion_pools(context)
+        )
 
     def _check_pool_retention_strategy(self, pool_retention_strategy):
         if not pool_retention_strategy:
             LOG.debug(
                 "Ignoring void minion pool retention strategy '%s'",
-                pool_retention_strategy)
+                pool_retention_strategy,
+            )
         valid_strats = [
             constants.MINION_POOL_MACHINE_RETENTION_STRATEGY_DELETE,
-            constants.MINION_POOL_MACHINE_RETENTION_STRATEGY_POWEROFF]
+            constants.MINION_POOL_MACHINE_RETENTION_STRATEGY_POWEROFF,
+        ]
         if pool_retention_strategy not in valid_strats:
             raise Exception(
                 "Invalid minion pool retention strategy '%s'. Must be one of "
-                "the following: %s" % (pool_retention_strategy, valid_strats))
+                "the following: %s" % (pool_retention_strategy, valid_strats)
+            )
 
     def _check_pool_numeric_values(
-            self, minimum_minions, maximum_minions, minion_max_idle_time):
+        self, minimum_minions, maximum_minions, minion_max_idle_time
+    ):
         if minimum_minions is not None:
             if minimum_minions <= 0:
                 raise Exception(
                     "'minimum_minions' must be a strictly positive integer. "
-                    "Got: %s" % minimum_minions)
+                    "Got: %s" % minimum_minions
+                )
         if maximum_minions is not None:
             if maximum_minions <= 0:
                 raise Exception(
                     "'maximum_minions' must be a strictly positive integer. "
-                    "Got: %s" % maximum_minions)
+                    "Got: %s" % maximum_minions
+                )
             if maximum_minions < minimum_minions:
                 raise Exception(
                     "'maximum_minions' value (%s) must be at least as large as"
-                    " the 'minimum_minions' value (%s)." %
-                    (maximum_minions, minimum_minions))
+                    " the 'minimum_minions' value (%s)."
+                    % (maximum_minions, minimum_minions)
+                )
         if minion_max_idle_time is not None:
             if minion_max_idle_time <= 0:
                 raise Exception(
                     "'minion_max_idle_time' must be a strictly positive "
-                    "integer. Got: %s" % maximum_minions)
+                    "integer. Got: %s" % maximum_minions
+                )
 
-    @api_utils.format_keyerror_message(resource='minion_pool',
-                                       method='create')
+    @api_utils.format_keyerror_message(resource='minion_pool', method='create')
     def _validate_create_body(self, ctxt, body):
         minion_pool = body["minion_pool"]
         name = minion_pool["name"]
@@ -83,116 +90,155 @@ class MinionPoolController(api_wsgi.Controller):
         if pool_os_type not in constants.VALID_OS_TYPES:
             raise Exception(
                 "The provided pool OS type '%s' is invalid. Must be one "
-                "of the following: %s" % (
-                    pool_os_type, constants.VALID_OS_TYPES))
+                "of the following: %s" % (pool_os_type, constants.VALID_OS_TYPES)
+            )
         pool_platform = minion_pool["platform"]
         supported_pool_platforms = [
             constants.PROVIDER_PLATFORM_SOURCE,
-            constants.PROVIDER_PLATFORM_DESTINATION]
+            constants.PROVIDER_PLATFORM_DESTINATION,
+        ]
         if pool_platform not in supported_pool_platforms:
             raise Exception(
                 "The provided pool platform ('%s') is invalid. Must be one"
-                " of the following: %s" % (
-                    pool_platform, supported_pool_platforms))
+                " of the following: %s" % (pool_platform, supported_pool_platforms)
+            )
         if pool_platform == constants.PROVIDER_PLATFORM_SOURCE and (
-                pool_os_type != constants.OS_TYPE_LINUX):
+            pool_os_type != constants.OS_TYPE_LINUX
+        ):
             raise Exception(
                 "Source Minion Pools are required to be of OS type "
-                "'%s', not '%s'." % (
-                    constants.OS_TYPE_LINUX, pool_os_type))
+                "'%s', not '%s'." % (constants.OS_TYPE_LINUX, pool_os_type)
+            )
         environment_options = minion_pool["environment_options"]
         if pool_platform == constants.PROVIDER_PLATFORM_SOURCE:
             self._endpoints_api.validate_endpoint_source_minion_pool_options(
-                ctxt, endpoint_id, environment_options)
+                ctxt, endpoint_id, environment_options
+            )
         elif pool_platform == constants.PROVIDER_PLATFORM_DESTINATION:
-            (self._endpoints_api.
-             validate_endpoint_destination_minion_pool_options)(
-                ctxt, endpoint_id, environment_options)
+            (self._endpoints_api.validate_endpoint_destination_minion_pool_options)(
+                ctxt, endpoint_id, environment_options
+            )
 
         minimum_minions = minion_pool.get("minimum_minions", 1)
-        maximum_minions = minion_pool.get(
-            "maximum_minions", minimum_minions)
-        minion_max_idle_time = minion_pool.get(
-            "minion_max_idle_time", 1)
+        maximum_minions = minion_pool.get("maximum_minions", minimum_minions)
+        minion_max_idle_time = minion_pool.get("minion_max_idle_time", 1)
         self._check_pool_numeric_values(
-            minimum_minions, maximum_minions, minion_max_idle_time)
+            minimum_minions, maximum_minions, minion_max_idle_time
+        )
         minion_retention_strategy = minion_pool.get(
             "minion_retention_strategy",
-            constants.MINION_POOL_MACHINE_RETENTION_STRATEGY_DELETE)
-        self._check_pool_retention_strategy(
-            minion_retention_strategy)
+            constants.MINION_POOL_MACHINE_RETENTION_STRATEGY_DELETE,
+        )
+        self._check_pool_retention_strategy(minion_retention_strategy)
         notes = minion_pool.get("notes")
 
         skip_allocation = minion_pool.get('skip_allocation', False)
         return (
-            name, endpoint_id, pool_platform, pool_os_type,
-            environment_options, minimum_minions, maximum_minions,
-            minion_max_idle_time, minion_retention_strategy, notes,
-            skip_allocation)
+            name,
+            endpoint_id,
+            pool_platform,
+            pool_os_type,
+            environment_options,
+            minimum_minions,
+            maximum_minions,
+            minion_max_idle_time,
+            minion_retention_strategy,
+            notes,
+            skip_allocation,
+        )
 
     def create(self, req, body):
         context = req.environ["coriolis.context"]
         context.can(pools_policies.get_minion_pools_policy_label("create"))
-        (name, endpoint_id, pool_platform, pool_os_type, environment_options,
-         minimum_minions, maximum_minions, minion_max_idle_time,
-         minion_retention_strategy, notes, skip_allocation) = (
-            self._validate_create_body(context, body))
-        return minion_pool_view.single(self._minion_pool_api.create(
-            context, name, endpoint_id, pool_platform, pool_os_type,
-            environment_options, minimum_minions, maximum_minions,
-            minion_max_idle_time, minion_retention_strategy, notes=notes,
-            skip_allocation=skip_allocation))
-
-    def _validate_updated_environment_options(self, context, minion_pool,
-                                              environment_options):
-        if minion_pool['platform'] == (
-                constants.PROVIDER_PLATFORM_SOURCE):
-            (self._endpoints_api.
-                validate_endpoint_source_minion_pool_options)(
-                context, minion_pool['endpoint_id'], environment_options)
-        elif minion_pool['platform'] == (
-                constants.PROVIDER_PLATFORM_DESTINATION):
-            (self._endpoints_api.
-                validate_endpoint_destination_minion_pool_options)(
-                context, minion_pool['endpoint_id'], environment_options)
+        (
+            name,
+            endpoint_id,
+            pool_platform,
+            pool_os_type,
+            environment_options,
+            minimum_minions,
+            maximum_minions,
+            minion_max_idle_time,
+            minion_retention_strategy,
+            notes,
+            skip_allocation,
+        ) = self._validate_create_body(context, body)
+        return minion_pool_view.single(
+            self._minion_pool_api.create(
+                context,
+                name,
+                endpoint_id,
+                pool_platform,
+                pool_os_type,
+                environment_options,
+                minimum_minions,
+                maximum_minions,
+                minion_max_idle_time,
+                minion_retention_strategy,
+                notes=notes,
+                skip_allocation=skip_allocation,
+            )
+        )
+
+    def _validate_updated_environment_options(
+        self, context, minion_pool, environment_options
+    ):
+        if minion_pool['platform'] == (constants.PROVIDER_PLATFORM_SOURCE):
+            (self._endpoints_api.validate_endpoint_source_minion_pool_options)(
+                context, minion_pool['endpoint_id'], environment_options
+            )
+        elif minion_pool['platform'] == (constants.PROVIDER_PLATFORM_DESTINATION):
+            (self._endpoints_api.validate_endpoint_destination_minion_pool_options)(
+                context, minion_pool['endpoint_id'], environment_options
+            )
         else:
-            raise Exception(
-                "Unknown pool platform: %s" % minion_pool[
-                    'platform'])
+            raise Exception("Unknown pool platform: %s" % minion_pool['platform'])
 
-    @api_utils.format_keyerror_message(resource='minion_pool',
-                                       method='update')
+    @api_utils.format_keyerror_message(resource='minion_pool', method='update')
     def _validate_update_body(self, id, context, body):
         minion_pool = body["minion_pool"]
         if 'endpoint_id' in minion_pool:
-            raise Exception(
-                "The 'endpoint_id' of a minion pool cannot be updated.")
+            raise Exception("The 'endpoint_id' of a minion pool cannot be updated.")
         if 'platform' in minion_pool:
-            raise Exception(
-                "The 'platform' of a minion pool cannot be updated.")
-        vals = {k: minion_pool[k] for k in minion_pool.keys() &
-                {"name", "environment_options", "minimum_minions",
-                 "maximum_minions", "minion_max_idle_time",
-                 "minion_retention_strategy", "notes", "os_type"}}
+            raise Exception("The 'platform' of a minion pool cannot be updated.")
+        vals = {
+            k: minion_pool[k]
+            for k in minion_pool.keys()
+            & {
+                "name",
+                "environment_options",
+                "minimum_minions",
+                "maximum_minions",
+                "minion_max_idle_time",
+                "minion_retention_strategy",
+                "notes",
+                "os_type",
+            }
+        }
         if 'minion_retention_strategy' in vals:
-            self._check_pool_retention_strategy(
-                vals['minion_retention_strategy'])
-        if any([
-                f in vals for f in [
-                    'environment_options', 'minimum_minions',
-                    'maximum_minions', 'minion_max_idle_time']]):
-            minion_pool = self._minion_pool_api.get_minion_pool(
-                context, id)
+            self._check_pool_retention_strategy(vals['minion_retention_strategy'])
+        if any(
+            [
+                f in vals
+                for f in [
+                    'environment_options',
+                    'minimum_minions',
+                    'maximum_minions',
+                    'minion_max_idle_time',
+                ]
+            ]
+        ):
+            minion_pool = self._minion_pool_api.get_minion_pool(context, id)
             self._check_pool_numeric_values(
-                vals.get(
-                    'minimum_minions', minion_pool['minimum_minions']),
-                vals.get(
-                    'maximum_minions', minion_pool['maximum_minions']),
-                vals.get('minion_max_idle_time'))
+                vals.get('minimum_minions', minion_pool['minimum_minions']),
+                vals.get('maximum_minions', minion_pool['maximum_minions']),
+                vals.get('minion_max_idle_time'),
+            )
 
             if 'environment_options' in vals:
                 self._validate_updated_environment_options(
-                    context, minion_pool, vals['environment_options'])
+                    context, minion_pool, vals['environment_options']
+                )
         return vals
 
     def update(self, req, id, body):
@@ -201,7 +247,9 @@ class MinionPoolController(api_wsgi.Controller):
         updated_values = self._validate_update_body(id, context, body)
         return minion_pool_view.single(
             self._minion_pool_api.update(
-                req.environ['coriolis.context'], id, updated_values))
+                req.environ['coriolis.context'], id, updated_values
+            )
+        )
 
     def delete(self, req, id):
         context = req.environ["coriolis.context"]

+ 5 - 2
coriolis/api/v1/provider_schemas.py

@@ -15,8 +15,11 @@ class ProviderSchemasController(api_wsgi.Controller):
         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)}
+        return {
+            "schemas": self._provider_api.get_provider_schemas(
+                req.environ["coriolis.context"], platform_name, provider_type
+            )
+        }
 
 
 def create_resource():

+ 3 - 4
coriolis/api/v1/providers.py

@@ -1,12 +1,12 @@
 # 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.policies import general as general_policies
 from coriolis.providers import api
 
-from oslo_log import log as logging
-
 LOG = logging.getLogger(__name__)
 
 
@@ -18,8 +18,7 @@ class ProviderController(api_wsgi.Controller):
     def index(self, req):
         context = req.environ['coriolis.context']
         context.can(general_policies.get_providers_policy_label('list'))
-        return {
-            "providers": self._provider_api.get_available_providers(context)}
+        return {"providers": self._provider_api.get_available_providers(context)}
 
 
 def create_resource():

+ 17 - 14
coriolis/api/v1/regions.py

@@ -1,16 +1,16 @@
 # Copyright 2020 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+from webob import exc
+
+from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1 import utils as api_utils
 from coriolis.api.v1.views import region_view
-from coriolis.api import wsgi as api_wsgi
-from coriolis import exception
 from coriolis.policies import regions as region_policies
 from coriolis.regions import api
 
-from oslo_log import log as logging
-from webob import exc
-
 LOG = logging.getLogger(__name__)
 
 
@@ -31,8 +31,7 @@ class RegionController(api_wsgi.Controller):
     def index(self, req):
         context = req.environ["coriolis.context"]
         context.can(region_policies.get_regions_policy_label("list"))
-        return region_view.collection(
-            self._region_api.get_regions(context))
+        return region_view.collection(self._region_api.get_regions(context))
 
     @api_utils.format_keyerror_message(resource='region', method='create')
     def _validate_create_body(self, body):
@@ -46,22 +45,26 @@ class RegionController(api_wsgi.Controller):
         context = req.environ["coriolis.context"]
         context.can(region_policies.get_regions_policy_label("create"))
         (name, description, enabled) = self._validate_create_body(body)
-        return region_view.single(self._region_api.create(
-            context, region_name=name, description=description,
-            enabled=enabled))
+        return region_view.single(
+            self._region_api.create(
+                context, region_name=name, description=description, enabled=enabled
+            )
+        )
 
     @api_utils.format_keyerror_message(resource='region', method='update')
     def _validate_update_body(self, body):
         region = body["region"]
-        return {k: region[k] for k in region.keys() &
-                {"name", "description", "enabled"}}
+        return {
+            k: region[k] for k in region.keys() & {"name", "description", "enabled"}
+        }
 
     def update(self, req, id, body):
         context = req.environ["coriolis.context"]
         context.can(region_policies.get_regions_policy_label("update"))
         updated_values = self._validate_update_body(body)
-        return region_view.single(self._region_api.update(
-            req.environ['coriolis.context'], id, updated_values))
+        return region_view.single(
+            self._region_api.update(req.environ['coriolis.context'], id, updated_values)
+        )
 
     def delete(self, req, id):
         context = req.environ["coriolis.context"]

+ 188 - 137
coriolis/api/v1/router.py

@@ -4,30 +4,32 @@
 from oslo_log import log as logging
 
 from coriolis import api
-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
-from coriolis.api.v1 import endpoint_instances
-from coriolis.api.v1 import endpoint_inventory
-from coriolis.api.v1 import endpoint_networks
-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 minion_pool_actions
-from coriolis.api.v1 import minion_pools
-from coriolis.api.v1 import provider_schemas
-from coriolis.api.v1 import providers
-from coriolis.api.v1 import regions
-from coriolis.api.v1 import services
-from coriolis.api.v1 import transfer_actions
-from coriolis.api.v1 import transfer_schedules
-from coriolis.api.v1 import transfer_tasks_execution_actions
-from coriolis.api.v1 import transfer_tasks_executions
-from coriolis.api.v1 import transfers
+from coriolis.api.v1 import (
+    deployment_actions,
+    deployments,
+    diagnostics,
+    endpoint_actions,
+    endpoint_destination_minion_pool_options,
+    endpoint_destination_options,
+    endpoint_instances,
+    endpoint_inventory,
+    endpoint_networks,
+    endpoint_source_minion_pool_options,
+    endpoint_source_options,
+    endpoint_storage,
+    endpoints,
+    minion_pool_actions,
+    minion_pools,
+    provider_schemas,
+    providers,
+    regions,
+    services,
+    transfer_actions,
+    transfer_schedules,
+    transfer_tasks_execution_actions,
+    transfer_tasks_executions,
+    transfers,
+)
 
 LOG = logging.getLogger(__name__)
 
@@ -47,163 +49,212 @@ class APIRouter(api.APIRouter):
         mapper.redirect("", "/")
 
         self.resources['providers'] = providers.create_resource()
-        mapper.resource('provider', 'providers',
-                        controller=self.resources['providers'])
+        mapper.resource('provider', 'providers', controller=self.resources['providers'])
 
         self.resources['regions'] = regions.create_resource()
-        mapper.resource('region', 'regions',
-                        controller=self.resources['regions'],
-                        collection={'detail': 'GET'})
+        mapper.resource(
+            'region',
+            'regions',
+            controller=self.resources['regions'],
+            collection={'detail': 'GET'},
+        )
 
         self.resources['endpoints'] = endpoints.create_resource()
-        mapper.resource('endpoint', 'endpoints',
-                        controller=self.resources['endpoints'],
-                        collection={'detail': 'GET'},
-                        member={'action': 'POST'})
+        mapper.resource(
+            'endpoint',
+            'endpoints',
+            controller=self.resources['endpoints'],
+            collection={'detail': 'GET'},
+            member={'action': 'POST'},
+        )
 
         self.resources['services'] = services.create_resource()
-        mapper.resource('service', 'services',
-                        controller=self.resources['services'],
-                        collection={'detail': 'GET'})
+        mapper.resource(
+            'service',
+            'services',
+            controller=self.resources['services'],
+            collection={'detail': 'GET'},
+        )
 
         self.resources['minion_pools'] = minion_pools.create_resource()
-        mapper.resource('minion_pool', 'minion_pools',
-                        controller=self.resources['minion_pools'],
-                        collection={'detail': 'GET'})
+        mapper.resource(
+            'minion_pool',
+            'minion_pools',
+            controller=self.resources['minion_pools'],
+            collection={'detail': 'GET'},
+        )
 
         minion_pool_actions_resource = minion_pool_actions.create_resource()
         self.resources['minion_pool_actions'] = minion_pool_actions_resource
         minion_pool_path = '/{project_id}/minion_pools/{id}'
-        mapper.connect('minion_pool_actions',
-                       minion_pool_path + '/actions',
-                       controller=self.resources['minion_pool_actions'],
-                       action='action',
-                       conditions={'method': 'POST'})
-
-        self.resources['endpoint_source_minion_pool_options'] = \
+        mapper.connect(
+            'minion_pool_actions',
+            minion_pool_path + '/actions',
+            controller=self.resources['minion_pool_actions'],
+            action='action',
+            conditions={'method': 'POST'},
+        )
+
+        self.resources['endpoint_source_minion_pool_options'] = (
             endpoint_source_minion_pool_options.create_resource()
-        mapper.resource('minion_pool_options',
-                        'endpoints/{endpoint_id}/source-minion-pool-options',
-                        controller=(
-                            self.resources[
-                                'endpoint_source_minion_pool_options']))
+        )
+        mapper.resource(
+            'minion_pool_options',
+            'endpoints/{endpoint_id}/source-minion-pool-options',
+            controller=(self.resources['endpoint_source_minion_pool_options']),
+        )
 
-        self.resources['endpoint_destination_minion_pool_options'] = \
+        self.resources['endpoint_destination_minion_pool_options'] = (
             endpoint_destination_minion_pool_options.create_resource()
+        )
         mapper.resource(
             'minion_pool_options',
             'endpoints/{endpoint_id}/destination-minion-pool-options',
-            controller=(self.resources
-                        ['endpoint_destination_minion_pool_options']))
+            controller=(self.resources['endpoint_destination_minion_pool_options']),
+        )
 
         endpoint_actions_resource = endpoint_actions.create_resource()
         self.resources['endpoint_actions'] = endpoint_actions_resource
         endpoint_path = '/{project_id}/endpoints/{id}'
-        mapper.connect('endpoint_actions',
-                       endpoint_path + '/actions',
-                       controller=self.resources['endpoint_actions'],
-                       action='action',
-                       conditions={'method': 'POST'})
-
-        self.resources['endpoint_instances'] = \
-            endpoint_instances.create_resource()
-        mapper.resource('instance', 'endpoints/{endpoint_id}/instances',
-                        controller=self.resources['endpoint_instances'])
-
-        self.resources['endpoint_inventory'] = \
-            endpoint_inventory.create_resource()
-        mapper.resource('inventory', 'endpoints/{endpoint_id}/inventory',
-                        controller=self.resources['endpoint_inventory'])
-
-        self.resources['endpoint_networks'] = \
-            endpoint_networks.create_resource()
-        mapper.resource('network', 'endpoints/{endpoint_id}/networks',
-                        controller=self.resources['endpoint_networks'])
-
-        self.resources['endpoint_storage'] = \
-            endpoint_storage.create_resource()
-        mapper.resource('storage', 'endpoints/{endpoint_id}/storage',
-                        controller=self.resources['endpoint_storage'])
-
-        self.resources['endpoint_destination_options'] = \
+        mapper.connect(
+            'endpoint_actions',
+            endpoint_path + '/actions',
+            controller=self.resources['endpoint_actions'],
+            action='action',
+            conditions={'method': 'POST'},
+        )
+
+        self.resources['endpoint_instances'] = endpoint_instances.create_resource()
+        mapper.resource(
+            'instance',
+            'endpoints/{endpoint_id}/instances',
+            controller=self.resources['endpoint_instances'],
+        )
+
+        self.resources['endpoint_inventory'] = endpoint_inventory.create_resource()
+        mapper.resource(
+            'inventory',
+            'endpoints/{endpoint_id}/inventory',
+            controller=self.resources['endpoint_inventory'],
+        )
+
+        self.resources['endpoint_networks'] = endpoint_networks.create_resource()
+        mapper.resource(
+            'network',
+            'endpoints/{endpoint_id}/networks',
+            controller=self.resources['endpoint_networks'],
+        )
+
+        self.resources['endpoint_storage'] = endpoint_storage.create_resource()
+        mapper.resource(
+            'storage',
+            'endpoints/{endpoint_id}/storage',
+            controller=self.resources['endpoint_storage'],
+        )
+
+        self.resources['endpoint_destination_options'] = (
             endpoint_destination_options.create_resource()
-        mapper.resource('destination_options',
-                        'endpoints/{endpoint_id}/destination-options',
-                        controller=(
-                            self.resources['endpoint_destination_options']))
+        )
+        mapper.resource(
+            'destination_options',
+            'endpoints/{endpoint_id}/destination-options',
+            controller=(self.resources['endpoint_destination_options']),
+        )
 
-        self.resources['endpoint_source_options'] = \
+        self.resources['endpoint_source_options'] = (
             endpoint_source_options.create_resource()
-        mapper.resource('source_options',
-                        'endpoints/{endpoint_id}/source-options',
-                        controller=(
-                            self.resources['endpoint_source_options']))
+        )
+        mapper.resource(
+            'source_options',
+            'endpoints/{endpoint_id}/source-options',
+            controller=(self.resources['endpoint_source_options']),
+        )
 
-        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['provider_schemas'] = provider_schemas.create_resource()
+        mapper.resource(
+            'provider_schemas',
+            'providers/{platform_name}/schemas/{provider_type}',
+            controller=self.resources['provider_schemas'],
+        )
 
         self.resources['deployments'] = deployments.create_resource()
-        mapper.resource('deployment', 'deployments',
-                        controller=self.resources['deployments'],
-                        collection={'detail': 'GET'},
-                        member={'action': 'POST'})
+        mapper.resource(
+            'deployment',
+            'deployments',
+            controller=self.resources['deployments'],
+            collection={'detail': 'GET'},
+            member={'action': 'POST'},
+        )
 
         deployments_actions_resource = deployment_actions.create_resource()
         self.resources['deployment_actions'] = deployments_actions_resource
         deployment_path = '/{project_id}/deployments/{id}'
-        mapper.connect('deployment_actions',
-                       deployment_path + '/actions',
-                       controller=self.resources['deployment_actions'],
-                       action='action',
-                       conditions={'method': 'POST'})
+        mapper.connect(
+            'deployment_actions',
+            deployment_path + '/actions',
+            controller=self.resources['deployment_actions'],
+            action='action',
+            conditions={'method': 'POST'},
+        )
 
         self.resources['transfers'] = transfers.create_resource()
-        mapper.resource('transfer', 'transfers',
-                        controller=self.resources['transfers'],
-                        collection={'detail': 'GET'},
-                        member={'action': 'POST'})
+        mapper.resource(
+            'transfer',
+            'transfers',
+            controller=self.resources['transfers'],
+            collection={'detail': 'GET'},
+            member={'action': 'POST'},
+        )
 
         transfer_actions_resource = transfer_actions.create_resource()
         self.resources['transfer_actions'] = transfer_actions_resource
         migration_path = '/{project_id}/transfers/{id}'
-        mapper.connect('transfer_actions',
-                       migration_path + '/actions',
-                       controller=self.resources['transfer_actions'],
-                       action='action',
-                       conditions={'method': 'POST'})
-
-        self.resources['transfer_tasks_executions'] = \
+        mapper.connect(
+            'transfer_actions',
+            migration_path + '/actions',
+            controller=self.resources['transfer_actions'],
+            action='action',
+            conditions={'method': 'POST'},
+        )
+
+        self.resources['transfer_tasks_executions'] = (
             transfer_tasks_executions.create_resource()
-        mapper.resource('execution', 'transfers/{transfer_id}/executions',
-                        controller=self.resources['transfer_tasks_executions'],
-                        collection={'detail': 'GET'},
-                        member={'action': 'POST'})
-
-        transfer_tasks_execution_actions_resource = \
+        )
+        mapper.resource(
+            'execution',
+            'transfers/{transfer_id}/executions',
+            controller=self.resources['transfer_tasks_executions'],
+            collection={'detail': 'GET'},
+            member={'action': 'POST'},
+        )
+
+        transfer_tasks_execution_actions_resource = (
             transfer_tasks_execution_actions.create_resource()
-        self.resources['transfer_tasks_execution_actions'] = \
+        )
+        self.resources['transfer_tasks_execution_actions'] = (
             transfer_tasks_execution_actions_resource
-        migration_path = ('/{project_id}/transfers/{transfer_id}/'
-                          'executions/{id}')
-        mapper.connect('transfer_tasks_execution_actions',
-                       migration_path + '/actions',
-                       controller=self.resources[
-                           'transfer_tasks_execution_actions'],
-                       action='action',
-                       conditions={'method': 'POST'})
+        )
+        migration_path = '/{project_id}/transfers/{transfer_id}/executions/{id}'
+        mapper.connect(
+            'transfer_tasks_execution_actions',
+            migration_path + '/actions',
+            controller=self.resources['transfer_tasks_execution_actions'],
+            action='action',
+            conditions={'method': 'POST'},
+        )
 
         sched = transfer_schedules.create_resource()
         self.resources['transfer_schedules'] = sched
-        mapper.resource('transfer_schedule',
-                        'transfers/{transfer_id}/schedules',
-                        controller=self.resources['transfer_schedules'],
-                        collection={'index': 'GET'},
-                        member={'action': 'POST'})
+        mapper.resource(
+            'transfer_schedule',
+            'transfers/{transfer_id}/schedules',
+            controller=self.resources['transfer_schedules'],
+            collection={'index': 'GET'},
+            member={'action': 'POST'},
+        )
 
         diag = diagnostics.create_resource()
         self.resources['diagnostics'] = diag
-        mapper.resource('diagnostics', 'diagnostics',
-                        controller=self.resources['diagnostics'])
+        mapper.resource(
+            'diagnostics', 'diagnostics', controller=self.resources['diagnostics']
+        )

+ 25 - 16
coriolis/api/v1/services.py

@@ -1,16 +1,16 @@
 # Copyright 2020 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+from webob import exc
+
+from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1 import utils as api_utils
 from coriolis.api.v1.views import service_view
-from coriolis.api import wsgi as api_wsgi
-from coriolis import exception
 from coriolis.policies import services as service_policies
 from coriolis.services import api
 
-from oslo_log import log as logging
-from webob import exc
-
 LOG = logging.getLogger(__name__)
 
 
@@ -31,8 +31,7 @@ class ServiceController(api_wsgi.Controller):
     def index(self, req):
         context = req.environ["coriolis.context"]
         context.can(service_policies.get_services_policy_label("list"))
-        return service_view.collection(
-            self._service_api.get_services(context))
+        return service_view.collection(self._service_api.get_services(context))
 
     @api_utils.format_keyerror_message(resource='service', method='create')
     def _validate_create_body(self, body):
@@ -47,24 +46,34 @@ class ServiceController(api_wsgi.Controller):
     def create(self, req, body):
         context = req.environ["coriolis.context"]
         context.can(service_policies.get_services_policy_label("create"))
-        (host, binary, topic, mapped_regions, enabled) = (
-            self._validate_create_body(body))
-        return service_view.single(self._service_api.create(
-            context, host=host, binary=binary, topic=topic,
-            mapped_regions=mapped_regions, enabled=enabled))
+        (host, binary, topic, mapped_regions, enabled) = self._validate_create_body(
+            body
+        )
+        return service_view.single(
+            self._service_api.create(
+                context,
+                host=host,
+                binary=binary,
+                topic=topic,
+                mapped_regions=mapped_regions,
+                enabled=enabled,
+            )
+        )
 
     @api_utils.format_keyerror_message(resource='service', method='update')
     def _validate_update_body(self, body):
         service = body["service"]
-        return {k: service[k] for k in service.keys() & {
-            "enabled", "mapped_regions"}}
+        return {k: service[k] for k in service.keys() & {"enabled", "mapped_regions"}}
 
     def update(self, req, id, body):
         context = req.environ["coriolis.context"]
         context.can(service_policies.get_services_policy_label("update"))
         updated_values = self._validate_update_body(body)
-        return service_view.single(self._service_api.update(
-            req.environ['coriolis.context'], id, updated_values))
+        return service_view.single(
+            self._service_api.update(
+                req.environ['coriolis.context'], id, updated_values
+            )
+        )
 
     def delete(self, req, id):
         context = req.environ["coriolis.context"]

+ 7 - 7
coriolis/api/v1/transfer_actions.py

@@ -1,14 +1,14 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import transfer_tasks_execution_view
-from coriolis.api import wsgi as api_wsgi
+from webob import exc
+
 from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import transfer_tasks_execution_view
 from coriolis.policies import transfers as transfer_policies
 from coriolis.transfers import api
 
-from webob import exc
-
 
 class TransferActionsController(api_wsgi.Controller):
     def __init__(self):
@@ -18,11 +18,11 @@ class TransferActionsController(api_wsgi.Controller):
     @api_wsgi.action('delete-disks')
     def _delete_disks(self, req, id, body):
         context = req.environ['coriolis.context']
-        context.can(
-            transfer_policies.get_transfers_policy_label("delete_disks"))
+        context.can(transfer_policies.get_transfers_policy_label("delete_disks"))
         try:
             return transfer_tasks_execution_view.single(
-                self._transfer_api.delete_disks(context, id))
+                self._transfer_api.delete_disks(context, id)
+            )
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
         except exception.InvalidParameterValue as ex:

+ 38 - 42
coriolis/api/v1/transfer_schedules.py

@@ -1,19 +1,16 @@
 # Copyright 2017 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis.api.v1.views import transfer_schedule_view
-from coriolis.api import wsgi as api_wsgi
-from coriolis import exception
-from coriolis.policies import transfer_schedules as schedules_policies
-from coriolis import schemas
-from coriolis.transfer_cron import api
-
 import jsonschema
 from oslo_log import log as logging
-from oslo_utils import strutils
-from oslo_utils import timeutils
+from oslo_utils import strutils, timeutils
 from webob import exc
 
+from coriolis import exception, schemas
+from coriolis.api import wsgi as api_wsgi
+from coriolis.api.v1.views import transfer_schedule_view
+from coriolis.policies import transfer_schedules as schedules_policies
+from coriolis.transfer_cron import api
 
 LOG = logging.getLogger(__name__)
 
@@ -25,8 +22,7 @@ class TransferScheduleController(api_wsgi.Controller):
 
     def show(self, req, transfer_id, id):
         context = req.environ["coriolis.context"]
-        context.can(
-            schedules_policies.get_transfer_schedules_policy_label("show"))
+        context.can(schedules_policies.get_transfer_schedules_policy_label("show"))
         schedule = self._schedule_api.get_schedule(context, transfer_id, id)
         if not schedule:
             raise exc.HTTPNotFound()
@@ -35,14 +31,14 @@ class TransferScheduleController(api_wsgi.Controller):
 
     def index(self, req, transfer_id):
         context = req.environ["coriolis.context"]
-        context.can(
-            schedules_policies.get_transfer_schedules_policy_label("list"))
+        context.can(schedules_policies.get_transfer_schedules_policy_label("list"))
 
         show_expired = strutils.bool_from_string(
-            req.GET.get("show_expired", True), strict=True)
+            req.GET.get("show_expired", True), strict=True
+        )
         return transfer_schedule_view.collection(
-            self._schedule_api.get_schedules(
-                context, transfer_id, expired=show_expired))
+            self._schedule_api.get_schedules(context, transfer_id, expired=show_expired)
+        )
 
     def _validate_schedule(self, schedule):
         schema = schemas.SCHEDULE_API_BODY_SCHEMA["properties"]["schedule"]
@@ -52,23 +48,22 @@ class TransferScheduleController(api_wsgi.Controller):
     def _validate_expiration_date(self, expiration_date):
         if expiration_date is None:
             return expiration_date
-        exp = timeutils.normalize_time(
-            timeutils.parse_isotime(expiration_date))
+        exp = timeutils.normalize_time(timeutils.parse_isotime(expiration_date))
         now = timeutils.utcnow()
         if now > exp:
-            raise exception.InvalidInput(
-                "expiration_date is in the past")
+            raise exception.InvalidInput("expiration_date is in the past")
         return exp
 
     def _validate_create_body(self, body):
         schedule = body.get("schedule")
         if schedule is None:
-            raise exception.InvalidInput(
-                "schedule is required")
+            raise exception.InvalidInput("schedule is required")
         schedule = self._validate_schedule(schedule)
         schemas.validate_value(
-            body, schemas.SCHEDULE_API_BODY_SCHEMA,
-            format_checker=jsonschema.FormatChecker())
+            body,
+            schemas.SCHEDULE_API_BODY_SCHEMA,
+            format_checker=jsonschema.FormatChecker(),
+        )
 
         enabled = body.get("enabled", True)
         exp = body.get("expiration_date", None)
@@ -94,52 +89,53 @@ class TransferScheduleController(api_wsgi.Controller):
         if auto_deploy is not None:
             body['auto_deploy'] = auto_deploy
         schemas.validate_value(
-            body, schemas.SCHEDULE_API_BODY_SCHEMA,
-            format_checker=jsonschema.FormatChecker())
+            body,
+            schemas.SCHEDULE_API_BODY_SCHEMA,
+            format_checker=jsonschema.FormatChecker(),
+        )
 
         exp = None
         if "expiration_date" in update_body:
-            exp = self._validate_expiration_date(
-                update_body.get("expiration_date"))
+            exp = self._validate_expiration_date(update_body.get("expiration_date"))
             body["expiration_date"] = exp
         return body
 
     def create(self, req, transfer_id, body):
         context = req.environ["coriolis.context"]
-        context.can(
-            schedules_policies.get_transfer_schedules_policy_label("create"))
+        context.can(schedules_policies.get_transfer_schedules_policy_label("create"))
 
         LOG.debug("Got request: %r %r %r" % (req, transfer_id, body))
         try:
             schedule, enabled, exp_date, shutdown, auto_deploy = (
-                self._validate_create_body(body))
+                self._validate_create_body(body)
+            )
         except Exception as err:
             raise exception.InvalidInput(err)
 
-        return transfer_schedule_view.single(self._schedule_api.create(
-            context, transfer_id, schedule, enabled, exp_date, shutdown,
-            auto_deploy))
+        return transfer_schedule_view.single(
+            self._schedule_api.create(
+                context, transfer_id, schedule, enabled, exp_date, shutdown, auto_deploy
+            )
+        )
 
     def update(self, req, transfer_id, id, body):
         context = req.environ["coriolis.context"]
-        context.can(
-            schedules_policies.get_transfer_schedules_policy_label("update"))
+        context.can(schedules_policies.get_transfer_schedules_policy_label("update"))
 
-        LOG.debug("Got request: %r %r %r %r" % (
-            req, transfer_id, id, body))
+        LOG.debug("Got request: %r %r %r %r" % (req, transfer_id, id, body))
 
         try:
             update_values = self._validate_update_body(body)
         except Exception as err:
             raise exception.InvalidInput(err)
 
-        return transfer_schedule_view.single(self._schedule_api.update(
-            context, transfer_id, id, update_values))
+        return transfer_schedule_view.single(
+            self._schedule_api.update(context, transfer_id, id, update_values)
+        )
 
     def delete(self, req, transfer_id, id):
         context = req.environ["coriolis.context"]
-        context.can(
-            schedules_policies.get_transfer_schedules_policy_label("delete"))
+        context.can(schedules_policies.get_transfer_schedules_policy_label("delete"))
 
         self._schedule_api.delete(context, transfer_id, id)
         raise exc.HTTPNoContent()

+ 3 - 5
coriolis/api/v1/transfer_tasks_execution_actions.py

@@ -3,8 +3,8 @@
 
 from webob import exc
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
 from coriolis.policies import transfer_tasks_executions as execution_policies
 from coriolis.transfer_tasks_executions import api
 
@@ -17,13 +17,11 @@ class TransferTasksExecutionActionsController(api_wsgi.Controller):
     @api_wsgi.action('cancel')
     def _cancel(self, req, transfer_id, id, body):
         context = req.environ['coriolis.context']
-        context.can(
-            execution_policies.get_transfer_executions_policy_label('cancel'))
+        context.can(execution_policies.get_transfer_executions_policy_label('cancel'))
         try:
             force = (body["cancel"] or {}).get("force", False)
 
-            self._transfer_tasks_execution_api.cancel(
-                context, transfer_id, id, force)
+            self._transfer_tasks_execution_api.cancel(context, transfer_id, id, force)
             raise exc.HTTPNoContent()
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)

+ 29 - 23
coriolis/api/v1/transfer_tasks_executions.py

@@ -1,16 +1,15 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from webob import exc
+
+from coriolis import constants, exception
 from coriolis.api import common
-from coriolis.api.v1.views import transfer_tasks_execution_view
 from coriolis.api import wsgi as api_wsgi
-from coriolis import constants
-from coriolis import exception
+from coriolis.api.v1.views import transfer_tasks_execution_view
 from coriolis.policies import transfer_tasks_executions as executions_policies
 from coriolis.transfer_tasks_executions import api
 
-from webob import exc
-
 
 class TransferTasksExecutionController(api_wsgi.Controller):
     def __init__(self):
@@ -19,10 +18,10 @@ class TransferTasksExecutionController(api_wsgi.Controller):
 
     def show(self, req, transfer_id, id):
         context = req.environ["coriolis.context"]
-        context.can(
-            executions_policies.get_transfer_executions_policy_label("show"))
+        context.can(executions_policies.get_transfer_executions_policy_label("show"))
         execution = self._transfer_tasks_execution_api.get_execution(
-            context, transfer_id, id)
+            context, transfer_id, id
+        )
         if not execution:
             raise exc.HTTPNotFound()
 
@@ -34,14 +33,14 @@ class TransferTasksExecutionController(api_wsgi.Controller):
         if status is not None:
             if status not in constants.ALL_EXECUTION_STATUSES:
                 raise exc.HTTPBadRequest(
-                    explanation=f"Unknown task execution status: {status}")
+                    explanation=f"Unknown task execution status: {status}"
+                )
             filters["status"] = status
         return filters
 
     def index(self, req, transfer_id):
         context = req.environ["coriolis.context"]
-        context.can(
-            executions_policies.get_transfer_executions_policy_label("list"))
+        context.can(executions_policies.get_transfer_executions_policy_label("list"))
 
         marker, limit = common.get_paging_params(req)
         sort_keys, sort_dirs = common.get_sort_params(req)
@@ -49,24 +48,30 @@ class TransferTasksExecutionController(api_wsgi.Controller):
 
         return transfer_tasks_execution_view.collection(
             self._transfer_tasks_execution_api.get_executions(
-                context, transfer_id, include_tasks=False,
-                marker=marker, limit=limit,
-                sort_keys=sort_keys, sort_dirs=sort_dirs,
-                filters=filters))
+                context,
+                transfer_id,
+                include_tasks=False,
+                marker=marker,
+                limit=limit,
+                sort_keys=sort_keys,
+                sort_dirs=sort_dirs,
+                filters=filters,
+            )
+        )
 
     def detail(self, req, transfer_id):
         context = req.environ["coriolis.context"]
-        context.can(
-            executions_policies.get_transfer_executions_policy_label("show"))
+        context.can(executions_policies.get_transfer_executions_policy_label("show"))
 
         return transfer_tasks_execution_view.collection(
             self._transfer_tasks_execution_api.get_executions(
-                context, transfer_id, include_tasks=True))
+                context, transfer_id, include_tasks=True
+            )
+        )
 
     def create(self, req, transfer_id, body):
         context = req.environ["coriolis.context"]
-        context.can(
-            executions_policies.get_transfer_executions_policy_label("create"))
+        context.can(executions_policies.get_transfer_executions_policy_label("create"))
 
         # TODO(alexpilotti): validate body
 
@@ -76,12 +81,13 @@ class TransferTasksExecutionController(api_wsgi.Controller):
 
         return transfer_tasks_execution_view.single(
             self._transfer_tasks_execution_api.create(
-                context, transfer_id, shutdown_instances, auto_deploy))
+                context, transfer_id, shutdown_instances, auto_deploy
+            )
+        )
 
     def delete(self, req, transfer_id, id):
         context = req.environ["coriolis.context"]
-        context.can(
-            executions_policies.get_transfer_executions_policy_label("delete"))
+        context.can(executions_policies.get_transfer_executions_policy_label("delete"))
 
         try:
             self._transfer_tasks_execution_api.delete(context, transfer_id, id)

+ 160 - 115
coriolis/api/v1/transfers.py

@@ -1,26 +1,24 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+from webob import exc
+
+from coriolis import constants, exception
 from coriolis.api import common
-from coriolis.api.v1 import utils as api_utils
-from coriolis.api.v1.views import transfer_tasks_execution_view
-from coriolis.api.v1.views import transfer_view
 from coriolis.api import wsgi as api_wsgi
-from coriolis import constants
+from coriolis.api.v1 import utils as api_utils
+from coriolis.api.v1.views import transfer_tasks_execution_view, transfer_view
 from coriolis.endpoints import api as endpoints_api
-from coriolis import exception
 from coriolis.policies import transfers as transfer_policies
 from coriolis.transfers import api
 
-from oslo_log import log as logging
-from webob import exc
-
-
 LOG = logging.getLogger(__name__)
 
 SUPPORTED_TRANSFER_SCENARIOS = [
     constants.TRANSFER_SCENARIO_REPLICA,
-    constants.TRANSFER_SCENARIO_LIVE_MIGRATION]
+    constants.TRANSFER_SCENARIO_LIVE_MIGRATION,
+]
 
 
 class TransferController(api_wsgi.Controller):
@@ -33,10 +31,11 @@ class TransferController(api_wsgi.Controller):
         context = req.environ["coriolis.context"]
         context.can(transfer_policies.get_transfers_policy_label("show"))
         include_task_info = api_utils.get_bool_url_arg(
-            req, "include_task_info", default=False)
+            req, "include_task_info", default=False
+        )
         transfer = self._transfer_api.get_transfer(
-            context, id,
-            include_task_info=include_task_info)
+            context, id, include_task_info=include_task_info
+        )
         if not transfer:
             raise exc.HTTPNotFound()
 
@@ -47,19 +46,18 @@ class TransferController(api_wsgi.Controller):
         status = req.GET.get("status")
         if status is not None:
             if status not in constants.ALL_TASK_STATUSES:
-                raise exc.HTTPBadRequest(
-                    explanation=f"Unknown task status: {status}")
+                raise exc.HTTPBadRequest(explanation=f"Unknown task status: {status}")
             filters["status"] = status
         return filters
 
     def _list(self, req):
-        show_deleted = api_utils.get_bool_url_arg(
-            req, "show_deleted", default=False)
+        show_deleted = api_utils.get_bool_url_arg(req, "show_deleted", default=False)
         context = req.environ["coriolis.context"]
         context.show_deleted = show_deleted
         context.can(transfer_policies.get_transfers_policy_label("list"))
         include_task_info = api_utils.get_bool_url_arg(
-            req, "include_task_info", default=False)
+            req, "include_task_info", default=False
+        )
         marker, limit = common.get_paging_params(req)
         sort_keys, sort_dirs = common.get_sort_params(req)
         filters = self._get_filters(req)
@@ -68,10 +66,13 @@ class TransferController(api_wsgi.Controller):
                 context,
                 include_tasks_executions=include_task_info,
                 include_task_info=include_task_info,
-                marker=marker, limit=limit,
-                sort_keys=sort_keys, sort_dirs=sort_dirs,
+                marker=marker,
+                limit=limit,
+                sort_keys=sort_keys,
+                sort_dirs=sort_dirs,
                 filters=filters,
-            ))
+            )
+        )
 
     def index(self, req):
         return self._list(req)
@@ -88,42 +89,46 @@ class TransferController(api_wsgi.Controller):
             if scenario not in SUPPORTED_TRANSFER_SCENARIOS:
                 raise exc.HTTPBadRequest(
                     explanation=f"Unsupported Transfer creation scenario "
-                                f"'{scenario}', must be one of: "  # noqa
-                                f"{SUPPORTED_TRANSFER_SCENARIOS}")  # noqa
+                    f"'{scenario}', must be one of: "  # noqa
+                    f"{SUPPORTED_TRANSFER_SCENARIOS}"
+                )  # noqa
         else:
             scenario = constants.TRANSFER_SCENARIO_REPLICA
             LOG.warn(
                 "No Transfer 'scenario' field set in Transfer body, "
-                f"defaulting to: '{scenario}'")
+                f"defaulting to: '{scenario}'"
+            )
 
         origin_endpoint_id = transfer["origin_endpoint_id"]
         destination_endpoint_id = transfer["destination_endpoint_id"]
-        destination_environment = transfer.get(
-            "destination_environment", {})
+        destination_environment = transfer.get("destination_environment", {})
         instances = api_utils.validate_instances_list_for_transfer(
-            transfer.get('instances'))
+            transfer.get('instances')
+        )
 
         notes = transfer.get("notes")
 
         source_environment = transfer.get("source_environment", {})
         self._endpoints_api.validate_source_environment(
-            context, origin_endpoint_id, source_environment)
+            context, origin_endpoint_id, source_environment
+        )
 
-        origin_minion_pool_id = transfer.get(
-            'origin_minion_pool_id')
-        destination_minion_pool_id = transfer.get(
-            'destination_minion_pool_id')
+        origin_minion_pool_id = transfer.get('origin_minion_pool_id')
+        destination_minion_pool_id = transfer.get('destination_minion_pool_id')
         instance_osmorphing_minion_pool_mappings = transfer.get(
-            'instance_osmorphing_minion_pool_mappings', {})
+            'instance_osmorphing_minion_pool_mappings', {}
+        )
         extras = [
             instance
             for instance in instance_osmorphing_minion_pool_mappings
-            if instance not in instances]
+            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 "
-                "Transfer's declared instances (%s)" % (extras, instances))
+                "Transfer's declared instances (%s)" % (extras, instances)
+            )
 
         # TODO(aznashwan): until the provider plugin interface is updated
         # to have separate 'network_map' and 'storage_mappings' fields,
@@ -132,7 +137,8 @@ class TransferController(api_wsgi.Controller):
         api_utils.validate_network_map(network_map)
         destination_environment['network_map'] = network_map
         self._endpoints_api.validate_target_environment(
-            context, destination_endpoint_id, destination_environment)
+            context, destination_endpoint_id, destination_environment
+        )
 
         user_scripts = transfer.get('user_scripts', {})
         api_utils.validate_user_scripts(user_scripts)
@@ -149,32 +155,66 @@ class TransferController(api_wsgi.Controller):
         clone_disks = transfer.get('clone_disks', True)
         skip_os_morphing = transfer.get('skip_os_morphing', False)
 
-        return (scenario, origin_endpoint_id, destination_endpoint_id,
-                source_environment, destination_environment, instances,
-                network_map, storage_mappings, notes,
-                origin_minion_pool_id, destination_minion_pool_id,
-                instance_osmorphing_minion_pool_mappings, user_scripts,
-                clone_disks, skip_os_morphing)
+        return (
+            scenario,
+            origin_endpoint_id,
+            destination_endpoint_id,
+            source_environment,
+            destination_environment,
+            instances,
+            network_map,
+            storage_mappings,
+            notes,
+            origin_minion_pool_id,
+            destination_minion_pool_id,
+            instance_osmorphing_minion_pool_mappings,
+            user_scripts,
+            clone_disks,
+            skip_os_morphing,
+        )
 
     def create(self, req, body):
         context = req.environ["coriolis.context"]
         context.can(transfer_policies.get_transfers_policy_label("create"))
 
-        (scenario, origin_endpoint_id, destination_endpoint_id,
-         source_environment, destination_environment, instances, network_map,
-         storage_mappings, notes, origin_minion_pool_id,
-         destination_minion_pool_id,
-         instance_osmorphing_minion_pool_mappings, user_scripts, clone_disks,
-         skip_os_morphing) = (
-            self._validate_create_body(context, body))
-
-        return transfer_view.single(self._transfer_api.create(
-            context, 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, notes, user_scripts, clone_disks,
-            skip_os_morphing))
+        (
+            scenario,
+            origin_endpoint_id,
+            destination_endpoint_id,
+            source_environment,
+            destination_environment,
+            instances,
+            network_map,
+            storage_mappings,
+            notes,
+            origin_minion_pool_id,
+            destination_minion_pool_id,
+            instance_osmorphing_minion_pool_mappings,
+            user_scripts,
+            clone_disks,
+            skip_os_morphing,
+        ) = self._validate_create_body(context, body)
+
+        return transfer_view.single(
+            self._transfer_api.create(
+                context,
+                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,
+                notes,
+                user_scripts,
+                clone_disks,
+                skip_os_morphing,
+            )
+        )
 
     def delete(self, req, id):
         context = req.environ["coriolis.context"]
@@ -186,46 +226,44 @@ class TransferController(api_wsgi.Controller):
             raise exc.HTTPNotFound(explanation=ex.msg)
 
     @staticmethod
-    def _update_storage_mappings(original_storage_mappings,
-                                 new_storage_mappings):
+    def _update_storage_mappings(original_storage_mappings, new_storage_mappings):
 
-        backend_mappings = original_storage_mappings.get(
-            'backend_mappings', [])
-        new_backend_mappings = new_storage_mappings.get(
-            'backend_mappings', [])
-        new_backend_mapping_sources = [mapping['source'] for mapping in
-                                       new_backend_mappings]
+        backend_mappings = original_storage_mappings.get('backend_mappings', [])
+        new_backend_mappings = new_storage_mappings.get('backend_mappings', [])
+        new_backend_mapping_sources = [
+            mapping['source'] for mapping in new_backend_mappings
+        ]
 
         disk_mappings = original_storage_mappings.get('disk_mappings', [])
         new_disk_mappings = new_storage_mappings.get('disk_mappings', [])
-        new_disk_mappings_disk_ids = [mapping['disk_id'] for mapping in
-                                      new_disk_mappings]
+        new_disk_mappings_disk_ids = [
+            mapping['disk_id'] for mapping in new_disk_mappings
+        ]
 
         non_duplicates_backend_mapping = []
         for mapping in backend_mappings:
             if mapping['source'] not in new_backend_mapping_sources:
                 non_duplicates_backend_mapping.append(mapping)
             else:
-                LOG.info("Storage Backend Mapping %s will be overwritten." %
-                         mapping)
+                LOG.info("Storage Backend Mapping %s will be overwritten." % mapping)
 
         non_duplicates_disk_mappings = []
         for mapping in disk_mappings:
             if mapping['disk_id'] not in new_disk_mappings_disk_ids:
                 non_duplicates_disk_mappings.append(mapping)
             else:
-                LOG.info("Storage Disk Mapping %s will be overwritten" %
-                         mapping)
+                LOG.info("Storage Disk Mapping %s will be overwritten" % mapping)
 
         non_duplicates_backend_mapping.extend(new_backend_mappings)
         non_duplicates_disk_mappings.extend(new_disk_mappings)
         storage_mappings = {
             'backend_mappings': non_duplicates_backend_mapping,
-            'disk_mappings': non_duplicates_disk_mappings}
+            'disk_mappings': non_duplicates_disk_mappings,
+        }
 
-        default_storage_backend = (
-            new_storage_mappings.get('default', None) or
-            original_storage_mappings.get('default', None))
+        default_storage_backend = new_storage_mappings.get(
+            'default', None
+        ) or original_storage_mappings.get('default', None)
         if default_storage_backend:
             storage_mappings['default'] = default_storage_backend
 
@@ -251,7 +289,7 @@ class TransferController(api_wsgi.Controller):
         return user_scripts
 
     def _get_merged_transfer_values(self, transfer, updated_values):
-        """ Looks for the following keys in the original transfer body and
+        """Looks for the following keys in the original transfer body and
         updated values (preferring the updated values where needed, but using
         `.update()` on dicts):
         "source_environment", "destination_environment", "network_map", "notes"
@@ -262,9 +300,7 @@ class TransferController(api_wsgi.Controller):
         final_values = {}
         # NOTE: this just replaces options at the top-level and does not do
         # merging of container types (ex: lists, dicts)
-        for option in [
-                "source_environment", "destination_environment",
-                "network_map"]:
+        for option in ["source_environment", "destination_environment", "network_map"]:
             before = transfer.get(option)
             after = updated_values.get(option)
             # NOTE: for Transfers created before the separation of these fields
@@ -284,14 +320,18 @@ class TransferController(api_wsgi.Controller):
         if new_storage_mappings is None:
             new_storage_mappings = {}
         final_values['storage_mappings'] = self._update_storage_mappings(
-            original_storage_mappings, new_storage_mappings)
+            original_storage_mappings, new_storage_mappings
+        )
 
         original_user_scripts = api_utils.validate_user_scripts(
-            transfer.get('user_scripts', {}))
+            transfer.get('user_scripts', {})
+        )
         new_user_scripts = api_utils.validate_user_scripts(
-            updated_values.get('user_scripts', {}))
+            updated_values.get('user_scripts', {})
+        )
         final_values['user_scripts'] = self._get_updated_user_scripts(
-            original_user_scripts, new_user_scripts)
+            original_user_scripts, new_user_scripts
+        )
 
         if 'notes' in updated_values:
             final_values['notes'] = updated_values.get('notes', '')
@@ -311,19 +351,24 @@ class TransferController(api_wsgi.Controller):
         final_storage_mappings = final_values['storage_mappings']
         final_network_map = final_values['network_map']
         if final_storage_mappings:
-            final_values['destination_environment'][
-                'storage_mappings'] = final_storage_mappings
+            final_values['destination_environment']['storage_mappings'] = (
+                final_storage_mappings
+            )
         if final_network_map:
-            final_values['destination_environment'][
-                'network_map'] = final_network_map
+            final_values['destination_environment']['network_map'] = final_network_map
 
         minion_pool_fields = [
-            "origin_minion_pool_id", "destination_minion_pool_id",
-            "instance_osmorphing_minion_pool_mappings"]
-        final_values.update({
-            mpf: updated_values[mpf]
-            for mpf in minion_pool_fields
-            if mpf in updated_values})
+            "origin_minion_pool_id",
+            "destination_minion_pool_id",
+            "instance_osmorphing_minion_pool_mappings",
+        ]
+        final_values.update(
+            {
+                mpf: updated_values[mpf]
+                for mpf in minion_pool_fields
+                if mpf in updated_values
+            }
+        )
 
         return final_values
 
@@ -335,46 +380,44 @@ class TransferController(api_wsgi.Controller):
         if scenario and scenario != transfer["scenario"]:
             raise exc.HTTPBadRequest(
                 explanation=f"Changing Transfer creation scenario is not "
-                            f"supported (original scenario is "  # noqa
-                            f"{transfer['scenario']}, received '{scenario}')")  # noqa
+                f"supported (original scenario is "  # noqa
+                f"{transfer['scenario']}, received '{scenario}')"
+            )  # noqa
 
         transfer_body = body['transfer']
         origin_endpoint_id = transfer_body.get('origin_endpoint_id', None)
-        destination_endpoint_id = transfer_body.get(
-            'destination_endpoint_id', None)
+        destination_endpoint_id = transfer_body.get('destination_endpoint_id', None)
         instances = body['transfer'].get('instances', None)
         if origin_endpoint_id or destination_endpoint_id:
             raise exc.HTTPBadRequest(
                 explanation="The source or destination endpoints for a "
-                            "Coriolis Transfer cannot be updated after its "
-                            "creation. If the credentials of any of the "
-                            "Transfer's endpoints need updating, please "
-                            "update the endpoints themselves.")
+                "Coriolis Transfer cannot be updated after its "
+                "creation. If the credentials of any of the "
+                "Transfer's endpoints need updating, please "
+                "update the endpoints themselves."
+            )
         if instances:
             raise exc.HTTPBadRequest(
-                explanation="The list of instances of a Transfer cannot be "
-                            "updated")
+                explanation="The list of instances of a Transfer cannot be updated"
+            )
 
-        merged_body = self._get_merged_transfer_values(
-            transfer, transfer_body)
+        merged_body = self._get_merged_transfer_values(transfer, transfer_body)
 
         transfer_origin_endpoint_id = transfer["origin_endpoint_id"]
-        transfer_destination_endpoint_id = transfer[
-            "destination_endpoint_id"]
+        transfer_destination_endpoint_id = transfer["destination_endpoint_id"]
 
         self._endpoints_api.validate_source_environment(
-            context, transfer_origin_endpoint_id,
-            merged_body["source_environment"])
+            context, transfer_origin_endpoint_id, merged_body["source_environment"]
+        )
 
         destination_environment = merged_body["destination_environment"]
         self._endpoints_api.validate_target_environment(
-            context, transfer_destination_endpoint_id,
-            destination_environment)
+            context, transfer_destination_endpoint_id, destination_environment
+        )
 
         api_utils.validate_network_map(merged_body["network_map"])
 
-        api_utils.validate_storage_mappings(
-            merged_body["storage_mappings"])
+        api_utils.validate_storage_mappings(merged_body["storage_mappings"])
 
         user_scripts = merged_body['user_scripts']
         api_utils.validate_user_scripts(user_scripts)
@@ -388,8 +431,10 @@ class TransferController(api_wsgi.Controller):
         updated_values = self._validate_update_body(id, context, body)
         try:
             return transfer_tasks_execution_view.single(
-                self._transfer_api.update(req.environ['coriolis.context'],
-                                          id, updated_values))
+                self._transfer_api.update(
+                    req.environ['coriolis.context'], id, updated_values
+                )
+            )
         except exception.NotFound as ex:
             raise exc.HTTPNotFound(explanation=ex.msg)
         except exception.InvalidParameterValue as ex:

+ 68 - 54
coriolis/api/v1/utils.py

@@ -7,10 +7,7 @@ from oslo_log import log as logging
 from oslo_utils import strutils
 from webob import exc
 
-from coriolis import constants
-from coriolis import exception
-from coriolis import schemas
-
+from coriolis import constants, exception, schemas
 
 LOG = logging.getLogger(__name__)
 
@@ -18,33 +15,28 @@ LOG = logging.getLogger(__name__)
 def get_bool_url_arg(req, arg_name, default=False):
     val = req.GET.get(arg_name, default)
     try:
-        return strutils.bool_from_string(
-            str(val), strict=True)
+        return strutils.bool_from_string(str(val), strict=True)
     except ValueError as err:
-        LOG.warn(
-            "failed to parse %s: %s, defaulting to %s" % (
-                arg_name, err, default))
+        LOG.warn("failed to parse %s: %s, defaulting to %s" % (arg_name, err, default))
     return default
 
 
 def validate_network_map(network_map):
-    """ Validates the JSON schema for the network_map. """
+    """Validates the JSON schema for the network_map."""
     try:
-        schemas.validate_value(
-            network_map, schemas.CORIOLIS_NETWORK_MAP_SCHEMA)
+        schemas.validate_value(network_map, schemas.CORIOLIS_NETWORK_MAP_SCHEMA)
     except exception.SchemaValidationException as ex:
-        raise exc.HTTPBadRequest(
-            explanation="Invalid network_map: %s" % str(ex))
+        raise exc.HTTPBadRequest(explanation="Invalid network_map: %s" % str(ex))
 
 
 def validate_storage_mappings(storage_mappings):
-    """ Validates the JSON schema for the storage_mappings. """
+    """Validates the JSON schema for the storage_mappings."""
     try:
         schemas.validate_value(
-            storage_mappings, schemas.CORIOLIS_STORAGE_MAPPINGS_SCHEMA)
+            storage_mappings, schemas.CORIOLIS_STORAGE_MAPPINGS_SCHEMA
+        )
     except exception.SchemaValidationException as ex:
-        raise exc.HTTPBadRequest(
-            explanation="Invalid storage_mappings: %s" % str(ex))
+        raise exc.HTTPBadRequest(explanation="Invalid storage_mappings: %s" % str(ex))
 
 
 def format_keyerror_message(resource='', method=''):
@@ -57,8 +49,7 @@ def format_keyerror_message(resource='', method=''):
                 LOG.exception(err)
                 if err.args:
                     key = err.args[0]
-                    exc_message = _build_keyerror_message(
-                        resource, method, key)
+                    exc_message = _build_keyerror_message(resource, method, key)
                 else:
                     exc_message = str(err)
                 raise exception.InvalidInput(exc_message)
@@ -66,7 +57,9 @@ def format_keyerror_message(resource='', method=''):
                 LOG.exception(err)
                 msg = getattr(err, "msg", str(err))
                 raise exception.InvalidInput(reason=msg)
+
         return _wrapper
+
     return _format_keyerror_message
 
 
@@ -74,14 +67,21 @@ def _build_keyerror_message(resource, method, key):
     msg = ''
     method_mapping = {
         "create": "creation",
-        "update": "update", }
+        "update": "update",
+    }
 
     if resource == key:
         msg = 'The %s %s body needs to be encased inside the "%s" key' % (
-            resource, method_mapping[method], key)
+            resource,
+            method_mapping[method],
+            key,
+        )
     else:
         msg = 'The %s %s body lacks a required attribute: "%s"' % (
-            resource, method_mapping[method], key)
+            resource,
+            method_mapping[method],
+            key,
+        )
 
     return msg
 
@@ -106,8 +106,8 @@ def _process_user_scripts(
             payload = _sanitize_newlines(payload)
         if not payload.strip("\r\n "):
             raise exception.InvalidInput(
-                "Empty script received. "
-                "Use 'None' if the script should be removed.")
+                "Empty script received. Use 'None' if the script should be removed."
+            )
         return [
             {
                 "phase": constants.PHASE_OSMORPHING_POST_OS_MOUNT,
@@ -119,14 +119,18 @@ def _process_user_scripts(
         for script_item in user_scripts:
             if not isinstance(script_item, dict):
                 raise exception.InvalidInput(
-                    reason="Invalid user script list item, expecting dict.")
+                    reason="Invalid user script list item, expecting dict."
+                )
 
             allowed_keys = ["payload", "phase"]
             for key in script_item:
                 if key not in allowed_keys:
                     raise exception.InvalidInput(
-                        reason=(f"Invalid script item key: {key}, "
-                                f"allowed keys: {allowed_keys}"))
+                        reason=(
+                            f"Invalid script item key: {key}, "
+                            f"allowed keys: {allowed_keys}"
+                        )
+                    )
 
             if not script_item.get("phase"):
                 script_item["phase"] = constants.PHASE_OSMORPHING_POST_OS_MOUNT
@@ -134,27 +138,31 @@ def _process_user_scripts(
                 raise exception.InvalidInput(
                     reason=(
                         f"Unknown user script phase: {script_item['phase']}, "
-                        f"supported phases: {constants.USER_SCRIPT_PHASES}."))
+                        f"supported phases: {constants.USER_SCRIPT_PHASES}."
+                    )
+                )
             if "payload" not in script_item:
-                raise exception.InvalidInput(
-                    reason="Missing 'payload' field.")
+                raise exception.InvalidInput(reason="Missing 'payload' field.")
             if not isinstance(script_item["payload"], str):
                 raise exception.InvalidInput(
-                    reason="Invalid payload type, expecting string.")
+                    reason="Invalid payload type, expecting string."
+                )
 
             if sanitize_newlines:
-                script_item["payload"] = _sanitize_newlines(
-                    script_item["payload"])
+                script_item["payload"] = _sanitize_newlines(script_item["payload"])
             if not script_item["payload"].strip("\r\n "):
                 raise exception.InvalidInput(
-                    "Empty script received. "
-                    "Use 'None' if the script should be removed.")
+                    "Empty script received. Use 'None' if the script should be removed."
+                )
 
         return user_scripts
     else:
         raise exception.InvalidInput(
-            reason=("Invalid user script format. Expecting a string or a "
-                    "list of dicts containing the payload and phase."))
+            reason=(
+                "Invalid user script format. Expecting a string or a "
+                "list of dicts containing the payload and phase."
+            )
+        )
 
 
 def validate_user_scripts(user_scripts):
@@ -195,49 +203,55 @@ def validate_user_scripts(user_scripts):
         user_scripts = {}
     if not isinstance(user_scripts, dict):
         raise exception.InvalidInput(
-            reason='"user_scripts" must be of JSON object format')
+            reason='"user_scripts" must be of JSON object format'
+        )
 
     global_scripts = user_scripts.get('global', {})
     if not isinstance(global_scripts, dict):
         raise exception.InvalidInput(
             reason='"global" must be a mapping between the identifiers of the '
-                   'supported OS types and their respective scripts.')
+            'supported OS types and their respective scripts.'
+        )
     for os_type in global_scripts.keys():
         if os_type not in constants.VALID_OS_TYPES:
             raise exception.InvalidInput(
                 reason='The provided global user script os_type "%s" is '
-                       'invalid. Must be one of the '
-                       'following: %s' % (os_type, constants.VALID_OS_TYPES))
+                'invalid. Must be one of the '
+                'following: %s' % (os_type, constants.VALID_OS_TYPES)
+            )
         global_scripts[os_type] = _process_user_scripts(
             global_scripts[os_type],
-            sanitize_newlines=(os_type == constants.OS_TYPE_LINUX))
+            sanitize_newlines=(os_type == constants.OS_TYPE_LINUX),
+        )
 
     instance_scripts = user_scripts.get('instances', {})
     if not isinstance(instance_scripts, dict):
         raise exception.InvalidInput(
             reason='"instances" must be a mapping between the identifiers of '
-                   'the instances in the Replica/Migration and their '
-                   'respective scripts.')
+            'the instances in the Replica/Migration and their '
+            'respective scripts.'
+        )
     for instance_id in instance_scripts:
         # The conductor used to do this, sanitizing newlines regardless
         # of the instance OS types.
         # TODO(lpetrut): consider moving it to the OS morphing side, which
         # has the OS type at hand.
         instance_scripts[instance_id] = _process_user_scripts(
-            instance_scripts[instance_id],
-            sanitize_newlines=True)
+            instance_scripts[instance_id], sanitize_newlines=True
+        )
     return user_scripts
 
 
 def validate_instances_list_for_transfer(instances):
     if not instances:
         raise exception.InvalidInput(
-            "No instance identifiers provided for transfer action.")
+            "No instance identifiers provided for transfer action."
+        )
 
     if not isinstance(instances, list):
         raise exception.InvalidInput(
-            "Instances must be a list. Got type %s: %s" % (
-                type(instances), instances))
+            "Instances must be a list. Got type %s: %s" % (type(instances), instances)
+        )
 
     appearances = {}
     for instance in instances:
@@ -245,11 +259,11 @@ def validate_instances_list_for_transfer(instances):
             appearances[instance] = appearances[instance] + 1
         else:
             appearances[instance] = 1
-    duplicates = {
-        inst: count for (inst, count) in appearances.items() if count > 1}
+    duplicates = {inst: count for (inst, count) in appearances.items() if count > 1}
     if duplicates:
         raise exception.InvalidInput(
-            "Transfer action instances (%s) list contained duplicates: %s " %
-            (instances, duplicates))
+            "Transfer action instances (%s) list contained duplicates: %s "
+            % (instances, duplicates)
+        )
 
     return instances

+ 3 - 3
coriolis/api/v1/views/deployment_view.py

@@ -10,7 +10,8 @@ def _format_deployment(deployment, keys=None):
 
     if len(deployment_dict.get("executions", [])):
         execution = view.format_transfer_tasks_execution(
-            deployment_dict["executions"][0], keys)
+            deployment_dict["executions"][0], keys
+        )
         del deployment_dict["executions"]
     else:
         execution = {}
@@ -27,6 +28,5 @@ def single(deployment, keys=None):
 
 
 def collection(deployments, keys=None):
-    formatted_deployments = [_format_deployment(m, keys)
-                             for m in deployments]
+    formatted_deployments = [_format_deployment(m, keys) for m in deployments]
     return {'deployments': formatted_deployments}

+ 6 - 9
coriolis/api/v1/views/endpoint_options_view.py

@@ -4,26 +4,23 @@
 from coriolis.api.v1.views import utils as view_utils
 
 
-def destination_minion_pool_options_collection(destination_pool_options,
-                                               keys=None):
+def destination_minion_pool_options_collection(destination_pool_options, keys=None):
     formatted_opts = [
-        view_utils.format_opt(opt, keys) for opt in destination_pool_options]
+        view_utils.format_opt(opt, keys) for opt in destination_pool_options
+    ]
     return {'destination_minion_pool_options': formatted_opts}
 
 
 def destination_options_collection(destination_options, keys=None):
-    formatted_opts = [
-        view_utils.format_opt(opt, keys) for opt in destination_options]
+    formatted_opts = [view_utils.format_opt(opt, keys) for opt in destination_options]
     return {'destination_options': formatted_opts}
 
 
 def source_minion_pool_options_collection(source_pool_options, keys=None):
-    formatted_opts = [
-        view_utils.format_opt(opt, keys) for opt in source_pool_options]
+    formatted_opts = [view_utils.format_opt(opt, keys) for opt in source_pool_options]
     return {'source_minion_pool_options': formatted_opts}
 
 
 def source_options_collection(source_options, keys=None):
-    formatted_opts = [
-        view_utils.format_opt(opt, keys) for opt in source_options]
+    formatted_opts = [view_utils.format_opt(opt, keys) for opt in source_options]
     return {'source_options': formatted_opts}

+ 2 - 4
coriolis/api/v1/views/endpoint_resources_view.py

@@ -9,8 +9,7 @@ def instance_single(instance, keys=None):
 
 
 def instances_collection(instances, keys=None):
-    formatted_instances = [view_utils.format_opt(m, keys)
-                           for m in instances]
+    formatted_instances = [view_utils.format_opt(m, keys) for m in instances]
     return {'instances': formatted_instances}
 
 
@@ -19,8 +18,7 @@ def network_single(network, keys=None):
 
 
 def networks_collection(networks, keys=None):
-    formatted_networks = [view_utils.format_opt(m, keys)
-                          for m in networks]
+    formatted_networks = [view_utils.format_opt(m, keys) for m in networks]
     return {'networks': formatted_networks}
 
 

+ 2 - 4
coriolis/api/v1/views/endpoint_view.py

@@ -7,8 +7,7 @@ from coriolis.api.v1.views import utils as view_utils
 def _format_endpoint(endpoint, keys=None):
     endpoint_dict = view_utils.format_opt(endpoint, keys)
     mapped_regions = endpoint_dict.get('mapped_regions', [])
-    endpoint_dict['mapped_regions'] = [
-        reg['id'] for reg in mapped_regions]
+    endpoint_dict['mapped_regions'] = [reg['id'] for reg in mapped_regions]
 
     return endpoint_dict
 
@@ -18,6 +17,5 @@ def single(endpoint, keys=None):
 
 
 def collection(endpoints, keys=None):
-    formatted_endpoints = [_format_endpoint(m, keys)
-                           for m in endpoints]
+    formatted_endpoints = [_format_endpoint(m, keys) for m in endpoints]
     return {'endpoints': formatted_endpoints}

+ 6 - 6
coriolis/api/v1/views/minion_pool_view.py

@@ -17,17 +17,18 @@ def _format_minion_pool(minion_pool, keys=None):
         if minion_conn.get('certificates'):
             for key in minion_conn['certificates']:
                 minion_conn['certificates'][key] = '***'
+
     if 'minion_machines' in minion_pool_dict:
         for machine in minion_pool_dict['minion_machines']:
             if 'connection_info' in machine:
                 _hide_minion_creds(machine['connection_info'])
             if 'backup_writer_connection_info' in machine:
                 if machine.get('backup_writer_connection_info') and (
-                        'connection_details' in machine[
-                            'backup_writer_connection_info']):
+                    'connection_details' in machine['backup_writer_connection_info']
+                ):
                     _hide_minion_creds(
-                        machine['backup_writer_connection_info'][
-                            'connection_details'])
+                        machine['backup_writer_connection_info']['connection_details']
+                    )
 
     return minion_pool_dict
 
@@ -37,6 +38,5 @@ def single(minion_pool, keys=None):
 
 
 def collection(minion_pools, keys=None):
-    formatted_minion_pools = [
-        _format_minion_pool(r, keys) for r in minion_pools]
+    formatted_minion_pools = [_format_minion_pool(r, keys) for r in minion_pools]
     return {'minion_pools': formatted_minion_pools}

+ 3 - 6
coriolis/api/v1/views/region_view.py

@@ -8,12 +8,10 @@ def _format_region(region, keys=None):
     region_dict = view_utils.format_opt(region, keys)
 
     mapped_endpoints = region_dict.get('mapped_endpoints', [])
-    region_dict['mapped_endpoints'] = [
-        endp['id'] for endp in mapped_endpoints]
+    region_dict['mapped_endpoints'] = [endp['id'] for endp in mapped_endpoints]
 
     mapped_services = region_dict.get('mapped_services', [])
-    region_dict['mapped_services'] = [
-        svc['id'] for svc in mapped_services]
+    region_dict['mapped_services'] = [svc['id'] for svc in mapped_services]
 
     return region_dict
 
@@ -23,6 +21,5 @@ def single(region, keys=None):
 
 
 def collection(regions, keys=None):
-    formatted_regions = [
-        _format_region(r, keys) for r in regions]
+    formatted_regions = [_format_region(r, keys) for r in regions]
     return {'regions': formatted_regions}

+ 2 - 4
coriolis/api/v1/views/service_view.py

@@ -8,8 +8,7 @@ def _format_service(service, keys=None):
     service_dict = view_utils.format_opt(service, keys)
 
     mapped_regions = service_dict.get('mapped_regions', [])
-    service_dict['mapped_regions'] = [
-        mapping['id'] for mapping in mapped_regions]
+    service_dict['mapped_regions'] = [mapping['id'] for mapping in mapped_regions]
 
     return service_dict
 
@@ -19,6 +18,5 @@ def single(service, keys=None):
 
 
 def collection(services, keys=None):
-    formatted_services = [
-        _format_service(r, keys) for r in services]
+    formatted_services = [_format_service(r, keys) for r in services]
     return {'services': formatted_services}

+ 1 - 2
coriolis/api/v1/views/transfer_schedule_view.py

@@ -9,6 +9,5 @@ def single(schedule, keys=None):
 
 
 def collection(schedules, keys=None):
-    formatted_schedules = [view_utils.format_opt(m, keys)
-                           for m in schedules]
+    formatted_schedules = [view_utils.format_opt(m, keys) for m in schedules]
     return {'schedules': formatted_schedules}

+ 7 - 9
coriolis/api/v1/views/transfer_tasks_execution_view.py

@@ -4,9 +4,8 @@
 
 from oslo_log import log as logging
 
-from coriolis.api.v1.views import utils as view_utils
 from coriolis import constants
-
+from coriolis.api.v1.views import utils as view_utils
 
 LOG = logging.getLogger(__name__)
 
@@ -18,11 +17,9 @@ def _sort_tasks(tasks, filter_error_only_tasks=True):
     """
     if filter_error_only_tasks:
         tasks = [
-            t for t in tasks
-            if t['status'] != (
-                constants.TASK_STATUS_ON_ERROR_ONLY)]
-    return sorted(
-        tasks, key=lambda t: t.get('index', 0))
+            t for t in tasks if t['status'] != (constants.TASK_STATUS_ON_ERROR_ONLY)
+        ]
+    return sorted(tasks, key=lambda t: t.get('index', 0))
 
 
 def format_transfer_tasks_execution(execution, keys=None):
@@ -39,6 +36,7 @@ def single(execution, keys=None):
 
 
 def collection(executions, keys=None):
-    formatted_executions = [format_transfer_tasks_execution(m, keys)
-                            for m in executions]
+    formatted_executions = [
+        format_transfer_tasks_execution(m, keys) for m in executions
+    ]
     return {'executions': formatted_executions}

+ 2 - 2
coriolis/api/v1/views/transfer_view.py

@@ -10,8 +10,8 @@ def _format_transfer(transfer, keys=None):
 
     executions = transfer_dict.get('executions', [])
     transfer_dict['executions'] = [
-        view.format_transfer_tasks_execution(ex)
-        for ex in executions]
+        view.format_transfer_tasks_execution(ex) for ex in executions
+    ]
 
     return transfer_dict
 

+ 3 - 2
coriolis/api/v1/views/utils.py

@@ -10,5 +10,6 @@ def format_opt(option, keys=None):
             return
         yield (key, value)
 
-    return dict(itertools.chain.from_iterable(
-        transform(k, v) for k, v in option.items()))
+    return dict(
+        itertools.chain.from_iterable(transform(k, v) for k, v in option.items())
+    )

+ 111 - 89
coriolis/api/wsgi.py

@@ -18,17 +18,15 @@ import inspect
 import math
 import time
 
-from oslo_log import log as logging
-from oslo_serialization import jsonutils
-from oslo_utils import excutils
 import six
 import webob
 import webob.dec
+from oslo_log import log as logging
+from oslo_serialization import jsonutils
+from oslo_utils import excutils
 
-from coriolis import exception
-from coriolis import i18n
-from coriolis.i18n import _, _LE, _LI  # noqa
-
+from coriolis import exception, i18n
+from coriolis.i18n import _LE, _LI, _  # noqa
 
 LOG = logging.getLogger(__name__)
 
@@ -228,12 +226,12 @@ class Request(webob.Request):
         self.cache_db_items(self.path, [volume], 'id')
 
     def get_db_volumes(self):
-        return (self.get_db_items('volumes') or
-                self.get_db_items(self.path))
+        return self.get_db_items('volumes') or self.get_db_items(self.path)
 
     def get_db_volume(self, volume_id):
-        return (self.get_db_item('volumes', volume_id) or
-                self.get_db_item(self.path, volume_id))
+        return self.get_db_item('volumes', volume_id) or self.get_db_item(
+            self.path, volume_id
+        )
 
     def cache_db_volume_types(self, volume_types):
         self.cache_db_items('volume_types', volume_types, 'id')
@@ -287,8 +285,9 @@ class Request(webob.Request):
             if not content_type:
                 content_type = self.accept.best_match(SUPPORTED_CONTENT_TYPES)
 
-            self.environ['coriolis.best_content_type'] = (content_type or
-                                                          'application/json')
+            self.environ['coriolis.best_content_type'] = (
+                content_type or 'application/json'
+            )
 
         return self.environ['coriolis.best_content_type']
 
@@ -346,8 +345,10 @@ class Middleware(Application):
         You could of course re-implement the `factory` method in subclasses,
         but using the kwarg passing it shouldn't be necessary.
         """
+
         def _factory(app):
             return cls(app, **local_config)
+
         return _factory
 
     def __init__(self, application):
@@ -399,7 +400,6 @@ class TextDeserializer(ActionDispatcher):
 
 
 class JSONDeserializer(TextDeserializer):
-
     def _from_json(self, datastring):
         try:
             return jsonutils.loads(datastring)
@@ -448,6 +448,7 @@ def serializers(**serializers):
             func.wsgi_serializers = {}
         func.wsgi_serializers.update(serializers)
         return func
+
     return decorator
 
 
@@ -464,6 +465,7 @@ def deserializers(**deserializers):
             func.wsgi_deserializers = {}
         func.wsgi_deserializers.update(deserializers)
         return func
+
     return decorator
 
 
@@ -478,6 +480,7 @@ def response(code):
     def decorator(func):
         func.wsgi_code = code
         return func
+
     return decorator
 
 
@@ -567,8 +570,7 @@ class ResponseObject(object):
         be accessed by extensions for, e.g., template extension.
         """
 
-        mtype, serializer = self.get_serializer(content_type,
-                                                default_serializers)
+        mtype, serializer = self.get_serializer(content_type, default_serializers)
         self.media_type = mtype
         self.serializer = serializer()
 
@@ -588,8 +590,7 @@ class ResponseObject(object):
         if self.serializer:
             serializer = self.serializer
         else:
-            _mtype, _serializer = self.get_serializer(content_type,
-                                                      default_serializers)
+            _mtype, _serializer = self.get_serializer(content_type, default_serializers)
             serializer = _serializer()
 
         response = webob.Response()
@@ -654,13 +655,16 @@ class ResourceExceptionHandler(object):
         if isinstance(ex_value, exception.NotAuthorized):
             raise Fault(webob.exc.HTTPForbidden(explanation=ex_value.msg))
         elif isinstance(ex_value, exception.Invalid):
-            raise Fault(exception.ConvertedException(
-                code=ex_value.code, explanation=ex_value.msg))
+            raise Fault(
+                exception.ConvertedException(
+                    code=ex_value.code, explanation=ex_value.msg
+                )
+            )
         elif isinstance(ex_value, TypeError):
             exc_info = (ex_type, ex_value, ex_traceback)
-            LOG.error(_LE(
-                'Exception handling resource: %s'),
-                ex_value, exc_info=exc_info)
+            LOG.error(
+                _LE('Exception handling resource: %s'), ex_value, exc_info=exc_info
+            )
             raise Fault(webob.exc.HTTPBadRequest())
         elif isinstance(ex_value, Fault):
             LOG.info(_LI("Fault thrown: %s"), ex_value)
@@ -705,8 +709,7 @@ class Resource(Application):
         default_deserializers.update(deserializers)
 
         self.default_deserializers = default_deserializers
-        self.default_serializers = dict(json=JSONDictSerializer,
-                                        csv=CSVSerializer)
+        self.default_serializers = dict(json=JSONDictSerializer, csv=CSVSerializer)
 
         self.action_peek = dict(json=action_peek_json)
         self.action_peek.update(action_peek or {})
@@ -832,8 +835,7 @@ class Resource(Application):
         # Run post-processing in the reverse order
         return None, reversed(post)
 
-    def post_process_extensions(self, extensions, resp_obj, request,
-                                action_args):
+    def post_process_extensions(self, extensions, resp_obj, request, action_args):
         for ext in extensions:
             response = None
             if inspect.isgenerator(ext):
@@ -851,8 +853,7 @@ class Resource(Application):
                 # Regular functions get post-processing...
                 try:
                     with ResourceExceptionHandler():
-                        response = ext(req=request, resp_obj=resp_obj,
-                                       **action_args)
+                        response = ext(req=request, resp_obj=resp_obj, **action_args)
                 except Fault as ex:
                     response = ex
 
@@ -866,9 +867,9 @@ class Resource(Application):
     def __call__(self, request):
         """WSGI method that controls (de)serialization and method dispatch."""
 
-        LOG.info(_LI("%(method)s %(url)s"),
-                 {"method": request.method,
-                  "url": request.url})
+        LOG.info(
+            _LI("%(method)s %(url)s"), {"method": request.method, "url": request.url}
+        )
 
         # Identify the action, its arguments, and the requested
         # content type
@@ -882,17 +883,16 @@ class Resource(Application):
         #            function.  If we try to audit __call__(), we can
         #            run into troubles due to the @webob.dec.wsgify()
         #            decorator.
-        return self._process_stack(request, action, action_args,
-                                   content_type, body, accept)
+        return self._process_stack(
+            request, action, action_args, content_type, body, accept
+        )
 
-    def _process_stack(self, request, action, action_args,
-                       content_type, body, accept):
+    def _process_stack(self, request, action, action_args, content_type, body, accept):
         """Implement the processing stack."""
 
         # Get the implementing method
         try:
-            meth, extensions = self.get_method(request, action,
-                                               content_type, body)
+            meth, extensions = self.get_method(request, action, content_type, body)
         except (AttributeError, TypeError):
             return Fault(webob.exc.HTTPNotFound())
         except KeyError as ex:
@@ -920,13 +920,12 @@ class Resource(Application):
 
         project_id = action_args.pop("project_id", None)
         context = request.environ.get('coriolis.context')
-        if (context and project_id and (project_id != context.project_id)):
+        if context and project_id and (project_id != context.project_id):
             msg = _("Malformed request url")
             return Fault(webob.exc.HTTPBadRequest(explanation=msg))
 
         # Run pre-processing extensions
-        response, post = self.pre_process_extensions(extensions,
-                                                     request, action_args)
+        response, post = self.pre_process_extensions(extensions, request, action_args)
 
         if not response:
             try:
@@ -957,12 +956,12 @@ class Resource(Application):
                 resp_obj.preserialize(accept, self.default_serializers)
 
                 # Process post-processing extensions
-                response = self.post_process_extensions(post, resp_obj,
-                                                        request, action_args)
+                response = self.post_process_extensions(
+                    post, resp_obj, request, action_args
+                )
 
             if resp_obj and not response:
-                response = resp_obj.serialize(request, accept,
-                                              self.default_serializers)
+                response = resp_obj.serialize(request, accept, self.default_serializers)
 
         try:
             msg_dict = dict(url=request.url, status=response.status_int)
@@ -986,10 +985,12 @@ class Resource(Application):
                 meth = getattr(self.controller, action)
         except AttributeError as e:
             with excutils.save_and_reraise_exception(e) as ctxt:
-                if (not self.wsgi_actions or action not in ['action',
-                                                            'create',
-                                                            'delete',
-                                                            'update']):
+                if not self.wsgi_actions or action not in [
+                    'action',
+                    'create',
+                    'delete',
+                    'update',
+                ]:
                     LOG.exception(_LE('Get method error.'))
                 else:
                     ctxt.reraise = False
@@ -1005,8 +1006,10 @@ class Resource(Application):
             action_name = action
 
         # Look up the action method
-        return (self.wsgi_actions[action_name],
-                self.wsgi_action_extensions.get(action_name, []))
+        return (
+            self.wsgi_actions[action_name],
+            self.wsgi_action_extensions.get(action_name, []),
+        )
 
     def dispatch(self, method, request, action_args):
         """Dispatch a call to the action-specific method."""
@@ -1026,6 +1029,7 @@ def action(name):
     def decorator(func):
         func.wsgi_action = name
         return func
+
     return decorator
 
 
@@ -1086,8 +1090,7 @@ class ControllerMetaclass(type):
         cls_dict['wsgi_actions'] = actions
         cls_dict['wsgi_extensions'] = extensions
 
-        return super(ControllerMetaclass, mcs).__new__(mcs, name, bases,
-                                                       cls_dict)
+        return super(ControllerMetaclass, mcs).__new__(mcs, name, bases, cls_dict)
 
 
 @six.add_metaclass(ControllerMetaclass)
@@ -1132,8 +1135,9 @@ class Controller(object):
         #       V2 api 'HTTPBadRequest' exception is getting raised.
         if not Controller.is_valid_body(body, entity_name):
             raise webob.exc.HTTPBadRequest(
-                explanation=_("Missing required element '%s' in "
-                              "request body.") % entity_name)
+                explanation=_("Missing required element '%s' in request body.")
+                % entity_name
+            )
 
     @staticmethod
     def validate_name_and_description(body):
@@ -1142,22 +1146,23 @@ class Controller(object):
             if isinstance(name, six.string_types):
                 body['name'] = name.strip()
             try:
-                _check_string_length(body['name'], 'Name',
-                                     min_length=0, max_length=255)
+                _check_string_length(body['name'], 'Name', min_length=0, max_length=255)
             except exception.InvalidInput as error:
                 raise webob.exc.HTTPBadRequest(explanation=error.msg)
 
         description = body.get('description')
         if description is not None:
             try:
-                _check_string_length(description, 'Description',
-                                     min_length=0, max_length=255)
+                _check_string_length(
+                    description, 'Description', min_length=0, max_length=255
+                )
             except exception.InvalidInput as error:
                 raise webob.exc.HTTPBadRequest(explanation=error.msg)
 
     @staticmethod
-    def validate_string_length(value, entity_name, min_length=0,
-                               max_length=None, remove_whitespaces=False):
+    def validate_string_length(
+        value, entity_name, min_length=0, max_length=None, remove_whitespaces=False
+    ):
         """Check the length of specified string.
 
         :param value: the value of the string
@@ -1170,9 +1175,9 @@ class Controller(object):
         if isinstance(value, six.string_types) and remove_whitespaces:
             value = value.strip()
         try:
-            _check_string_length(value, entity_name,
-                                 min_length=min_length,
-                                 max_length=max_length)
+            _check_string_length(
+                value, entity_name, min_length=min_length, max_length=max_length
+            )
         except exception.InvalidInput as error:
             raise webob.exc.HTTPBadRequest(explanation=error.msg)
 
@@ -1189,17 +1194,24 @@ class Controller(object):
         try:
             value = int(value)
         except (TypeError, ValueError, UnicodeEncodeError):
-            raise webob.exc.HTTPBadRequest(explanation=(
-                _('%s must be an integer.') % name))
+            raise webob.exc.HTTPBadRequest(
+                explanation=(_('%s must be an integer.') % name)
+            )
 
         if min_value is not None and value < min_value:
             raise webob.exc.HTTPBadRequest(
-                explanation=(_('%(value_name)s must be >= %(min_value)d') %
-                             {'value_name': name, 'min_value': min_value}))
+                explanation=(
+                    _('%(value_name)s must be >= %(min_value)d')
+                    % {'value_name': name, 'min_value': min_value}
+                )
+            )
         if max_value is not None and value > max_value:
             raise webob.exc.HTTPBadRequest(
-                explanation=(_('%(value_name)s must be <= %(max_value)d') %
-                             {'value_name': name, 'max_value': max_value}))
+                explanation=(
+                    _('%(value_name)s must be <= %(max_value)d')
+                    % {'value_name': name, 'max_value': max_value}
+                )
+            )
 
         return value
 
@@ -1207,16 +1219,18 @@ class Controller(object):
 class Fault(webob.exc.HTTPException):
     """Wrap webob.exc.HTTPException to provide API friendly response."""
 
-    _fault_names = {400: "badRequest",
-                    401: "unauthorized",
-                    403: "forbidden",
-                    404: "itemNotFound",
-                    405: "badMethod",
-                    409: "conflictingRequest",
-                    413: "overLimit",
-                    415: "badMediaType",
-                    501: "notImplemented",
-                    503: "serviceUnavailable"}
+    _fault_names = {
+        400: "badRequest",
+        401: "unauthorized",
+        403: "forbidden",
+        404: "itemNotFound",
+        405: "badMethod",
+        409: "conflictingRequest",
+        413: "overLimit",
+        415: "badMediaType",
+        501: "notImplemented",
+        503: "serviceUnavailable",
+    }
 
     def __init__(self, exception):
         """Create a Fault for the given webob.exc.exception."""
@@ -1235,7 +1249,9 @@ class Fault(webob.exc.HTTPException):
             'error': {
                 'fault': fault_name,
                 'code': code,
-                'message': i18n.translate(explanation, locale)}}
+                'message': i18n.translate(explanation, locale),
+            }
+        }
         if code == 413:
             retry = self.wrapped_exc.headers.get('Retry-After', None)
             if retry:
@@ -1278,13 +1294,17 @@ def _check_string_length(value, name, min_length=0, max_length=None):
         raise exception.InvalidInput(message=msg)
 
     if len(value) < min_length:
-        msg = _("%(name)s has a minimum character requirement of "
-                "%(min_length)s.") % {'name': name, 'min_length': min_length}
+        msg = _("%(name)s has a minimum character requirement of %(min_length)s.") % {
+            'name': name,
+            'min_length': min_length,
+        }
         raise exception.InvalidInput(message=msg)
 
     if max_length and len(value) > max_length:
-        msg = _("%(name)s has more than %(max_length)s "
-                "characters.") % {'name': name, 'max_length': max_length}
+        msg = _("%(name)s has more than %(max_length)s characters.") % {
+            'name': name,
+            'max_length': max_length,
+        }
         raise exception.InvalidInput(message=msg)
 
 
@@ -1318,10 +1338,12 @@ class OverLimitFault(webob.exc.HTTPException):
             locale = request.best_match_language()
             return i18n.translate(msg, locale)
 
-        self.content['overLimitFault']['message'] = \
-            translate(self.content['overLimitFault']['message'])
-        self.content['overLimitFault']['details'] = \
-            translate(self.content['overLimitFault']['details'])
+        self.content['overLimitFault']['message'] = translate(
+            self.content['overLimitFault']['message']
+        )
+        self.content['overLimitFault']['details'] = translate(
+            self.content['overLimitFault']['details']
+        )
 
         # Error responses are always JSON, regardless of what content
         # type the client requested.

+ 4 - 6
coriolis/cache.py

@@ -1,11 +1,11 @@
 # Copyright 2019 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from coriolis import exception
-
 from oslo_cache import core as cache
 from oslo_config import cfg
 
+from coriolis import exception
+
 opts = [
     cfg.BoolOpt('caching', default=False),
     cfg.IntOpt('cache_time', default=7200),
@@ -20,8 +20,6 @@ cache.configure_cache_region(CONF, cache_region)
 
 def get_cache_decorator(provider):
     if type(provider) is not str or provider == "":
-        raise exception.CoriolisException(
-            "Invalid provider name")
-    MEMOIZE = cache.get_memoization_decorator(
-        CONF, cache_region, provider)
+        raise exception.CoriolisException("Invalid provider name")
+    MEMOIZE = cache.get_memoization_decorator(CONF, cache_region, provider)
     return MEMOIZE

+ 9 - 8
coriolis/cmd/api.py

@@ -8,13 +8,16 @@ from oslo_config import cfg
 from oslo_reports import guru_meditation_report as gmr
 from oslo_reports import opts as gmr_opts
 
-from coriolis import service
-from coriolis import utils
+from coriolis import service, utils
 
 api_opts = [
     cfg.IntOpt(
-        'worker_count', min=1, default=processutils.get_worker_count(),
-        help='Number of processes in which the service will be running')]
+        'worker_count',
+        min=1,
+        default=processutils.get_worker_count(),
+        help='Number of processes in which the service will be running',
+    )
+]
 
 CONF = cfg.CONF
 CONF.register_opts(api_opts, 'api')
@@ -30,10 +33,8 @@ def main():
     gmr_opts.set_defaults(CONF)
     gmr.TextGuruMeditation.setup_autorun(version="1.0.0", conf=CONF)
 
-    server = service.WSGIService(
-        'coriolis-api', worker_count=worker_count)
-    launcher = service.service.launch(
-        CONF, server, workers=server.get_workers_count())
+    server = service.WSGIService('coriolis-api', worker_count=worker_count)
+    launcher = service.service.launch(CONF, server, workers=server.get_workers_count())
     launcher.wait()
 
 

+ 11 - 8
coriolis/cmd/conductor.py

@@ -8,15 +8,17 @@ from oslo_config import cfg
 from oslo_reports import guru_meditation_report as gmr
 from oslo_reports import opts as gmr_opts
 
+from coriolis import constants, service, utils
 from coriolis.conductor.rpc import server as rpc_server
-from coriolis import constants
-from coriolis import service
-from coriolis import utils
 
 conductor_opts = [
     cfg.IntOpt(
-        'worker_count', min=1, default=processutils.get_worker_count(),
-        help='Number of processes in which the service will be running')]
+        'worker_count',
+        min=1,
+        default=processutils.get_worker_count(),
+        help='Number of processes in which the service will be running',
+    )
+]
 
 CONF = cfg.CONF
 CONF.register_opts(conductor_opts, 'conductor')
@@ -36,9 +38,10 @@ def main():
     server = service.MessagingService(
         constants.CONDUCTOR_MAIN_MESSAGING_TOPIC,
         [rpc_server.ConductorServerEndpoint()],
-        rpc_server.VERSION, worker_count=worker_count)
-    launcher = service.service.launch(
-        CONF, server, workers=server.get_workers_count())
+        rpc_server.VERSION,
+        worker_count=worker_count,
+    )
+    launcher = service.service.launch(CONF, server, workers=server.get_workers_count())
     launcher.wait()
 
 

+ 2 - 3
coriolis/cmd/db_sync.py

@@ -5,15 +5,14 @@ import sys
 
 from oslo_config import cfg
 
-from coriolis.db import api as db_api
 from coriolis import utils
+from coriolis.db import api as db_api
 
 CONF = cfg.CONF
 
 
 def main():
-    CONF(sys.argv[1:], project='coriolis',
-         version="1.0.0")
+    CONF(sys.argv[1:], project='coriolis', version="1.0.0")
     utils.setup_logging()
 
     db_api.db_sync(db_api.get_engine())

+ 11 - 8
coriolis/cmd/deployer_manager.py

@@ -7,15 +7,17 @@ from oslo_config import cfg
 from oslo_reports import guru_meditation_report as gmr
 from oslo_reports import opts as gmr_opts
 
-from coriolis import constants
+from coriolis import constants, service, utils
 from coriolis.deployer_manager.rpc import server as rpc_server
-from coriolis import service
-from coriolis import utils
 
 deployer_manager_opts = [
     cfg.IntOpt(
-        'worker_count', min=1, default=1,
-        help="Number of processes in which the service will be running")]
+        'worker_count',
+        min=1,
+        default=1,
+        help="Number of processes in which the service will be running",
+    )
+]
 CONF = cfg.CONF
 CONF.register_opts(deployer_manager_opts, 'deployer_manager')
 
@@ -30,9 +32,10 @@ def main():
     server = service.MessagingService(
         constants.DEPLOYER_MANAGER_MAIN_MESSAGING_TOPIC,
         [rpc_server.DeployerManagerServerEndpoint()],
-        rpc_server.VERSION, worker_count=CONF.deployer_manager.worker_count)
-    launcher = service.service.launch(
-        CONF, server, workers=server.get_workers_count())
+        rpc_server.VERSION,
+        worker_count=CONF.deployer_manager.worker_count,
+    )
+    launcher = service.service.launch(CONF, server, workers=server.get_workers_count())
     launcher.wait()
 
 

+ 12 - 10
coriolis/cmd/minion_manager.py

@@ -7,23 +7,24 @@ from oslo_config import cfg
 from oslo_reports import guru_meditation_report as gmr
 from oslo_reports import opts as gmr_opts
 
-from coriolis import constants
+from coriolis import constants, service, utils
 from coriolis.minion_manager.rpc import server as rpc_server
-from coriolis import service
-from coriolis import utils
 
 minion_manager_opts = [
     cfg.IntOpt(
-        'worker_count', min=1, default=1,
-        help='Number of processes in which the service will be running')]
+        'worker_count',
+        min=1,
+        default=1,
+        help='Number of processes in which the service will be running',
+    )
+]
 
 CONF = cfg.CONF
 CONF.register_opts(minion_manager_opts, 'minion_manager')
 
 
 def main():
-    CONF(sys.argv[1:], project='coriolis',
-         version="1.0.0")
+    CONF(sys.argv[1:], project='coriolis', version="1.0.0")
     utils.setup_logging()
 
     gmr_opts.set_defaults(CONF)
@@ -32,9 +33,10 @@ def main():
     server = service.MessagingService(
         constants.MINION_MANAGER_MAIN_MESSAGING_TOPIC,
         [rpc_server.MinionManagerServerEndpoint()],
-        rpc_server.VERSION, worker_count=CONF.minion_manager.worker_count)
-    launcher = service.service.launch(
-        CONF, server, workers=server.get_workers_count())
+        rpc_server.VERSION,
+        worker_count=CONF.minion_manager.worker_count,
+    )
+    launcher = service.service.launch(CONF, server, workers=server.get_workers_count())
     launcher.wait()
 
 

+ 12 - 10
coriolis/cmd/scheduler.py

@@ -7,23 +7,24 @@ from oslo_config import cfg
 from oslo_reports import guru_meditation_report as gmr
 from oslo_reports import opts as gmr_opts
 
-from coriolis import constants
+from coriolis import constants, service, utils
 from coriolis.scheduler.rpc import server as rpc_server
-from coriolis import service
-from coriolis import utils
 
 scheduler_opts = [
     cfg.IntOpt(
-        'worker_count', min=1, default=1,
-        help='Number of processes in which the service will be running')]
+        'worker_count',
+        min=1,
+        default=1,
+        help='Number of processes in which the service will be running',
+    )
+]
 
 CONF = cfg.CONF
 CONF.register_opts(scheduler_opts, 'scheduler')
 
 
 def main():
-    CONF(sys.argv[1:], project='coriolis',
-         version="1.0.0")
+    CONF(sys.argv[1:], project='coriolis', version="1.0.0")
     utils.setup_logging()
 
     gmr_opts.set_defaults(CONF)
@@ -32,9 +33,10 @@ def main():
     server = service.MessagingService(
         constants.SCHEDULER_MAIN_MESSAGING_TOPIC,
         [rpc_server.SchedulerServerEndpoint()],
-        rpc_server.VERSION, worker_count=CONF.scheduler.worker_count)
-    launcher = service.service.launch(
-        CONF, server, workers=server.get_workers_count())
+        rpc_server.VERSION,
+        worker_count=CONF.scheduler.worker_count,
+    )
+    launcher = service.service.launch(CONF, server, workers=server.get_workers_count())
     launcher.wait()
 
 

+ 6 - 8
coriolis/cmd/transfer_cron.py

@@ -7,17 +7,14 @@ from oslo_config import cfg
 from oslo_reports import guru_meditation_report as gmr
 from oslo_reports import opts as gmr_opts
 
-from coriolis import constants
-from coriolis import service
+from coriolis import constants, service, utils
 from coriolis.transfer_cron.rpc import server as rpc_server
-from coriolis import utils
 
 CONF = cfg.CONF
 
 
 def main():
-    CONF(sys.argv[1:], project='coriolis',
-         version="1.0.0")
+    CONF(sys.argv[1:], project='coriolis', version="1.0.0")
     utils.setup_logging()
 
     gmr_opts.set_defaults(CONF)
@@ -26,9 +23,10 @@ def main():
     server = service.MessagingService(
         constants.TRANSFER_CRON_MAIN_MESSAGING_TOPIC,
         [rpc_server.TransferCronServerEndpoint()],
-        rpc_server.VERSION, worker_count=1)
-    launcher = service.service.launch(
-        CONF, server, workers=server.get_workers_count())
+        rpc_server.VERSION,
+        worker_count=1,
+    )
+    launcher = service.service.launch(CONF, server, workers=server.get_workers_count())
     launcher.wait()
 
 

+ 12 - 8
coriolis/cmd/worker.py

@@ -8,16 +8,18 @@ from oslo_config import cfg
 from oslo_reports import guru_meditation_report as gmr
 from oslo_reports import opts as gmr_opts
 
-from coriolis import constants
+from coriolis import constants, service, utils
 from coriolis.osmorphing.osmount import luks_mixin
-from coriolis import service
-from coriolis import utils
 from coriolis.worker.rpc import server as rpc_server
 
 worker_opts = [
     cfg.IntOpt(
-        'worker_count', min=1, default=processutils.get_worker_count(),
-        help='Number of processes in which the service will be running')]
+        'worker_count',
+        min=1,
+        default=processutils.get_worker_count(),
+        help='Number of processes in which the service will be running',
+    )
+]
 
 CONF = cfg.CONF
 CONF.register_opts(worker_opts, 'worker')
@@ -37,9 +39,11 @@ def main():
     server = service.MessagingService(
         constants.WORKER_MAIN_MESSAGING_TOPIC,
         [rpc_server.WorkerServerEndpoint()],
-        rpc_server.VERSION, worker_count=worker_count, init_rpc=False)
-    launcher = service.service.launch(
-        CONF, server, workers=server.get_workers_count())
+        rpc_server.VERSION,
+        worker_count=worker_count,
+        init_rpc=False,
+    )
+    launcher = service.service.launch(CONF, server, workers=server.get_workers_count())
     launcher.wait()
 
 

+ 403 - 240
coriolis/conductor/rpc/client.py

@@ -1,21 +1,20 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+import oslo_messaging as messaging
 from oslo_config import cfg
 from oslo_log import log as logging
-import oslo_messaging as messaging
 
-from coriolis import constants
-from coriolis import events
-from coriolis import rpc
+from coriolis import constants, events, rpc
 
 VERSION = "1.0"
 LOG = logging.getLogger(__name__)
 
 conductor_opts = [
-    cfg.IntOpt("conductor_rpc_timeout",
-               help="Number of seconds until RPC calls to the "
-                    "conductor timeout.")
+    cfg.IntOpt(
+        "conductor_rpc_timeout",
+        help="Number of seconds until RPC calls to the conductor timeout.",
+    )
 ]
 
 CONF = cfg.CONF
@@ -23,134 +22,165 @@ CONF.register_opts(conductor_opts, 'conductor')
 
 
 class ConductorClient(rpc.BaseRPCClient):
-    def __init__(self, timeout=None,
-                 topic=constants.CONDUCTOR_MAIN_MESSAGING_TOPIC):
+    def __init__(self, timeout=None, topic=constants.CONDUCTOR_MAIN_MESSAGING_TOPIC):
         target = messaging.Target(topic=topic, version=VERSION)
         if timeout is None:
             timeout = CONF.conductor.conductor_rpc_timeout
-        super(ConductorClient, self).__init__(
-            target, timeout=timeout)
+        super(ConductorClient, self).__init__(target, timeout=timeout)
 
-    def create_endpoint(self, ctxt, name, endpoint_type, description,
-                        connection_info, mapped_regions):
+    def create_endpoint(
+        self, ctxt, name, endpoint_type, description, connection_info, mapped_regions
+    ):
         return self._call(
-            ctxt, 'create_endpoint', name=name, endpoint_type=endpoint_type,
-            description=description, connection_info=connection_info,
-            mapped_regions=mapped_regions)
+            ctxt,
+            'create_endpoint',
+            name=name,
+            endpoint_type=endpoint_type,
+            description=description,
+            connection_info=connection_info,
+            mapped_regions=mapped_regions,
+        )
 
     def update_endpoint(self, ctxt, endpoint_id, updated_values):
         return self._call(
-            ctxt, 'update_endpoint',
+            ctxt,
+            'update_endpoint',
             endpoint_id=endpoint_id,
-            updated_values=updated_values)
+            updated_values=updated_values,
+        )
 
     def get_endpoints(self, ctxt):
-        return self._call(
-            ctxt, 'get_endpoints')
+        return self._call(ctxt, 'get_endpoints')
 
     def get_endpoint(self, ctxt, endpoint_id):
-        return self._call(
-            ctxt, 'get_endpoint', endpoint_id=endpoint_id)
+        return self._call(ctxt, 'get_endpoint', endpoint_id=endpoint_id)
 
     def delete_endpoint(self, ctxt, endpoint_id):
-        return self._call(
-            ctxt, 'delete_endpoint', endpoint_id=endpoint_id)
-
-    def get_endpoint_instances(self, ctxt, endpoint_id, source_environment,
-                               marker=None, limit=None,
-                               instance_name_pattern=None, refresh=False):
-        return self._call(
-            ctxt, 'get_endpoint_instances',
+        return self._call(ctxt, 'delete_endpoint', endpoint_id=endpoint_id)
+
+    def get_endpoint_instances(
+        self,
+        ctxt,
+        endpoint_id,
+        source_environment,
+        marker=None,
+        limit=None,
+        instance_name_pattern=None,
+        refresh=False,
+    ):
+        return self._call(
+            ctxt,
+            'get_endpoint_instances',
             endpoint_id=endpoint_id,
             source_environment=source_environment,
             marker=marker,
             limit=limit,
             instance_name_pattern=instance_name_pattern,
-            refresh=refresh)
+            refresh=refresh,
+        )
 
     def get_endpoint_instance(
-            self, ctxt, endpoint_id, source_environment, instance_name):
+        self, ctxt, endpoint_id, source_environment, instance_name
+    ):
         return self._call(
-            ctxt, 'get_endpoint_instance',
+            ctxt,
+            'get_endpoint_instance',
             endpoint_id=endpoint_id,
             source_environment=source_environment,
-            instance_name=instance_name)
+            instance_name=instance_name,
+        )
 
-    def get_endpoint_source_options(
-            self, ctxt, endpoint_id, env, option_names):
+    def get_endpoint_source_options(self, ctxt, endpoint_id, env, option_names):
         return self._call(
-            ctxt, 'get_endpoint_source_options',
+            ctxt,
+            'get_endpoint_source_options',
             endpoint_id=endpoint_id,
-            env=env, option_names=option_names)
+            env=env,
+            option_names=option_names,
+        )
 
-    def get_endpoint_destination_options(
-            self, ctxt, endpoint_id, env, option_names):
+    def get_endpoint_destination_options(self, ctxt, endpoint_id, env, option_names):
         return self._call(
-            ctxt, 'get_endpoint_destination_options',
+            ctxt,
+            'get_endpoint_destination_options',
             endpoint_id=endpoint_id,
-            env=env, option_names=option_names)
+            env=env,
+            option_names=option_names,
+        )
 
     def get_endpoint_networks(self, ctxt, endpoint_id, env):
         return self._call(
-            ctxt, 'get_endpoint_networks',
-            endpoint_id=endpoint_id,
-            env=env)
+            ctxt, 'get_endpoint_networks', endpoint_id=endpoint_id, env=env
+        )
 
     def get_endpoint_storage(self, ctxt, endpoint_id, env):
         return self._call(
-            ctxt, 'get_endpoint_storage',
-            endpoint_id=endpoint_id,
-            env=env)
+            ctxt, 'get_endpoint_storage', endpoint_id=endpoint_id, env=env
+        )
 
-    def get_endpoint_inventory_csv(
-            self, ctxt, endpoint_id, source_environment):
+    def get_endpoint_inventory_csv(self, ctxt, endpoint_id, source_environment):
         return self._call(
-            ctxt, 'get_endpoint_inventory_csv',
+            ctxt,
+            'get_endpoint_inventory_csv',
             endpoint_id=endpoint_id,
-            source_environment=source_environment)
+            source_environment=source_environment,
+        )
 
     def validate_endpoint_connection(self, ctxt, endpoint_id):
-        return self._call(
-            ctxt, 'validate_endpoint_connection',
-            endpoint_id=endpoint_id)
+        return self._call(ctxt, 'validate_endpoint_connection', endpoint_id=endpoint_id)
 
-    def validate_endpoint_target_environment(
-            self, ctxt, endpoint_id, target_env):
+    def validate_endpoint_target_environment(self, ctxt, endpoint_id, target_env):
         return self._call(
-            ctxt, 'validate_endpoint_target_environment',
-            endpoint_id=endpoint_id, target_env=target_env)
+            ctxt,
+            'validate_endpoint_target_environment',
+            endpoint_id=endpoint_id,
+            target_env=target_env,
+        )
 
-    def validate_endpoint_source_environment(
-            self, ctxt, endpoint_id, source_env):
+    def validate_endpoint_source_environment(self, ctxt, endpoint_id, source_env):
         return self._call(
-            ctxt, 'validate_endpoint_source_environment',
-            endpoint_id=endpoint_id, source_env=source_env)
+            ctxt,
+            'validate_endpoint_source_environment',
+            endpoint_id=endpoint_id,
+            source_env=source_env,
+        )
 
     def get_available_providers(self, ctxt):
-        return self._call(
-            ctxt, 'get_available_providers')
+        return self._call(ctxt, 'get_available_providers')
 
     def get_provider_schemas(self, ctxt, platform_name, provider_type):
         return self._call(
-            ctxt, 'get_provider_schemas',
+            ctxt,
+            'get_provider_schemas',
             platform_name=platform_name,
-            provider_type=provider_type)
+            provider_type=provider_type,
+        )
 
-    def execute_transfer_tasks(self, ctxt, transfer_id,
-                               shutdown_instances=False, auto_deploy=False):
+    def execute_transfer_tasks(
+        self, ctxt, transfer_id, shutdown_instances=False, auto_deploy=False
+    ):
         return self._call(
-            ctxt, 'execute_transfer_tasks', transfer_id=transfer_id,
-            shutdown_instances=shutdown_instances, auto_deploy=auto_deploy)
+            ctxt,
+            'execute_transfer_tasks',
+            transfer_id=transfer_id,
+            shutdown_instances=shutdown_instances,
+            auto_deploy=auto_deploy,
+        )
 
-    def get_transfer_tasks_executions(self, ctxt, transfer_id,
-                                      include_tasks=False,
-                                      marker=None,
-                                      limit=None,
-                                      sort_keys=None,
-                                      sort_dirs=None,
-                                      filters=None):
-        return self._call(
-            ctxt, 'get_transfer_tasks_executions',
+    def get_transfer_tasks_executions(
+        self,
+        ctxt,
+        transfer_id,
+        include_tasks=False,
+        marker=None,
+        limit=None,
+        sort_keys=None,
+        sort_dirs=None,
+        filters=None,
+    ):
+        return self._call(
+            ctxt,
+            'get_transfer_tasks_executions',
             transfer_id=transfer_id,
             include_tasks=include_tasks,
             marker=marker,
@@ -160,43 +190,64 @@ class ConductorClient(rpc.BaseRPCClient):
             filters=filters,
         )
 
-    def get_transfer_tasks_execution(self, ctxt, transfer_id, execution_id,
-                                     include_task_info=False):
+    def get_transfer_tasks_execution(
+        self, ctxt, transfer_id, execution_id, include_task_info=False
+    ):
         return self._call(
-            ctxt, 'get_transfer_tasks_execution', transfer_id=transfer_id,
-            execution_id=execution_id, include_task_info=include_task_info)
+            ctxt,
+            'get_transfer_tasks_execution',
+            transfer_id=transfer_id,
+            execution_id=execution_id,
+            include_task_info=include_task_info,
+        )
 
     def delete_transfer_tasks_execution(self, ctxt, transfer_id, execution_id):
         return self._call(
-            ctxt, 'delete_transfer_tasks_execution', transfer_id=transfer_id,
-            execution_id=execution_id)
+            ctxt,
+            'delete_transfer_tasks_execution',
+            transfer_id=transfer_id,
+            execution_id=execution_id,
+        )
 
-    def cancel_transfer_tasks_execution(self, ctxt, transfer_id, execution_id,
-                                        force):
+    def cancel_transfer_tasks_execution(self, ctxt, transfer_id, execution_id, force):
         return self._call(
-            ctxt, 'cancel_transfer_tasks_execution', transfer_id=transfer_id,
-            execution_id=execution_id, force=force)
+            ctxt,
+            'cancel_transfer_tasks_execution',
+            transfer_id=transfer_id,
+            execution_id=execution_id,
+            force=force,
+        )
 
-    def create_instances_transfer(self, ctxt,
-                                  transfer_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,
-                                  notes=None, user_scripts=None,
-                                  clone_disks=True, skip_os_morphing=False):
-        return self._call(
-            ctxt, 'create_instances_transfer',
+    def create_instances_transfer(
+        self,
+        ctxt,
+        transfer_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,
+        notes=None,
+        user_scripts=None,
+        clone_disks=True,
+        skip_os_morphing=False,
+    ):
+        return self._call(
+            ctxt,
+            'create_instances_transfer',
             transfer_scenario=transfer_scenario,
             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),
+                instance_osmorphing_minion_pool_mappings
+            ),
             destination_environment=destination_environment,
             instances=instances,
             notes=notes,
@@ -205,15 +256,23 @@ class ConductorClient(rpc.BaseRPCClient):
             source_environment=source_environment,
             user_scripts=user_scripts,
             clone_disks=clone_disks,
-            skip_os_morphing=skip_os_morphing)
+            skip_os_morphing=skip_os_morphing,
+        )
 
-    def get_transfers(self, ctxt, include_tasks_executions=False,
-                      include_task_info=False,
-                      marker=None, limit=None,
-                      sort_keys=None, sort_dirs=None,
-                      filters=None):
-        return self._call(
-            ctxt, 'get_transfers',
+    def get_transfers(
+        self,
+        ctxt,
+        include_tasks_executions=False,
+        include_task_info=False,
+        marker=None,
+        limit=None,
+        sort_keys=None,
+        sort_dirs=None,
+        filters=None,
+    ):
+        return self._call(
+            ctxt,
+            'get_transfers',
             include_tasks_executions=include_tasks_executions,
             include_task_info=include_task_info,
             marker=marker,
@@ -225,24 +284,33 @@ class ConductorClient(rpc.BaseRPCClient):
 
     def get_transfer(self, ctxt, transfer_id, include_task_info=False):
         return self._call(
-            ctxt, 'get_transfer', transfer_id=transfer_id,
-            include_task_info=include_task_info)
+            ctxt,
+            'get_transfer',
+            transfer_id=transfer_id,
+            include_task_info=include_task_info,
+        )
 
     def delete_transfer(self, ctxt, transfer_id):
-        self._call(
-            ctxt, 'delete_transfer', transfer_id=transfer_id)
+        self._call(ctxt, 'delete_transfer', transfer_id=transfer_id)
 
     def delete_transfer_disks(self, ctxt, transfer_id):
-        return self._call(
-            ctxt, 'delete_transfer_disks', transfer_id=transfer_id)
-
-    def get_deployments(self, ctxt, include_tasks=False,
-                        include_task_info=False,
-                        marker=None, limit=None,
-                        sort_keys=None, sort_dirs=None,
-                        filters=None):
-        return self._call(
-            ctxt, 'get_deployments', include_tasks=include_tasks,
+        return self._call(ctxt, 'delete_transfer_disks', transfer_id=transfer_id)
+
+    def get_deployments(
+        self,
+        ctxt,
+        include_tasks=False,
+        include_task_info=False,
+        marker=None,
+        limit=None,
+        sort_keys=None,
+        sort_dirs=None,
+        filters=None,
+    ):
+        return self._call(
+            ctxt,
+            'get_deployments',
+            include_tasks=include_tasks,
             include_task_info=include_task_info,
             marker=marker,
             limit=limit,
@@ -253,142 +321,192 @@ class ConductorClient(rpc.BaseRPCClient):
 
     def get_deployment(self, ctxt, deployment_id, include_task_info=False):
         return self._call(
-            ctxt, 'get_deployment', deployment_id=deployment_id,
-            include_task_info=include_task_info)
+            ctxt,
+            'get_deployment',
+            deployment_id=deployment_id,
+            include_task_info=include_task_info,
+        )
 
-    def confirm_deployer_completed(
-            self, ctxt, deployment_id, force=False):
+    def confirm_deployer_completed(self, ctxt, deployment_id, force=False):
         return self._cast(
-            ctxt, 'confirm_deployer_completed', deployment_id=deployment_id,
-            force=force)
+            ctxt, 'confirm_deployer_completed', deployment_id=deployment_id, force=force
+        )
 
-    def report_deployer_failure(
-            self, ctxt, deployemnt_id, deployer_error_details):
+    def report_deployer_failure(self, ctxt, deployemnt_id, deployer_error_details):
         return self._cast(
-            ctxt, 'report_deployer_failure', deployment_id=deployemnt_id,
-            deployer_error_details=deployer_error_details)
+            ctxt,
+            'report_deployer_failure',
+            deployment_id=deployemnt_id,
+            deployer_error_details=deployer_error_details,
+        )
 
     def deploy_transfer_instances(
-            self, ctxt, transfer_id, force, wait_for_execution=None,
-            instance_osmorphing_minion_pool_mappings=None, clone_disks=None,
-            skip_os_morphing=None, user_scripts=None, trust_id=None):
-        return self._call(
-            ctxt, 'deploy_transfer_instances', transfer_id=transfer_id,
+        self,
+        ctxt,
+        transfer_id,
+        force,
+        wait_for_execution=None,
+        instance_osmorphing_minion_pool_mappings=None,
+        clone_disks=None,
+        skip_os_morphing=None,
+        user_scripts=None,
+        trust_id=None,
+    ):
+        return self._call(
+            ctxt,
+            'deploy_transfer_instances',
+            transfer_id=transfer_id,
             wait_for_execution=wait_for_execution,
             instance_osmorphing_minion_pool_mappings=(
-                instance_osmorphing_minion_pool_mappings),
-            clone_disks=clone_disks, force=force,
+                instance_osmorphing_minion_pool_mappings
+            ),
+            clone_disks=clone_disks,
+            force=force,
             skip_os_morphing=skip_os_morphing,
-            user_scripts=user_scripts, trust_id=trust_id)
+            user_scripts=user_scripts,
+            trust_id=trust_id,
+        )
 
     def delete_deployment(self, ctxt, deployment_id):
-        self._call(
-            ctxt, 'delete_deployment', deployment_id=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)
+        self._call(ctxt, 'cancel_deployment', deployment_id=deployment_id, force=force)
 
     def set_task_host(self, ctxt, task_id, host):
-        self._call(
-            ctxt, 'set_task_host', task_id=task_id, host=host)
+        self._call(ctxt, 'set_task_host', task_id=task_id, host=host)
 
     def set_task_process(self, ctxt, task_id, process_id):
-        self._call(
-            ctxt, 'set_task_process', task_id=task_id, process_id=process_id)
+        self._call(ctxt, 'set_task_process', task_id=task_id, process_id=process_id)
 
     def task_completed(self, ctxt, task_id, task_result):
-        self._call(
-            ctxt, 'task_completed', task_id=task_id, task_result=task_result)
+        self._call(ctxt, 'task_completed', task_id=task_id, task_result=task_result)
 
     def confirm_task_cancellation(self, ctxt, task_id, cancellation_details):
         self._call(
-            ctxt, 'confirm_task_cancellation', task_id=task_id,
-            cancellation_details=cancellation_details)
+            ctxt,
+            'confirm_task_cancellation',
+            task_id=task_id,
+            cancellation_details=cancellation_details,
+        )
 
     def set_task_error(self, ctxt, task_id, exception_details):
         self._call(
-            ctxt, 'set_task_error', task_id=task_id,
-            exception_details=exception_details)
+            ctxt, 'set_task_error', task_id=task_id, exception_details=exception_details
+        )
 
     def add_task_event(self, ctxt, task_id, level, message):
-        self._cast(ctxt, 'add_task_event', task_id=task_id,
-                   level=level, message=message)
+        self._cast(
+            ctxt, 'add_task_event', task_id=task_id, level=level, message=message
+        )
 
     def add_task_progress_update(
-            self, ctxt, task_id, message, initial_step=0, total_steps=0,
-            return_event=False):
+        self, ctxt, task_id, message, initial_step=0, total_steps=0, return_event=False
+    ):
         operation = self._cast
         if return_event:
             operation = self._call
         return operation(
-            ctxt, 'add_task_progress_update', task_id=task_id,
-            message=message, initial_step=initial_step,
-            total_steps=total_steps)
+            ctxt,
+            'add_task_progress_update',
+            task_id=task_id,
+            message=message,
+            initial_step=initial_step,
+            total_steps=total_steps,
+        )
 
     def update_task_progress_update(
-            self, ctxt, task_id, progress_update_index, new_current_step,
-            new_total_steps=None, new_message=None, sync=False):
+        self,
+        ctxt,
+        task_id,
+        progress_update_index,
+        new_current_step,
+        new_total_steps=None,
+        new_message=None,
+        sync=False,
+    ):
         # Use _call on the last step to make sure the DB is updated
         # and the UI is showing the correct progress.
         # Intermediate steps use cast to avoid blocking on every tick.
         if sync:
             return self._call(
-                ctxt, 'update_task_progress_update', task_id=task_id,
+                ctxt,
+                'update_task_progress_update',
+                task_id=task_id,
                 progress_update_index=progress_update_index,
                 new_current_step=new_current_step,
-                new_total_steps=new_total_steps, new_message=new_message)
+                new_total_steps=new_total_steps,
+                new_message=new_message,
+            )
         return self._cast(
-            ctxt, 'update_task_progress_update', task_id=task_id,
+            ctxt,
+            'update_task_progress_update',
+            task_id=task_id,
             progress_update_index=progress_update_index,
             new_current_step=new_current_step,
-            new_total_steps=new_total_steps, new_message=new_message)
+            new_total_steps=new_total_steps,
+            new_message=new_message,
+        )
 
-    def create_transfer_schedule(self, ctxt, transfer_id,
-                                 schedule, enabled, exp_date,
-                                 shutdown_instance, auto_deploy):
-        return self._call(
-            ctxt, 'create_transfer_schedule',
+    def create_transfer_schedule(
+        self,
+        ctxt,
+        transfer_id,
+        schedule,
+        enabled,
+        exp_date,
+        shutdown_instance,
+        auto_deploy,
+    ):
+        return self._call(
+            ctxt,
+            'create_transfer_schedule',
             transfer_id=transfer_id,
             schedule=schedule,
             enabled=enabled,
             exp_date=exp_date,
             shutdown_instance=shutdown_instance,
-            auto_deploy=auto_deploy)
+            auto_deploy=auto_deploy,
+        )
 
-    def update_transfer_schedule(self, ctxt, transfer_id, schedule_id,
-                                 updated_values):
+    def update_transfer_schedule(self, ctxt, transfer_id, schedule_id, updated_values):
         return self._call(
-            ctxt, 'update_transfer_schedule',
+            ctxt,
+            'update_transfer_schedule',
             transfer_id=transfer_id,
             schedule_id=schedule_id,
-            updated_values=updated_values)
+            updated_values=updated_values,
+        )
 
     def delete_transfer_schedule(self, ctxt, transfer_id, schedule_id):
         return self._call(
-            ctxt, 'delete_transfer_schedule',
+            ctxt,
+            'delete_transfer_schedule',
             transfer_id=transfer_id,
-            schedule_id=schedule_id)
+            schedule_id=schedule_id,
+        )
 
     def get_transfer_schedules(self, ctxt, transfer_id=None, expired=True):
         return self._call(
-            ctxt, 'get_transfer_schedules',
-            transfer_id=transfer_id, expired=expired)
+            ctxt, 'get_transfer_schedules', transfer_id=transfer_id, expired=expired
+        )
 
-    def get_transfer_schedule(self, ctxt, transfer_id,
-                              schedule_id, expired=True):
+    def get_transfer_schedule(self, ctxt, transfer_id, schedule_id, expired=True):
         return self._call(
-            ctxt, 'get_transfer_schedule',
+            ctxt,
+            'get_transfer_schedule',
             transfer_id=transfer_id,
             schedule_id=schedule_id,
-            expired=expired)
+            expired=expired,
+        )
 
     def update_transfer(self, ctxt, transfer_id, updated_properties):
         return self._call(
-            ctxt, 'update_transfer',
+            ctxt,
+            'update_transfer',
             transfer_id=transfer_id,
-            updated_properties=updated_properties)
+            updated_properties=updated_properties,
+        )
 
     def get_diagnostics(self, ctxt):
         return self._call(ctxt, 'get_diagnostics')
@@ -396,87 +514,110 @@ class ConductorClient(rpc.BaseRPCClient):
     def get_all_diagnostics(self, ctxt):
         return self._call(ctxt, 'get_all_diagnostics')
 
-    def create_region(
-            self, ctxt, region_name, description="", enabled=True):
+    def create_region(self, ctxt, region_name, description="", enabled=True):
         return self._call(
-            ctxt, 'create_region',
+            ctxt,
+            'create_region',
             region_name=region_name,
             description=description,
-            enabled=enabled)
+            enabled=enabled,
+        )
 
     def get_regions(self, ctxt):
         return self._call(ctxt, 'get_regions')
 
     def get_region(self, ctxt, region_id):
-        return self._call(
-            ctxt, 'get_region', region_id=region_id)
+        return self._call(ctxt, 'get_region', region_id=region_id)
 
     def update_region(self, ctxt, region_id, updated_values):
         return self._call(
-            ctxt, 'update_region',
-            region_id=region_id,
-            updated_values=updated_values)
+            ctxt, 'update_region', region_id=region_id, updated_values=updated_values
+        )
 
     def delete_region(self, ctxt, region_id):
-        return self._call(
-            ctxt, 'delete_region', region_id=region_id)
+        return self._call(ctxt, 'delete_region', region_id=region_id)
 
     def register_service(
-            self, ctxt, host, binary, topic, enabled, mapped_regions,
-            providers=None, specs=None):
-        return self._call(
-            ctxt, 'register_service', host=host, binary=binary,
-            topic=topic, enabled=enabled, mapped_regions=mapped_regions,
-            providers=providers, specs=specs)
+        self,
+        ctxt,
+        host,
+        binary,
+        topic,
+        enabled,
+        mapped_regions,
+        providers=None,
+        specs=None,
+    ):
+        return self._call(
+            ctxt,
+            'register_service',
+            host=host,
+            binary=binary,
+            topic=topic,
+            enabled=enabled,
+            mapped_regions=mapped_regions,
+            providers=providers,
+            specs=specs,
+        )
 
     def check_service_registered(self, ctxt, host, binary, topic):
         return self._call(
-            ctxt, 'check_service_registered', host=host, binary=binary,
-            topic=topic)
+            ctxt, 'check_service_registered', host=host, binary=binary, topic=topic
+        )
 
     def get_services(self, ctxt):
         return self._call(ctxt, 'get_services')
 
     def get_service(self, ctxt, service_id):
-        return self._call(
-            ctxt, 'get_service', service_id=service_id)
+        return self._call(ctxt, 'get_service', service_id=service_id)
 
     def update_service(self, ctxt, service_id, updated_values):
         return self._call(
-            ctxt, 'update_service', service_id=service_id,
-            updated_values=updated_values)
+            ctxt, 'update_service', service_id=service_id, updated_values=updated_values
+        )
 
     def delete_service(self, ctxt, service_id):
-        return self._call(
-            ctxt, 'delete_service', service_id=service_id)
+        return self._call(ctxt, 'delete_service', service_id=service_id)
 
     def confirm_transfer_minions_allocation(
-            self, ctxt, transfer_id, minion_machine_allocations):
+        self, ctxt, transfer_id, minion_machine_allocations
+    ):
         self._call(
-            ctxt, 'confirm_transfer_minions_allocation',
+            ctxt,
+            'confirm_transfer_minions_allocation',
             transfer_id=transfer_id,
-            minion_machine_allocations=minion_machine_allocations)
+            minion_machine_allocations=minion_machine_allocations,
+        )
 
     def report_transfer_minions_allocation_error(
-            self, ctxt, transfer_id, minion_allocation_error_details):
+        self, ctxt, transfer_id, minion_allocation_error_details
+    ):
         self._call(
-            ctxt, 'report_transfer_minions_allocation_error',
+            ctxt,
+            'report_transfer_minions_allocation_error',
             transfer_id=transfer_id,
-            minion_allocation_error_details=minion_allocation_error_details)
+            minion_allocation_error_details=minion_allocation_error_details,
+        )
 
     def confirm_deployment_minions_allocation(
-            self, ctxt, deployment_id, minion_machine_allocations):
+        self, ctxt, deployment_id, minion_machine_allocations
+    ):
         self._call(
-            ctxt, 'confirm_deployment_minions_allocation',
+            ctxt,
+            'confirm_deployment_minions_allocation',
             deployment_id=deployment_id,
-            minion_machine_allocations=minion_machine_allocations)
+            minion_machine_allocations=minion_machine_allocations,
+        )
 
     def report_deployment_minions_allocation_error(
-            self, ctxt, deployment_id, minion_allocation_error_details):
+        self, ctxt, deployment_id, minion_allocation_error_details
+    ):
         self._call(
-            ctxt, 'report_deployment_minions_allocation_error',
+            ctxt,
+            'report_deployment_minions_allocation_error',
             deployment_id=deployment_id,
-            minion_allocation_error_details=minion_allocation_error_details)
+            minion_allocation_error_details=minion_allocation_error_details,
+        )
 
 
 class ConductorTaskRpcEventHandler(events.BaseEventHandler):
@@ -499,25 +640,47 @@ class ConductorTaskRpcEventHandler(events.BaseEventHandler):
         return progress_update['index']
 
     def add_progress_update(
-            self, message, initial_step=0, total_steps=0, return_event=False):
+        self, message, initial_step=0, total_steps=0, return_event=False
+    ):
         LOG.info(
             "Sending progress update for task '%s' to conductor: %s",
-            self._task_id, message)
+            self._task_id,
+            message,
+        )
         return self._rpc_conductor_client.add_task_progress_update(
-            self._ctxt, self._task_id, message, initial_step=initial_step,
-            total_steps=total_steps, return_event=return_event)
+            self._ctxt,
+            self._task_id,
+            message,
+            initial_step=initial_step,
+            total_steps=total_steps,
+            return_event=return_event,
+        )
 
     def update_progress_update(
-            self, update_identifier, new_current_step,
-            new_total_steps=None, new_message=None, sync=False):
+        self,
+        update_identifier,
+        new_current_step,
+        new_total_steps=None,
+        new_message=None,
+        sync=False,
+    ):
         LOG.info(
             "Updating progress update '%s' for task '%s' with new step %s",
-            update_identifier, self._task_id, new_current_step)
+            update_identifier,
+            self._task_id,
+            new_current_step,
+        )
         self._rpc_conductor_client.update_task_progress_update(
-            self._ctxt, self._task_id, update_identifier, new_current_step,
-            new_total_steps=new_total_steps, new_message=new_message,
-            sync=sync)
+            self._ctxt,
+            self._task_id,
+            update_identifier,
+            new_current_step,
+            new_total_steps=new_total_steps,
+            new_message=new_message,
+            sync=sync,
+        )
 
     def add_event(self, message, level=constants.TASK_EVENT_INFO):
         self._rpc_conductor_client.add_task_event(
-            self._ctxt, self._task_id, level, message)
+            self._ctxt, self._task_id, level, message
+        )

Разница между файлами не показана из-за своего большого размера
+ 352 - 214
coriolis/conductor/rpc/server.py


+ 40 - 17
coriolis/conductor/rpc/utils.py

@@ -7,14 +7,22 @@ from oslo_log import log as logging
 
 from coriolis import utils
 
-
 LOG = logging.getLogger(__name__)
 
 
 def check_create_registration_for_service(
-        conductor_rpc, request_context, host, binary, topic, enabled=False,
-        mapped_regions=None, providers=None, specs=None, retry_period=30):
-    """ Checks with the conductor whether or not a service has already been
+    conductor_rpc,
+    request_context,
+    host,
+    binary,
+    topic,
+    enabled=False,
+    mapped_regions=None,
+    providers=None,
+    specs=None,
+    retry_period=30,
+):
+    """Checks with the conductor whether or not a service has already been
     registered for this host and topic and creates one if not.
     If the service is already registered, directs the conductor to refresh the
     service status.
@@ -25,30 +33,45 @@ def check_create_registration_for_service(
             # check is service already exists:
             LOG.info(
                 "Checking with conductor if service with following porperties "
-                "was already registered: %s", props)
+                "was already registered: %s",
+                props,
+            )
             worker_service = conductor_rpc.check_service_registered(
-                request_context, host, binary, topic)
+                request_context, host, binary, topic
+            )
             if worker_service:
                 LOG.info(
                     "A service with properties %s has already been registered "
                     "under ID '%s'. Updating existing registration.",
-                    props, worker_service['id'])
+                    props,
+                    worker_service['id'],
+                )
                 worker_service = conductor_rpc.update_service(
-                    request_context, worker_service['id'], updated_values={
-                        "providers": providers,
-                        "specs": specs})
+                    request_context,
+                    worker_service['id'],
+                    updated_values={"providers": providers, "specs": specs},
+                )
             else:
                 LOG.debug(
-                    "Attempting to register new service with properties: %s",
-                    props)
+                    "Attempting to register new service with properties: %s", props
+                )
                 worker_service = conductor_rpc.register_service(
-                    request_context, host, binary, topic, enabled,
-                    mapped_regions=mapped_regions, providers=providers,
-                    specs=specs)
+                    request_context,
+                    host,
+                    binary,
+                    topic,
+                    enabled,
+                    mapped_regions=mapped_regions,
+                    providers=providers,
+                    specs=specs,
+                )
             return worker_service
         except Exception:
             LOG.warn(
                 "Failed to register service with specs %s. Retrying again in "
-                "%d seconds. Error was: %s", props, retry_period,
-                utils.get_exception_details())
+                "%d seconds. Error was: %s",
+                props,
+                retry_period,
+                utils.get_exception_details(),
+            )
             time.sleep(retry_period)

+ 5 - 3
coriolis/conf.py

@@ -6,9 +6,11 @@ from oslo_config import cfg
 
 def init_common_opts():
     opts = [
-        cfg.IntOpt('default_requests_timeout',
-                   default=60,
-                   help='Number of seconds for HTTP request timeouts.'),
+        cfg.IntOpt(
+            'default_requests_timeout',
+            default=60,
+            help='Number of seconds for HTTP request timeouts.',
+        ),
     ]
 
     cfg.CONF.register_opts(opts)

+ 61 - 60
coriolis/constants.py

@@ -23,7 +23,7 @@ EXECUTION_STATUS_PENDING = "PENDING"
 ACTIVE_EXECUTION_STATUSES = [
     EXECUTION_STATUS_RUNNING,
     EXECUTION_STATUS_CANCELLING,
-    EXECUTION_STATUS_AWAITING_MINION_ALLOCATIONS
+    EXECUTION_STATUS_AWAITING_MINION_ALLOCATIONS,
 ]
 
 FINALIZED_EXECUTION_STATUSES = [
@@ -32,13 +32,10 @@ FINALIZED_EXECUTION_STATUSES = [
     EXECUTION_STATUS_ERROR,
     EXECUTION_STATUS_CANCELED_FOR_DEBUGGING,
     EXECUTION_STATUS_DEADLOCKED,
-    EXECUTION_STATUS_ERROR_ALLOCATING_MINIONS
+    EXECUTION_STATUS_ERROR_ALLOCATING_MINIONS,
 ]
 
-ALL_EXECUTION_STATUSES = (
-    ACTIVE_EXECUTION_STATUSES +
-    FINALIZED_EXECUTION_STATUSES
-)
+ALL_EXECUTION_STATUSES = ACTIVE_EXECUTION_STATUSES + FINALIZED_EXECUTION_STATUSES
 
 TASK_STATUS_SCHEDULED = "SCHEDULED"
 TASK_STATUS_PENDING = "PENDING"
@@ -65,7 +62,7 @@ ACTIVE_TASK_STATUSES = [
     TASK_STATUS_RUNNING,
     TASK_STATUS_SYNCING,
     TASK_STATUS_CANCELLING,
-    TASK_STATUS_CANCELLING_AFTER_COMPLETION
+    TASK_STATUS_CANCELLING_AFTER_COMPLETION,
 ]
 
 CANCELED_TASK_STATUSES = [
@@ -76,7 +73,7 @@ CANCELED_TASK_STATUSES = [
     TASK_STATUS_CANCELED_FOR_DEBUGGING,
     TASK_STATUS_CANCELED_FROM_DEADLOCK,
     TASK_STATUS_FAILED_TO_SCHEDULE,
-    TASK_STATUS_FAILED_TO_CANCEL
+    TASK_STATUS_FAILED_TO_CANCEL,
 ]
 
 # Statuses that indicate a non-error parent task completed its work and
@@ -99,18 +96,15 @@ FINALIZED_TASK_STATUSES = [
     TASK_STATUS_CANCELED_FROM_DEADLOCK,
     TASK_STATUS_CANCELED_AFTER_COMPLETION,
     TASK_STATUS_FAILED_TO_SCHEDULE,
-    TASK_STATUS_FAILED_TO_CANCEL
+    TASK_STATUS_FAILED_TO_CANCEL,
 ]
 
 ALL_TASK_STATUSES = (
-    ACTIVE_TASK_STATUSES +
-    CANCELED_TASK_STATUSES +
-    FINALIZED_TASK_STATUSES
+    ACTIVE_TASK_STATUSES + CANCELED_TASK_STATUSES + FINALIZED_TASK_STATUSES
 )
 
 TASK_TYPE_FINALIZE_INSTANCE_DEPLOYMENT = "FINALIZE_INSTANCE_DEPLOYMENT"
-TASK_TYPE_CLEANUP_FAILED_INSTANCE_DEPLOYMENT = (
-    "CLEANUP_FAILED_INSTANCE_DEPLOYMENT")
+TASK_TYPE_CLEANUP_FAILED_INSTANCE_DEPLOYMENT = "CLEANUP_FAILED_INSTANCE_DEPLOYMENT"
 
 TASK_TYPE_DEPLOY_OS_MORPHING_RESOURCES = "DEPLOY_OS_MORPHING_RESOURCES"
 TASK_TYPE_OS_MORPHING = "OS_MORPHING"
@@ -119,7 +113,8 @@ TASK_TYPE_DELETE_OS_MORPHING_RESOURCES = "DELETE_OS_MORPHING_RESOURCES"
 TASK_TYPE_GET_INSTANCE_INFO = "GET_INSTANCE_INFO"
 TASK_TYPE_DEPLOY_TRANSFER_DISKS = "DEPLOY_TRANSFER_DISKS"
 TASK_TYPE_DELETE_TRANSFER_SOURCE_DISK_SNAPSHOTS = (
-    "DELETE_TRANSFER_SOURCE_DISK_SNAPSHOTS")
+    "DELETE_TRANSFER_SOURCE_DISK_SNAPSHOTS"
+)
 TASK_TYPE_DELETE_TRANSFER_DISKS = "DELETE_TRANSFER_DISKS"
 TASK_TYPE_REPLICATE_DISKS = "REPLICATE_DISKS"
 TASK_TYPE_DEPLOY_TRANSFER_SOURCE_RESOURCES = "DEPLOY_TRANSFER_SOURCE_RESOURCES"
@@ -130,51 +125,55 @@ TASK_TYPE_SHUTDOWN_INSTANCE = "SHUTDOWN_INSTANCE"
 TASK_TYPE_DEPLOY_INSTANCE_RESOURCES = "DEPLOY_INSTANCE_RESOURCES"
 TASK_TYPE_CREATE_TRANSFER_DISK_SNAPSHOTS = "CREATE_TRANSFER_DISK_SNAPSHOTS"
 TASK_TYPE_DELETE_TRANSFER_TARGET_DISK_SNAPSHOTS = (
-    "DELETE_TRANSFER_TARGET_DISK_SNAPSHOTS")
+    "DELETE_TRANSFER_TARGET_DISK_SNAPSHOTS"
+)
 TASK_TYPE_RESTORE_TRANSFER_DISK_SNAPSHOTS = "RESTORE_TRANSFER_DISK_SNAPSHOTS"
 TASK_TYPE_GET_OPTIMAL_FLAVOR = "GET_OPTIMAL_FLAVOR"
 TASK_TYPE_VALIDATE_TRANSFER_SOURCE_INPUTS = "VALIDATE_TRANSFER_SOURCE_INPUTS"
-TASK_TYPE_VALIDATE_TRANSFER_DESTINATION_INPUTS = (
-    "VALIDATE_TRANSFER_DESTINATION_INPUTS")
+TASK_TYPE_VALIDATE_TRANSFER_DESTINATION_INPUTS = "VALIDATE_TRANSFER_DESTINATION_INPUTS"
 TASK_TYPE_VALIDATE_DEPLOYMENT_INPUTS = "VALIDATE_DEPLOYMENT_INPUTS"
 TASK_TYPE_UPDATE_SOURCE_TRANSFER = "UPDATE_SOURCE_TRANSFER"
 TASK_TYPE_UPDATE_DESTINATION_TRANSFER = "UPDATE_DESTINATION_TRANSFER"
 
 TASK_TYPE_VALIDATE_SOURCE_MINION_POOL_OPTIONS = (
-    "VALIDATE_SOURCE_MINION_POOL_ENVIRONMENT_OPTIONS")
+    "VALIDATE_SOURCE_MINION_POOL_ENVIRONMENT_OPTIONS"
+)
 TASK_TYPE_VALIDATE_DESTINATION_MINION_POOL_OPTIONS = (
-    "VALIDATE_DESTINATION_MINION_POOL_ENVIRONMENT_OPTIONS")
+    "VALIDATE_DESTINATION_MINION_POOL_ENVIRONMENT_OPTIONS"
+)
 TASK_TYPE_CREATE_SOURCE_MINION_MACHINE = "CREATE_SOURCE_MINION_MACHINE"
-TASK_TYPE_CREATE_DESTINATION_MINION_MACHINE = (
-    "CREATE_DESTINATION_MINION_MACHINE")
+TASK_TYPE_CREATE_DESTINATION_MINION_MACHINE = "CREATE_DESTINATION_MINION_MACHINE"
 TASK_TYPE_DELETE_SOURCE_MINION_MACHINE = "DELETE_SOURCE_MINION_MACHINE"
-TASK_TYPE_DELETE_DESTINATION_MINION_MACHINE = (
-    "DELETE_DESTINATION_MINION_MACHINE")
-TASK_TYPE_SET_UP_SOURCE_POOL_SHARED_RESOURCES = (
-    "SET_UP_SOURCE_POOL_SHARED_RESOURCES")
+TASK_TYPE_DELETE_DESTINATION_MINION_MACHINE = "DELETE_DESTINATION_MINION_MACHINE"
+TASK_TYPE_SET_UP_SOURCE_POOL_SHARED_RESOURCES = "SET_UP_SOURCE_POOL_SHARED_RESOURCES"
 TASK_TYPE_SET_UP_DESTINATION_POOL_SHARED_RESOURCES = (
-    "SET_UP_DESTINATION_POOL_SHARED_RESOURCES")
+    "SET_UP_DESTINATION_POOL_SHARED_RESOURCES"
+)
 TASK_TYPE_TEAR_DOWN_SOURCE_POOL_SHARED_RESOURCES = (
-    "TEAR_DOWN_SOURCE_POOL_SHARED_RESOURCES")
+    "TEAR_DOWN_SOURCE_POOL_SHARED_RESOURCES"
+)
 TASK_TYPE_TEAR_DOWN_DESTINATION_POOL_SHARED_RESOURCES = (
-    "TEAR_DOWN_DESTINATION_POOL_SHARED_RESOURCES")
+    "TEAR_DOWN_DESTINATION_POOL_SHARED_RESOURCES"
+)
 TASK_TYPE_ATTACH_VOLUMES_TO_SOURCE_MINION = "ATTACH_VOLUMES_TO_SOURCE_MINION"
-TASK_TYPE_DETACH_VOLUMES_FROM_SOURCE_MINION = (
-    "DETACH_VOLUMES_FROM_SOURCE_MINION")
-TASK_TYPE_ATTACH_VOLUMES_TO_DESTINATION_MINION = (
-    "ATTACH_VOLUMES_TO_DESTINATION_MINION")
+TASK_TYPE_DETACH_VOLUMES_FROM_SOURCE_MINION = "DETACH_VOLUMES_FROM_SOURCE_MINION"
+TASK_TYPE_ATTACH_VOLUMES_TO_DESTINATION_MINION = "ATTACH_VOLUMES_TO_DESTINATION_MINION"
 TASK_TYPE_DETACH_VOLUMES_FROM_DESTINATION_MINION = (
-    "DETACH_VOLUMES_FROM_DESTINATION_MINION")
-TASK_TYPE_ATTACH_VOLUMES_TO_OSMORPHING_MINION = (
-    "ATTACH_VOLUMES_TO_OSMORPHING_MINION")
+    "DETACH_VOLUMES_FROM_DESTINATION_MINION"
+)
+TASK_TYPE_ATTACH_VOLUMES_TO_OSMORPHING_MINION = "ATTACH_VOLUMES_TO_OSMORPHING_MINION"
 TASK_TYPE_DETACH_VOLUMES_FROM_OSMORPHING_MINION = (
-    "DETACH_VOLUMES_FROM_OSMORPHING_MINION")
+    "DETACH_VOLUMES_FROM_OSMORPHING_MINION"
+)
 TASK_TYPE_VALIDATE_SOURCE_MINION_POOL_COMPATIBILITY = (
-    "VALIDATE_SOURCE_MINION_POOL_COMPATIBILITY")
+    "VALIDATE_SOURCE_MINION_POOL_COMPATIBILITY"
+)
 TASK_TYPE_VALIDATE_DESTINATION_MINION_POOL_COMPATIBILITY = (
-    "VALIDATE_DESTINATION_MINION_POOL_COMPATIBILITY")
+    "VALIDATE_DESTINATION_MINION_POOL_COMPATIBILITY"
+)
 TASK_TYPE_VALIDATE_OSMORPHING_MINION_POOL_COMPATIBILITY = (
-    "VALIDATE_OSMORPHING_MINION_POOL_COMPATIBILITY")
+    "VALIDATE_OSMORPHING_MINION_POOL_COMPATIBILITY"
+)
 TASK_TYPE_RELEASE_SOURCE_MINION = "RELEASE_SOURCE_MINION"
 TASK_TYPE_RELEASE_DESTINATION_MINION = "RELEASE_DESTINATION_MINION"
 TASK_TYPE_RELEASE_OSMORPHING_MINION = "RELEASE_OSMORPHING_MINION"
@@ -207,7 +206,7 @@ MINION_POOL_OPERATIONS_TASKS = [
     TASK_TYPE_POWER_ON_SOURCE_MINION,
     TASK_TYPE_POWER_OFF_SOURCE_MINION,
     TASK_TYPE_POWER_ON_DESTINATION_MINION,
-    TASK_TYPE_POWER_OFF_DESTINATION_MINION
+    TASK_TYPE_POWER_OFF_DESTINATION_MINION,
 ]
 
 TASK_PLATFORM_SOURCE = "source"
@@ -280,8 +279,13 @@ OS_TYPE_UNKNOWN = "unknown"
 
 DEFAULT_OS_TYPE = OS_TYPE_LINUX
 
-VALID_OS_TYPES = [OS_TYPE_BSD, OS_TYPE_LINUX,
-                  OS_TYPE_OS_X, OS_TYPE_SOLARIS, OS_TYPE_WINDOWS]
+VALID_OS_TYPES = [
+    OS_TYPE_BSD,
+    OS_TYPE_LINUX,
+    OS_TYPE_OS_X,
+    OS_TYPE_SOLARIS,
+    OS_TYPE_WINDOWS,
+]
 
 PROTOCOL_SSH = "ssh"
 # WinRM is the Microsoft implementation of WSMAN.
@@ -292,10 +296,7 @@ TMP_DIRS_KEY = "__tmp_dirs"
 COMPRESSION_FORMAT_GZIP = "gzip"
 COMPRESSION_FORMAT_ZLIB = "zlib"
 
-VALID_COMPRESSION_FORMATS = [
-    COMPRESSION_FORMAT_GZIP,
-    COMPRESSION_FORMAT_ZLIB
-]
+VALID_COMPRESSION_FORMATS = [COMPRESSION_FORMAT_GZIP, COMPRESSION_FORMAT_ZLIB]
 
 TRANSFER_ACTION_TYPE_DEPLOYMENT = "deployment"
 TRANSFER_ACTION_TYPE_TRANSFER = "transfer"
@@ -307,12 +308,13 @@ EXECUTION_TYPE_TRANSFER_UPDATE = "transfer_update"
 EXECUTION_TYPE_MINION_POOL_MAINTENANCE = "minion_pool_maintenance"
 EXECUTION_TYPE_MINION_POOL_UPDATE = "minion_pool_update"
 EXECUTION_TYPE_MINION_POOL_SET_UP_SHARED_RESOURCES = (
-    "minion_pool_set_up_shared_resources")
+    "minion_pool_set_up_shared_resources"
+)
 EXECUTION_TYPE_MINION_POOL_TEAR_DOWN_SHARED_RESOURCES = (
-    "minion_pool_tear_down_shared_resources")
+    "minion_pool_tear_down_shared_resources"
+)
 EXECUTION_TYPE_MINION_POOL_ALLOCATE_MINIONS = "minion_pool_allocate_minions"
-EXECUTION_TYPE_MINION_POOL_DEALLOCATE_MINIONS = (
-    "minion_pool_deallocate_minions")
+EXECUTION_TYPE_MINION_POOL_DEALLOCATE_MINIONS = "minion_pool_deallocate_minions"
 
 TASK_LOCK_NAME_FORMAT = "task-%s"
 TASKFLOW_LOCK_NAME_FORMAT = "taskflow-%s"
@@ -333,12 +335,12 @@ EXECUTION_TYPE_TO_ACTION_LOCK_NAME_FORMAT_MAP = {
     EXECUTION_TYPE_TRANSFER_DISKS_DELETE: TRANSFER_LOCK_NAME_FORMAT,
     EXECUTION_TYPE_MINION_POOL_MAINTENANCE: MINION_POOL_LOCK_NAME_FORMAT,
     EXECUTION_TYPE_MINION_POOL_UPDATE: MINION_POOL_LOCK_NAME_FORMAT,
-    EXECUTION_TYPE_MINION_POOL_SET_UP_SHARED_RESOURCES: (
-        MINION_POOL_LOCK_NAME_FORMAT),
+    EXECUTION_TYPE_MINION_POOL_SET_UP_SHARED_RESOURCES: (MINION_POOL_LOCK_NAME_FORMAT),
     EXECUTION_TYPE_MINION_POOL_TEAR_DOWN_SHARED_RESOURCES: (
-        MINION_POOL_LOCK_NAME_FORMAT),
+        MINION_POOL_LOCK_NAME_FORMAT
+    ),
     EXECUTION_TYPE_MINION_POOL_ALLOCATE_MINIONS: MINION_POOL_LOCK_NAME_FORMAT,
-    EXECUTION_TYPE_MINION_POOL_DEALLOCATE_MINIONS: MINION_POOL_LOCK_NAME_FORMAT
+    EXECUTION_TYPE_MINION_POOL_DEALLOCATE_MINIONS: MINION_POOL_LOCK_NAME_FORMAT,
 }
 
 SERVICE_STATUS_UP = "UP"
@@ -363,8 +365,7 @@ MINION_POOL_STATUS_VALIDATING_INPUTS = "VALIDATING_INPUTS"
 MINION_POOL_STATUS_ALLOCATING_SHARED_RESOURCES = "ALLOCATING_SHARED_RESOURCES"
 MINION_POOL_STATUS_ALLOCATING_MACHINES = "ALLOCATING_MACHINES"
 MINION_POOL_STATUS_DEALLOCATING_MACHINES = "DEALLOCATING_MACHINES"
-MINION_POOL_STATUS_DEALLOCATING_SHARED_RESOURCES = (
-    "DEALLOCATING_SHARED_RESOURCES")
+MINION_POOL_STATUS_DEALLOCATING_SHARED_RESOURCES = "DEALLOCATING_SHARED_RESOURCES"
 MINION_POOL_STATUS_ALLOCATED = "ALLOCATED"
 MINION_POOL_STATUS_POOL_MAINTENANCE = "IN_MAINTENANCE"
 
@@ -373,10 +374,10 @@ ACTIVE_MINION_POOL_STATUSES = [
     MINION_POOL_STATUS_ALLOCATING_SHARED_RESOURCES,
     MINION_POOL_STATUS_ALLOCATING_MACHINES,
     MINION_POOL_STATUS_DEALLOCATING_MACHINES,
-    MINION_POOL_STATUS_DEALLOCATING_SHARED_RESOURCES]
+    MINION_POOL_STATUS_DEALLOCATING_SHARED_RESOURCES,
+]
 
-MINION_MACHINE_IDENTIFIER_FORMAT = (
-    "coriolis-pool-%(pool_id)s-minion-%(minion_id)s")
+MINION_MACHINE_IDENTIFIER_FORMAT = "coriolis-pool-%(pool_id)s-minion-%(minion_id)s"
 MINION_MACHINE_STATUS_UNINITIALIZED = "UNINITIALIZED"
 MINION_MACHINE_STATUS_HEALTHCHECKING = "HEALTHCHECKING"
 MINION_MACHINE_STATUS_ALLOCATING = "ALLOCATING"

+ 40 - 23
coriolis/context.py

@@ -7,30 +7,50 @@ from oslo_context import context
 from oslo_db.sqlalchemy import enginefacade
 from oslo_utils import timeutils
 
-from coriolis import exception
-from coriolis import policy
+from coriolis import exception, policy
 
 
 @enginefacade.transaction_context_provider
 class RequestContext(context.RequestContext):
-    def __init__(self, user, project_id, is_admin=None,
-                 roles=None, project_name=None, remote_address=None,
-                 timestamp=None, request_id=None, auth_token=None,
-                 overwrite=True, domain_name=None, domain_id=None,
-                 user_domain_name=None, user_domain_id=None,
-                 project_domain_name=None, project_domain_id=None,
-                 show_deleted=None, trust_id=None,
-                 delete_trust_id=False, **kwargs):
+    def __init__(
+        self,
+        user,
+        project_id,
+        is_admin=None,
+        roles=None,
+        project_name=None,
+        remote_address=None,
+        timestamp=None,
+        request_id=None,
+        auth_token=None,
+        overwrite=True,
+        domain_name=None,
+        domain_id=None,
+        user_domain_name=None,
+        user_domain_id=None,
+        project_domain_name=None,
+        project_domain_id=None,
+        show_deleted=None,
+        trust_id=None,
+        delete_trust_id=False,
+        **kwargs,
+    ):
 
-        super(
-            RequestContext, self).__init__(
-            auth_token=auth_token, user=user, project_id=project_id,
-            domain_name=domain_name, domain_id=domain_id,
-            user_domain_name=user_domain_name, user_domain_id=user_domain_id,
+        super(RequestContext, self).__init__(
+            auth_token=auth_token,
+            user=user,
+            project_id=project_id,
+            domain_name=domain_name,
+            domain_id=domain_id,
+            user_domain_name=user_domain_name,
+            user_domain_id=user_domain_id,
             project_domain_name=(project_domain_name),
             project_domain_id=(project_domain_id),
-            is_admin=is_admin, show_deleted=show_deleted,
-            request_id=request_id, overwrite=overwrite)
+            is_admin=is_admin,
+            show_deleted=show_deleted,
+            request_id=request_id,
+            overwrite=overwrite,
+        )
         self.roles = roles or []
         self.project_name = project_name
         self.remote_address = remote_address
@@ -73,11 +93,10 @@ class RequestContext(context.RequestContext):
         return policy
 
     def can(self, action, target=None, fatal=True):
-        """ Validates policies allow the requested action to be
+        """Validates policies allow the requested action to be
         perfomed in the given context, and raises otherwise.
         """
-        default_target = {
-            'project_id': self.project_id, 'user_id': self.user_id}
+        default_target = {'project_id': self.project_id, 'user_id': self.user_id}
         if target is None:
             target = default_target
         else:
@@ -95,6 +114,4 @@ class RequestContext(context.RequestContext):
 
 
 def get_admin_context(trust_id=None):
-    return RequestContext(
-        user=None, project_id=None, is_admin=True,
-        trust_id=trust_id)
+    return RequestContext(user=None, project_id=None, is_admin=True, trust_id=trust_id)

+ 46 - 35
coriolis/cron/cron.py

@@ -4,14 +4,11 @@ import sys
 import threading
 import time
 
+import schedule
 from oslo_log import log
 from oslo_utils import timeutils
-import schedule
-
-from coriolis import exception
-from coriolis import schemas
-from coriolis import utils
 
+from coriolis import exception, schemas, utils
 
 LOG = log.getLogger(__name__)
 
@@ -19,10 +16,19 @@ SCHEDULE_FIELDS = ("minute", "hour", "dom", "month", "dow")
 
 
 class CronJob(object):
-
-    def __init__(self, name, description, schedule, enabled,
-                 expires, on_success, on_error,
-                 job_callable, *args, **kw):
+    def __init__(
+        self,
+        name,
+        description,
+        schedule,
+        enabled,
+        expires,
+        on_success,
+        on_error,
+        job_callable,
+        *args,
+        **kw,
+    ):
         # param: name: string: unique ID that describes this job
         # param: description: string: a short description of the job
         # param: schedule: dict: cron job schedule. This is of the form:
@@ -71,8 +77,7 @@ class CronJob(object):
         self._enabled = enabled
         if expires:
             if not isinstance(expires, datetime.datetime):
-                raise exception.CoriolisException(
-                    "Invalid expires")
+                raise exception.CoriolisException("Invalid expires")
         self._expires = expires
 
     def _compare(self, pairs):
@@ -105,12 +110,10 @@ class CronJob(object):
             LOG.debug('Job %s is not enabled', self.name)
             return False
 
-        fields = ('year', 'month', 'dom', 'hour',
-                  'minute', 'second', 'dow')
+        fields = ('year', 'month', 'dom', 'hour', 'minute', 'second', 'dow')
         dt_fields = dict(zip(fields, dt.timetuple()))
 
-        pairs = [(dt_fields[i], self.schedule.get(i))
-                 for i in SCHEDULE_FIELDS]
+        pairs = [(dt_fields[i], self.schedule.get(i)) for i in SCHEDULE_FIELDS]
         compared = self._compare(pairs)
         return False not in compared
 
@@ -136,14 +139,16 @@ class CronJob(object):
                     LOG.exception(callback_err)
         self._send_status(
             status_queue,
-            {"result": result,
-             "description": self._description,
-             "name": self.name,
-             "error_info": exc_info})
+            {
+                "result": result,
+                "description": self._description,
+                "name": self.name,
+                "error_info": exc_info,
+            },
+        )
 
 
 class Cron(object):
-
     def __init__(self):
         self._queue = queue.Queue(maxsize=1000)
         self._should_stop = False
@@ -167,13 +172,14 @@ class Cron(object):
                 del self._jobs[name]
 
     def unregister_jobs_with_prefix(self, prefix):
-        jobs = [
-            job for job in self._jobs
-            if job.startswith(prefix)]
+        jobs = [job for job in self._jobs if job.startswith(prefix)]
         if jobs:
             LOG.debug(
                 "Unregistering the following cron jobs based on "
-                "the requested prefix ('%s'): %s", prefix, jobs)
+                "the requested prefix ('%s'): %s",
+                prefix,
+                jobs,
+            )
             with self._semaphore:
                 for job in jobs:
                     del self._jobs[job]
@@ -186,8 +192,11 @@ class Cron(object):
         now = timeutils.utcnow()
         if job_nr:
             for job in jobs:
-                LOG.debug('Checking job %s with schedule: %s', jobs[job].name,
-                          jobs[job].schedule)
+                LOG.debug(
+                    'Checking job %s with schedule: %s',
+                    jobs[job].name,
+                    jobs[job].schedule,
+                )
                 if jobs[job].should_run(now):
                     LOG.debug("Spawning job %s" % job)
                     utils.start_thread(jobs[job].start, args=[self._queue])
@@ -195,14 +204,15 @@ class Cron(object):
 
         done = timeutils.utcnow()
         delta = done - now
-        LOG.debug("Spawned %(jobs)d jobs in %(seconds)d seconds" % {
-            "seconds": delta.seconds,
-            "jobs": spawned})
+        LOG.debug(
+            "Spawned %(jobs)d jobs in %(seconds)d seconds"
+            % {"seconds": delta.seconds, "jobs": spawned}
+        )
 
     def _loop(self):
         while not self._should_stop:
             schedule.run_pending()
-            time.sleep(.2)
+            time.sleep(0.2)
 
     def _result_loop(self):
         while not self._should_stop:
@@ -214,12 +224,13 @@ class Cron(object):
             # the logs table...or do something much more meaningful
             if error:
                 LOG.error(
-                    "Job %(job_desc)s exited with error: %(job_err)r" %
-                    {"job_desc": desc, "job_err": error})
+                    "Job %(job_desc)s exited with error: %(job_err)r"
+                    % {"job_desc": desc, "job_err": error}
+                )
             if result:
-                LOG.info("Job %(desc)s returned: %(ret)r" % {
-                    "desc": desc,
-                    "ret": result})
+                LOG.info(
+                    "Job %(desc)s returned: %(ret)r" % {"desc": desc, "ret": result}
+                )
 
     def _janitor(self):
         # remove expired jobs from memory. The check for expired

+ 34 - 30
coriolis/data_transfer.py

@@ -6,24 +6,24 @@ import os
 import stat
 import struct
 import zlib
+from urllib import parse
 
 import requests
 import requests_unixsocket
-
 from oslo_config import cfg
 from oslo_log import log as logging
-from urllib import parse
 
-from coriolis import constants
-from coriolis import exception
+from coriolis import constants, exception
 
 compressor_opts = [
-    cfg.StrOpt('compressor_address',
-               default=None,
-               help='Compressor address. If set, all gzip/zlib compression '
-                    'will be done through this service. This value can be '
-                    'either a unix socket path (/var/run/compressor.sock '
-                    'or an IP:PORT.'),
+    cfg.StrOpt(
+        'compressor_address',
+        default=None,
+        help='Compressor address. If set, all gzip/zlib compression '
+        'will be done through this service. This value can be '
+        'either a unix socket path (/var/run/compressor.sock '
+        'or an IP:PORT.',
+    ),
 ]
 
 CONF = cfg.CONF
@@ -46,22 +46,26 @@ def _get_session_and_address():
         if os.path.exists(CONF.compressor_address):
             mode = os.stat(CONF.compressor_address).st_mode
             if stat.S_ISSOCK(mode):
-                return (requests_unixsocket.Session(),
-                        "http+unix://%s/" % parse.quote_plus(
-                            CONF.compressor_address))
+                return (
+                    requests_unixsocket.Session(),
+                    "http+unix://%s/" % parse.quote_plus(CONF.compressor_address),
+                )
             else:
                 raise exception.CoriolisException(
-                    "compressor_address is not a valid unix socket")
+                    "compressor_address is not a valid unix socket"
+                )
         else:
             raise exception.CoriolisException(
-                "compressor_address is not a valid unix socket")
+                "compressor_address is not a valid unix socket"
+            )
     return (requests.Session(), "http://%s/" % CONF.compressor_address)
 
 
 def compression_proxy(content, fmt):
     if fmt not in constants.VALID_COMPRESSION_FORMATS:
         raise exception.CoriolisException(
-            "Invalid compression format requested: %s" % fmt)
+            "Invalid compression format requested: %s" % fmt
+        )
     data = content
     sess, url = _get_session_and_address()
     if None in (sess, url):
@@ -71,13 +75,13 @@ def compression_proxy(content, fmt):
             headers = {
                 "X-Compression-Format": fmt,
             }
-            ret = sess.post(url, data=data, headers=headers,
-                            timeout=CONF.default_requests_timeout)
+            ret = sess.post(
+                url, data=data, headers=headers, timeout=CONF.default_requests_timeout
+            )
             ret.raise_for_status()
             compressed_data = ret.content
         except Exception as err:
-            LOG.exception(
-                "failed to compress using coriolis-compressor: %s" % err)
+            LOG.exception("failed to compress using coriolis-compressor: %s" % err)
             LOG.info("falling back to built-in compressor")
             compressed_data = _COMPRESS_FUNC[fmt](content)
         finally:
@@ -86,8 +90,7 @@ def compression_proxy(content, fmt):
     data_len = len(compressed_data)
     data_len_inflated = len(data)
     compression_saving = 100.0 * (1 - float(data_len) / data_len_inflated)
-    LOG.debug("Compression space saving: {:.02f}%".format(
-        compression_saving))
+    LOG.debug("Compression space saving: {:.02f}%".format(compression_saving))
 
     if data_len >= data_len_inflated:
         # No advantage in sending the compressed data
@@ -99,16 +102,15 @@ def compression_proxy(content, fmt):
 
 
 def encode_data(msg_id, path, offset, content, compress=True):
-    inflated_content = (path.encode() + b'\0' +
-                        struct.pack("<Q", offset) +
-                        content)
+    inflated_content = path.encode() + b'\0' + struct.pack("<Q", offset) + content
 
     data_len_inflated = len(inflated_content)
 
     compressed = False
     if compress:
         data_content, compressed = compression_proxy(
-            inflated_content, constants.COMPRESSION_FORMAT_ZLIB)
+            inflated_content, constants.COMPRESSION_FORMAT_ZLIB
+        )
         data_len = len(data_content)
 
     if not compressed:
@@ -116,10 +118,12 @@ def encode_data(msg_id, path, offset, content, compress=True):
         data_len_inflated = 0
         data_content = inflated_content
 
-    return (struct.pack("<I", msg_id) +
-            struct.pack("<I", data_len) +
-            struct.pack("<I", data_len_inflated) +
-            data_content)
+    return (
+        struct.pack("<I", msg_id)
+        + struct.pack("<I", data_len)
+        + struct.pack("<I", data_len_inflated)
+        + data_content
+    )
 
 
 def encode_eod(msg_id):

Разница между файлами не показана из-за своего большого размера
+ 306 - 240
coriolis/db/api.py


+ 1 - 2
coriolis/db/sqlalchemy/alembic/env.py

@@ -2,8 +2,7 @@
 # All Rights Reserved.
 
 from alembic import context
-from sqlalchemy import engine_from_config
-from sqlalchemy import pool
+from sqlalchemy import engine_from_config, pool
 
 from coriolis.db.sqlalchemy import models
 

+ 89 - 62
coriolis/db/sqlalchemy/alembic/versions/001_initial.py

@@ -10,8 +10,8 @@ Create Date: 2016-01-15 22:28:25.000000
 
 import uuid
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "001"
@@ -23,131 +23,158 @@ depends_on = None
 def upgrade():
     op.create_table(
         'base_transfer_action',
-        sqlalchemy.Column("base_id", sqlalchemy.String(36), primary_key=True,
-                          default=lambda: str(uuid.uuid4())),
+        sqlalchemy.Column(
+            "base_id",
+            sqlalchemy.String(36),
+            primary_key=True,
+            default=lambda: str(uuid.uuid4()),
+        ),
         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted', sqlalchemy.String(36)),
         sqlalchemy.Column("user_id", sqlalchemy.String(255), nullable=False),
-        sqlalchemy.Column("project_id", sqlalchemy.String(255),
-                          nullable=False),
+        sqlalchemy.Column("project_id", sqlalchemy.String(255), nullable=False),
         sqlalchemy.Column("origin", sqlalchemy.Text, nullable=False),
-        sqlalchemy.Column("destination", sqlalchemy.Text,
-                          nullable=False),
+        sqlalchemy.Column("destination", sqlalchemy.Text, nullable=False),
         sqlalchemy.Column("instances", sqlalchemy.Text, nullable=False),
         sqlalchemy.Column("type", sqlalchemy.String(50), nullable=False),
         sqlalchemy.Column("info", sqlalchemy.Text, nullable=False),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
     op.create_table(
         'replica',
-        sqlalchemy.Column("id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey(
-                              'base_transfer_action.base_id'),
-                          primary_key=True),
+        sqlalchemy.Column(
+            "id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('base_transfer_action.base_id'),
+            primary_key=True,
+        ),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
     op.create_table(
         'migration',
-        sqlalchemy.Column("id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey(
-                              'base_transfer_action.base_id'),
-                          primary_key=True),
-        sqlalchemy.Column("replica_id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey(
-                              'replica.id'), nullable=True),
+        sqlalchemy.Column(
+            "id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('base_transfer_action.base_id'),
+            primary_key=True,
+        ),
+        sqlalchemy.Column(
+            "replica_id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('replica.id'),
+            nullable=True,
+        ),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
     op.create_table(
         'tasks_execution',
-        sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                          default=lambda: str(uuid.uuid4())),
+        sqlalchemy.Column(
+            'id',
+            sqlalchemy.String(36),
+            primary_key=True,
+            default=lambda: str(uuid.uuid4()),
+        ),
         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted', sqlalchemy.String(36)),
-        sqlalchemy.Column("action_id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey(
-                              'base_transfer_action.base_id'),
-                          nullable=False),
+        sqlalchemy.Column(
+            "action_id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('base_transfer_action.base_id'),
+            nullable=False,
+        ),
         sqlalchemy.Column("status", sqlalchemy.String(100), nullable=False),
         sqlalchemy.Column("number", sqlalchemy.Integer, nullable=False),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
     op.create_table(
-        'task', sqlalchemy.Column(
-            'id', sqlalchemy.String(36),
-            primary_key=True, default=lambda: str(uuid.uuid4())),
+        'task',
+        sqlalchemy.Column(
+            'id',
+            sqlalchemy.String(36),
+            primary_key=True,
+            default=lambda: str(uuid.uuid4()),
+        ),
         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted', sqlalchemy.String(36)),
         sqlalchemy.Column(
-            "execution_id", sqlalchemy.String(36),
+            "execution_id",
+            sqlalchemy.String(36),
             sqlalchemy.ForeignKey('tasks_execution.id'),
-            nullable=False),
-        sqlalchemy.Column(
-            "instance", sqlalchemy.String(1024),
-            nullable=False),
-        sqlalchemy.Column(
-            "host", sqlalchemy.String(1024),
-            nullable=True),
-        sqlalchemy.Column(
-            "process_id", sqlalchemy.Integer, nullable=True),
-        sqlalchemy.Column(
-            "status", sqlalchemy.String(100),
-            nullable=False),
-        sqlalchemy.Column(
-            "task_type", sqlalchemy.String(100),
-            nullable=False),
-        sqlalchemy.Column(
-            "exception_details", sqlalchemy.Text, nullable=True),
+            nullable=False,
+        ),
+        sqlalchemy.Column("instance", sqlalchemy.String(1024), nullable=False),
+        sqlalchemy.Column("host", sqlalchemy.String(1024), nullable=True),
+        sqlalchemy.Column("process_id", sqlalchemy.Integer, nullable=True),
+        sqlalchemy.Column("status", sqlalchemy.String(100), nullable=False),
+        sqlalchemy.Column("task_type", sqlalchemy.String(100), nullable=False),
+        sqlalchemy.Column("exception_details", sqlalchemy.Text, nullable=True),
         sqlalchemy.Column("depends_on", sqlalchemy.Text, nullable=True),
         sqlalchemy.Column("on_error", sqlalchemy.Boolean, nullable=True),
-        mysql_engine='InnoDB', mysql_charset='utf8')
+        mysql_engine='InnoDB',
+        mysql_charset='utf8',
+    )
 
     op.create_table(
         'task_progress_update',
-        sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                          default=lambda: str(uuid.uuid4())),
+        sqlalchemy.Column(
+            'id',
+            sqlalchemy.String(36),
+            primary_key=True,
+            default=lambda: str(uuid.uuid4()),
+        ),
         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted', sqlalchemy.String(36)),
-        sqlalchemy.Column("task_id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey('task.id'),
-                          nullable=False),
+        sqlalchemy.Column(
+            "task_id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('task.id'),
+            nullable=False,
+        ),
         sqlalchemy.Column("current_step", sqlalchemy.Integer, nullable=False),
         sqlalchemy.Column("total_steps", sqlalchemy.Integer, nullable=True),
         sqlalchemy.Column("message", sqlalchemy.String(1024), nullable=True),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
     op.create_table(
         'task_event',
-        sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                          default=lambda: str(uuid.uuid4())),
+        sqlalchemy.Column(
+            'id',
+            sqlalchemy.String(36),
+            primary_key=True,
+            default=lambda: str(uuid.uuid4()),
+        ),
         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted', sqlalchemy.String(36)),
-        sqlalchemy.Column("task_id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey('task.id'),
-                          nullable=False),
+        sqlalchemy.Column(
+            "task_id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('task.id'),
+            nullable=False,
+        ),
         sqlalchemy.Column("level", sqlalchemy.String(50), nullable=False),
         sqlalchemy.Column("message", sqlalchemy.String(1024), nullable=False),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
 

+ 21 - 11
coriolis/db/sqlalchemy/alembic/versions/002_adds_endpoints.py

@@ -10,8 +10,8 @@ Create Date: 2017-03-22 22:17:09.000000
 
 import uuid
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "002"
@@ -23,37 +23,47 @@ depends_on = None
 def upgrade():
     op.create_table(
         'endpoint',
-        sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                          default=lambda: str(uuid.uuid4())),
+        sqlalchemy.Column(
+            'id',
+            sqlalchemy.String(36),
+            primary_key=True,
+            default=lambda: str(uuid.uuid4()),
+        ),
         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted', sqlalchemy.String(36)),
         sqlalchemy.Column("user_id", sqlalchemy.String(255), nullable=False),
-        sqlalchemy.Column("project_id", sqlalchemy.String(255),
-                          nullable=False),
+        sqlalchemy.Column("project_id", sqlalchemy.String(255), nullable=False),
         sqlalchemy.Column("connection_info", sqlalchemy.Text, nullable=False),
         sqlalchemy.Column("type", sqlalchemy.String(255), nullable=False),
         sqlalchemy.Column("name", sqlalchemy.String(255), nullable=False),
         sqlalchemy.Column("description", sqlalchemy.Text),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
     # NOTE(alexpilotti) delete all records in base_transfer_action
     # before performing this migration
     origin_endpoint_id = sqlalchemy.Column(
-        "origin_endpoint_id", sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
+        "origin_endpoint_id",
+        sqlalchemy.String(36),
+        sqlalchemy.ForeignKey('endpoint.id'),
+        nullable=False,
+    )
     op.add_column("base_transfer_action", origin_endpoint_id)
 
     destination_endpoint_id = sqlalchemy.Column(
-        "destination_endpoint_id", sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
+        "destination_endpoint_id",
+        sqlalchemy.String(36),
+        sqlalchemy.ForeignKey('endpoint.id'),
+        nullable=False,
+    )
     op.add_column("base_transfer_action", destination_endpoint_id)
 
     destination_environment = sqlalchemy.Column(
-        "destination_environment", sqlalchemy.Text, nullable=True)
+        "destination_environment", sqlalchemy.Text, nullable=True
+    )
     op.add_column("base_transfer_action", destination_environment)
 
     op.drop_column("base_transfer_action", "origin")

+ 2 - 3
coriolis/db/sqlalchemy/alembic/versions/003_adds_notes.py

@@ -8,8 +8,8 @@ Revises: 002
 Create Date: 2017-05-04 13:47:52.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "003"
@@ -19,8 +19,7 @@ depends_on = None
 
 
 def upgrade():
-    notes = sqlalchemy.Column(
-        "notes", sqlalchemy.Text, nullable=True)
+    notes = sqlalchemy.Column("notes", sqlalchemy.Text, nullable=True)
 
     op.add_column("base_transfer_action", notes)
 

+ 18 - 11
coriolis/db/sqlalchemy/alembic/versions/004_adds_replica_schedules.py

@@ -7,8 +7,8 @@ Create Date: 2017-11-04 18:17:31.000000
 
 import uuid
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "004"
@@ -20,24 +20,31 @@ depends_on = None
 def upgrade():
     op.create_table(
         'replica_schedules',
-        sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                          default=lambda: str(uuid.uuid4())),
+        sqlalchemy.Column(
+            'id',
+            sqlalchemy.String(36),
+            primary_key=True,
+            default=lambda: str(uuid.uuid4()),
+        ),
         sqlalchemy.Column('created_at', sqlalchemy.DateTime),
         sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
         sqlalchemy.Column('deleted', sqlalchemy.String(36)),
-        sqlalchemy.Column("replica_id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey(
-                              'replica.id'), nullable=False),
+        sqlalchemy.Column(
+            "replica_id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('replica.id'),
+            nullable=False,
+        ),
         sqlalchemy.Column("schedule", sqlalchemy.String(255), nullable=False),
         sqlalchemy.Column("expiration_date", sqlalchemy.DateTime),
-        sqlalchemy.Column("enabled", sqlalchemy.Boolean,
-                          default=True, nullable=False),
-        sqlalchemy.Column("shutdown_instance", sqlalchemy.Boolean,
-                          default=False, nullable=False),
+        sqlalchemy.Column("enabled", sqlalchemy.Boolean, default=True, nullable=False),
+        sqlalchemy.Column(
+            "shutdown_instance", sqlalchemy.Boolean, default=False, nullable=False
+        ),
         sqlalchemy.Column('trust_id', sqlalchemy.String(36)),
         mysql_engine='InnoDB',
-        mysql_charset='utf8'
+        mysql_charset='utf8',
     )
 
 

+ 3 - 2
coriolis/db/sqlalchemy/alembic/versions/005_adds_transfer_result.py

@@ -8,8 +8,8 @@ Revises: 004
 Create Date: 2018-09-18 18:33:14.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "005"
@@ -21,7 +21,8 @@ depends_on = None
 def upgrade():
     # add 'transfer_result' column to 'base_transfer_action':
     transfer_result = sqlalchemy.Column(
-        "transfer_result", sqlalchemy.Text, nullable=True)
+        "transfer_result", sqlalchemy.Text, nullable=True
+    )
     op.add_column("base_transfer_action", transfer_result)
 
 

+ 2 - 3
coriolis/db/sqlalchemy/alembic/versions/006_adds_network_map.py

@@ -8,8 +8,8 @@ Revises: 005
 Create Date: 2018-11-01 16:43:05.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "006"
@@ -20,8 +20,7 @@ depends_on = None
 
 def upgrade():
     # add 'network_map' column to 'base_transfer_action':
-    network_map = sqlalchemy.Column(
-        "network_map", sqlalchemy.Text, nullable=True)
+    network_map = sqlalchemy.Column("network_map", sqlalchemy.Text, nullable=True)
     op.add_column("base_transfer_action", network_map)
 
 

+ 3 - 2
coriolis/db/sqlalchemy/alembic/versions/007_adds_storage_mappings.py

@@ -8,8 +8,8 @@ Revises: 006
 Create Date: 2018-11-13 13:37:09.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "007"
@@ -21,7 +21,8 @@ depends_on = None
 def upgrade():
     # add 'storage_mappings' column to 'base_transfer_action':
     storage_mappings = sqlalchemy.Column(
-        "storage_mappings", sqlalchemy.Text, nullable=True)
+        "storage_mappings", sqlalchemy.Text, nullable=True
+    )
     op.add_column("base_transfer_action", storage_mappings)
 
 

+ 3 - 2
coriolis/db/sqlalchemy/alembic/versions/008_adds_source_environment.py

@@ -8,8 +8,8 @@ Revises: 007
 Create Date: 2018-11-27 18:48:35.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "008"
@@ -21,7 +21,8 @@ depends_on = None
 def upgrade():
     # add 'source_environment' column to 'base_transfer_action':
     source_environment = sqlalchemy.Column(
-        "source_environment", sqlalchemy.Text, nullable=True)
+        "source_environment", sqlalchemy.Text, nullable=True
+    )
     op.add_column("base_transfer_action", source_environment)
 
 

+ 1 - 2
coriolis/db/sqlalchemy/alembic/versions/009_migrate_info_to_blob.py

@@ -16,8 +16,7 @@ depends_on = None
 
 
 def upgrade():
-    op.alter_column(
-        'base_transfer_action', 'info', type_=types.LargeBinary(4294967295))
+    op.alter_column('base_transfer_action', 'info', type_=types.LargeBinary(4294967295))
 
 
 def downgrade():

+ 3 - 2
coriolis/db/sqlalchemy/alembic/versions/010_adds_reservation_id.py

@@ -8,8 +8,8 @@ Revises: 009
 Create Date: 2019-04-26 22:47:10.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "010"
@@ -21,7 +21,8 @@ depends_on = None
 def upgrade():
     # add 'reservation_id' column to 'base_transfer_action':
     reservation_id = sqlalchemy.Column(
-        "reservation_id", sqlalchemy.String(36), nullable=True)
+        "reservation_id", sqlalchemy.String(36), nullable=True
+    )
     op.add_column("base_transfer_action", reservation_id)
 
 

+ 2 - 3
coriolis/db/sqlalchemy/alembic/versions/011_adds_execution_type.py

@@ -8,8 +8,8 @@ Revises: 010
 Create Date: 2019-08-15 07:30:35.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "011"
@@ -20,8 +20,7 @@ depends_on = None
 
 def upgrade():
     # add 'type' column to 'tasks_execution':
-    execution_type = sqlalchemy.Column(
-        "type", sqlalchemy.String(20))
+    execution_type = sqlalchemy.Column("type", sqlalchemy.String(20))
     op.add_column("tasks_execution", execution_type)
 
 

+ 8 - 5
coriolis/db/sqlalchemy/alembic/versions/012_adds_migration_sync_fields.py

@@ -5,8 +5,8 @@ Revises: 011
 Create Date: 2019-10-16 15:40:42.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "012"
@@ -17,13 +17,16 @@ depends_on = None
 
 def upgrade():
     shutdown_instances = sqlalchemy.Column(
-        "shutdown_instances", sqlalchemy.Boolean,
-        nullable=False, server_default=sqlalchemy.false())
+        "shutdown_instances",
+        sqlalchemy.Boolean,
+        nullable=False,
+        server_default=sqlalchemy.false(),
+    )
     op.add_column("migration", shutdown_instances)
 
     replication_count = sqlalchemy.Column(
-        "replication_count", sqlalchemy.Integer,
-        nullable=False, server_default="0")
+        "replication_count", sqlalchemy.Integer, nullable=False, server_default="0"
+    )
     op.add_column("migration", replication_count)
 
 

+ 3 - 2
coriolis/db/sqlalchemy/alembic/versions/013_adds_task_index.py

@@ -5,8 +5,8 @@ Revises: 012
 Create Date: 2019-10-18 19:35:20.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "013"
@@ -17,7 +17,8 @@ depends_on = None
 
 def upgrade():
     index = sqlalchemy.Column(
-        "index", sqlalchemy.Integer, nullable=False, server_default="0")
+        "index", sqlalchemy.Integer, nullable=False, server_default="0"
+    )
     op.add_column("task", index)
 
 

+ 50 - 34
coriolis/db/sqlalchemy/alembic/versions/014_adds_worker_service_regions.py

@@ -10,8 +10,8 @@ Create Date: 2020-07-28 18:21:57.000000
 
 import uuid
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "014"
@@ -34,20 +34,25 @@ def upgrade():
         sqlalchemy.Table(
             'region',
             meta,
-            sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                              default=lambda: str(uuid.uuid4())),
-            sqlalchemy.Column('name', sqlalchemy.String(255), nullable=False),
             sqlalchemy.Column(
-                'description', sqlalchemy.String(1024), nullable=True),
+                'id',
+                sqlalchemy.String(36),
+                primary_key=True,
+                default=lambda: str(uuid.uuid4()),
+            ),
+            sqlalchemy.Column('name', sqlalchemy.String(255), nullable=False),
+            sqlalchemy.Column('description', sqlalchemy.String(1024), nullable=True),
             sqlalchemy.Column('created_at', sqlalchemy.DateTime),
             sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted', sqlalchemy.String(36)),
             sqlalchemy.Column(
-                'enabled', sqlalchemy.Boolean, nullable=True,
-                default=lambda: False),
+                'enabled', sqlalchemy.Boolean, nullable=True, default=lambda: False
+            ),
             mysql_engine='InnoDB',
-            mysql_charset='utf8'))
+            mysql_charset='utf8',
+        )
+    )
 
     # declare endpoint-region-mapping table:
     tables.append(
@@ -58,23 +63,28 @@ def upgrade():
                 'id',
                 sqlalchemy.String(36),
                 primary_key=True,
-                default=lambda: str(uuid.uuid4())),
+                default=lambda: str(uuid.uuid4()),
+            ),
             sqlalchemy.Column(
                 'endpoint_id',
                 sqlalchemy.String(36),
                 sqlalchemy.ForeignKey('endpoint.id'),
-                nullable=False),
+                nullable=False,
+            ),
             sqlalchemy.Column(
                 'region_id',
                 sqlalchemy.String(36),
                 sqlalchemy.ForeignKey('region.id'),
-                nullable=False),
+                nullable=False,
+            ),
             sqlalchemy.Column('created_at', sqlalchemy.DateTime),
             sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted', sqlalchemy.String(36)),
             mysql_engine='InnoDB',
-            mysql_charset='utf8'))
+            mysql_charset='utf8',
+        )
+    )
 
     # declare service table:
     tables.append(
@@ -85,29 +95,30 @@ def upgrade():
                 'id',
                 sqlalchemy.String(36),
                 primary_key=True,
-                default=lambda: str(uuid.uuid4())),
-            sqlalchemy.Column(
-                'enabled', sqlalchemy.Boolean, nullable=True,
-                default=lambda: False),
-            sqlalchemy.Column(
-                'host', sqlalchemy.String(255), nullable=False),
-            sqlalchemy.Column(
-                'binary', sqlalchemy.String(255), nullable=False),
-            sqlalchemy.Column(
-                'topic', sqlalchemy.String(255), nullable=False),
-            sqlalchemy.Column(
-                'status', sqlalchemy.String(255), nullable=False,
-                default=lambda: "UNKNOWN"),
-            sqlalchemy.Column(
-                'providers', sqlalchemy.Text(), nullable=False),
-            sqlalchemy.Column(
-                'specs', sqlalchemy.Text(), nullable=False),
+                default=lambda: str(uuid.uuid4()),
+            ),
+            sqlalchemy.Column(
+                'enabled', sqlalchemy.Boolean, nullable=True, default=lambda: False
+            ),
+            sqlalchemy.Column('host', sqlalchemy.String(255), nullable=False),
+            sqlalchemy.Column('binary', sqlalchemy.String(255), nullable=False),
+            sqlalchemy.Column('topic', sqlalchemy.String(255), nullable=False),
+            sqlalchemy.Column(
+                'status',
+                sqlalchemy.String(255),
+                nullable=False,
+                default=lambda: "UNKNOWN",
+            ),
+            sqlalchemy.Column('providers', sqlalchemy.Text(), nullable=False),
+            sqlalchemy.Column('specs', sqlalchemy.Text(), nullable=False),
             sqlalchemy.Column('created_at', sqlalchemy.DateTime),
             sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted', sqlalchemy.String(36)),
             mysql_engine='InnoDB',
-            mysql_charset='utf8'))
+            mysql_charset='utf8',
+        )
+    )
 
     # declare service-region mappings table:
     tables.append(
@@ -118,23 +129,28 @@ def upgrade():
                 'id',
                 sqlalchemy.String(36),
                 primary_key=True,
-                default=lambda: str(uuid.uuid4())),
+                default=lambda: str(uuid.uuid4()),
+            ),
             sqlalchemy.Column(
                 'service_id',
                 sqlalchemy.String(36),
                 sqlalchemy.ForeignKey('service.id'),
-                nullable=False),
+                nullable=False,
+            ),
             sqlalchemy.Column(
                 'region_id',
                 sqlalchemy.String(36),
                 sqlalchemy.ForeignKey('region.id'),
-                nullable=False),
+                nullable=False,
+            ),
             sqlalchemy.Column('created_at', sqlalchemy.DateTime),
             sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted', sqlalchemy.String(36)),
             mysql_engine='InnoDB',
-            mysql_charset='utf8'))
+            mysql_charset='utf8',
+        )
+    )
 
     for table in tables:
         table.create(bind=op.get_bind())

+ 6 - 3
coriolis/db/sqlalchemy/alembic/versions/015_adds_action_last_execution_status.py

@@ -8,8 +8,8 @@ Revises: 014
 Create Date: 2020-08-27 20:38:25.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "015"
@@ -21,8 +21,11 @@ depends_on = None
 def upgrade():
     # add 'last_execution_status' column to 'base_transfer_action':
     last_execution_status = sqlalchemy.Column(
-        "last_execution_status", sqlalchemy.String(255),
-        nullable=False, server_default="UNEXECUTED")
+        "last_execution_status",
+        sqlalchemy.String(255),
+        nullable=False,
+        server_default="UNEXECUTED",
+    )
     op.add_column("base_transfer_action", last_execution_status)
 
 

+ 135 - 101
coriolis/db/sqlalchemy/alembic/versions/016_adds_minion_vm_pools.py

@@ -10,8 +10,8 @@ Create Date: 2020-08-26 07:10:03.000000
 
 import uuid
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "016"
@@ -25,11 +25,13 @@ def upgrade():
 
     # extend tasks execution 'type' column:
     op.alter_column(
-        'tasks_execution', 'type',
+        'tasks_execution',
+        'type',
         existing_type=sqlalchemy.String(20),
         existing_nullable=True,
         type_=sqlalchemy.String(255),
-        nullable=True)
+        nullable=True,
+    )
 
     # load 'endpoint' into meta so the 'endpoint_id' foreign key below can
     # be resolved against it.
@@ -40,153 +42,185 @@ def upgrade():
     # add table for pool lifecycles:
     tables.append(
         sqlalchemy.Table(
-            'minion_pool', meta, sqlalchemy.Column(
-                "id", sqlalchemy.String(36),
+            'minion_pool',
+            meta,
+            sqlalchemy.Column(
+                "id",
+                sqlalchemy.String(36),
                 default=lambda: str(uuid.uuid4()),
-                primary_key=True),
+                primary_key=True,
+            ),
             sqlalchemy.Column("notes", sqlalchemy.Text, nullable=True),
+            sqlalchemy.Column("user_id", sqlalchemy.String(255), nullable=False),
+            sqlalchemy.Column("project_id", sqlalchemy.String(255), nullable=False),
             sqlalchemy.Column(
-                "user_id", sqlalchemy.String(255),
-                nullable=False),
-            sqlalchemy.Column(
-                "project_id", sqlalchemy.String(255),
-                nullable=False),
-            sqlalchemy.Column(
-                "maintenance_trust_id", sqlalchemy.String(255),
-                nullable=True),
+                "maintenance_trust_id", sqlalchemy.String(255), nullable=True
+            ),
             sqlalchemy.Column('created_at', sqlalchemy.DateTime),
             sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted', sqlalchemy.String(36)),
+            sqlalchemy.Column("name", sqlalchemy.String(255), nullable=False),
             sqlalchemy.Column(
-                "name", sqlalchemy.String(255),
-                nullable=False),
-            sqlalchemy.Column(
-                "endpoint_id", sqlalchemy.String(36),
+                "endpoint_id",
+                sqlalchemy.String(36),
                 sqlalchemy.ForeignKey('endpoint.id'),
-                nullable=False),
-            sqlalchemy.Column(
-                "environment_options", sqlalchemy.Text, nullable=False),
-            sqlalchemy.Column(
-                "os_type", sqlalchemy.String(255),
-                nullable=False),
-            sqlalchemy.Column(
-                "platform", sqlalchemy.String(255),
-                nullable=True),
-            sqlalchemy.Column(
-                "status", sqlalchemy.String(255),
-                nullable=False, default=lambda: "UNKNOWN"),
-            sqlalchemy.Column(
-                "shared_resources", sqlalchemy.Text, nullable=True),
-            sqlalchemy.Column(
-                'minimum_minions', sqlalchemy.Integer, nullable=False),
-            sqlalchemy.Column(
-                'maximum_minions', sqlalchemy.Integer, nullable=False),
-            sqlalchemy.Column(
-                'minion_max_idle_time', sqlalchemy.Integer, nullable=False),
-            sqlalchemy.Column(
-                'minion_retention_strategy', sqlalchemy.String(255),
-                nullable=False),
+                nullable=False,
+            ),
+            sqlalchemy.Column("environment_options", sqlalchemy.Text, nullable=False),
+            sqlalchemy.Column("os_type", sqlalchemy.String(255), nullable=False),
+            sqlalchemy.Column("platform", sqlalchemy.String(255), nullable=True),
+            sqlalchemy.Column(
+                "status",
+                sqlalchemy.String(255),
+                nullable=False,
+                default=lambda: "UNKNOWN",
+            ),
+            sqlalchemy.Column("shared_resources", sqlalchemy.Text, nullable=True),
+            sqlalchemy.Column('minimum_minions', sqlalchemy.Integer, nullable=False),
+            sqlalchemy.Column('maximum_minions', sqlalchemy.Integer, nullable=False),
+            sqlalchemy.Column(
+                'minion_max_idle_time', sqlalchemy.Integer, nullable=False
+            ),
+            sqlalchemy.Column(
+                'minion_retention_strategy', sqlalchemy.String(255), nullable=False
+            ),
             mysql_engine="InnoDB",
-            mysql_charset="utf8"))
+            mysql_charset="utf8",
+        )
+    )
 
     # declare minion machine table:
     tables.append(
         sqlalchemy.Table(
             'minion_machine',
             meta,
-            sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                              default=lambda: str(uuid.uuid4())),
-            sqlalchemy.Column(
-                "user_id", sqlalchemy.String(255), nullable=False),
             sqlalchemy.Column(
-                "project_id", sqlalchemy.String(255), nullable=False),
+                'id',
+                sqlalchemy.String(36),
+                primary_key=True,
+                default=lambda: str(uuid.uuid4()),
+            ),
+            sqlalchemy.Column("user_id", sqlalchemy.String(255), nullable=False),
+            sqlalchemy.Column("project_id", sqlalchemy.String(255), nullable=False),
             sqlalchemy.Column('created_at', sqlalchemy.DateTime),
             sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted', sqlalchemy.String(36)),
             sqlalchemy.Column(
-                'pool_id', sqlalchemy.String(36),
+                'pool_id',
+                sqlalchemy.String(36),
                 sqlalchemy.ForeignKey('minion_pool.id'),
-                nullable=False),
-            sqlalchemy.Column(
-                'allocated_action', sqlalchemy.String(36), nullable=True),
-            sqlalchemy.Column(
-                'last_used_at', sqlalchemy.DateTime, nullable=True),
-            sqlalchemy.Column(
-                'allocation_status', sqlalchemy.String(255), nullable=False,
-                default=lambda: "UNINITIALIZED"),
-            sqlalchemy.Column(
-                'power_status', sqlalchemy.String(255), nullable=False,
-                default=lambda: "UNINITIALIZED"),
+                nullable=False,
+            ),
+            sqlalchemy.Column('allocated_action', sqlalchemy.String(36), nullable=True),
+            sqlalchemy.Column('last_used_at', sqlalchemy.DateTime, nullable=True),
+            sqlalchemy.Column(
+                'allocation_status',
+                sqlalchemy.String(255),
+                nullable=False,
+                default=lambda: "UNINITIALIZED",
+            ),
+            sqlalchemy.Column(
+                'power_status',
+                sqlalchemy.String(255),
+                nullable=False,
+                default=lambda: "UNINITIALIZED",
+            ),
             sqlalchemy.Column('connection_info', sqlalchemy.Text),
             sqlalchemy.Column(
-                'backup_writer_connection_info', sqlalchemy.Text,
-                nullable=True),
-            sqlalchemy.Column(
-                'provider_properties', sqlalchemy.Text,
-                nullable=True),
+                'backup_writer_connection_info', sqlalchemy.Text, nullable=True
+            ),
+            sqlalchemy.Column('provider_properties', sqlalchemy.Text, nullable=True),
             mysql_engine="InnoDB",
-            mysql_charset="utf8"))
-
-    tables.append(sqlalchemy.Table(
-        'minion_pool_event', meta,
-        sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
-                          default=lambda: str(uuid.uuid4())),
-        sqlalchemy.Column('created_at', sqlalchemy.DateTime),
-        sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
-        sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
-        sqlalchemy.Column('deleted', sqlalchemy.String(36)),
-        sqlalchemy.Column('index', sqlalchemy.Integer, default=0),
-        sqlalchemy.Column("pool_id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey('minion_pool.id'),
-                          nullable=False),
-        sqlalchemy.Column("level", sqlalchemy.String(50), nullable=False),
-        sqlalchemy.Column("message", sqlalchemy.Text, nullable=False),
-        mysql_engine='InnoDB',
-        mysql_charset='utf8'))
+            mysql_charset="utf8",
+        )
+    )
 
     tables.append(
         sqlalchemy.Table(
-            'minion_pool_progress_update', meta, sqlalchemy.Column(
-                'id', sqlalchemy.String(36),
-                primary_key=True, default=lambda: str(uuid.uuid4())),
+            'minion_pool_event',
+            meta,
+            sqlalchemy.Column(
+                'id',
+                sqlalchemy.String(36),
+                primary_key=True,
+                default=lambda: str(uuid.uuid4()),
+            ),
             sqlalchemy.Column('created_at', sqlalchemy.DateTime),
             sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
             sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
-            sqlalchemy.Column('index', sqlalchemy.Integer, default=0),
             sqlalchemy.Column('deleted', sqlalchemy.String(36)),
+            sqlalchemy.Column('index', sqlalchemy.Integer, default=0),
             sqlalchemy.Column(
-                "pool_id", sqlalchemy.String(36),
+                "pool_id",
+                sqlalchemy.String(36),
                 sqlalchemy.ForeignKey('minion_pool.id'),
-                nullable=False),
-            sqlalchemy.Column(
-                "current_step", sqlalchemy.BigInteger, nullable=False),
+                nullable=False,
+            ),
+            sqlalchemy.Column("level", sqlalchemy.String(50), nullable=False),
+            sqlalchemy.Column("message", sqlalchemy.Text, nullable=False),
+            mysql_engine='InnoDB',
+            mysql_charset='utf8',
+        )
+    )
+
+    tables.append(
+        sqlalchemy.Table(
+            'minion_pool_progress_update',
+            meta,
             sqlalchemy.Column(
-                "total_steps", sqlalchemy.BigInteger, nullable=True),
+                'id',
+                sqlalchemy.String(36),
+                primary_key=True,
+                default=lambda: str(uuid.uuid4()),
+            ),
+            sqlalchemy.Column('created_at', sqlalchemy.DateTime),
+            sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
+            sqlalchemy.Column('deleted_at', sqlalchemy.DateTime),
+            sqlalchemy.Column('index', sqlalchemy.Integer, default=0),
+            sqlalchemy.Column('deleted', sqlalchemy.String(36)),
             sqlalchemy.Column(
-                "message", sqlalchemy.Text, nullable=True),
-            mysql_engine='InnoDB', mysql_charset='utf8'))
+                "pool_id",
+                sqlalchemy.String(36),
+                sqlalchemy.ForeignKey('minion_pool.id'),
+                nullable=False,
+            ),
+            sqlalchemy.Column("current_step", sqlalchemy.BigInteger, nullable=False),
+            sqlalchemy.Column("total_steps", sqlalchemy.BigInteger, nullable=True),
+            sqlalchemy.Column("message", sqlalchemy.Text, nullable=True),
+            mysql_engine='InnoDB',
+            mysql_charset='utf8',
+        )
+    )
 
     for table in tables:
         table.create(bind=op.get_bind())
 
     # add the pool option properties for the transfer:
     origin_minion_pool_id = sqlalchemy.Column(
-        "origin_minion_pool_id", sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('minion_pool.id'), nullable=True)
+        "origin_minion_pool_id",
+        sqlalchemy.String(36),
+        sqlalchemy.ForeignKey('minion_pool.id'),
+        nullable=True,
+    )
     op.add_column("base_transfer_action", origin_minion_pool_id)
 
     destination_minion_pool_id = sqlalchemy.Column(
-        "destination_minion_pool_id", sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('minion_pool.id'), nullable=True)
+        "destination_minion_pool_id",
+        sqlalchemy.String(36),
+        sqlalchemy.ForeignKey('minion_pool.id'),
+        nullable=True,
+    )
     op.add_column("base_transfer_action", destination_minion_pool_id)
 
     instance_osmorphing_minion_pool_mappings = sqlalchemy.Column(
-        "instance_osmorphing_minion_pool_mappings", sqlalchemy.Text,
-        nullable=False, server_default='{}')
-    op.add_column(
-        "base_transfer_action", instance_osmorphing_minion_pool_mappings)
+        "instance_osmorphing_minion_pool_mappings",
+        sqlalchemy.Text,
+        nullable=False,
+        server_default='{}',
+    )
+    op.add_column("base_transfer_action", instance_osmorphing_minion_pool_mappings)
 
 
 def downgrade():

+ 2 - 3
coriolis/db/sqlalchemy/alembic/versions/017_adds_user_scripts_column.py

@@ -8,8 +8,8 @@ Revises: 016
 Create Date: 2021-01-26 19:16:44.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "017"
@@ -20,8 +20,7 @@ depends_on = None
 
 def upgrade():
     # add 'user_scripts' column to 'base_transfer_action':
-    user_scripts = sqlalchemy.Column(
-        "user_scripts", sqlalchemy.Text, nullable=True)
+    user_scripts = sqlalchemy.Column("user_scripts", sqlalchemy.Text, nullable=True)
     op.add_column("base_transfer_action", user_scripts)
 
 

+ 13 - 7
coriolis/db/sqlalchemy/alembic/versions/018_adds_task_progress_idices.py

@@ -5,8 +5,8 @@ Revises: 017
 Create Date: 2021-01-07 17:33:05.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "018"
@@ -17,24 +17,30 @@ depends_on = None
 
 def upgrade():
     event_index = sqlalchemy.Column(
-        "index", sqlalchemy.Integer, nullable=False, server_default="0")
+        "index", sqlalchemy.Integer, nullable=False, server_default="0"
+    )
     op.add_column("task_event", event_index)
 
     progress_index = sqlalchemy.Column(
-        "index", sqlalchemy.Integer, nullable=False, server_default="0")
+        "index", sqlalchemy.Integer, nullable=False, server_default="0"
+    )
     op.add_column("task_progress_update", progress_index)
     op.alter_column(
-        "task_progress_update", "current_step",
+        "task_progress_update",
+        "current_step",
         existing_type=sqlalchemy.Integer,
         existing_nullable=False,
         type_=sqlalchemy.BigInteger,
-        nullable=False)
+        nullable=False,
+    )
     op.alter_column(
-        "task_progress_update", "total_steps",
+        "task_progress_update",
+        "total_steps",
         existing_type=sqlalchemy.Integer,
         existing_nullable=True,
         type_=sqlalchemy.BigInteger,
-        nullable=True)
+        nullable=True,
+    )
 
 
 def downgrade():

+ 3 - 3
coriolis/db/sqlalchemy/alembic/versions/019_add_replica_scenario_field.py

@@ -8,8 +8,8 @@ Revises: 018
 Create Date: 2024-04-09 14:42:14.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "019"
@@ -20,8 +20,8 @@ depends_on = None
 
 def upgrade():
     replica_scenario = sqlalchemy.Column(
-        "scenario", sqlalchemy.String(255), nullable=False,
-        server_default="replica")
+        "scenario", sqlalchemy.String(255), nullable=False, server_default="replica"
+    )
     op.add_column("replica", replica_scenario)
 
 

+ 25 - 17
coriolis/db/sqlalchemy/alembic/versions/020_rename_tables.py

@@ -5,8 +5,8 @@ Revises: 019
 Create Date: 2024-10-29 15:26:01.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "020"
@@ -32,36 +32,44 @@ def upgrade():
 
     # load 'base_transfer_action' and 'transfer' into meta so the foreign
     # keys below can be resolved against them.
-    sqlalchemy.Table(
-        'base_transfer_action', meta, autoload_with=op.get_bind())
+    sqlalchemy.Table('base_transfer_action', meta, autoload_with=op.get_bind())
     sqlalchemy.Table('transfer', meta, autoload_with=op.get_bind())
 
     deployment = sqlalchemy.Table(
-        'deployment', meta,
-        sqlalchemy.Column("id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey(
-                              'base_transfer_action.base_id'),
-                          primary_key=True),
-        sqlalchemy.Column("transfer_id", sqlalchemy.String(36),
-                          sqlalchemy.ForeignKey('transfer.id'),
-                          nullable=False),
+        'deployment',
+        meta,
+        sqlalchemy.Column(
+            "id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('base_transfer_action.base_id'),
+            primary_key=True,
+        ),
+        sqlalchemy.Column(
+            "transfer_id",
+            sqlalchemy.String(36),
+            sqlalchemy.ForeignKey('transfer.id'),
+            nullable=False,
+        ),
         mysql_engine="InnoDB",
-        mysql_charset="utf8")
+        mysql_charset="utf8",
+    )
     deployment.create(bind=op.get_bind())
 
     op.rename_table('replica_schedules', 'transfer_schedules')
     op.alter_column(
-        'transfer_schedules', 'replica_id',
+        'transfer_schedules',
+        'replica_id',
         new_column_name='transfer_id',
         existing_type=sqlalchemy.String(36),
-        existing_nullable=False)
+        existing_nullable=False,
+    )
 
     for table, old_type, new_type in _TYPE_RENAMES:
         op.execute(
             sqlalchemy.text(
-                f"UPDATE {table} SET type = :new_type "
-                f"WHERE type = :old_type"
-            ).bindparams(new_type=new_type, old_type=old_type))
+                f"UPDATE {table} SET type = :new_type WHERE type = :old_type"
+            ).bindparams(new_type=new_type, old_type=old_type)
+        )
 
 
 def downgrade():

+ 11 - 5
coriolis/db/sqlalchemy/alembic/versions/021_add_deployment_defaults.py

@@ -5,8 +5,8 @@ Revises: 020
 Create Date: 2025-01-29 19:13:39.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "021"
@@ -17,12 +17,18 @@ depends_on = None
 
 def upgrade():
     clone_disks = sqlalchemy.Column(
-        "clone_disks", sqlalchemy.Boolean, nullable=False,
-        server_default=sqlalchemy.true())
+        "clone_disks",
+        sqlalchemy.Boolean,
+        nullable=False,
+        server_default=sqlalchemy.true(),
+    )
     op.add_column("base_transfer_action", clone_disks)
     skip_os_morphing = sqlalchemy.Column(
-        "skip_os_morphing", sqlalchemy.Boolean, nullable=False,
-        server_default=sqlalchemy.false())
+        "skip_os_morphing",
+        sqlalchemy.Boolean,
+        nullable=False,
+        server_default=sqlalchemy.false(),
+    )
     op.add_column("base_transfer_action", skip_os_morphing)
 
 

+ 6 - 3
coriolis/db/sqlalchemy/alembic/versions/022_adds_auto_deploy_column.py

@@ -5,8 +5,8 @@ Revises: 021
 Create Date: 2025-01-30 13:54:39.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "022"
@@ -17,8 +17,11 @@ depends_on = None
 
 def upgrade():
     auto_deploy = sqlalchemy.Column(
-        'auto_deploy', sqlalchemy.Boolean, nullable=False,
-        server_default=sqlalchemy.false())
+        'auto_deploy',
+        sqlalchemy.Boolean,
+        nullable=False,
+        server_default=sqlalchemy.false(),
+    )
     op.add_column("transfer_schedules", auto_deploy)
 
 

+ 3 - 5
coriolis/db/sqlalchemy/alembic/versions/023_add_deployer_id.py

@@ -5,8 +5,8 @@ Revises: 022
 Create Date: 2025-02-06 14:42:29.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "023"
@@ -16,11 +16,9 @@ depends_on = None
 
 
 def upgrade():
-    deployer_id = sqlalchemy.Column(
-        'deployer_id', sqlalchemy.String(36), nullable=True)
+    deployer_id = sqlalchemy.Column('deployer_id', sqlalchemy.String(36), nullable=True)
     op.add_column("deployment", deployer_id)
-    trust_id = sqlalchemy.Column(
-        'trust_id', sqlalchemy.String(255), nullable=True)
+    trust_id = sqlalchemy.Column('trust_id', sqlalchemy.String(255), nullable=True)
     op.add_column("deployment", trust_id)
 
 

+ 7 - 5
coriolis/db/sqlalchemy/alembic/versions/024_add_clustered_to_base_transfer_action.py

@@ -8,8 +8,8 @@ Revises: 023
 Create Date: 2026-04-09 04:03:23.000000
 """
 
-from alembic import op
 import sqlalchemy
+from alembic import op
 
 # revision identifiers, used by Alembic.
 revision = "024"
@@ -20,15 +20,17 @@ depends_on = None
 
 def upgrade():
     inspector = sqlalchemy.inspect(op.get_bind())
-    columns = [c['name'] for c in inspector.get_columns(
-        'base_transfer_action')]
+    columns = [c['name'] for c in inspector.get_columns('base_transfer_action')]
     if 'clustered' in columns:
         return
     # server_default so existing rows get a value when the column is added
     # (MySQL stores booleans as TINYINT).
     clustered = sqlalchemy.Column(
-        'clustered', sqlalchemy.Boolean, nullable=False,
-        server_default=sqlalchemy.text('0'))
+        'clustered',
+        sqlalchemy.Boolean,
+        nullable=False,
+        server_default=sqlalchemy.text('0'),
+    )
     op.add_column("base_transfer_action", clustered)
 
 

+ 3 - 2
coriolis/db/sqlalchemy/api.py

@@ -7,8 +7,8 @@ from oslo_config import cfg
 from oslo_db import options as db_options
 from oslo_db.sqlalchemy import session as db_session
 
-from coriolis.db.sqlalchemy import migration
 from coriolis import exception
+from coriolis.db.sqlalchemy import migration
 from coriolis.i18n import _
 
 CONF = cfg.CONF
@@ -43,7 +43,8 @@ def db_sync(engine, version=None):
         current_version = db_version(engine)
         if current_version is not None and int(version) < int(current_version):
             raise exception.CoriolisException(
-                _("Cannot migrate to lower schema version."))
+                _("Cannot migrate to lower schema version.")
+            )
 
     return migration.db_sync(engine, version=version)
 

+ 11 - 8
coriolis/db/sqlalchemy/migration.py

@@ -3,10 +3,10 @@
 
 import os
 
+import sqlalchemy
 from alembic import command
 from alembic import config as alembic_config
 from alembic.runtime import migration as alembic_migration
-import sqlalchemy
 
 from coriolis import exception
 from coriolis.i18n import _
@@ -39,16 +39,19 @@ def _stamp_legacy_database_if_needed(engine, config):
 
     with engine.connect() as conn:
         legacy_version = conn.execute(
-            sqlalchemy.text(
-                f"SELECT version FROM {LEGACY_VERSION_TABLE}")).scalar()
+            sqlalchemy.text(f"SELECT version FROM {LEGACY_VERSION_TABLE}")
+        ).scalar()
 
     if legacy_version > LEGACY_FINAL_VERSION:
         raise exception.CoriolisException(
-            _("This database was last migrated using the legacy "
-              "sqlalchemy-migrate based coriolis-dbsync (version %(cur)s), "
-              "which is newer than the last version known to alembic "
-              "(%(final)s).") % {
-                "cur": legacy_version, "final": LEGACY_FINAL_VERSION})
+            _(
+                "This database was last migrated using the legacy "
+                "sqlalchemy-migrate based coriolis-dbsync (version %(cur)s), "
+                "which is newer than the last version known to alembic "
+                "(%(final)s)."
+            )
+            % {"cur": legacy_version, "final": LEGACY_FINAL_VERSION}
+        )
 
     config.attributes["connection"] = engine.connect()
     command.stamp(config, "%03d" % legacy_version)

+ 279 - 268
coriolis/db/sqlalchemy/models.py

@@ -3,11 +3,10 @@
 
 import uuid
 
-from oslo_db.sqlalchemy import models
 import sqlalchemy
+from oslo_db.sqlalchemy import models
+from sqlalchemy import orm, schema
 from sqlalchemy.ext import declarative
-from sqlalchemy import orm
-from sqlalchemy import schema
 
 from coriolis import constants
 from coriolis.db.sqlalchemy import types
@@ -17,21 +16,20 @@ BASE = declarative.declarative_base()
 MAX_EVENT_MESSAGE_LENGHT = 1024
 
 
-class TaskEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin,
-                models.ModelBase):
-
+class TaskEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin, models.ModelBase):
     __tablename__ = 'task_event'
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
-    task_id = sqlalchemy.Column(sqlalchemy.String(36),
-                                sqlalchemy.ForeignKey('task.id'),
-                                nullable=False)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
+    task_id = sqlalchemy.Column(
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('task.id'), nullable=False
+    )
     level = sqlalchemy.Column(sqlalchemy.String(20), nullable=False)
     index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     message = sqlalchemy.Column(
-        sqlalchemy.String(MAX_EVENT_MESSAGE_LENGHT), nullable=False)
+        sqlalchemy.String(MAX_EVENT_MESSAGE_LENGHT), nullable=False
+    )
 
     def to_dict(self):
         result = {
@@ -48,16 +46,17 @@ class TaskEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin,
         return result
 
 
-class MinionPoolEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin,
-                      models.ModelBase):
+class MinionPoolEvent(
+    BASE, models.TimestampMixin, models.SoftDeleteMixin, models.ModelBase
+):
     __tablename__ = 'minion_pool_event'
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
-    pool_id = sqlalchemy.Column(sqlalchemy.String(36),
-                                sqlalchemy.ForeignKey('minion_pool.id'),
-                                nullable=False)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
+    pool_id = sqlalchemy.Column(
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('minion_pool.id'), nullable=False
+    )
     level = sqlalchemy.Column(sqlalchemy.String(20), nullable=False)
     index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     message = sqlalchemy.Column(sqlalchemy.Text, nullable=False)
@@ -77,18 +76,18 @@ class MinionPoolEvent(BASE, models.TimestampMixin, models.SoftDeleteMixin,
         return result
 
 
-class TaskProgressUpdate(BASE, models.TimestampMixin, models.SoftDeleteMixin,
-                         models.ModelBase):
+class TaskProgressUpdate(
+    BASE, models.TimestampMixin, models.SoftDeleteMixin, models.ModelBase
+):
     __tablename__ = 'task_progress_update'
-    __table_args__ = (
-        schema.UniqueConstraint("task_id", "index", "deleted"),)
+    __table_args__ = (schema.UniqueConstraint("task_id", "index", "deleted"),)
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
-    task_id = sqlalchemy.Column(sqlalchemy.String(36),
-                                sqlalchemy.ForeignKey('task.id'),
-                                nullable=False)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
+    task_id = sqlalchemy.Column(
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('task.id'), nullable=False
+    )
 
     index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     current_step = sqlalchemy.Column(sqlalchemy.BigInteger, nullable=False)
@@ -112,17 +111,17 @@ class TaskProgressUpdate(BASE, models.TimestampMixin, models.SoftDeleteMixin,
 
 
 class MinionPoolProgressUpdate(
-        BASE, models.TimestampMixin, models.SoftDeleteMixin, models.ModelBase):
+    BASE, models.TimestampMixin, models.SoftDeleteMixin, models.ModelBase
+):
     __tablename__ = 'minion_pool_progress_update'
-    __table_args__ = (
-        schema.UniqueConstraint("pool_id", "index", "deleted"),)
-
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
-    pool_id = sqlalchemy.Column(sqlalchemy.String(36),
-                                sqlalchemy.ForeignKey('minion_pool.id'),
-                                nullable=False)
+    __table_args__ = (schema.UniqueConstraint("pool_id", "index", "deleted"),)
+
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
+    pool_id = sqlalchemy.Column(
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('minion_pool.id'), nullable=False
+    )
     index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     current_step = sqlalchemy.Column(sqlalchemy.BigInteger, nullable=False)
     total_steps = sqlalchemy.Column(sqlalchemy.BigInteger, nullable=True)
@@ -144,16 +143,17 @@ class MinionPoolProgressUpdate(
         return result
 
 
-class Task(BASE, models.TimestampMixin, models.SoftDeleteMixin,
-           models.ModelBase):
+class Task(BASE, models.TimestampMixin, models.SoftDeleteMixin, models.ModelBase):
     __tablename__ = 'task'
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
     execution_id = sqlalchemy.Column(
         sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('tasks_execution.id'), nullable=False)
+        sqlalchemy.ForeignKey('tasks_execution.id'),
+        nullable=False,
+    )
     instance = sqlalchemy.Column(sqlalchemy.String(1024), nullable=False)
     host = sqlalchemy.Column(sqlalchemy.String(1024), nullable=True)
     process_id = sqlalchemy.Column(sqlalchemy.Integer, nullable=True)
@@ -164,15 +164,19 @@ class Task(BASE, models.TimestampMixin, models.SoftDeleteMixin,
     index = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     on_error = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
     # TODO(alexpilotti): Add soft delete filter
-    events = orm.relationship(TaskEvent, cascade="all,delete",
-                              backref=orm.backref('task'),
-                              order_by=TaskEvent.index)
+    events = orm.relationship(
+        TaskEvent,
+        cascade="all,delete",
+        backref=orm.backref('task'),
+        order_by=TaskEvent.index,
+    )
     # TODO(alexpilotti): Add soft delete filter
-    progress_updates = orm.relationship(TaskProgressUpdate,
-                                        cascade="all,delete",
-                                        backref=orm.backref('task'),
-                                        order_by=(
-                                            TaskProgressUpdate.index))
+    progress_updates = orm.relationship(
+        TaskProgressUpdate,
+        cascade="all,delete",
+        backref=orm.backref('task'),
+        order_by=(TaskProgressUpdate.index),
+    )
 
     def to_dict(self):
         result = {
@@ -199,24 +203,27 @@ class Task(BASE, models.TimestampMixin, models.SoftDeleteMixin,
             result["events"].append(evt.to_dict())
 
         for pgu in self.progress_updates:
-            result["progress_updates"].append(
-                pgu.to_dict())
+            result["progress_updates"].append(pgu.to_dict())
         return result
 
 
-class TasksExecution(BASE, models.TimestampMixin, models.ModelBase,
-                     models.SoftDeleteMixin):
+class TasksExecution(
+    BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin
+):
     __tablename__ = 'tasks_execution'
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
     action_id = sqlalchemy.Column(
         sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('base_transfer_action.base_id'), nullable=False)
+        sqlalchemy.ForeignKey('base_transfer_action.base_id'),
+        nullable=False,
+    )
     # TODO(alexpilotti): Add soft delete filter
-    tasks = orm.relationship(Task, cascade="all,delete",
-                             backref=orm.backref('execution'))
+    tasks = orm.relationship(
+        Task, cascade="all,delete", backref=orm.backref('execution')
+    )
     status = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)
     number = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     type = sqlalchemy.Column(sqlalchemy.String(255))
@@ -239,56 +246,62 @@ class TasksExecution(BASE, models.TimestampMixin, models.ModelBase,
         return result
 
 
-class BaseTransferAction(BASE, models.TimestampMixin, models.ModelBase,
-                         models.SoftDeleteMixin):
+class BaseTransferAction(
+    BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin
+):
     __tablename__ = 'base_transfer_action'
 
-    base_id = sqlalchemy.Column(sqlalchemy.String(36),
-                                default=lambda: str(uuid.uuid4()),
-                                primary_key=True)
+    base_id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
     user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     destination_environment = sqlalchemy.Column(types.Json, nullable=True)
     type = sqlalchemy.Column(sqlalchemy.String(50))
-    executions = orm.relationship(TasksExecution, cascade="all,delete",
-                                  backref=orm.backref('action'),
-                                  primaryjoin="and_(BaseTransferAction."
-                                  "base_id==TasksExecution.action_id, "
-                                  "TasksExecution.deleted=='0')")
+    executions = orm.relationship(
+        TasksExecution,
+        cascade="all,delete",
+        backref=orm.backref('action'),
+        primaryjoin="and_(BaseTransferAction."
+        "base_id==TasksExecution.action_id, "
+        "TasksExecution.deleted=='0')",
+    )
     instances = sqlalchemy.Column(types.List, nullable=False)
     last_execution_status = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False,
-        default=lambda: constants.EXECUTION_STATUS_UNEXECUTED)
+        sqlalchemy.String(255),
+        nullable=False,
+        default=lambda: constants.EXECUTION_STATUS_UNEXECUTED,
+    )
     reservation_id = sqlalchemy.Column(sqlalchemy.String(36), nullable=True)
     info = orm.deferred(sqlalchemy.Column(types.Bson, nullable=False))
     notes = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
     origin_endpoint_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('endpoint.id'), nullable=False
+    )
     destination_endpoint_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('endpoint.id'), nullable=False
+    )
     transfer_result = sqlalchemy.Column(types.Json, nullable=True)
     network_map = sqlalchemy.Column(types.Json, nullable=True)
     storage_mappings = sqlalchemy.Column(types.Json, nullable=True)
     source_environment = sqlalchemy.Column(types.Json, nullable=True)
     origin_minion_pool_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('minion_pool.id'), nullable=True)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('minion_pool.id'), nullable=True
+    )
     destination_minion_pool_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('minion_pool.id'), nullable=True)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('minion_pool.id'), nullable=True
+    )
     instance_osmorphing_minion_pool_mappings = sqlalchemy.Column(
-        types.Json, nullable=False, default=lambda: {})
+        types.Json, nullable=False, default=lambda: {}
+    )
     user_scripts = sqlalchemy.Column(types.Json, nullable=True)
-    clone_disks = sqlalchemy.Column(
-        sqlalchemy.Boolean, nullable=False, default=True)
+    clone_disks = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=True)
     skip_os_morphing = sqlalchemy.Column(
-        sqlalchemy.Boolean, nullable=False, default=False)
+        sqlalchemy.Boolean, nullable=False, default=False
+    )
     # Multi-instance transfer: enables cross-instance sync barriers and
     # shared-disk handling. Must be set on INSERT (MySQL NOT NULL).
-    clustered = sqlalchemy.Column(
-        sqlalchemy.Boolean, nullable=False, default=False)
+    clustered = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False)
 
     __mapper_args__ = {
         'polymorphic_identity': 'base_transfer_action',
@@ -319,8 +332,7 @@ class BaseTransferAction(BASE, models.TimestampMixin, models.ModelBase,
             "deleted": self.deleted,
             "origin_minion_pool_id": self.origin_minion_pool_id,
             "destination_minion_pool_id": self.destination_minion_pool_id,
-            "instance_osmorphing_minion_pool_mappings":
-                self.instance_osmorphing_minion_pool_mappings,
+            "instance_osmorphing_minion_pool_mappings": self.instance_osmorphing_minion_pool_mappings,
             "user_scripts": self.user_scripts,
             "clone_disks": self.clone_disks,
             "skip_os_morphing": self.skip_os_morphing,
@@ -339,11 +351,14 @@ class Transfer(BaseTransferAction):
 
     id = sqlalchemy.Column(
         sqlalchemy.String(36),
-        sqlalchemy.ForeignKey(
-            'base_transfer_action.base_id'), primary_key=True)
+        sqlalchemy.ForeignKey('base_transfer_action.base_id'),
+        primary_key=True,
+    )
     scenario = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False,
-        default=constants.TRANSFER_SCENARIO_REPLICA)
+        sqlalchemy.String(255),
+        nullable=False,
+        default=constants.TRANSFER_SCENARIO_REPLICA,
+    )
 
     __mapper_args__ = {
         'polymorphic_identity': 'transfer',
@@ -351,11 +366,9 @@ class Transfer(BaseTransferAction):
 
     def to_dict(self, include_task_info=True, include_executions=True):
         base = super(Transfer, self).to_dict(
-            include_task_info=include_task_info,
-            include_executions=include_executions)
-        base.update({
-            "id": self.id,
-            "scenario": self.scenario})
+            include_task_info=include_task_info, include_executions=include_executions
+        )
+        base.update({"id": self.id, "scenario": self.scenario})
         return base
 
 
@@ -364,14 +377,15 @@ class Deployment(BaseTransferAction):
 
     id = sqlalchemy.Column(
         sqlalchemy.String(36),
-        sqlalchemy.ForeignKey(
-            'base_transfer_action.base_id'), primary_key=True)
+        sqlalchemy.ForeignKey('base_transfer_action.base_id'),
+        primary_key=True,
+    )
     transfer_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('transfer.id'), nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('transfer.id'), nullable=False
+    )
     transfer = orm.relationship(
-        Transfer, backref=orm.backref("deployments"),
-        foreign_keys=[transfer_id])
+        Transfer, backref=orm.backref("deployments"), foreign_keys=[transfer_id]
+    )
     deployer_id = sqlalchemy.Column(sqlalchemy.String(36), nullable=True)
     trust_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=True)
 
@@ -381,160 +395,155 @@ class Deployment(BaseTransferAction):
 
     def to_dict(self, include_task_info=True, include_tasks=True):
         base = super(Deployment, self).to_dict(
-            include_task_info=include_task_info,
-            include_executions=include_tasks)
-
-        base.update({
-            "id": self.id,
-            "transfer_id": self.transfer_id,
-            "transfer_scenario_type": self.transfer.scenario,
-            "deployer_id": self.deployer_id,
-            "trust_id": self.trust_id,
-        })
+            include_task_info=include_task_info, include_executions=include_tasks
+        )
+
+        base.update(
+            {
+                "id": self.id,
+                "transfer_id": self.transfer_id,
+                "transfer_scenario_type": self.transfer.scenario,
+                "deployer_id": self.deployer_id,
+                "trust_id": self.trust_id,
+            }
+        )
         return base
 
 
 class ServiceRegionMapping(
-        BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
+    BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin
+):
     __tablename__ = "service_region_mapping"
 
     id = sqlalchemy.Column(
         sqlalchemy.String(36),
         default=lambda: str(uuid.uuid4()),
         nullable=False,
-        primary_key=True)
+        primary_key=True,
+    )
 
     service_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('service.id'),
-        nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('service.id'), nullable=False
+    )
 
     region_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('region.id'),
-        nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('region.id'), nullable=False
+    )
 
 
-class Service(BASE, models.TimestampMixin, models.ModelBase,
-              models.SoftDeleteMixin):
+class Service(BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
     __tablename__ = "service"
     __table_args__ = (
-        schema.UniqueConstraint("host", "topic", "deleted",
-                                name="uniq_services0host0topic0deleted"),
-        schema.UniqueConstraint("host", "binary", "deleted",
-                                name="uniq_services0host0binary0deleted"))
+        schema.UniqueConstraint(
+            "host", "topic", "deleted", name="uniq_services0host0topic0deleted"
+        ),
+        schema.UniqueConstraint(
+            "host", "binary", "deleted", name="uniq_services0host0binary0deleted"
+        ),
+    )
 
     id = sqlalchemy.Column(
-        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()),
-        primary_key=True)
-
-    host = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False)
-    binary = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False)
-    topic = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=True, default=None)
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
+
+    host = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
+    binary = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
+    topic = sqlalchemy.Column(sqlalchemy.String(255), nullable=True, default=None)
     enabled = sqlalchemy.Column(
-        sqlalchemy.Boolean, nullable=False, default=lambda: False)
+        sqlalchemy.Boolean, nullable=False, default=lambda: False
+    )
     status = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False,
-        default=lambda: constants.SERVICE_STATUS_UNKNOWN)
+        sqlalchemy.String(255),
+        nullable=False,
+        default=lambda: constants.SERVICE_STATUS_UNKNOWN,
+    )
     providers = sqlalchemy.Column(types.Json(), nullable=True)
     specs = sqlalchemy.Column(types.Json(), nullable=True)
     mapped_regions = orm.relationship(
-        'Region', back_populates='mapped_services',
-        secondary="service_region_mapping")
+        'Region', back_populates='mapped_services', secondary="service_region_mapping"
+    )
 
 
 class EndpointRegionMapping(
-        BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
+    BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin
+):
     __tablename__ = "endpoint_region_mapping"
 
     id = sqlalchemy.Column(
         sqlalchemy.String(36),
         default=lambda: str(uuid.uuid4()),
         nullable=False,
-        primary_key=True)
+        primary_key=True,
+    )
 
     endpoint_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('endpoint.id'),
-        nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('endpoint.id'), nullable=False
+    )
 
     region_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('region.id'),
-        nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('region.id'), nullable=False
+    )
 
 
-class Region(
-        BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
+class Region(BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
     __tablename__ = "region"
 
     id = sqlalchemy.Column(
         sqlalchemy.String(36),
         default=lambda: str(uuid.uuid4()),
         nullable=False,
-        primary_key=True)
+        primary_key=True,
+    )
 
-    name = sqlalchemy.Column(
-        sqlalchemy.String(255),
-        nullable=False)
+    name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
 
-    description = sqlalchemy.Column(
-        sqlalchemy.String(1024),
-        nullable=True)
+    description = sqlalchemy.Column(sqlalchemy.String(1024), nullable=True)
 
     enabled = sqlalchemy.Column(
-        sqlalchemy.Boolean,
-        default=lambda: False,
-        nullable=False)
+        sqlalchemy.Boolean, default=lambda: False, nullable=False
+    )
 
     mapped_endpoints = orm.relationship(
-        'Endpoint', back_populates='mapped_regions',
-        secondary="endpoint_region_mapping")
+        'Endpoint', back_populates='mapped_regions', secondary="endpoint_region_mapping"
+    )
 
     mapped_services = orm.relationship(
-        'Service', back_populates='mapped_regions',
-        secondary="service_region_mapping")
+        'Service', back_populates='mapped_regions', secondary="service_region_mapping"
+    )
 
 
-class MinionMachine(BASE, models.TimestampMixin, models.ModelBase,
-                    models.SoftDeleteMixin):
+class MinionMachine(
+    BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin
+):
     __tablename__ = "minion_machine"
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
     user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
 
     pool_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('minion_pool.id'),
-        nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('minion_pool.id'), nullable=False
+    )
 
     allocation_status = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False,
-        default=lambda: constants.MINION_MACHINE_STATUS_UNINITIALIZED)
+        sqlalchemy.String(255),
+        nullable=False,
+        default=lambda: constants.MINION_MACHINE_STATUS_UNINITIALIZED,
+    )
 
-    allocated_action = sqlalchemy.Column(
-        sqlalchemy.String(36), nullable=True)
+    allocated_action = sqlalchemy.Column(sqlalchemy.String(36), nullable=True)
 
-    power_status = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False)
+    power_status = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
 
-    last_used_at = sqlalchemy.Column(
-        sqlalchemy.types.DateTime, nullable=True)
+    last_used_at = sqlalchemy.Column(sqlalchemy.types.DateTime, nullable=True)
 
-    connection_info = sqlalchemy.Column(
-        types.Json, nullable=True)
+    connection_info = sqlalchemy.Column(types.Json, nullable=True)
 
-    backup_writer_connection_info = sqlalchemy.Column(
-        types.Json, nullable=True)
+    backup_writer_connection_info = sqlalchemy.Column(types.Json, nullable=True)
 
-    provider_properties = sqlalchemy.Column(
-        types.Json, nullable=True)
+    provider_properties = sqlalchemy.Column(types.Json, nullable=True)
 
     def to_dict(self):
         result = {
@@ -551,68 +560,63 @@ class MinionMachine(BASE, models.TimestampMixin, models.ModelBase,
             "connection_info": self.connection_info,
             "allocated_action": self.allocated_action,
             "last_used_at": self.last_used_at,
-            "backup_writer_connection_info": (
-                self.backup_writer_connection_info),
-            "provider_properties": self.provider_properties
+            "backup_writer_connection_info": (self.backup_writer_connection_info),
+            "provider_properties": self.provider_properties,
         }
         return result
 
 
-class MinionPool(
-    BASE, models.TimestampMixin, models.ModelBase,
-    models.SoftDeleteMixin):
+class MinionPool(BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
     __tablename__ = 'minion_pool'
 
-    id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        primary_key=True)
+    id = sqlalchemy.Column(sqlalchemy.String(36), primary_key=True)
     user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
-    maintenance_trust_id = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=True)
+    maintenance_trust_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=True)
 
-    name = sqlalchemy.Column(
-        sqlalchemy.String(255),
-        nullable=False)
+    name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     notes = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
     endpoint_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('endpoint.id'), nullable=False)
-    os_type = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False)
-    platform = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('endpoint.id'), nullable=False
+    )
+    os_type = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
+    platform = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     environment_options = sqlalchemy.Column(types.Json, nullable=True)
     status = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False,
-        default=lambda: constants.MINION_POOL_STATUS_UNKNOWN)
-    shared_resources = sqlalchemy.Column(
-        types.Json, nullable=True)
-    minimum_minions = sqlalchemy.Column(
-        sqlalchemy.Integer, nullable=False)
-    maximum_minions = sqlalchemy.Column(
-        sqlalchemy.Integer, nullable=False)
-    minion_max_idle_time = sqlalchemy.Column(
-        sqlalchemy.Integer, nullable=False)
+        sqlalchemy.String(255),
+        nullable=False,
+        default=lambda: constants.MINION_POOL_STATUS_UNKNOWN,
+    )
+    shared_resources = sqlalchemy.Column(types.Json, nullable=True)
+    minimum_minions = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
+    maximum_minions = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
+    minion_max_idle_time = sqlalchemy.Column(sqlalchemy.Integer, nullable=False)
     minion_retention_strategy = sqlalchemy.Column(
-        sqlalchemy.String(255), nullable=False)
+        sqlalchemy.String(255), nullable=False
+    )
 
     minion_machines = orm.relationship(
-        MinionMachine, backref=orm.backref('minion_pool'),
+        MinionMachine,
+        backref=orm.backref('minion_pool'),
         primaryjoin="and_(MinionMachine.pool_id==MinionPool.id, "
-                    "MinionMachine.deleted=='0')")
-    events = orm.relationship(MinionPoolEvent, cascade="all,delete",
-                              backref=orm.backref('minion_pool'),
-                              order_by=MinionPoolEvent.index)
-    progress_updates = orm.relationship(MinionPoolProgressUpdate,
-                                        cascade="all,delete",
-                                        backref=orm.backref('minion_pool'),
-                                        order_by=(
-                                            MinionPoolProgressUpdate.index))
+        "MinionMachine.deleted=='0')",
+    )
+    events = orm.relationship(
+        MinionPoolEvent,
+        cascade="all,delete",
+        backref=orm.backref('minion_pool'),
+        order_by=MinionPoolEvent.index,
+    )
+    progress_updates = orm.relationship(
+        MinionPoolProgressUpdate,
+        cascade="all,delete",
+        backref=orm.backref('minion_pool'),
+        order_by=(MinionPoolProgressUpdate.index),
+    )
 
     def to_dict(
-            self, include_machines=True, include_events=True,
-            include_progress_updates=True):
+        self, include_machines=True, include_events=True, include_progress_updates=True
+    ):
         base = {
             "id": self.id,
             "name": self.name,
@@ -631,27 +635,26 @@ class MinionPool(
             "minimum_minions": self.minimum_minions,
             "maximum_minions": self.maximum_minions,
             "minion_max_idle_time": self.minion_max_idle_time,
-            "minion_retention_strategy": self.minion_retention_strategy}
+            "minion_retention_strategy": self.minion_retention_strategy,
+        }
         base["minion_machines"] = []
         if include_machines:
             base["minion_machines"] = [
-                machine.to_dict() for machine in self.minion_machines]
+                machine.to_dict() for machine in self.minion_machines
+            ]
         if include_events:
-            base["events"] = [
-                ev.to_dict() for ev in self.events]
+            base["events"] = [ev.to_dict() for ev in self.events]
         if include_progress_updates:
-            base["progress_updates"] = [
-                pu.to_dict() for pu in self.progress_updates]
+            base["progress_updates"] = [pu.to_dict() for pu in self.progress_updates]
         return base
 
 
-class Endpoint(BASE, models.TimestampMixin, models.ModelBase,
-               models.SoftDeleteMixin):
+class Endpoint(BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin):
     __tablename__ = 'endpoint'
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
     user_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     project_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     connection_info = sqlalchemy.Column(types.Json, nullable=False)
@@ -659,41 +662,49 @@ class Endpoint(BASE, models.TimestampMixin, models.ModelBase,
     name = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)
     description = sqlalchemy.Column(sqlalchemy.String(1024), nullable=True)
     origin_actions = orm.relationship(
-        BaseTransferAction, backref=orm.backref('origin_endpoint'),
+        BaseTransferAction,
+        backref=orm.backref('origin_endpoint'),
         primaryjoin="and_(BaseTransferAction.origin_endpoint_id==Endpoint.id, "
-                    "BaseTransferAction.deleted=='0')")
+        "BaseTransferAction.deleted=='0')",
+    )
     destination_actions = orm.relationship(
-        BaseTransferAction, backref=orm.backref('destination_endpoint'),
+        BaseTransferAction,
+        backref=orm.backref('destination_endpoint'),
         primaryjoin="and_(BaseTransferAction.destination_endpoint_id=="
-                    "Endpoint.id, BaseTransferAction.deleted=='0')")
+        "Endpoint.id, BaseTransferAction.deleted=='0')",
+    )
     minion_pools = orm.relationship(
-        MinionPool, backref=orm.backref('endpoint'),
+        MinionPool,
+        backref=orm.backref('endpoint'),
         primaryjoin="and_(MinionPool.endpoint_id=="
-                    "Endpoint.id, MinionPool.deleted=='0')")
+        "Endpoint.id, MinionPool.deleted=='0')",
+    )
     mapped_regions = orm.relationship(
-        'Region', back_populates='mapped_endpoints',
-        secondary="endpoint_region_mapping")
+        'Region', back_populates='mapped_endpoints', secondary="endpoint_region_mapping"
+    )
 
 
-class TransferSchedule(BASE, models.TimestampMixin, models.ModelBase,
-                       models.SoftDeleteMixin):
+class TransferSchedule(
+    BASE, models.TimestampMixin, models.ModelBase, models.SoftDeleteMixin
+):
     __tablename__ = "transfer_schedules"
 
-    id = sqlalchemy.Column(sqlalchemy.String(36),
-                           default=lambda: str(uuid.uuid4()),
-                           primary_key=True)
+    id = sqlalchemy.Column(
+        sqlalchemy.String(36), default=lambda: str(uuid.uuid4()), primary_key=True
+    )
     transfer_id = sqlalchemy.Column(
-        sqlalchemy.String(36),
-        sqlalchemy.ForeignKey('transfer.id'), nullable=False)
+        sqlalchemy.String(36), sqlalchemy.ForeignKey('transfer.id'), nullable=False
+    )
     transfer = orm.relationship(
-        Transfer, backref=orm.backref("schedules"), foreign_keys=[transfer_id])
+        Transfer, backref=orm.backref("schedules"), foreign_keys=[transfer_id]
+    )
     schedule = sqlalchemy.Column(types.Json, nullable=False)
-    expiration_date = sqlalchemy.Column(
-        sqlalchemy.types.DateTime, nullable=True)
+    expiration_date = sqlalchemy.Column(sqlalchemy.types.DateTime, nullable=True)
     enabled = sqlalchemy.Column(
-        sqlalchemy.Boolean, nullable=False, default=lambda: False)
+        sqlalchemy.Boolean, nullable=False, default=lambda: False
+    )
     shutdown_instance = sqlalchemy.Column(
-        sqlalchemy.Boolean, nullable=False, default=False)
-    auto_deploy = sqlalchemy.Column(
-        sqlalchemy.Boolean, nullable=False, default=False)
+        sqlalchemy.Boolean, nullable=False, default=False
+    )
+    auto_deploy = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False, default=False)
     trust_id = sqlalchemy.Column(sqlalchemy.String(255), nullable=False)

+ 2 - 5
coriolis/db/sqlalchemy/types.py

@@ -17,8 +17,8 @@
 import zlib
 
 from oslo_serialization import jsonutils
-from sqlalchemy.dialects import mysql
 from sqlalchemy import types
+from sqlalchemy.dialects import mysql
 
 
 class LongText(types.TypeDecorator):
@@ -42,7 +42,6 @@ class Blob(types.TypeDecorator):
 
 
 class Json(LongText):
-
     def process_bind_param(self, value, dialect):
         return jsonutils.dumps(value)
 
@@ -53,10 +52,8 @@ class Json(LongText):
 
 
 class Bson(Blob):
-
     def process_bind_param(self, value, dialect):
-        return zlib.compress(
-            jsonutils.dumps(value).encode('utf-8'))
+        return zlib.compress(jsonutils.dumps(value).encode('utf-8'))
 
     def process_result_value(self, value, dialect):
         if value is None:

+ 15 - 14
coriolis/deployer_manager/rpc/client.py

@@ -1,36 +1,37 @@
 # Copyright 2025 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from oslo_config import cfg
 import oslo_messaging as messaging
+from oslo_config import cfg
 
-from coriolis import constants
-from coriolis import rpc
+from coriolis import constants, rpc
 
 VERSION = "1.0"
 
 deployer_manager_opts = [
     cfg.IntOpt(
         'deployer_manager_rpc_timeout',
-        help="Number of seconds until RPC calls to the deployer manager "
-             "timeout.")]
+        help="Number of seconds until RPC calls to the deployer manager timeout.",
+    )
+]
 CONF = cfg.CONF
 CONF.register_opts(deployer_manager_opts, 'deployer_manager')
 
 
 class DeployerManagerClient(rpc.BaseRPCClient):
-
-    def __init__(
-            self, timeout=None):
+    def __init__(self, timeout=None):
         target = messaging.Target(
-            topic=constants.DEPLOYER_MANAGER_MAIN_MESSAGING_TOPIC,
-            version=VERSION)
+            topic=constants.DEPLOYER_MANAGER_MAIN_MESSAGING_TOPIC, version=VERSION
+        )
         if timeout is None:
             timeout = CONF.deployer_manager.deployer_manager_rpc_timeout
         super(DeployerManagerClient, self).__init__(target, timeout=timeout)
 
-    def execute_auto_deployment(
-            self, ctxt, transfer_id, deployer_id, **kwargs):
+    def execute_auto_deployment(self, ctxt, transfer_id, deployer_id, **kwargs):
         self._cast(
-            ctxt, 'execute_auto_deployment', transfer_id=transfer_id,
-            deployer_id=deployer_id, **kwargs)
+            ctxt,
+            'execute_auto_deployment',
+            transfer_id=transfer_id,
+            deployer_id=deployer_id,
+            **kwargs,
+        )

+ 47 - 39
coriolis/deployer_manager/rpc/server.py

@@ -6,12 +6,8 @@ import time
 from oslo_config import cfg
 from oslo_log import log as logging
 
+from coriolis import constants, context, exception, keystone, utils
 from coriolis.conductor.rpc import client as rpc_conductor_client
-from coriolis import constants
-from coriolis import context
-from coriolis import exception
-from coriolis import keystone
-from coriolis import utils
 
 CONF = cfg.CONF
 LOG = logging.getLogger(__name__)
@@ -20,7 +16,6 @@ VERSION = "1.0"
 
 
 class DeployerManagerServerEndpoint:
-
     def __init__(self):
         self._admin_ctx = context.get_admin_context()
         self._conductor_client_instance = None
@@ -29,35 +24,36 @@ class DeployerManagerServerEndpoint:
     @property
     def _rpc_conductor_client(self):
         if not getattr(self, '_conductor_client_instance', None):
-            self._conductor_client_instance = (
-                rpc_conductor_client.ConductorClient())
+            self._conductor_client_instance = rpc_conductor_client.ConductorClient()
         return self._conductor_client_instance
 
     def _wait_for_pending_deployment_status_change(self, deployment_id):
         pending = constants.EXECUTION_STATUS_PENDING
         LOG.info(
-            f"Waiting for deployment '{deployment_id}' to be out of "
-            f"'{pending}' status")
+            f"Waiting for deployment '{deployment_id}' to be out of '{pending}' status"
+        )
         i = 0
         max_retries = 60
         while i < max_retries:
             deployment = self._rpc_conductor_client.get_deployment(
-                self._admin_ctx, deployment_id)
+                self._admin_ctx, deployment_id
+            )
             deployment_status = deployment['last_execution_status']
             if deployment_status != pending:
                 LOG.info(
                     f"Deployment '{deployment_id}' changed into "
-                    f"'{deployment_status}' and not {pending} anymore.")
+                    f"'{deployment_status}' and not {pending} anymore."
+                )
                 return
 
-            LOG.info(
-                f"Deployment '{deployment_id}' is still '{deployment_status}'")
+            LOG.info(f"Deployment '{deployment_id}' is still '{deployment_status}'")
             i += 1
             time.sleep(1)
 
         raise exception.InvalidDeploymentState(
             f"Timed out waiting for deployment '{deployment_id}' to be out of "
-            f"'{pending}' status.")
+            f"'{pending}' status."
+        )
 
     def _check_deployer_status(self, deployment_id):
         active_statuses = [
@@ -75,73 +71,85 @@ class DeployerManagerServerEndpoint:
         ]
         try:
             deployment = self._rpc_conductor_client.get_deployment(
-                self._admin_ctx, deployment_id)
+                self._admin_ctx, deployment_id
+            )
             deployer_id = deployment.get('deployer_id')
             transfer_id = deployment.get('transfer_id')
             if not deployer_id:
                 raise exception.InvalidDeploymentState(
                     f"Deployment '{deployment['id']}' is in {PENDING_STATUS} "
-                    f"status, without any deployer execution registered.")
+                    f"status, without any deployer execution registered."
+                )
             deployer_execution = (
                 self._rpc_conductor_client.get_transfer_tasks_execution(
-                    self._admin_ctx, transfer_id, deployer_id))
-            LOG.debug(
-                f"Waiting for deployer '{deployer_id}' to complete.")
+                    self._admin_ctx, transfer_id, deployer_id
+                )
+            )
+            LOG.debug(f"Waiting for deployer '{deployer_id}' to complete.")
             ex_status = deployer_execution['status']
             LOG.debug(f"Deployer '{deployer_id}' status is {ex_status}")
             if ex_status in active_statuses:
                 return
             elif ex_status == constants.EXECUTION_STATUS_COMPLETED:
-                LOG.debug(
-                    f"Confirming deployer '{deployer_id}' completed.")
-                admin_ctx = context.get_admin_context(
-                    trust_id=deployment['trust_id'])
+                LOG.debug(f"Confirming deployer '{deployer_id}' completed.")
+                admin_ctx = context.get_admin_context(trust_id=deployment['trust_id'])
                 admin_ctx.delete_trust_id = True
                 self._rpc_conductor_client.confirm_deployer_completed(
-                    admin_ctx, deployment['id'], force=False)
-                return self._wait_for_pending_deployment_status_change(
-                    deployment_id)
+                    admin_ctx, deployment['id'], force=False
+                )
+                return self._wait_for_pending_deployment_status_change(deployment_id)
             else:
                 if ex_status in error_statuses:
                     raise exception.InvalidTransferState(
                         f"Got status '{ex_status}' for execution with ID "
-                        f"'{deployer_id}'. Deployment cannot occur.")
+                        f"'{deployer_id}'. Deployment cannot occur."
+                    )
                 else:
                     raise exception.InvalidTransferState(
                         f"Deployer with ID '{deployer_id}' is in invalid "
-                        f"state '{ex_status}'. Deployment cannot occur.")
+                        f"state '{ex_status}'. Deployment cannot occur."
+                    )
         except BaseException as ex:
             LOG.error(
                 f"Reporting deployer failure for deployment "
                 f"'{deployment_id}'. Error was: "
-                f"{utils.get_exception_details()}")
+                f"{utils.get_exception_details()}"
+            )
             self._rpc_conductor_client.report_deployer_failure(
-                self._admin_ctx, deployment_id, str(ex))
+                self._admin_ctx, deployment_id, str(ex)
+            )
 
     def _loop(self):
         while True:
             try:
                 deployments = self._rpc_conductor_client.get_deployments(
-                    self._admin_ctx, include_tasks=False,
+                    self._admin_ctx,
+                    include_tasks=False,
                     include_task_info=False,
-                    filters={'status': PENDING_STATUS})
+                    filters={'status': PENDING_STATUS},
+                )
                 for pending_deployment in deployments:
                     self._check_deployer_status(pending_deployment['id'])
             except Exception:
                 LOG.warning(
                     f"Deployer manager failed to list pending deployments. "
-                    f"Error was: {utils.get_exception_details()}")
+                    f"Error was: {utils.get_exception_details()}"
+                )
             time.sleep(10)
 
     def _init_loop(self):
         utils.start_thread(self._loop)
 
-    def execute_auto_deployment(
-            self, ctxt, transfer_id, deployer_id, **kwargs):
+    def execute_auto_deployment(self, ctxt, transfer_id, deployer_id, **kwargs):
         LOG.debug(
             f"Creating deployment for deployer ID '{deployer_id}' of transfer "
-            f"'{transfer_id}'")
+            f"'{transfer_id}'"
+        )
         keystone.create_trust(ctxt)
         self._rpc_conductor_client.deploy_transfer_instances(
-            ctxt, transfer_id, wait_for_execution=deployer_id,
-            trust_id=ctxt.trust_id, **kwargs)
+            ctxt,
+            transfer_id,
+            wait_for_execution=deployer_id,
+            trust_id=ctxt.trust_id,
+            **kwargs,
+        )

+ 39 - 17
coriolis/deployments/api.py

@@ -8,16 +8,27 @@ class API(object):
     def __init__(self):
         self._rpc_client = rpc_client.ConductorClient()
 
-    def deploy_transfer_instances(self, ctxt, transfer_id,
-                                  instance_osmorphing_minion_pool_mappings,
-                                  clone_disks=False, force=False,
-                                  skip_os_morphing=False, user_scripts=None):
+    def deploy_transfer_instances(
+        self,
+        ctxt,
+        transfer_id,
+        instance_osmorphing_minion_pool_mappings,
+        clone_disks=False,
+        force=False,
+        skip_os_morphing=False,
+        user_scripts=None,
+    ):
         return self._rpc_client.deploy_transfer_instances(
-            ctxt, transfer_id, instance_osmorphing_minion_pool_mappings=(
-                instance_osmorphing_minion_pool_mappings),
-            clone_disks=clone_disks, force=force,
+            ctxt,
+            transfer_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)
+            user_scripts=user_scripts,
+        )
 
     def delete(self, ctxt, deployment_id):
         self._rpc_client.delete_deployment(ctxt, deployment_id)
@@ -25,18 +36,29 @@ class API(object):
     def cancel(self, ctxt, deployment_id, force):
         self._rpc_client.cancel_deployment(ctxt, deployment_id, force)
 
-    def get_deployments(self, ctxt, include_tasks=False,
-                        include_task_info=False,
-                        marker=None, limit=None,
-                        sort_keys=None, sort_dirs=None,
-                        filters=None):
+    def get_deployments(
+        self,
+        ctxt,
+        include_tasks=False,
+        include_task_info=False,
+        marker=None,
+        limit=None,
+        sort_keys=None,
+        sort_dirs=None,
+        filters=None,
+    ):
         return self._rpc_client.get_deployments(
-            ctxt, include_tasks, include_task_info=include_task_info,
-            marker=marker, limit=limit,
-            sort_keys=sort_keys, sort_dirs=sort_dirs,
+            ctxt,
+            include_tasks,
+            include_task_info=include_task_info,
+            marker=marker,
+            limit=limit,
+            sort_keys=sort_keys,
+            sort_dirs=sort_dirs,
             filters=filters,
         )
 
     def get_deployment(self, ctxt, deployment_id, include_task_info=False):
         return self._rpc_client.get_deployment(
-            ctxt, deployment_id, include_task_info=include_task_info)
+            ctxt, deployment_id, include_task_info=include_task_info
+        )

+ 1 - 1
coriolis/diagnostics/api.py

@@ -1,9 +1,9 @@
 # Copyright 2024 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from coriolis import utils
 from coriolis.conductor.rpc import client as conductor_rpc
 from coriolis.transfer_cron.rpc import client as cron_rpc
-from coriolis import utils
 from coriolis.worker.rpc import client as worker_rpc
 
 

+ 20 - 13
coriolis/endpoint_options/api.py

@@ -8,27 +8,34 @@ from coriolis.minion_manager.rpc import client as rpc_minion_manager_client
 class API(object):
     def __init__(self):
         self._rpc_minion_manager_client = (
-            rpc_minion_manager_client.MinionManagerClient())
+            rpc_minion_manager_client.MinionManagerClient()
+        )
         self._rpc_conductor_client = rpc_conductor_client.ConductorClient()
 
     def get_endpoint_source_options(
-            self, ctxt, endpoint_id, env=None, option_names=None):
+        self, ctxt, endpoint_id, env=None, option_names=None
+    ):
         return self._rpc_conductor_client.get_endpoint_source_options(
-            ctxt, endpoint_id, env, option_names)
+            ctxt, endpoint_id, env, option_names
+        )
 
     def get_endpoint_destination_options(
-            self, ctxt, endpoint_id, env=None, option_names=None):
+        self, ctxt, endpoint_id, env=None, option_names=None
+    ):
         return self._rpc_conductor_client.get_endpoint_destination_options(
-            ctxt, endpoint_id, env, option_names)
+            ctxt, endpoint_id, env, option_names
+        )
 
     def get_endpoint_source_minion_pool_options(
-            self, ctxt, endpoint_id, env=None, option_names=None):
-        return (self._rpc_minion_manager_client.
-                get_endpoint_source_minion_pool_options)(
-            ctxt, endpoint_id, env, option_names)
+        self, ctxt, endpoint_id, env=None, option_names=None
+    ):
+        return (
+            self._rpc_minion_manager_client.get_endpoint_source_minion_pool_options
+        )(ctxt, endpoint_id, env, option_names)
 
     def get_endpoint_destination_minion_pool_options(
-            self, ctxt, endpoint_id, env=None, option_names=None):
-        return (self._rpc_minion_manager_client.
-                get_endpoint_destination_minion_pool_options)(
-            ctxt, endpoint_id, env, option_names)
+        self, ctxt, endpoint_id, env=None, option_names=None
+    ):
+        return (
+            self._rpc_minion_manager_client.get_endpoint_destination_minion_pool_options
+        )(ctxt, endpoint_id, env, option_names)

+ 27 - 14
coriolis/endpoint_resources/api.py

@@ -8,27 +8,40 @@ class API(object):
     def __init__(self):
         self._rpc_client = rpc_client.ConductorClient()
 
-    def get_endpoint_instances(self, ctxt, endpoint_id, source_environment,
-                               marker=None, limit=None,
-                               instance_name_pattern=None, refresh=False):
+    def get_endpoint_instances(
+        self,
+        ctxt,
+        endpoint_id,
+        source_environment,
+        marker=None,
+        limit=None,
+        instance_name_pattern=None,
+        refresh=False,
+    ):
         return self._rpc_client.get_endpoint_instances(
-            ctxt, endpoint_id, source_environment, marker,
-            limit, instance_name_pattern, refresh=refresh)
+            ctxt,
+            endpoint_id,
+            source_environment,
+            marker,
+            limit,
+            instance_name_pattern,
+            refresh=refresh,
+        )
 
     def get_endpoint_instance(
-            self, ctxt, endpoint_id, source_environment, instance_name):
+        self, ctxt, endpoint_id, source_environment, instance_name
+    ):
         return self._rpc_client.get_endpoint_instance(
-            ctxt, endpoint_id, source_environment, instance_name)
+            ctxt, endpoint_id, source_environment, instance_name
+        )
 
     def get_endpoint_networks(self, ctxt, endpoint_id, env):
-        return self._rpc_client.get_endpoint_networks(
-            ctxt, endpoint_id, env)
+        return self._rpc_client.get_endpoint_networks(ctxt, endpoint_id, env)
 
     def get_endpoint_storage(self, ctxt, endpoint_id, env):
-        return self._rpc_client.get_endpoint_storage(
-            ctxt, endpoint_id, env)
+        return self._rpc_client.get_endpoint_storage(ctxt, endpoint_id, env)
 
-    def get_endpoint_inventory_csv(
-            self, ctxt, endpoint_id, source_environment):
+    def get_endpoint_inventory_csv(self, ctxt, endpoint_id, source_environment):
         return self._rpc_client.get_endpoint_inventory_csv(
-            ctxt, endpoint_id, source_environment)
+            ctxt, endpoint_id, source_environment
+        )

+ 26 - 21
coriolis/endpoints/api.py

@@ -1,26 +1,27 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from coriolis import utils
 from coriolis.conductor.rpc import client as rpc_conductor_client
 from coriolis.minion_manager.rpc import client as rpc_minion_manager_client
-from coriolis import utils
 
 
 class API(object):
     def __init__(self):
         self._rpc_conductor_client = rpc_conductor_client.ConductorClient()
         self._rpc_minion_manager_client = (
-            rpc_minion_manager_client.MinionManagerClient())
+            rpc_minion_manager_client.MinionManagerClient()
+        )
 
-    def create(self, ctxt, name, endpoint_type, description,
-               connection_info, mapped_regions):
+    def create(
+        self, ctxt, name, endpoint_type, description, connection_info, mapped_regions
+    ):
         return self._rpc_conductor_client.create_endpoint(
-            ctxt, name, endpoint_type, description, connection_info,
-            mapped_regions)
+            ctxt, name, endpoint_type, description, connection_info, mapped_regions
+        )
 
     def update(self, ctxt, endpoint_id, properties):
-        return self._rpc_conductor_client.update_endpoint(
-            ctxt, endpoint_id, properties)
+        return self._rpc_conductor_client.update_endpoint(ctxt, endpoint_id, properties)
 
     def delete(self, ctxt, endpoint_id):
         self._rpc_conductor_client.delete_endpoint(ctxt, endpoint_id)
@@ -33,29 +34,33 @@ class API(object):
 
     def validate_connection(self, ctxt, endpoint_id):
         return self._rpc_conductor_client.validate_endpoint_connection(
-            ctxt, endpoint_id)
+            ctxt, endpoint_id
+        )
 
     @utils.bad_request_on_error("Invalid destination environment: %s")
     def validate_target_environment(self, ctxt, endpoint_id, target_env):
         return self._rpc_conductor_client.validate_endpoint_target_environment(
-            ctxt, endpoint_id, target_env)
+            ctxt, endpoint_id, target_env
+        )
 
     @utils.bad_request_on_error("Invalid source environment: %s")
     def validate_source_environment(self, ctxt, endpoint_id, source_env):
         return self._rpc_conductor_client.validate_endpoint_source_environment(
-            ctxt, endpoint_id, source_env)
+            ctxt, endpoint_id, source_env
+        )
 
     @utils.bad_request_on_error("Invalid source minion pool environment: %s")
     def validate_endpoint_source_minion_pool_options(
-            self, ctxt, endpoint_id, pool_environment):
-        return (self._rpc_minion_manager_client.
-                validate_endpoint_source_minion_pool_options)(
-            ctxt, endpoint_id, pool_environment)
+        self, ctxt, endpoint_id, pool_environment
+    ):
+        return (
+            self._rpc_minion_manager_client.validate_endpoint_source_minion_pool_options
+        )(ctxt, endpoint_id, pool_environment)
 
-    @utils.bad_request_on_error(
-        "Invalid destination minion pool environment: %s")
+    @utils.bad_request_on_error("Invalid destination minion pool environment: %s")
     def validate_endpoint_destination_minion_pool_options(
-            self, ctxt, endpoint_id, pool_environment):
-        return (self._rpc_minion_manager_client.
-                validate_endpoint_destination_minion_pool_options)(
-            ctxt, endpoint_id, pool_environment)
+        self, ctxt, endpoint_id, pool_environment
+    ):
+        return (
+            self._rpc_minion_manager_client.validate_endpoint_destination_minion_pool_options
+        )(ctxt, endpoint_id, pool_environment)

+ 46 - 38
coriolis/events.py

@@ -10,15 +10,14 @@ from six import with_metaclass
 
 from coriolis import constants
 
-
 LOG = logging.getLogger(__name__)
 
 _PercStepData = collections.namedtuple(
-    "_PercStepData", "progress_update_id last_perc last_value total_steps")
+    "_PercStepData", "progress_update_id last_perc last_value total_steps"
+)
 
 
 class EventManager(object, with_metaclass(abc.ABCMeta)):
-
     def __init__(self, event_handler):
         self._event_handler = event_handler
         self._perc_steps = {}
@@ -28,15 +27,14 @@ class EventManager(object, with_metaclass(abc.ABCMeta)):
             method_obj = getattr(self._event_handler, str(method_name), None)
             if not method_obj:
                 raise AttributeError(
-                    "No method named '%s' for event handler of type '%s'." % (
-                        method_name, type(self._event_handler)))
+                    "No method named '%s' for event handler of type '%s'."
+                    % (method_name, type(self._event_handler))
+                )
             return method_obj(*args, **kwargs)
 
     def add_percentage_step(self, message, total_steps, initial_step=0):
         if total_steps < 0:
-            LOG.warn(
-                "Max percentage value was negative (%s). Reset to 0",
-                total_steps)
+            LOG.warn("Max percentage value was negative (%s). Reset to 0", total_steps)
             total_steps = 0
         if total_steps == 0:
             LOG.warn("Max percentage value set to 0 (zero)")
@@ -44,31 +42,37 @@ class EventManager(object, with_metaclass(abc.ABCMeta)):
         if initial_step > total_steps:
             raise ValueError(
                 "Provided percent step initial value '%s' is larger than the "
-                "maximum value '%s'" % (initial_step, total_steps))
+                "maximum value '%s'" % (initial_step, total_steps)
+            )
         progress_update = self._call_event_handler(
-            'add_progress_update', message, initial_step=initial_step,
-            total_steps=total_steps, return_event=True)
-        progress_update_id = (
-            self._call_event_handler(
-                'get_progress_update_identifier', progress_update))
+            'add_progress_update',
+            message,
+            initial_step=initial_step,
+            total_steps=total_steps,
+            return_event=True,
+        )
+        progress_update_id = self._call_event_handler(
+            'get_progress_update_identifier', progress_update
+        )
 
         perc = 0
         if initial_step > 0 and total_steps > 0:
             perc = int(initial_step * 100 // total_steps)
         self._perc_steps[progress_update_id] = _PercStepData(
-            progress_update_id, perc, initial_step, total_steps)
+            progress_update_id, perc, initial_step, total_steps
+        )
 
         return self._perc_steps[progress_update_id]
 
     def set_percentage_step(self, step, new_current_step):
-        perc_step = self._perc_steps.get(
-            step.progress_update_id, None)
+        perc_step = self._perc_steps.get(step.progress_update_id, None)
         if perc_step is None:
             return
 
         if perc_step.last_value > new_current_step:
-            LOG.warn("rollback for perc update %s not allowed" %
-                     step.progress_update_id)
+            LOG.warn(
+                "rollback for perc update %s not allowed" % step.progress_update_id
+            )
             return
 
         perc = 0
@@ -77,53 +81,57 @@ class EventManager(object, with_metaclass(abc.ABCMeta)):
 
         if self._call_event_handler and perc > perc_step.last_perc:
             sync_final = (
-                perc_step.total_steps > 0 and
-                new_current_step >= perc_step.total_steps)
+                perc_step.total_steps > 0 and new_current_step >= perc_step.total_steps
+            )
             self._call_event_handler(
-                'update_progress_update', step.progress_update_id,
-                new_current_step, sync=sync_final)
+                'update_progress_update',
+                step.progress_update_id,
+                new_current_step,
+                sync=sync_final,
+            )
             perc_id = copy.copy(step.progress_update_id)
             total_steps = perc_step.total_steps
             del self._perc_steps[step.progress_update_id]
             del perc_step
-            self._perc_steps[perc_id] = _PercStepData(
-                perc_id, perc, 0, total_steps)
+            self._perc_steps[perc_id] = _PercStepData(perc_id, perc, 0, total_steps)
 
     def progress_update(self, message):
-        self._call_event_handler(
-            'add_progress_update', message, return_event=False)
+        self._call_event_handler('add_progress_update', message, return_event=False)
 
     def info(self, message):
-        self._call_event_handler(
-            'add_event', message, level=constants.TASK_EVENT_INFO)
+        self._call_event_handler('add_event', message, level=constants.TASK_EVENT_INFO)
 
     def warn(self, message):
         self._call_event_handler(
-            'add_event', message, level=constants.TASK_EVENT_WARNING)
+            'add_event', message, level=constants.TASK_EVENT_WARNING
+        )
 
     def error(self, message):
-        self._call_event_handler(
-            'add_event', message, level=constants.TASK_EVENT_ERROR)
+        self._call_event_handler('add_event', message, level=constants.TASK_EVENT_ERROR)
 
 
 class BaseEventHandler(object, with_metaclass(abc.ABCMeta)):
-
     @abc.abstractmethod
     def add_progress_update(
-            self, message, initial_step=0, total_steps=0,
-            return_event=False):
+        self, message, initial_step=0, total_steps=0, return_event=False
+    ):
         pass
 
     @abc.abstractmethod
     def update_progress_update(
-            self, update_identifier, new_current_step,
-            new_total_steps=None, new_message=None, sync=False):
+        self,
+        update_identifier,
+        new_current_step,
+        new_total_steps=None,
+        new_message=None,
+        sync=False,
+    ):
         pass
 
     @classmethod
     @abc.abstractmethod
     def get_progress_update_identifier(cls, progress_update):
-        """ Returns the identifier for a given progress update. """
+        """Returns the identifier for a given progress update."""
         pass
 
     @abc.abstractmethod

+ 45 - 41
coriolis/exception.py

@@ -16,26 +16,23 @@
 
 import sys
 
+import six
+import webob.exc
 from oslo_config import cfg
 from oslo_log import log as logging
 from oslo_versionedobjects import exception as obj_exc
-import six
-import webob.exc
-from webob.util import status_generic_reasons
-from webob.util import status_reasons
+from webob.util import status_generic_reasons, status_reasons
 
-from coriolis.i18n import _, _LE  # noqa
+from coriolis.i18n import _LE, _  # noqa
 
 LOG = logging.getLogger(__name__)
 
 CONF = cfg.CONF
 
-TASK_ALREADY_CANCELLING_EXCEPTION_FMT = (
-    "Task %(task_id)s is in CANCELLING status.")
+TASK_ALREADY_CANCELLING_EXCEPTION_FMT = "Task %(task_id)s is in CANCELLING status."
 
 
 class ConvertedException(webob.exc.WSGIHTTPException):
-
     def __init__(self, code=500, title="", explanation=""):
         self.code = code
         # There is a strict rule about constructing status line for HTTP:
@@ -69,6 +66,7 @@ class CoriolisException(Exception):
     with the keyword arguments provided to the constructor.
 
     """
+
     message = _("An unknown exception occurred.")
     code = 500
     headers = {}
@@ -97,8 +95,9 @@ class CoriolisException(Exception):
                 # log the issue and the kwargs
                 LOG.exception(_LE('Exception in string format operation'))
                 for name, value in kwargs.items():
-                    LOG.error(_LE("%(name)s: %(value)s"),
-                              {'name': name, 'value': value})
+                    LOG.error(
+                        _LE("%(name)s: %(value)s"), {'name': name, 'value': value}
+                    )
                 if CONF.fatal_exception_format_errors:
                     six.reraise(*exc_info)
                 # at least get the core message out if something happened
@@ -209,18 +208,15 @@ class InvalidAuthKey(Invalid):
 
 
 class InvalidConfigurationValue(Invalid):
-    message = _('Value "%(value)s" is not valid for '
-                'configuration option "%(option)s"')
+    message = _('Value "%(value)s" is not valid for configuration option "%(option)s"')
 
 
 class InvalidTaskState(Invalid):
-    message = _(
-        'Task "%(task_id)s" in in an invalid state: %(task_state)s')
+    message = _('Task "%(task_id)s" in in an invalid state: %(task_state)s')
 
 
 class InvalidMinionPoolState(Invalid):
-    message = _(
-        'Minion pool "%(pool_id)s" in in an invalid state: %(pool_state)s')
+    message = _('Minion pool "%(pool_id)s" in in an invalid state: %(pool_state)s')
 
 
 class TaskIsCancelling(InvalidTaskState):
@@ -260,9 +256,7 @@ class TaskFieldsConflict(CoriolisException):
 
 
 class TaskDependencyException(CoriolisException):
-    message = _(
-        "Execution task has non-existent tasks referenced as dependencies."
-    )
+    message = _("Execution task has non-existent tasks referenced as dependencies.")
 
 
 class ServiceUnavailable(Invalid):
@@ -290,9 +284,7 @@ class NotFound(CoriolisException):
 
 
 class MarkerNotFound(NotFound):
-    message = _(
-        "Could not find database record "
-        "identified by marker: %(marker)s")
+    message = _("Could not find database record identified by marker: %(marker)s")
 
 
 class RegionNotFound(NotFound):
@@ -307,7 +299,8 @@ class OSMorphingToolsNotFound(NotFound):
         'Suggestions include performing any needed OSMorphing steps manually '
         'within the source VM and then re-syncing with the "Skip OS Morphing" '
         'option enabled to bypass this stage, or contacting Cloudbase support '
-        'for further assistance.')
+        'for further assistance.'
+    )
 
 
 class OSDetectToolsNotFound(NotFound):
@@ -319,7 +312,8 @@ class OSDetectToolsNotFound(NotFound):
         'Suggestions include performing any needed OSMorphing steps manually '
         'within the source VM and then re-syncing with the "Skip OS Morphing" '
         'option enabled to bypass this stage, or contacting Cloudbase support '
-        'for further assistance.')
+        'for further assistance.'
+    )
 
 
 class FileNotFound(NotFound):
@@ -339,8 +333,7 @@ class DiskStorageMappingNotFound(NotFound):
 
 
 class StorageBackendNotFound(NotFound):
-    message = _(
-        'Storage backend with name "%(storage_name)s" could not be found.')
+    message = _('Storage backend with name "%(storage_name)s" could not be found.')
 
 
 class ImageNotFound(NotFound):
@@ -432,6 +425,7 @@ class QEMUException(Exception):
 
 
 if six.PY2:
+
     class ConnectionRefusedError(OSError):
         pass
 else:
@@ -442,41 +436,44 @@ class UnrecognizedWorkerInitSystem(CoriolisException):
     message = _(
         "Could not determine init system for temporary worker VM. The image "
         "used for the worker VM must use systemd as an init system for "
-        "Coriolis to be able to use it for data Replication.")
+        "Coriolis to be able to use it for data Replication."
+    )
 
 
 class NoRegionError(CoriolisException):
     safe = True
     code = 503
     message = _(
-        "No Coriolis region is avaialable to process this request at this "
-        "time.")
+        "No Coriolis region is avaialable to process this request at this time."
+    )
 
 
 class NoSuitableRegionError(NoRegionError):
     message = _(
         "No Coriolis Region(s) fitting the criteria of the required operation "
-        "could be found.")
+        "could be found."
+    )
 
 
 class NoServiceError(CoriolisException):
     safe = True
     code = 503
-    message = _(
-        "No service is avaialable to process this request at this time.")
+    message = _("No service is avaialable to process this request at this time.")
 
 
 class NoWorkerServiceError(NoServiceError):
     message = _(
         "No Coriolis Worker Service(s) were found. Please ensure that "
         "at least one or Coriolis Worker Service(s) are registered "
-        "within the Coriolis installation.")
+        "within the Coriolis installation."
+    )
 
 
 class NoSuitableWorkerServiceError(NoServiceError):
     message = _(
         "No suitable Coriolis Worker service was found which fits the "
-        "criteria for the required operation.")
+        "criteria for the required operation."
+    )
 
 
 class OSMorphingException(CoriolisException):
@@ -496,13 +493,15 @@ class FailedPackageInstallationException(PackageManagerOperationException):
         "additional repositories within the source machine which contain the "
         "packages Coriolis requires, or attempt to manually install the "
         "packages on the source machine and then migrate the VM using Coriolis"
-        " with the OSMorphing process disabled. Error was: %(error)s")
+        " with the OSMorphing process disabled. Error was: %(error)s"
+    )
 
 
 class FailedPackageUninstallationException(PackageManagerOperationException):
     message = (
         "Failed to remove unwanted packages (%(package_names)s) through "
-        "%(package_manager)s. Error was: %(error)s")
+        "%(package_manager)s. Error was: %(error)s"
+    )
 
 
 class MinionMachineCommandTimeout(CoriolisException):
@@ -529,7 +528,8 @@ class OSMorphingSSHOperationTimeout(OSMorphingOperationTimeout):
         "Coriolis may have encountered connection issues to the minion machine"
         " or the command execution time exceeds the timeout set. Try extending"
         " the timeout by editing the 'default_osmorphing_operation_timeout' "
-        "in Coriolis' static configuration file.")
+        "in Coriolis' static configuration file."
+    )
 
 
 class OSMorphingWinRMOperationTimeout(OSMorphingOperationTimeout):
@@ -538,19 +538,22 @@ class OSMorphingWinRMOperationTimeout(OSMorphingOperationTimeout):
         "Coriolis may have encountered connection issues to the minion machine"
         " or the command execution time exceeds the timeout set. Try extending"
         " the timeout by editing the 'default_osmorphing_operation_timeout' "
-        "in Coriolis' static configuration file.")
+        "in Coriolis' static configuration file."
+    )
 
 
 class ChecksumAlgorithmMismatch(CoriolisException):
     message = (
         "Checksum algorithm mismatch for disk '%(disk)s': "
-        "source=%(source_alg)s, destination=%(dest_alg)s")
+        "source=%(source_alg)s, destination=%(dest_alg)s"
+    )
 
 
 class ChecksumMismatch(CoriolisException):
     message = (
         "Checksum mismatch for disk '%(disk)s': "
-        "source=%(source_checksum)s, destination=%(dest_checksum)s")
+        "source=%(source_checksum)s, destination=%(dest_checksum)s"
+    )
 
 
 class LicenceReservationFulfilledException(Invalid):
@@ -558,4 +561,5 @@ class LicenceReservationFulfilledException(Invalid):
         "The %(scenario)s operation with ID '%(action_id)s' (licensing "
         "reservation '%(reservation_id)s' of type '%(reservation_type)s') "
         "has already been fulfilled. Please create a new %(scenario)s "
-        "operation to create a new licensing reservation.")
+        "operation to create a new licensing reservation."
+    )

+ 68 - 45
coriolis/keystone.py

@@ -11,21 +11,27 @@ from oslo_log import log as logging
 from coriolis import exception
 
 opts = [
-    cfg.StrOpt('auth_url',
-               default=None,
-               help='Default auth URL to be used when not specified in the'
-               ' migration\'s connection info.'),
-    cfg.StrOpt('cafile',
-               default=None,
-               help='The CA file used to validate openstack service'
-               ' API endpoints.'),
-    cfg.IntOpt('identity_api_version',
-               min=2, max=3,
-               default=2,
-               help='Default Keystone API version.'),
-    cfg.BoolOpt('allow_untrusted',
-                default=False,
-                help='Allow untrusted SSL/TLS certificates.'),
+    cfg.StrOpt(
+        'auth_url',
+        default=None,
+        help='Default auth URL to be used when not specified in the'
+        ' migration\'s connection info.',
+    ),
+    cfg.StrOpt(
+        'cafile',
+        default=None,
+        help='The CA file used to validate openstack service API endpoints.',
+    ),
+    cfg.IntOpt(
+        'identity_api_version',
+        min=2,
+        max=3,
+        default=2,
+        help='Default Keystone API version.',
+    ),
+    cfg.BoolOpt(
+        'allow_untrusted', default=False, help='Allow untrusted SSL/TLS certificates.'
+    ),
 ]
 
 CONF = cfg.CONF
@@ -34,12 +40,16 @@ CONF.register_opts(opts, 'keystone')
 LOG = logging.getLogger(__name__)
 
 TRUSTEE_CONF_GROUP = 'trustee'
-loading.register_auth_conf_options(CONF, TRUSTEE_CONF_GROUP, )
+loading.register_auth_conf_options(
+    CONF,
+    TRUSTEE_CONF_GROUP,
+)
 
 
 def _get_trusts_auth_plugin(trust_id=None):
     return loading.load_auth_from_conf_options(
-        CONF, TRUSTEE_CONF_GROUP, trust_id=trust_id)
+        CONF, TRUSTEE_CONF_GROUP, trust_id=trust_id
+    )
 
 
 def _get_verify_option():
@@ -65,9 +75,9 @@ def create_trust(ctxt):
         auth_url=trusts_auth_plugin.auth_url,
         token=ctxt.auth_token,
         project_name=ctxt.project_name,
-        project_domain_name=ctxt.project_domain_name)
-    session = ks_session.Session(
-        auth=auth, verify=_get_verify_option())
+        project_domain_name=ctxt.project_domain_name,
+    )
+    session = ks_session.Session(auth=auth, verify=_get_verify_option())
 
     try:
         trustee_user_id = trusts_auth_plugin.get_user_id(session)
@@ -83,17 +93,23 @@ def create_trust(ctxt):
         "Granting Keystone trust. Trustor: %(trustor_user_id)s, trustee:"
         " %(trustee_user_id)s, project: %(trustor_proj_id)s, roles:"
         " %(roles)s",
-        {"trustor_user_id": trustor_user_id,
-         "trustee_user_id": trustee_user_id,
-         "trustor_proj_id": trustor_proj_id, "roles": roles})
+        {
+            "trustor_user_id": trustor_user_id,
+            "trustee_user_id": trustee_user_id,
+            "trustor_proj_id": trustor_proj_id,
+            "roles": roles,
+        },
+    )
 
     # Trusts are not supported before Keystone v3
     client = kc_v3.Client(session=session)
-    trust = client.trusts.create(trustor_user=trustor_user_id,
-                                 trustee_user=trustee_user_id,
-                                 project=trustor_proj_id,
-                                 impersonation=True,
-                                 role_names=roles)
+    trust = client.trusts.create(
+        trustor_user=trustor_user_id,
+        trustee_user=trustee_user_id,
+        project=trustor_proj_id,
+        impersonation=True,
+        role_names=roles,
+    )
     LOG.debug("Trust id: %s" % trust.id)
     ctxt.trust_id = trust.id
 
@@ -103,8 +119,7 @@ def delete_trust(ctxt):
         LOG.debug("Deleting trust id: %s", ctxt.trust_id)
 
         auth = _get_trusts_auth_plugin(ctxt.trust_id)
-        session = ks_session.Session(
-            auth=auth, verify=_get_verify_option())
+        session = ks_session.Session(auth=auth, verify=_get_verify_option())
         client = kc_v3.Client(session=session)
         try:
             client.trusts.delete(ctxt.trust_id)
@@ -126,9 +141,7 @@ def create_keystone_session(ctxt, connection_info={}):
             auth = _get_trusts_auth_plugin(ctxt.trust_id)
         else:
             plugin_name = "token"
-            plugin_args = {
-                "token": ctxt.auth_token
-            }
+            plugin_args = {"token": ctxt.auth_token}
     else:
         plugin_name = "password"
         password = connection_info.get("password")
@@ -145,53 +158,63 @@ def create_keystone_session(ctxt, connection_info={}):
             raise exception.CoriolisException(
                 '"auth_url" not provided in "connection_info" and option '
                 '"auth_url" in group "[openstack_migration_provider]" '
-                'not set')
+                'not set'
+            )
 
-        plugin_args.update({
-            "auth_url": auth_url,
-            "project_name": project_name,
-        })
+        plugin_args.update(
+            {
+                "auth_url": auth_url,
+                "project_name": project_name,
+            }
+        )
 
         keystone_version = connection_info.get(
-            "identity_api_version", CONF.keystone.identity_api_version)
+            "identity_api_version", CONF.keystone.identity_api_version
+        )
 
         if keystone_version == 3:
             plugin_name = "v3" + plugin_name
 
             project_domain_name = connection_info.get(
-                "project_domain_name", ctxt.project_domain_name)
+                "project_domain_name", ctxt.project_domain_name
+            )
             # NOTE: only set the kwarg if proper argument is provided:
             if project_domain_name:
                 plugin_args["project_domain_name"] = project_domain_name
 
             project_domain_id = connection_info.get(
-                "project_domain_id", ctxt.project_domain_id)
+                "project_domain_id", ctxt.project_domain_id
+            )
             if project_domain_id:
                 plugin_args["project_domain_id"] = project_domain_id
 
             if not project_domain_name and not project_domain_id:
                 raise exception.CoriolisException(
                     "Either 'project_domain_name' or 'project_domain_id' is "
-                    "required for Keystone v3 Auth.")
+                    "required for Keystone v3 Auth."
+                )
 
             # NOTE: The v3token plugin does not allow the user_domain_name
             #       or user_domain_id options, while the v3password plugin
             #       requires at least any of these.
             if plugin_name != "v3token":
                 user_domain_name = connection_info.get(
-                    "user_domain_name", ctxt.user_domain_name)
+                    "user_domain_name", ctxt.user_domain_name
+                )
                 if user_domain_name:
                     plugin_args["user_domain_name"] = user_domain_name
 
                 user_domain_id = connection_info.get(
-                    "user_domain_id", ctxt.user_domain_id)
+                    "user_domain_id", ctxt.user_domain_id
+                )
                 if user_domain_id:
                     plugin_args["user_domain_id"] = user_domain_id
 
                 if not user_domain_name and not user_domain_id:
                     raise exception.CoriolisException(
                         "Either 'user_domain_name' or 'user_domain_id' is "
-                        "required for Keystone v3 Auth.")
+                        "required for Keystone v3 Auth."
+                    )
 
         loader = loading.get_plugin_loader(plugin_name)
         auth = loader.load_from_options(**plugin_args)

Некоторые файлы не были показаны из-за большого количества измененных файлов