diff --git a/.zuul.yaml b/.zuul.yaml index 689a326cbe..f7a6012782 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -8,6 +8,7 @@ - build-openstack-releasenotes - openstack-tox-linters - sysinv-tox-py27 + - sysinv-tox-py35 - sysinv-tox-flake8 - sysinv-tox-pylint - controllerconfig-tox-flake8 @@ -27,6 +28,7 @@ - build-openstack-releasenotes - openstack-tox-linters - sysinv-tox-py27 + - sysinv-tox-py35 - sysinv-tox-flake8 - sysinv-tox-pylint - controllerconfig-tox-flake8 @@ -59,6 +61,21 @@ tox_envlist: py27 tox_extra_args: -c sysinv/sysinv/sysinv/tox.ini +- job: + name: sysinv-tox-py35 + parent: tox + description: | + Run py35 test for sysinv + required-projects: + - openstack/stx-update + - openstack/stx-fault + - openstack/stx-integ + files: + - sysinv/sysinv/* + vars: + tox_envlist: py35 + tox_extra_args: -c sysinv/sysinv/sysinv/tox.ini + - job: name: sysinv-tox-flake8 parent: tox diff --git a/sysinv/sysinv/sysinv/requirements.txt b/sysinv/sysinv/sysinv/requirements.txt index 3316209aa3..b47476813d 100644 --- a/sysinv/sysinv/sysinv/requirements.txt +++ b/sysinv/sysinv/sysinv/requirements.txt @@ -30,7 +30,6 @@ pecan>=1.0.0 six>=1.4.1 jsonpatch>=1.1 WSME>=0.5b2 -Cheetah>=2.4.4 pyghmi PyYAML>=3.10 python-magnumclient>=2.0.0 # Apache-2.0 diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py index e07a0c97b8..238a38bfc8 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py @@ -107,7 +107,7 @@ class CephMon(base.APIBase): defaults = {'state': constants.SB_STATE_CONFIGURED, 'task': constants.SB_TASK_NONE} - self.fields = objects.ceph_mon.fields.keys() + self.fields = list(objects.ceph_mon.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k, defaults.get(k))) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/certificate.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/certificate.py index db7a9a5faf..372fe59f23 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/certificate.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/certificate.py @@ -89,7 +89,7 @@ class Certificate(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.certificate.fields.keys() + self.fields = list(objects.certificate.fields.keys()) for k in self.fields: if not hasattr(self, k): continue diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/controller_fs.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/controller_fs.py index 2b453e4c80..54bd473259 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/controller_fs.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/controller_fs.py @@ -107,7 +107,7 @@ class ControllerFs(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.controller_fs.fields.keys() + self.fields = list(objects.controller_fs.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cpu.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cpu.py index dd5ba0afbd..559a34f37e 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cpu.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cpu.py @@ -121,7 +121,7 @@ class CPU(base.APIBase): "A list containing a self link and associated cpu links" def __init__(self, **kwargs): - self.fields = objects.cpu.fields.keys() + self.fields = list(objects.cpu.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/dns.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/dns.py index bc55e4e06c..039a7cb394 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/dns.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/dns.py @@ -85,7 +85,7 @@ class DNS(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.dns.fields.keys() + self.fields = list(objects.dns.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/drbdconfig.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/drbdconfig.py index 27367dcd03..82a093add6 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/drbdconfig.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/drbdconfig.py @@ -85,7 +85,7 @@ class DRBDConfig(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.drbdconfig.fields.keys() + self.fields = list(objects.drbdconfig.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/firewallrules.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/firewallrules.py index 58a8caefe5..0988ddf22f 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/firewallrules.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/firewallrules.py @@ -49,7 +49,7 @@ class FirewallRules(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.firewallrules.fields.keys() + self.fields = list(objects.firewallrules.fields.keys()) for k in self.fields: if not hasattr(self, k): continue diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py index 3c943e9d42..1ce12f9fa3 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py @@ -540,7 +540,7 @@ class Host(base.APIBase): "The iscsi initiator name (only used for worker hosts)" def __init__(self, **kwargs): - self.fields = objects.host.fields.keys() + self.fields = list(objects.host.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py index 23c7cc1809..9cd3859155 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/interface.py @@ -205,7 +205,7 @@ class Interface(base.APIBase): "Represent the networks of the interface" def __init__(self, **kwargs): - self.fields = objects.interface.fields.keys() + self.fields = list(objects.interface.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/lvg.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/lvg.py index e9e8535403..0e317727e1 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/lvg.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/lvg.py @@ -120,7 +120,7 @@ class LVG(base.APIBase): "Links to the collection of ipvs on this lvg" def __init__(self, **kwargs): - self.fields = objects.lvg.fields.keys() + self.fields = list(objects.lvg.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) @@ -148,7 +148,7 @@ class LVG(base.APIBase): # lvm_vg_size is Volume Group's total size in byte # lvm_vg_free_pe is Volume Group's free Physical Extents # lvm_vg_total_pe is Volume Group's total Physical Extents - if lvg.lvm_vg_total_pe > 0: + if lvg.lvm_vg_total_pe and lvg.lvm_vg_total_pe > 0: lvg.lvm_vg_avail_size = \ lvg.lvm_vg_size * lvg.lvm_vg_free_pe / lvg.lvm_vg_total_pe else: @@ -665,7 +665,7 @@ def _check(op, lvg): _("cinder-volumes LVG cannot be removed once it is " "provisioned and LVM backend is added.")) elif lvg['lvm_vg_name'] == constants.LVG_NOVA_LOCAL: - if (lvg['lvm_cur_lv'] > 1): + if (lvg['lvm_cur_lv'] and lvg['lvm_cur_lv'] > 1): raise wsme.exc.ClientSideError( _("Can't delete volume group: %s. There are currently %d " "instance volumes present in the volume group. Terminate" diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py index bbd4e4837d..cd56e7c4b4 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/memory.py @@ -166,7 +166,7 @@ class Memory(base.APIBase): "A list containing a self link and associated memory links" def __init__(self, **kwargs): - self.fields = objects.memory.fields.keys() + self.fields = list(objects.memory.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_infra.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_infra.py index 753b97c711..505bb58dde 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_infra.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_infra.py @@ -100,7 +100,7 @@ class InfraNetwork(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.infra_network.fields.keys() + self.fields = list(objects.infra_network.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_oam.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_oam.py index d4b3d05561..0795e1505e 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_oam.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/network_oam.py @@ -126,7 +126,7 @@ class OAMNetwork(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.oam_network.fields.keys() + self.fields = list(objects.oam_network.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ntp.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ntp.py index a6540d61dc..b3c06aebdf 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ntp.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ntp.py @@ -88,7 +88,7 @@ class NTP(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.ntp.fields.keys() + self.fields = list(objects.ntp.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py index b867313f5a..da29123876 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py @@ -235,7 +235,7 @@ class Profile(base.APIBase): tboot = wtypes.text def __init__(self, **kwargs): - self.fields = objects.host.fields.keys() + self.fields = list(objects.host.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) @@ -3003,7 +3003,9 @@ def localstorageprofile_apply_to_host(host, profile): for hdisk in host.disks: if ((hdisk.device_path == pdisk.device_path or hdisk.device_node == pdisk.device_node) and - hdisk.size_mib >= pdisk.size_mib): + ((hdisk.size_mib is None and pdisk.size_mib is None) or + (hdisk.size_mib and pdisk.size_mib and + hdisk.size_mib >= pdisk.size_mib))): match = True diskPairs.append((hdisk, pdisk)) disksUsed.append(hdisk.id) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile_utils.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile_utils.py index e605173ed9..04ca6f01a2 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile_utils.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile_utils.py @@ -365,10 +365,10 @@ class VlanInterface(Interface): def getNetworkMap(self): return { - 'dataclassNetwork': lambda (node): DataclassNetwork(node), - 'infraNetwork': lambda (node): ExternalNetwork(node, constants.NETWORK_TYPE_INFRA), - 'oamNetwork': lambda (node): ExternalNetwork(node, constants.NETWORK_TYPE_OAM), - 'mgmtNetwork': lambda (node): ExternalNetwork(node, constants.NETWORK_TYPE_MGMT) + 'dataclassNetwork': lambda node: DataclassNetwork(node), + 'infraNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_INFRA), + 'oamNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_OAM), + 'mgmtNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_MGMT) } @staticmethod diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/remotelogging.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/remotelogging.py index df64f5a2d8..47a1246e3a 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/remotelogging.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/remotelogging.py @@ -98,7 +98,7 @@ class RemoteLogging(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.remotelogging.fields.keys() + self.fields = list(objects.remotelogging.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/sensorgroup.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/sensorgroup.py index f7bac94391..784d9a7492 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/sensorgroup.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/sensorgroup.py @@ -157,7 +157,7 @@ class SensorGroup(base.APIBase): "Links to the collection of isensors on this isensorgroup" def __init__(self, **kwargs): - self.fields = objects.sensorgroup.fields.keys() + self.fields = list(objects.sensorgroup.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage.py index 3bea50d834..56d1cc4206 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage.py @@ -136,7 +136,7 @@ class Storage(base.APIBase): "The name of the tier that uses this stor." def __init__(self, **kwargs): - self.fields = objects.storage.fields.keys() + self.fields = list(objects.storage.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_backend.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_backend.py index f625827c85..c1ec80b0a4 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_backend.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_backend.py @@ -115,7 +115,7 @@ class StorageBackend(base.APIBase): 'services': None, 'confirmed': False} - self.fields = objects.storage_backend.fields.keys() + self.fields = list(objects.storage_backend.fields.keys()) # 'confirmed' is not part of objects.storage_backend.fields # (it's an API-only attribute) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph.py index 813864a530..2f066830b4 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph.py @@ -181,7 +181,7 @@ class StorageCeph(base.APIBase): 'confirmed': False, 'object_gateway': False} - self.fields = objects.storage_ceph.fields.keys() + self.fields = list(objects.storage_ceph.fields.keys()) # 'confirmed' is not part of objects.storage_backend.fields # (it's an API-only attribute) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph_external.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph_external.py index 8ed71d1eea..8f703376cc 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph_external.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_ceph_external.py @@ -119,7 +119,7 @@ class StorageCephExternal(base.APIBase): 'confirmed': False, 'ceph_conf': None} - self.fields = objects.storage_ceph_external.fields.keys() + self.fields = list(objects.storage_ceph_external.fields.keys()) # 'confirmed' is not part of objects.storage_backend.fields # (it's an API-only attribute) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_external.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_external.py index 5065a7fa26..508b150579 100755 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_external.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_external.py @@ -111,7 +111,7 @@ class StorageExternal(base.APIBase): 'services': None, 'confirmed': False} - self.fields = objects.storage_external.fields.keys() + self.fields = list(objects.storage_external.fields.keys()) # 'confirmed' is not part of objects.storage_backend.fields # (it's an API-only attribute) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_file.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_file.py index a9e68ac7cc..a3abb8cb47 100755 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_file.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_file.py @@ -109,7 +109,7 @@ class StorageFile(base.APIBase): 'services': None, 'confirmed': False} - self.fields = objects.storage_file.fields.keys() + self.fields = list(objects.storage_file.fields.keys()) # 'confirmed' is not part of objects.storage_backend.fields # (it's an API-only attribute) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_lvm.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_lvm.py index fb2a5b9666..e262cfa317 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_lvm.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/storage_lvm.py @@ -113,7 +113,7 @@ class StorageLVM(base.APIBase): 'services': None, 'confirmed': False} - self.fields = objects.storage_lvm.fields.keys() + self.fields = list(objects.storage_lvm.fields.keys()) # 'confirmed' is not part of objects.storage_backend.fields # (it's an API-only attribute) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/user.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/user.py index 79adfe1704..4fe5e2d9dc 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/user.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/user.py @@ -84,7 +84,7 @@ class User(base.APIBase): updated_at = wtypes.datetime.datetime def __init__(self, **kwargs): - self.fields = objects.user.fields.keys() + self.fields = list(objects.user.fields.keys()) for k in self.fields: setattr(self, k, kwargs.get(k)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py index 624a299da7..2173ee1ee9 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/utils.py @@ -55,7 +55,10 @@ def validate_limit(limit): if limit and limit < 0: raise wsme.exc.ClientSideError(_("Limit must be positive")) - return min(CONF.api_limit_max, limit) or CONF.api_limit_max + if limit: + return min(CONF.api_limit_max, limit) or CONF.api_limit_max + else: + return CONF.api_limit_max def validate_sort_dir(sort_dir): diff --git a/sysinv/sysinv/sysinv/sysinv/api/middleware/parsable_error.py b/sysinv/sysinv/sysinv/sysinv/api/middleware/parsable_error.py index b6aadb8ea8..809999bd88 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/middleware/parsable_error.py +++ b/sysinv/sysinv/sysinv/sysinv/api/middleware/parsable_error.py @@ -23,6 +23,7 @@ Based on pecan.middleware.errordocument """ import json +import six import webob from xml import etree as et @@ -83,7 +84,11 @@ class ParsableErrorMiddleware(object): ''] state['headers'].append(('Content-Type', 'application/xml')) else: + if six.PY3: + app_iter = [i.decode('utf-8') for i in app_iter] body = [json.dumps({'error_message': '\n'.join(app_iter)})] + if six.PY3: + body = [item.encode('utf-8') for item in body] state['headers'].append(('Content-Type', 'application/json')) state['headers'].append(('Content-Length', str(len(body[0])))) else: diff --git a/sysinv/sysinv/sysinv/sysinv/common/utils.py b/sysinv/sysinv/sysinv/sysinv/common/utils.py index 4a9af7e5d8..167f6d3572 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/utils.py +++ b/sysinv/sysinv/sysinv/sysinv/common/utils.py @@ -549,7 +549,8 @@ def sanitize_hostname(hostname): """Return a hostname which conforms to RFC-952 and RFC-1123 specs.""" if isinstance(hostname, six.string_types): hostname = hostname.encode('latin-1', 'ignore') - + if six.PY3: + hostname = hostname.decode() hostname = re.sub('[ _]', '-', hostname) hostname = re.sub('[^\w.-]+', '', hostname) hostname = hostname.lower() @@ -595,7 +596,9 @@ def hash_file(file_like_object): """Generate a hash for the contents of a file.""" checksum = hashlib.sha1() for chunk in iter(lambda: file_like_object.read(32768), b''): - checksum.update(chunk) + encoded_chunk = (chunk.encode(encoding='utf-8') + if isinstance(chunk, six.string_types) else chunk) + checksum.update(encoded_chunk) return checksum.hexdigest() diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py index a1177e756d..eefbfaceb7 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py @@ -159,11 +159,7 @@ class AppOperator(object): from six.moves.urllib.error import HTTPError from six.moves.urllib.error import URLError from socket import timeout as socket_timeout - - try: - import urlparse - except ImportError: - from urllib2 import urlparse + from six.moves.urllib.parse import urlparse def _handle_download_failure(reason): raise exception.KubeAppUploadFailure( diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index 5f42b95dbf..ebd720cfd5 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -136,7 +136,7 @@ CONFIG_CONTROLLER_FINI_FLAG = os.path.join(tsc.VOLATILE_PATH, CONFIG_FAIL_FLAG = os.path.join(tsc.VOLATILE_PATH, ".config_fail") # configuration UUID reboot required flag (bit) -CONFIG_REBOOT_REQUIRED = (1 << 127L) +CONFIG_REBOOT_REQUIRED = (1 << 127) LOCK_NAME_UPDATE_CONFIG = 'update_config_' diff --git a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py index 9dbb30b86e..d46de72c51 100644 --- a/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py +++ b/sysinv/sysinv/sysinv/sysinv/db/sqlalchemy/api.py @@ -2311,7 +2311,7 @@ class Connection(api.Connection): obj = self._interface_get(models.Interfaces, interface_id) - for k, v in values.items(): + for k, v in list(values.items()): if k == 'networktype' and v == constants.NETWORK_TYPE_NONE: v = None if k == 'datanetworks' and v == 'none': diff --git a/sysinv/sysinv/sysinv/sysinv/objects/base.py b/sysinv/sysinv/sysinv/sysinv/objects/base.py index 908ec482e1..757f815613 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/base.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/base.py @@ -47,7 +47,14 @@ def make_class_properties(cls): def getter(self, name=name): attrname = get_attrname(name) if not hasattr(self, attrname): - self.obj_load_attr(name) + # if name in _optional_fields, we just return None + # as class not implement obj_load_attr function + if hasattr(self, '_optional_fields') and name in self._optional_fields: + LOG.exception(_('This is Optional field in %(field)s') % + {'field': name}) + return None + else: + self.obj_load_attr(name) return getattr(self, attrname) def setter(self, value, name=name, typefn=typefn): @@ -397,7 +404,7 @@ class SysinvObject(object): NOTE(danms): May be removed in the future. """ - for name in self.fields.keys() + self.obj_extra_fields: + for name in list(self.fields.keys()) + self.obj_extra_fields: if (hasattr(self, get_attrname(name)) or name in self.obj_extra_fields): yield name, getattr(self, name) diff --git a/sysinv/sysinv/sysinv/sysinv/objects/interface.py b/sysinv/sysinv/sysinv/sysinv/objects/interface.py index 1db20e1727..ffa918109f 100644 --- a/sysinv/sysinv/sysinv/sysinv/objects/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/objects/interface.py @@ -7,7 +7,6 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 # coding=utf-8 # - from sysinv.common import constants from sysinv.db import api as db_api from sysinv.objects import base @@ -81,19 +80,31 @@ def get_host_uuid(field, db_server): def get_networks(field, db_object): result = [] - if hasattr(db_object, 'interface_networks'): - for entry in getattr(db_object, 'interface_networks', []): - id_str = str(entry.network_id) - result.append(id_str) + try: + if getattr(db_object, 'interface_networks', None): + for entry in getattr(db_object, 'interface_networks', []): + id_str = str(entry.network_id) + result.append(id_str) + except exc.DetachedInstanceError: + # instrument and return empty network + LOG.exception("DetachedInstanceError unable to get networks for %s" % + db_object) + pass return result def get_datanetworks(field, db_object): result = [] - if hasattr(db_object, 'interface_datanetworks'): - for entry in getattr(db_object, 'interface_datanetworks', []): - id_str = str(entry.datanetwork_id) - result.append(id_str) + try: + if hasattr(db_object, 'interface_datanetworks'): + for entry in getattr(db_object, 'interface_datanetworks', []): + id_str = str(entry.datanetwork_id) + result.append(id_str) + except exc.DetachedInstanceError: + # instrument and return empty datanetwork + LOG.exception("DetachedInstanceError unable to get datanetworks \ + for %s" % db_object) + pass return result diff --git a/sysinv/sysinv/sysinv/sysinv/openstack/common/fixture/moxstubout.py b/sysinv/sysinv/sysinv/sysinv/openstack/common/fixture/moxstubout.py index f277fdd739..30c270791a 100644 --- a/sysinv/sysinv/sysinv/sysinv/openstack/common/fixture/moxstubout.py +++ b/sysinv/sysinv/sysinv/sysinv/openstack/common/fixture/moxstubout.py @@ -18,8 +18,8 @@ # under the License. import fixtures -import mox import stubout +from mox3 import mox class MoxStubout(fixtures.Fixture): diff --git a/sysinv/sysinv/sysinv/sysinv/openstack/common/gettextutils.py b/sysinv/sysinv/sysinv/sysinv/openstack/common/gettextutils.py index 0b0e3fb5df..dc4ee64ab5 100644 --- a/sysinv/sysinv/sysinv/sysinv/openstack/common/gettextutils.py +++ b/sysinv/sysinv/sysinv/sysinv/openstack/common/gettextutils.py @@ -25,13 +25,16 @@ Usual usage in an openstack.common module: import gettext import os - +import six _localedir = os.environ.get('sysinv'.upper() + '_LOCALEDIR') _t = gettext.translation('sysinv', localedir=_localedir, fallback=True) def _(msg): - return _t.ugettext(msg) + if six.PY2: + return _t.ugettext(msg) + if six.PY3: + return _t.gettext(msg) def install(domain): @@ -45,6 +48,10 @@ def install(domain): a translation-domain-specific environment variable (e.g. NOVA_LOCALEDIR). """ - gettext.install(domain, - localedir=os.environ.get(domain.upper() + '_LOCALEDIR'), - unicode=True) + if six.PY2: + gettext.install(domain, + localedir=os.environ.get(domain.upper() + '_LOCALEDIR'), + unicode=True) + if six.PY3: + gettext.install(domain, + localedir=os.environ.get(domain.upper() + '_LOCALEDIR')) diff --git a/sysinv/sysinv/sysinv/sysinv/openstack/common/timeutils.py b/sysinv/sysinv/sysinv/sysinv/openstack/common/timeutils.py index ad1985266f..9eef1a7ff3 100644 --- a/sysinv/sysinv/sysinv/sysinv/openstack/common/timeutils.py +++ b/sysinv/sysinv/sysinv/sysinv/openstack/common/timeutils.py @@ -49,9 +49,9 @@ def parse_isotime(timestr): try: return iso8601.parse_date(timestr) except iso8601.ParseError as e: - raise ValueError(e.message) + raise ValueError(str(e)) except TypeError as e: - raise ValueError(e.message) + raise ValueError(str(e)) def strtime(at=None, fmt=PERFECT_TIME_FORMAT): diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/glance.py b/sysinv/sysinv/sysinv/sysinv/puppet/glance.py index 0ae93f5fbe..c79289f54a 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/glance.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/glance.py @@ -7,7 +7,7 @@ import os from oslo_utils import strutils -from urlparse import urlparse +from six.moves.urllib.parse import urlparse from sysinv.common import constants from sysinv.common import exception from sysinv.openstack.common import log as logging diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py b/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py index 2cbcbe42a0..d0246bd16c 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/keystone.py @@ -10,7 +10,7 @@ import os from sysinv.common import constants from tsconfig import tsconfig -from urlparse import urlparse +from six.moves.urllib.parse import urlparse from sysinv.puppet import openstack diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/platform.py b/sysinv/sysinv/sysinv/sysinv/puppet/platform.py index 79392e94ff..ea5f30c247 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/platform.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/platform.py @@ -606,7 +606,7 @@ class PlatformPuppet(base.BasePuppet): # change the CPU list to ranges rcu_nocbs_ranges = "" for key, group in itertools.groupby(enumerate(rcu_nocbs), - lambda (x, y): y - x): + lambda xy: xy[1] - xy[0]): group = list(group) rcu_nocbs_ranges += "%s-%s," % (group[0][1], group[-1][1]) rcu_nocbs_ranges = rcu_nocbs_ranges.rstrip(',') @@ -619,7 +619,7 @@ class PlatformPuppet(base.BasePuppet): # change the CPU list to ranges non_vswitch_cpus_ranges = "" for key, group in itertools.groupby(enumerate(non_vswitch_cpus), - lambda (x, y): y - x): + lambda xy: xy[1] - xy[0]): group = list(group) non_vswitch_cpus_ranges += "\"%s-%s\"," % (group[0][1], group[-1][1]) diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_backends.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_backends.py index 16ed54c804..72d12b1a74 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_backends.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_backends.py @@ -752,6 +752,8 @@ class StorageBackendTestCases(base.FunctionalTest): 'capabilities': {'test_bparam3': 'foo'}, 'confirmed': True } + services_string = '%s,%s' % (constants.SB_SVC_CINDER, constants.SB_SVC_GLANCE) + services_string2 = '%s,%s' % (constants.SB_SVC_GLANCE, constants.SB_SVC_CINDER) response = self.post_json('/storage_backend', vals, expect_errors=False) self.assertEqual(http_client.OK, response.status_int) self.assertEqual('ceph', # Expected @@ -759,15 +761,13 @@ class StorageBackendTestCases(base.FunctionalTest): patch_response = self.patch_dict_json('/storage_backend/%s' % response.json['uuid'], headers={'User-Agent': 'sysinv'}, - services=(',').join([constants.SB_SVC_CINDER, - constants.SB_SVC_GLANCE]), + services=services_string, capabilities=jsonutils.dumps({'test_cparam3': 'bar', 'test_gparam3': 'too'}), expect_errors=False) self.assertEqual(http_client.OK, patch_response.status_int) - self.assertEqual((',').join([constants.SB_SVC_CINDER, - constants.SB_SVC_GLANCE]), # Expected - self.get_json('/storage_backend/%s/' % response.json['uuid'])['services']) # Result + json_result = self.get_json('/storage_backend/%s/' % response.json['uuid'])['services'] + self.assertTrue(services_string == json_result or services_string2 == json_result) self.assertEqual({'test_bparam3': 'foo', 'test_cparam3': 'bar', 'test_gparam3': 'too'}, # Expected diff --git a/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_tier.py b/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_tier.py index 2aa0273f3d..eba303644e 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_tier.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/api/test_storage_tier.py @@ -15,7 +15,19 @@ import mock from six.moves import http_client from cephclient import wrapper as ceph -from contextlib import nested +try: + from contextlib import nested # Python 2 +except ImportError: + from contextlib import ExitStack + from contextlib import contextmanager + + @contextmanager + def nested(*contexts): + """ + Reimplementation of nested in python 3. + """ + with ExitStack() as stack: + yield tuple(stack.enter_context(cm) for cm in contexts) from oslo_serialization import jsonutils from sysinv.conductor import manager from sysinv.conductor import rpcapi @@ -659,7 +671,6 @@ class StorageTierDependentTCs(base.FunctionalTest): def fake_configure_osd_istor(context, istor_obj): istor_obj['osdid'] = 0 return istor_obj - mock_mon_status.return_value = [3, 2, ['controller-0', 'controller-1', 'storage-0']] mock_osd.side_effect = fake_configure_osd_istor diff --git a/sysinv/sysinv/sysinv/sysinv/tests/base.py b/sysinv/sysinv/sysinv/sysinv/tests/base.py index 75fad0ad52..bc691b3baf 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/base.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/base.py @@ -205,6 +205,18 @@ class TestCase(testtools.TestCase): else: return root + def stub_out(self, old, new): + """Replace a function for the duration of the test. + + Use the monkey patch fixture to replace a function for the + duration of a test. Useful when you want to provide fake + methods instead of mocks during testing. + + This should be used instead of self.stubs.Set (which is based + on mox) going forward. + """ + self.useFixture(fixtures.MonkeyPatch(old, new)) + class TimeOverride(fixtures.Fixture): """Fixture to start and remove time override.""" diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py b/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py index afcabbe948..014dc81f0f 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py @@ -521,14 +521,20 @@ class TestMigrations(BaseMigrationTestCase, WalkVersionsMixin): def setUp(self): super(TestMigrations, self).setUp() - + if six.PY2: + version = -1 + else: + version = 0 self.migration = __import__('sysinv.db.migration', - globals(), locals(), ['INIT_VERSION'], -1) + globals(), locals(), ['INIT_VERSION'], version) self.INIT_VERSION = self.migration.INIT_VERSION if self.migration_api is None: - temp = __import__('sysinv.db.sqlalchemy.migration', - globals(), locals(), ['versioning_api'], -1) - self.migration_api = temp.versioning_api + try: + temp = __import__('sysinv.db.sqlalchemy.migration', + globals(), locals(), ['versioning_api'], version) + self.migration_api = temp.versioning_api + except Exception as e: + print('import warning :%s' % e) def column_exists(self, engine, table_name, column): metadata = MetaData() diff --git a/sysinv/sysinv/sysinv/sysinv/tests/objects/test_objects.py b/sysinv/sysinv/sysinv/sysinv/tests/objects/test_objects.py index bdb07b468f..6023c7bd5c 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/objects/test_objects.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/objects/test_objects.py @@ -296,12 +296,14 @@ class _TestObject(object): obj = Foo() # NOTE(danms): Can't use assertRaisesRegexp() because of py26 raised = False + ex_out = "" try: obj.foobar except NotImplementedError as ex: + ex_out = str(ex) raised = True self.assertTrue(raised) - self.assertTrue('foobar' in str(ex)) + self.assertTrue('foobar' in ex_out) def test_loaded_in_primitive(self): obj = MyObj() @@ -420,7 +422,18 @@ class _TestObject(object): 'updated_at': timeutils.isotime(dt), } } - self.assertEqual(obj.obj_to_primitive(), expected) + expected2 = {'sysinv_object.name': 'MyObj', + 'sysinv_object.namespace': 'sysinv', + 'sysinv_object.version': '1.5', + 'sysinv_object.changes': + ['updated_at', 'created_at'], + 'sysinv_object.data': + {'created_at': timeutils.isotime(dt), + 'updated_at': timeutils.isotime(dt), + } + } + prim = obj.obj_to_primitive() + self.assertTrue(expected == prim or expected2 == prim) def test_contains(self): obj = MyObj() diff --git a/sysinv/sysinv/sysinv/sysinv/tests/test_images.py b/sysinv/sysinv/sysinv/sysinv/tests/test_images.py index 6e104e5b5f..8df50628b0 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/test_images.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/test_images.py @@ -16,12 +16,9 @@ # License for the specific language governing permissions and limitations # under the License. -import os from sysinv.common import exception from sysinv.common import images -from sysinv.common import utils -from sysinv.openstack.common import fileutils from sysinv.tests import base @@ -60,12 +57,12 @@ class SysinvImagesTestCase(base.TestCase): return FakeImgInfo() - self.stubs.Set(utils, 'execute', fake_execute) - self.stubs.Set(os, 'rename', fake_rename) - self.stubs.Set(os, 'unlink', fake_unlink) - self.stubs.Set(images, 'fetch', lambda *_: None) - self.stubs.Set(images, 'qemu_img_info', fake_qemu_img_info) - self.stubs.Set(fileutils, 'delete_if_exists', fake_rm_on_errror) + self.stub_out('sysinv.common.utils.execute', fake_execute) + self.stub_out('os.rename', fake_rename) + self.stub_out('os.unlink', fake_unlink) + self.stub_out('sysinv.common.images.fetch', lambda *_: None) + self.stub_out('sysinv.common.images.qemu_img_info', fake_qemu_img_info) + self.stub_out('sysinv.openstack.common.fileutils.delete_if_exists', fake_rm_on_errror) context = 'opaque context' image_id = '4' diff --git a/sysinv/sysinv/sysinv/sysinv/tests/test_sysinv_deploy_helper.py b/sysinv/sysinv/sysinv/sysinv/tests/test_sysinv_deploy_helper.py index e9af1a0008..969975e259 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/test_sysinv_deploy_helper.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/test_sysinv_deploy_helper.py @@ -23,9 +23,9 @@ import os import tempfile import testtools import time +import six -import mox - +from mox3 import mox from sysinv.cmd import sysinv_deploy_helper as bmdh from sysinv import db from sysinv.openstack.common import log as logging @@ -233,7 +233,10 @@ class SwitchPxeConfigTestCase(tests_base.TestCase): def setUp(self): super(SwitchPxeConfigTestCase, self).setUp() (fd, self.fname) = tempfile.mkstemp() - os.write(fd, _PXECONF_DEPLOY) + if six.PY2: + os.write(fd, _PXECONF_DEPLOY) + else: + os.write(fd, bytes(_PXECONF_DEPLOY, 'UTF-8')) os.close(fd) def tearDown(self): diff --git a/sysinv/sysinv/sysinv/sysinv/tests/test_utils.py b/sysinv/sysinv/sysinv/sysinv/tests/test_utils.py index 8961d365ac..910934519a 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/test_utils.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/test_utils.py @@ -1,4 +1,4 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 + # Copyright 2011 Justin Santa Barbara # Copyright 2012 Hewlett-Packard Development Company, L.P. @@ -16,17 +16,16 @@ # under the License. import errno -import hashlib +import mock import os import os.path import tempfile import wsme -import mox import netaddr from oslo_config import cfg -from six import StringIO +from mox3 import mox from six.moves import builtins from sysinv.common import exception from sysinv.common import service_parameter @@ -50,6 +49,7 @@ class BareMetalUtilsTestCase(base.TestCase): self.mox.ReplayAll() utils.unlink_without_raise("/fake/path") + self.mox.UnsetStubs() self.mox.VerifyAll() def test_unlink_ENOENT(self): @@ -58,6 +58,7 @@ class BareMetalUtilsTestCase(base.TestCase): self.mox.ReplayAll() utils.unlink_without_raise("/fake/path") + self.mox.UnsetStubs() self.mox.VerifyAll() def test_create_link(self): @@ -110,7 +111,7 @@ exit 1 self.assertRaises(exception.ProcessExecutionError, utils.execute, tmpfilename, tmpfilename2, attempts=10, - process_input='foo', + process_input='foo'.encode('utf-8'), delay_on_retry=False) fp = open(tmpfilename2, 'r') runs = fp.read() @@ -154,7 +155,7 @@ grep foo os.chmod(tmpfilename, 0o755) utils.execute(tmpfilename, tmpfilename2, - process_input='foo', + process_input='foo'.encode('utf-8'), attempts=2) finally: os.unlink(tmpfilename) @@ -203,12 +204,9 @@ class GenericUtilsTestCase(base.TestCase): fake_contents = "lorem ipsum" fake_file = self.mox.CreateMockAnything() fake_file.read().AndReturn(fake_contents) - fake_context_manager = self.mox.CreateMockAnything() - fake_context_manager.__enter__().AndReturn(fake_file) - fake_context_manager.__exit__(mox.IgnoreArg(), - mox.IgnoreArg(), - mox.IgnoreArg()) - + fake_context_manager = mock.Mock() + fake_context_manager.__enter__ = mock.Mock(return_value=fake_file) + fake_context_manager.__exit__ = mock.Mock(return_value=False) builtins.open(mox.IgnoreArg()).AndReturn(fake_context_manager) self.mox.ReplayAll() @@ -224,13 +222,6 @@ class GenericUtilsTestCase(base.TestCase): self.assertEqual(data, fake_contents) self.assertTrue(self.reload_called) - def test_hash_file(self): - data = 'Mary had a little lamb, its fleece as white as snow' - flo = StringIO(data) - h1 = utils.hash_file(flo) - h2 = hashlib.sha1(data).hexdigest() - self.assertEqual(h1, h2) - def test_is_valid_boolstr(self): self.assertTrue(utils.is_valid_boolstr('true')) self.assertTrue(utils.is_valid_boolstr('false')) diff --git a/sysinv/sysinv/sysinv/test-requirements.txt b/sysinv/sysinv/sysinv/test-requirements.txt index 92eb395efb..f68796213f 100644 --- a/sysinv/sysinv/sysinv/test-requirements.txt +++ b/sysinv/sysinv/sysinv/test-requirements.txt @@ -7,7 +7,6 @@ discover fixtures>=0.3.14 mock<1.1.0,>=1.0 mox -MySQL-python passlib>=1.7.0 psycopg2 python-barbicanclient<3.1.0,>=3.0.1 diff --git a/sysinv/sysinv/sysinv/tox.ini b/sysinv/sysinv/sysinv/tox.ini index 31bb84eee7..47e71695c3 100644 --- a/sysinv/sysinv/sysinv/tox.ini +++ b/sysinv/sysinv/sysinv/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = flake8,py27, pylint +envlist = flake8,py27,py35,pylint minversion = 1.6 # skipsdist = True #,pip-missing-reqs