Przeglądaj źródła

Adds tox.ini and fixes issues

Fixes pep8 and py27 issues.

Co-Authored-By: Gabriel Samfira <gsamfira@cloudbasesolutions.com>
Claudiu Belu 8 lat temu
rodzic
commit
87000159e1
45 zmienionych plików z 188 dodań i 128 usunięć
  1. 7 0
      .testr.conf
  2. 4 3
      coriolis/api/__init__.py
  3. 1 2
      coriolis/api/middleware/auth.py
  4. 1 1
      coriolis/api/middleware/fault.py
  5. 1 1
      coriolis/api/v1/endpoint_actions.py
  6. 1 1
      coriolis/api/v1/endpoint_instances.py
  7. 1 1
      coriolis/api/v1/endpoint_networks.py
  8. 3 4
      coriolis/api/v1/endpoints.py
  9. 3 4
      coriolis/api/v1/migrations.py
  10. 2 2
      coriolis/api/v1/replica_tasks_executions.py
  11. 2 3
      coriolis/api/v1/replicas.py
  12. 3 3
      coriolis/api/v1/router.py
  13. 6 1
      coriolis/api/wsgi.py
  14. 5 0
      coriolis/cmd/__init__.py
  15. 4 7
      coriolis/cmd/api.py
  16. 5 8
      coriolis/cmd/conductor.py
  17. 5 8
      coriolis/cmd/worker.py
  18. 1 0
      coriolis/db/api.py
  19. 3 3
      coriolis/db/sqlalchemy/models.py
  20. 8 1
      coriolis/exception.py
  21. 1 1
      coriolis/keystone.py
  22. 4 4
      coriolis/migrations/manager.py
  23. 1 1
      coriolis/osmorphing/manager.py
  24. 0 1
      coriolis/osmorphing/openwrt.py
  25. 3 3
      coriolis/osmorphing/osmount/base.py
  26. 15 6
      coriolis/osmorphing/osmount/windows.py
  27. 1 1
      coriolis/osmorphing/redhat.py
  28. 2 2
      coriolis/osmorphing/suse.py
  29. 2 2
      coriolis/osmorphing/windows.py
  30. 11 7
      coriolis/providers/base.py
  31. 1 1
      coriolis/qemu_reader.py
  32. 6 6
      coriolis/schemas.py
  33. 5 7
      coriolis/schemas_exceptions.py
  34. 1 3
      coriolis/tasks/base.py
  35. 6 6
      coriolis/tasks/migration_tasks.py
  36. 2 2
      coriolis/tasks/replica_tasks.py
  37. 2 2
      coriolis/tests/providers/base.py
  38. 1 1
      coriolis/tests/test_base.py
  39. 3 3
      coriolis/tests/test_schemas.py
  40. 3 3
      coriolis/tests/testutils.py
  41. 6 7
      coriolis/utils.py
  42. 5 4
      coriolis/worker/rpc/server.py
  43. 2 2
      setup.py
  44. 2 0
      test-requirements.txt
  45. 37 0
      tox.ini

+ 7 - 0
.testr.conf

@@ -0,0 +1,7 @@
+[DEFAULT]
+test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
+             OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
+             OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
+             ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
+test_id_option=--load-list $IDFILE
+test_list_option=--list

+ 4 - 3
coriolis/api/__init__.py

@@ -18,14 +18,15 @@
 WSGI middleware for OpenStack API controllers.
 """
 
-from oslo_log import log as logging
-from oslo_service import wsgi as base_wsgi
 from paste import urlmap
 import routes
 
+from oslo_log import log as logging
+from oslo_service import wsgi as base_wsgi
+
 from coriolis.api import wsgi
 from coriolis import exception
-from coriolis.i18n import _, _LW
+from coriolis.i18n import _, _LW  # noqa
 
 
 LOG = logging.getLogger(__name__)

+ 1 - 2
coriolis/api/middleware/auth.py

@@ -1,11 +1,10 @@
 # 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

+ 1 - 1
coriolis/api/middleware/fault.py

@@ -21,7 +21,7 @@ import webob.exc
 
 from coriolis.api import wsgi
 from coriolis import exception
-from coriolis.i18n import _, _LE, _LI
+from coriolis.i18n import _, _LE, _LI  # noqa
 from coriolis import utils
 
 

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

@@ -4,8 +4,8 @@
 from webob import exc
 
 from coriolis.api import wsgi as api_wsgi
-from coriolis import exception
 from coriolis.endpoints import api
+from coriolis import exception
 
 
 class EndpointActionsController(api_wsgi.Controller):

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

@@ -4,8 +4,8 @@
 from oslo_log import log as logging
 
 from coriolis.api import common
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import endpoint_instance_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoint_instances import api
 from coriolis import utils
 

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

@@ -3,8 +3,8 @@
 
 from oslo_log import log as logging
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import endpoint_network_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoint_networks import api
 from coriolis import utils
 

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

@@ -1,14 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from webob import exc
-
 from oslo_log import log as logging
+from webob import exc
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import endpoint_view
-from coriolis import exception
+from coriolis.api import wsgi as api_wsgi
 from coriolis.endpoints import api
+from coriolis import exception
 
 LOG = logging.getLogger(__name__)
 

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

@@ -1,12 +1,11 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from webob import exc
-
 from oslo_log import log as logging
+from webob import exc
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import migration_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
 from coriolis.migrations import api
 
@@ -57,7 +56,7 @@ class MigrationController(api_wsgi.Controller):
             raise exception.InvalidInput(msg)
 
     def create(self, req, body):
-        # TODO: validate body
+        # TODO(alexpilotti): validate body
         migration_body = body.get("migration", {})
         context = req.environ['coriolis.context']
 

+ 2 - 2
coriolis/api/v1/replica_tasks_executions.py

@@ -3,8 +3,8 @@
 
 from webob import exc
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import replica_tasks_execution_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
 from coriolis.replica_tasks_executions import api
 
@@ -35,7 +35,7 @@ class ReplicaTasksExecutionController(api_wsgi.Controller):
                 include_tasks=True))
 
     def create(self, req, replica_id, body):
-        # TODO: validate body
+        # TODO(alexpilotti): validate body
 
         execution_body = body.get("execution", {})
         shutdown_instances = execution_body.get("shutdown_instances", False)

+ 2 - 3
coriolis/api/v1/replicas.py

@@ -1,12 +1,11 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from webob import exc
-
 from oslo_log import log as logging
+from webob import exc
 
-from coriolis.api import wsgi as api_wsgi
 from coriolis.api.v1.views import replica_view
+from coriolis.api import wsgi as api_wsgi
 from coriolis import exception
 from coriolis.replicas import api
 

+ 3 - 3
coriolis/api/v1/router.py

@@ -5,16 +5,16 @@ from oslo_log import log as logging
 
 from coriolis import api
 from coriolis.api.v1 import endpoint_actions
-from coriolis.api.v1 import endpoints
 from coriolis.api.v1 import endpoint_instances
 from coriolis.api.v1 import endpoint_networks
-from coriolis.api.v1 import migrations
+from coriolis.api.v1 import endpoints
 from coriolis.api.v1 import migration_actions
+from coriolis.api.v1 import migrations
 from coriolis.api.v1 import provider_schemas
 from coriolis.api.v1 import providers
 from coriolis.api.v1 import replica_actions
-from coriolis.api.v1 import replica_tasks_executions
 from coriolis.api.v1 import replica_tasks_execution_actions
+from coriolis.api.v1 import replica_tasks_executions
 from coriolis.api.v1 import replicas
 
 LOG = logging.getLogger(__name__)

+ 6 - 1
coriolis/api/wsgi.py

@@ -23,10 +23,11 @@ from oslo_serialization import jsonutils
 from oslo_utils import excutils
 import six
 import webob
+import webob.dec
 
 from coriolis import exception
 from coriolis import i18n
-from coriolis.i18n import _, _LE, _LI
+from coriolis.i18n import _, _LE, _LI  # noqa
 
 
 LOG = logging.getLogger(__name__)
@@ -319,6 +320,7 @@ class Request(webob.Request):
 
 class Middleware(Application):
     """Base WSGI middleware.
+
     These classes require an application to be
     initialized that will be called next.  By default the middleware will
     simply call its wrapped app, or you can override __call__ to customize its
@@ -328,6 +330,7 @@ class Middleware(Application):
     @classmethod
     def factory(cls, global_config, **local_config):
         """Used for paste app factories in paste.deploy config files.
+
         Any local configuration (that is, values under the [filter:APPNAME]
         section of the paste config) will be passed into the `__init__` method
         as kwargs.
@@ -350,6 +353,7 @@ class Middleware(Application):
 
     def process_request(self, req):
         """Called on each request.
+
         If this returns None, the next application down the stack will be
         executed. If it returns a response then that response will be returned
         and execution will stop here.
@@ -1250,6 +1254,7 @@ def _set_request_id_header(req, headers):
 
 def _check_string_length(value, name, min_length=0, max_length=None):
     """Check the length of specified string.
+
     :param value: the value of the string
     :param name: the name of the string
     :param min_length: the min_length of the string

+ 5 - 0
coriolis/cmd/__init__.py

@@ -0,0 +1,5 @@
+# Copyright 2017 Cloudbase Solutions Srl
+# All Rights Reserved.
+
+import eventlet
+eventlet.monkey_patch()

+ 4 - 7
coriolis/cmd/api.py

@@ -1,15 +1,12 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-import eventlet
-eventlet.monkey_patch()
+import sys
 
-import sys # noqa
+from oslo_config import cfg
 
-from coriolis import service # noqa
-from coriolis import utils # noqa
-
-from oslo_config import cfg # noqa
+from coriolis import service
+from coriolis import utils
 
 CONF = cfg.CONF
 

+ 5 - 8
coriolis/cmd/conductor.py

@@ -1,16 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-import eventlet
-eventlet.monkey_patch()
+import sys
 
-import sys # noqa
+from oslo_config import cfg
 
-from oslo_config import cfg # noqa
-
-from coriolis.conductor.rpc import server as rpc_server # noqa
-from coriolis import service # noqa
-from coriolis import utils # noqa
+from coriolis.conductor.rpc import server as rpc_server
+from coriolis import service
+from coriolis import utils
 
 CONF = cfg.CONF
 

+ 5 - 8
coriolis/cmd/worker.py

@@ -1,16 +1,13 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-import eventlet
-eventlet.monkey_patch()
+import sys
 
-import sys # noqa
+from oslo_config import cfg
 
-from oslo_config import cfg # noqa
-
-from coriolis.worker.rpc import server as rpc_server # noqa
-from coriolis import service # noqa
-from coriolis import utils # noqa
+from coriolis import service
+from coriolis import utils
+from coriolis.worker.rpc import server as rpc_server
 
 CONF = cfg.CONF
 

+ 1 - 0
coriolis/db/api.py

@@ -48,6 +48,7 @@ def _model_query(context, *args):
 
 def _soft_delete_aware_query(context, *args, **kwargs):
     """Query helper that accounts for context's `show_deleted` field.
+
     :param show_deleted: if True, overrides context's show_deleted field.
     """
     query = _model_query(context, *args)

+ 3 - 3
coriolis/db/sqlalchemy/models.py

@@ -60,10 +60,10 @@ class Task(BASE, models.TimestampMixin, models.SoftDeleteMixin,
     exception_details = sqlalchemy.Column(sqlalchemy.Text, nullable=True)
     depends_on = sqlalchemy.Column(types.List, nullable=True)
     on_error = sqlalchemy.Column(sqlalchemy.Boolean, nullable=False)
-    # TODO: Add soft delete filter
+    # TODO(alexpilotti): Add soft delete filter
     events = orm.relationship(TaskEvent, cascade="all,delete",
                               backref=orm.backref('task'))
-    # TODO: Add soft delete filter
+    # TODO(alexpilotti): Add soft delete filter
     progress_updates = orm.relationship(TaskProgressUpdate,
                                         cascade="all,delete",
                                         backref=orm.backref('task'))
@@ -79,7 +79,7 @@ class TasksExecution(BASE, models.TimestampMixin, models.ModelBase,
     action_id = sqlalchemy.Column(
         sqlalchemy.String(36),
         sqlalchemy.ForeignKey('base_transfer_action.base_id'), nullable=False)
-    # TODO: Add soft delete filter
+    # TODO(alexpilotti): Add soft delete filter
     tasks = orm.relationship(Task, cascade="all,delete",
                              backref=orm.backref('execution'))
     status = sqlalchemy.Column(sqlalchemy.String(100), nullable=False)

+ 8 - 1
coriolis/exception.py

@@ -24,7 +24,7 @@ import webob.exc
 from webob.util import status_generic_reasons
 from webob.util import status_reasons
 
-from coriolis.i18n import _, _LE
+from coriolis.i18n import _, _LE  # noqa
 
 
 LOG = logging.getLogger(__name__)
@@ -306,3 +306,10 @@ class SchemaValidationException(CoriolisException):
 
 class QEMUException(Exception):
     pass
+
+
+if six.PY2:
+    class ConnectionRefusedError(OSError):
+        pass
+else:
+    ConnectionRefusedError = six.moves.builtins.ConnectionRefusedError

+ 1 - 1
coriolis/keystone.py

@@ -101,7 +101,7 @@ def delete_trust(ctxt):
 def create_keystone_session(ctxt, connection_info={}):
     allow_untrusted = connection_info.get(
         "allow_untrusted", CONF.keystone.allow_untrusted)
-    # TODO: add "ca_cert" to connection_info
+    # TODO(alexpilotti): add "ca_cert" to connection_info
     verify = not allow_untrusted
 
     username = connection_info.get("username")

+ 4 - 4
coriolis/migrations/manager.py

@@ -1,16 +1,16 @@
 # Copyright 2017 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-import eventlet
 import gc
 import sys
 
+import eventlet
 from oslo_log import log as logging
 from oslo_utils import units
 
 from coriolis import events
-from coriolis import qemu_reader
 from coriolis.providers import backup_writers
+from coriolis import qemu_reader
 from coriolis import utils
 
 LOG = logging.getLogger(__name__)
@@ -64,7 +64,7 @@ def _copy_wrapper(job_args):
 
 
 def copy_disk_data(target_conn_info, volumes_info, event_handler):
-    # TODO (gsamfira): the disk image should be an URI that can either be local
+    # TODO(gsamfira): the disk image should be an URI that can either be local
     # (file://) or remote (https://, ftp://, smb://, nfs:// etc).
     # This must happen if we are to implement multi-worker scenarios.
     # In such cases, it is not guaranteed that the disk sync task
@@ -92,7 +92,7 @@ def copy_disk_data(target_conn_info, volumes_info, event_handler):
     job_data = [(vol, disk_image_reader, backup_writer, event_manager)
                 for vol in volumes_info]
     for result, disk_id, error in pool.imap(_copy_wrapper, job_data):
-        # TODO (gsamfira): There is no use in letting the other disks finish
+        # TODO(gsamfira): There is no use in letting the other disks finish
         # sync-ing as we don't save the state of the disk sync anywhere (yet).
         # When/If we ever do add this info to the database, keep track of
         # failures, and allow any other paralel sync to finish

+ 1 - 1
coriolis/osmorphing/manager.py

@@ -4,8 +4,8 @@
 from oslo_config import cfg
 from oslo_log import log as logging
 
-from coriolis import exception
 from coriolis import events
+from coriolis import exception
 from coriolis.osmorphing.osmount import factory as osmount_factory
 
 proxy_opts = [

+ 0 - 1
coriolis/osmorphing/openwrt.py

@@ -28,4 +28,3 @@ class BaseOpenWRTMorphingTools(base.BaseLinuxOSMorphingTools):
 
     def set_net_config(self, nics_info, dhcp):
         pass
-

+ 3 - 3
coriolis/osmorphing/osmount/base.py

@@ -184,15 +184,15 @@ class BaseLinuxOSMountTools(BaseSSHOSMountTools):
             self._exec_cmd('sudo mount %s %s' % (dev_path, tmp_dir))
             dirs = self._exec_cmd('ls %s' % tmp_dir).decode().split('\n')
 
-            # TODO: better ways to check for a linux root?
+            # TODO(alexpilotti): better ways to check for a linux root?
             if (not os_root_dir and 'etc' in dirs and 'bin' in dirs and
                     'sbin' in dirs):
                 os_root_dir = tmp_dir
                 os_root_device = dev_path
                 LOG.info("OS root device: %s", dev_path)
-            # TODO: better ways to check for a linux boot dir?
+            # TODO(alexpilotti): better ways to check for a linux boot dir?
             else:
-                # TODO: better ways to check for a linux boot dir?
+                # TODO(alexpilotti): better ways to check for a linux boot dir?
                 if not boot_dev_path and ('grub' in dirs or 'grub2' in dirs):
                     # Needs to be remounted under os_root_dir
                     boot_dev_path = dev_path

+ 15 - 6
coriolis/osmorphing/osmount/windows.py

@@ -58,8 +58,11 @@ class WindowsMountTools(base.BaseOSMountTools):
             "Update-HostStorageCache", ignore_stdout=True)
 
     def _run_diskpart_script(self, script):
-        """ Writes the given script data to a file and runs diskpart.exe,
-        returning the output. """
+        """Executes the given script with diskpart.exe.
+
+        Writes the given script data to a file and runs diskpart.exe,
+        returning the output.
+        """
         tempdir = self._conn.exec_ps_command("$env:TEMP")
 
         # NOTE: diskpart is interactive, so we must either pipe it its input
@@ -72,8 +75,11 @@ class WindowsMountTools(base.BaseOSMountTools):
     def _service_disks_with_status(
             self, status, service_script_with_id_fmt,
             logmsg_fmt="Operating on disk with index '%s'"):
-        """ Uses diskpart.exe to detect all disks with the given 'status', and
-        execute the given service script after formatting the disk ID in. """
+        """Executes given service script on detected disks.
+
+        Uses diskpart.exe to detect all disks with the given 'status', and
+        execute the given service script after formatting the disk ID in.
+        """
         disk_list_script = "LIST DISK\r\nEXIT"
 
         disk_entry_re = r"\s+Disk (%s)\s+%s\s+"
@@ -109,8 +115,11 @@ class WindowsMountTools(base.BaseOSMountTools):
             logmsg_fmt="Clearing R/O flag on foreign disk with ID '%s'.")
 
     def _import_foreign_disks(self):
-        """ Uses diskpart.exe to import all disks which are foreign to the
-        worker. Needed when servicing installations on Dynamic Disks. """
+        """Imports foreign disks.
+
+        Uses diskpart.exe to import all disks which are foreign to the
+        worker. Needed when servicing installations on Dynamic Disks.
+        """
         # NOTE: foreign disks are not exposed via the APIs the PowerShell
         # disk cmdlets use, thus any disk which is foreign is is likely
         # still RO, which is why we must change the RO attribute as well:

+ 1 - 1
coriolis/osmorphing/redhat.py

@@ -70,7 +70,7 @@ class BaseRedHatMorphingTools(base.BaseLinuxOSMorphingTools):
         try:
             self._exec_cmd_chroot("rpm -q systemd")
             return True
-        except:
+        except Exception:
             return False
 
     def _set_dhcp_net_config(self, ifcfgs_ethernet):

+ 2 - 2
coriolis/osmorphing/suse.py

@@ -30,7 +30,7 @@ class BaseSUSEMorphingTools(base.BaseLinuxOSMorphingTools):
             return ('SUSE', release)
 
     def set_net_config(self, nics_info, dhcp):
-        # TODO: add networking support
+        # TODO(alexpilotti): add networking support
         pass
 
     def _run_dracut(self):
@@ -50,7 +50,7 @@ class BaseSUSEMorphingTools(base.BaseLinuxOSMorphingTools):
         try:
             self._exec_cmd_chroot("rpm -q systemd")
             return True
-        except:
+        except Exception:
             return False
 
     def install_packages(self, package_names):

+ 2 - 2
coriolis/osmorphing/windows.py

@@ -1,11 +1,11 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from distutils import version
 import os
 import re
 import uuid
 
-from distutils import version
 from oslo_log import log as logging
 
 from coriolis import exception
@@ -32,7 +32,7 @@ class BaseWindowsMorphingTools(base.BaseOSMorphingTools):
             LOG.debug("Exception during OS detection: %s", ex)
 
     def set_net_config(self, nics_info, dhcp):
-        # TODO: implement
+        # TODO(alexpilotti): implement
         pass
 
     def _get_dism_path(self):

+ 11 - 7
coriolis/providers/base.py

@@ -31,26 +31,26 @@ class BaseEndpointProvider(BaseProvider):
 
 
 class BaseEndpointInstancesProvider(BaseEndpointProvider):
-    """ Defines operations for listing instances off of Endpoints """
+    """Defines operations for listing instances off of Endpoints."""
 
     @abc.abstractmethod
     def get_instances(self, ctxt, connection_info, limit=None,
                       last_seen_id=None, instance_name_pattern=None):
-        """ Returns a list of instances """
+        """Returns a list of instances."""
         raise NotImplementedError()
 
     @abc.abstractmethod
     def get_instance(self, ctxt, connection_info, instance_name):
-        """ Returns detailed info for a given instance """
+        """Returns detailed info for a given instance."""
         raise NotImplementedError()
 
 
 class BaseEndpointNetworksProvider(object, with_metaclass(abc.ABCMeta)):
-    """ Defines operations for endpoints networks """
+    """Defines operations for endpoints networks."""
 
     @abc.abstractmethod
     def get_networks(self, ctxt, connection_info, env):
-        """ Returns a list of networks """
+        """Returns a list of networks """
         raise NotImplementedError()
 
 
@@ -90,7 +90,9 @@ class BaseImportProvider(BaseImportInstanceProvider):
     @abc.abstractmethod
     def import_instance(self, ctxt, connection_info, target_environment,
                         instance_name, export_info):
-        """ Imports the instance given by its name to the specified target
+        """Imports the given instance.
+
+        Imports the instance given by its name to the specified target
         environment within the destination cloud based on the provided
         connection and export info.
         """
@@ -175,7 +177,9 @@ class BaseExportProvider(BaseInstanceProvider):
     @abc.abstractmethod
     def export_instance(self, ctxt, connection_info, instance_name,
                         export_path):
-        """ Exports the instance given by its name from the given source cloud
+        """Exports the given instance.
+
+         Exports the instance given by its name from the given source cloud
         to the provided export directory path using the given connection info.
         """
         pass

+ 1 - 1
coriolis/qemu_reader.py

@@ -99,7 +99,7 @@ class QEMUDiskImageReaderImpl(object):
         if ret < 0:
             raise exception.QEMUException("blk_pread failed")
 
-        return (ctypes.c_ubyte*read_size).from_address(self._buf)
+        return (ctypes.c_ubyte * read_size).from_address(self._buf)
 
 
 class QEMUDiskImageReader(object):

+ 6 - 6
coriolis/schemas.py

@@ -1,13 +1,12 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-""" Defines various schemas used for validation throughout the project. """
+"""Defines various schemas used for validation throughout the project."""
 
 import json
 
 import jinja2
 import jsonschema
-
 from oslo_log import log as logging
 
 from coriolis import exception
@@ -29,7 +28,9 @@ _CORIOLIS_VM_NETWORK_SCHEMA_NAME = "vm_network_schema.json"
 
 def get_schema(package_name, schema_name,
                schemas_directory=DEFAULT_SCHEMAS_DIRECTORY):
-    """ Loads the schema with the given 'schema_name' using jinja2 template
+    """Loads the schema using jinja2 template loading.
+
+    Loads the schema with the given 'schema_name' using jinja2 template
     loading from the provided 'package_name' under the given
     'schemas_directory'.
     """
@@ -44,7 +45,7 @@ def get_schema(package_name, schema_name,
 
 
 def validate_value(val, schema):
-    """ Simple wrapper for jsonschema.validate for usability.
+    """Simple wrapper for jsonschema.validate for usability.
 
     NOTE: silently passes empty schemas.
     """
@@ -59,8 +60,7 @@ def validate_value(val, schema):
 
 
 def validate_string(json_string, schema):
-    """ Attempts to validate the json value provided as a string against the
-    given JSON schema.
+    """Attempts to validate the given json string against the JSON schema.
 
     Runs silently on success or raises an exception otherwise.
     Silently passes empty schemas.

+ 5 - 7
coriolis/schemas_exceptions.py

@@ -1,7 +1,7 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-""" Defines a set of exceptions possible during schema loading/validation. """
+"""Defines a set of exceptions possible during schema loading/validation."""
 
 import jinja2
 import jsonschema
@@ -10,25 +10,23 @@ from coriolis import exception
 
 
 class CoriolisSchemaException(exception.CoriolisException):
-    """ Base class for all coriolis schema handling exceptions. """
+    """Base class for all coriolis schema handling exceptions."""
     message = "Exception occured during schema validation: %(msg)s."
 
 
 class CoriolisSchemaValidationError(
         CoriolisSchemaException, jsonschema.ValidationError):
-    """ Raised when a schema validation has failed. """
+    """Raised when a schema validation has failed."""
     message = "Failed to validate JSON schema: %(msg)s."
 
 
 class CoriolisSchemaParsingError(
         CoriolisSchemaException, ValueError):
-    """ Raised when decoding of either the JSON schema or the JSON value being
-    validated occurs.
-    """
+    """Raised when decoding a JSON schema or when validating a JSON value."""
     message = "Failed to parse JSON for schema validation: %(msg)s."
 
 
 class CoriolisSchemaLoadingException(
         CoriolisSchemaException, jinja2.TemplateNotFound):
-    """ Raised when schema files are not found. """
+    """Raised when schema files are not found."""
     message = "Failed to load schema: %(msg)s."

+ 1 - 3
coriolis/tasks/base.py

@@ -3,13 +3,11 @@
 
 import abc
 
-from coriolis import utils
-
 from oslo_config import cfg
 from oslo_log import log as logging
-
 from six import with_metaclass
 
+from coriolis import utils
 
 serialization_opts = [
     cfg.StrOpt('temp_keypair_password',

+ 6 - 6
coriolis/tasks/migration_tasks.py

@@ -1,16 +1,16 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+
 from coriolis import constants
 from coriolis import events
-from coriolis.providers import factory as providers_factory
-from coriolis import schemas
 from coriolis import exception
 from coriolis.migrations import manager
+from coriolis.providers import factory as providers_factory
+from coriolis import schemas
 from coriolis.tasks import base
 
-from oslo_log import log as logging
-
 LOG = logging.getLogger(__name__)
 
 
@@ -55,7 +55,7 @@ class ImportInstanceTask(base.TaskRunner):
         task_info["origin_provider_type"] = constants.PROVIDER_TYPE_EXPORT
         task_info["destination_provider_type"] = constants.PROVIDER_TYPE_IMPORT
         # We need to retain export info until after disk sync
-        # TODO (gsamfira): remove this when we implement multi-worker, and by
+        # TODO(gsamfira): remove this when we implement multi-worker, and by
         # extension some external storage for needed resources (like swift)
         task_info["retain_export_path"] = True
 
@@ -83,7 +83,7 @@ class DeployDiskCopyResources(base.TaskRunner):
         task_info["instance_deployment_info"][
             "disk_sync_connection_info"] = conn_info
         # We need to retain export info until after disk sync
-        # TODO (gsamfira): remove this when we implement multi-worker, and by
+        # TODO(gsamfira): remove this when we implement multi-worker, and by
         # extension some external storage for needed resources (like swift)
         task_info["retain_export_path"] = True
 

+ 2 - 2
coriolis/tasks/replica_tasks.py

@@ -1,14 +1,14 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
+from oslo_log import log as logging
+
 from coriolis import constants
 from coriolis import exception
 from coriolis.providers import factory as providers_factory
 from coriolis import schemas
 from coriolis.tasks import base
 
-from oslo_log import log as logging
-
 LOG = logging.getLogger(__name__)
 
 

+ 2 - 2
coriolis/tests/providers/base.py

@@ -1,9 +1,9 @@
-""" Defines base classes for all provider tests. """
+"""Defines base classes for all provider tests."""
 
 import mock
 
-from coriolis.tests import testutils
 from coriolis.tests import test_base
+from coriolis.tests import testutils
 
 
 class ProvidersBaseTestCase(test_base.CoriolisBaseTestCase):

+ 1 - 1
coriolis/tests/test_base.py

@@ -1,7 +1,7 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-""" Defines base class for all tests. """
+"""Defines base class for all tests."""
 
 from oslotest import base
 

+ 3 - 3
coriolis/tests/test_schemas.py

@@ -2,10 +2,10 @@
 # All Rights Reserved.
 
 import json
-import jsonschema
-import mock
 
 import jinja2
+import jsonschema
+import mock
 
 from coriolis import schemas
 from coriolis.tests import test_base
@@ -25,7 +25,7 @@ def _get_mock_template_env():
 
 
 class SchemasTestCase(test_base.CoriolisBaseTestCase):
-    """ Collection of tests for the Coriolis schemas package. """
+    """Collection of tests for the Coriolis schemas package."""
 
     def setUp(self):
         super(SchemasTestCase, self).setUp()

+ 3 - 3
coriolis/tests/testutils.py

@@ -1,13 +1,13 @@
-""" Defines general utilities for all tests. """
+"""Defines general utilities for all tests."""
 
 import mock
 
 
 def identity_dec(item, *args, **kwargs):
-    """ A decorator which adds nothing to the decorated item. """
+    """A decorator which adds nothing to the decorated item."""
     return item
 
 
 def make_identity_decorator_mock():
-    """ Returns a MagicMock with identity_dec as a side-effect. """
+    """Returns a MagicMock with identity_dec as a side-effect."""
     return mock.MagicMock(side_effect=identity_dec)

+ 6 - 7
coriolis/utils.py

@@ -54,8 +54,9 @@ def ignore_exceptions(func):
 
 
 def get_single_result(lis):
-    """ Indexes the head of a single element list.
-    Raises a KeyError if the list is empty or its length is greater than 1.
+    """Indexes the head of a single element list.
+
+    :raises KeyError: if the list is empty or its length is greater than 1.
     """
     if len(lis) == 0:
         raise KeyError("Result list is empty.")
@@ -198,7 +199,7 @@ def _check_port_open(host, port):
         s.settimeout(1)
         s.connect((host, port))
         return True
-    except (ConnectionRefusedError, socket.timeout, OSError):
+    except (exception.ConnectionRefusedError, socket.timeout, OSError):
         return False
     finally:
         s.close()
@@ -324,9 +325,7 @@ def to_dict(obj, max_depth=10):
 
 def topological_graph_sorting(items, id="id", depends_on="depends_on",
                               sort_key=None):
-    """
-    Kahn's algorithm
-    """
+    """Kahn's algorithm"""
     if sort_key:
         # Sort siblings
         items = sorted(items, key=lambda t: t[sort_key], reverse=True)
@@ -405,7 +404,7 @@ def quote_url(text):
 def get_url_with_credentials(url, username, password):
     parts = parse.urlsplit(url)
     # Remove previous credentials if set
-    netloc = parts.netloc[parts.netloc.find('@')+1:]
+    netloc = parts.netloc[parts.netloc.find('@') + 1:]
     netloc = "%s:%s@%s" % (
         quote_url(username), quote_url(password or ''), netloc)
     parts = parts._replace(netloc=netloc)

+ 5 - 4
coriolis/worker/rpc/server.py

@@ -1,17 +1,17 @@
 # Copyright 2016 Cloudbase Solutions Srl
 # All Rights Reserved.
 
-from logging import handlers
 import multiprocessing
 import os
-import queue
 import shutil
 import signal
 import sys
 
-import psutil
+from logging import handlers
 from oslo_config import cfg
 from oslo_log import log as logging
+import psutil
+from six.moves import queue
 
 from coriolis.conductor.rpc import client as rpc_conductor_client
 from coriolis import constants
@@ -152,7 +152,8 @@ class WorkerServerEndpoint(object):
             if new_task_info:
                 LOG.info("Task info: %s", new_task_info)
 
-            # TODO: replace the temp storage with a host independent option
+            # TODO(alexpilotti): replace the temp storage with a host
+            # independent option
             retain_export_path = new_task_info.get("retain_export_path", False)
             if not retain_export_path:
                 del new_task_info["export_path"]

+ 2 - 2
setup.py

@@ -1,7 +1,7 @@
+import os
+import platform
 import setuptools
 import subprocess
-import platform
-import os
 
 
 def _compile_and_install():

+ 2 - 0
test-requirements.txt

@@ -1,3 +1,5 @@
 coverage
 discover
 oslotest
+
+hacking>=0.12.0,<0.13 # Apache-2.0

+ 37 - 0
tox.ini

@@ -0,0 +1,37 @@
+[tox]
+minversion = 2.0
+envlist = py35,py27,pep8
+skipsdist = True
+
+[testenv]
+usedevelop = True
+whitelist_externals = rm
+install_command = pip install {opts} {packages}
+setenv =
+   VIRTUAL_ENV={envdir}
+   BRANCH_NAME=master
+   CLIENT_NAME=coriolis-core
+   DEFAULT_REPO=git@bitbucket.org:cloudbase
+   PYTHONWARNINGS=default::DeprecationWarning
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
+commands =
+  python setup.py test --slowest --testr-args='{posargs}'
+  rm -f .testrepository/times.dbm
+
+[testenv:pep8]
+commands = flake8 {posargs}
+
+[testenv:venv]
+commands = {posargs}
+
+[testenv:cover]
+commands = python setup.py test --coverage --testr-args='{posargs}'
+
+[flake8]
+# E123, E125 skipped as they are invalid PEP-8.
+
+show-source = True
+ignore = E123,E125
+builtins = _
+exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build