diff --git a/actions/actions.py b/actions/actions.py index 4e426b01..91bc06bc 100755 --- a/actions/actions.py +++ b/actions/actions.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright 2016 Canonical Ltd # @@ -33,6 +33,8 @@ _add_path(_hooks) from charmhelpers.core.hookenv import action_fail +sys.path.append('hooks/') + from glance_utils import ( pause_unit_helper, resume_unit_helper, diff --git a/actions/openstack_upgrade.py b/actions/openstack_upgrade.py index 1fc909de..b87c59e7 100755 --- a/actions/openstack_upgrade.py +++ b/actions/openstack_upgrade.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright 2016 Canonical Ltd # @@ -14,27 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import sys -_path = os.path.dirname(os.path.realpath(__file__)) -_parent = os.path.abspath(os.path.join(_path, "..")) -_hooks = os.path.abspath(os.path.join(_parent, "hooks")) - - -def _add_path(path): - if path not in sys.path: - sys.path.insert(1, path) - - -_add_path(_parent) -_add_path(_hooks) - - from charmhelpers.contrib.openstack.utils import ( do_action_openstack_upgrade, ) +sys.path.append('hooks/') + from glance_relations import ( config_changed, CONFIGS diff --git a/hooks/glance_contexts.py b/hooks/glance_contexts.py index be51fe12..fa09413e 100644 --- a/hooks/glance_contexts.py +++ b/hooks/glance_contexts.py @@ -110,7 +110,7 @@ class MultiStoreContext(OSContextGenerator): 'ceph': 'glance.store.rbd.Store', 'object-store': 'glance.store.swift.Store', } - for store_relation, store_type in store_mapping.iteritems(): + for store_relation, store_type in store_mapping.items(): if relation_ids(store_relation): stores.append(store_type) _release = os_release('glance-common') @@ -121,6 +121,7 @@ class MultiStoreContext(OSContextGenerator): # means that glance should not store images in cinder by default # but can read images from cinder. stores.append('glance.store.cinder.Store') + stores.sort() return { 'known_stores': ','.join(stores) } diff --git a/hooks/glance_relations.py b/hooks/glance_relations.py index 1323bbfd..a0f814e0 100755 --- a/hooks/glance_relations.py +++ b/hooks/glance_relations.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright 2016 Canonical Ltd # @@ -208,7 +208,7 @@ def db_changed(): migrate_database() else: juju_log('allowed_units either not presented, or local unit ' - 'not in acl list: %s' % allowed_units) + 'not in acl list: {}'.format(allowed_units)) for rid in relation_ids('image-service'): image_service_joined(rid) diff --git a/hooks/glance_utils.py b/hooks/glance_utils.py index b35fb44e..0b533c83 100644 --- a/hooks/glance_utils.py +++ b/hooks/glance_utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 # # Copyright 2016 Canonical Ltd # @@ -304,7 +304,7 @@ def restart_map(): that should be restarted when file changes. ''' _map = [] - for f, ctxt in CONFIG_FILES.iteritems(): + for f, ctxt in CONFIG_FILES.items(): svcs = [] for svc in ctxt['services']: svcs.append(svc) diff --git a/hooks/install b/hooks/install index 29ff6894..50b8cad9 100755 --- a/hooks/install +++ b/hooks/install @@ -11,7 +11,7 @@ check_and_install() { fi } -PYTHON="python" +PYTHON="python3" for dep in ${DEPS[@]}; do check_and_install ${PYTHON} ${dep} diff --git a/templates/icehouse/glance-api.conf b/templates/icehouse/glance-api.conf index 350c2717..a2cb708c 100644 --- a/templates/icehouse/glance-api.conf +++ b/templates/icehouse/glance-api.conf @@ -35,7 +35,7 @@ registry_port = 9191 registry_client_protocol = http {% if api_config_flags -%} -{% for key, value in api_config_flags.iteritems() -%} +{% for key, value in api_config_flags.items() -%} {{ key }} = {{ value }} {% endfor -%} {% endif -%} diff --git a/templates/icehouse/glance-registry.conf b/templates/icehouse/glance-registry.conf index af7fa344..ccf5d57a 100644 --- a/templates/icehouse/glance-registry.conf +++ b/templates/icehouse/glance-registry.conf @@ -13,7 +13,7 @@ api_limit_max = 1000 limit_param_default = 25 {% if registry_config_flags -%} -{% for key, value in registry_config_flags.iteritems() -%} +{% for key, value in registry_config_flags.items() -%} {{ key }} = {{ value }} {% endfor -%} {% endif -%} diff --git a/templates/juno/glance-api.conf b/templates/juno/glance-api.conf index 56195e33..0ed37d62 100644 --- a/templates/juno/glance-api.conf +++ b/templates/juno/glance-api.conf @@ -38,7 +38,7 @@ registry_port = 9191 registry_client_protocol = http {% if api_config_flags -%} -{% for key, value in api_config_flags.iteritems() -%} +{% for key, value in api_config_flags.items() -%} {{ key }} = {{ value }} {% endfor -%} {% endif -%} diff --git a/templates/kilo/glance-api.conf b/templates/kilo/glance-api.conf index 9b592f45..cd9e024b 100644 --- a/templates/kilo/glance-api.conf +++ b/templates/kilo/glance-api.conf @@ -30,7 +30,7 @@ show_image_direct_url = {{ expose_image_locations }} {% endif -%} {% if api_config_flags -%} -{% for key, value in api_config_flags.iteritems() -%} +{% for key, value in api_config_flags.items() -%} {{ key }} = {{ value }} {% endfor -%} {% endif -%} diff --git a/templates/kilo/glance-registry.conf b/templates/kilo/glance-registry.conf index f5b70ef1..1918a5d5 100644 --- a/templates/kilo/glance-registry.conf +++ b/templates/kilo/glance-registry.conf @@ -12,7 +12,7 @@ api_limit_max = 1000 limit_param_default = 25 {% if registry_config_flags -%} -{% for key, value in registry_config_flags.iteritems() -%} +{% for key, value in registry_config_flags.items() -%} {{ key }} = {{ value }} {% endfor -%} {% endif -%} diff --git a/templates/mitaka/glance-api.conf b/templates/mitaka/glance-api.conf index 2ef96d78..5c592c68 100644 --- a/templates/mitaka/glance-api.conf +++ b/templates/mitaka/glance-api.conf @@ -26,7 +26,7 @@ show_image_direct_url = {{ expose_image_locations }} {% endif -%} {% if api_config_flags -%} -{% for key, value in api_config_flags.iteritems() -%} +{% for key, value in api_config_flags.items() -%} {{ key }} = {{ value }} {% endfor -%} {% endif -%} diff --git a/templates/mitaka/glance-registry.conf b/templates/mitaka/glance-registry.conf index 03e49b8c..b2314604 100644 --- a/templates/mitaka/glance-registry.conf +++ b/templates/mitaka/glance-registry.conf @@ -12,7 +12,7 @@ api_limit_max = 1000 limit_param_default = 25 {% if registry_config_flags -%} -{% for key, value in registry_config_flags.iteritems() -%} +{% for key, value in registry_config_flags.items() -%} {{ key }} = {{ value }} {% endfor -%} {% endif -%} diff --git a/test-requirements.txt b/test-requirements.txt index 9edd4bbf..db21f458 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -5,12 +5,12 @@ coverage>=3.6 mock>=1.2 flake8>=2.2.4,<=2.4.1 os-testr>=0.4.1 -charm-tools>=2.0.0 +charm-tools>=2.0.0;python_version=='2.7' requests==2.6.0 # BEGIN: Amulet OpenStack Charm Helper Requirements # Liberty client lower constraints -amulet>=1.14.3,<2.0 -bundletester>=0.6.1,<1.0 +amulet>=1.14.3,<2.0;python_version=='2.7' +bundletester>=0.6.1,<1.0;python_version=='2.7' python-ceilometerclient>=1.5.0 python-cinderclient>=1.4.0 python-glanceclient>=1.1.0 diff --git a/tox.ini b/tox.ini index 930d5264..7201b237 100644 --- a/tox.ini +++ b/tox.ini @@ -2,8 +2,9 @@ # This file is managed centrally by release-tools and should not be modified # within individual charm repos. [tox] -envlist = pep8,py27 +envlist = pep8,py27,py35,py36 skipsdist = True +skip_missing_interpreters = True [testenv] setenv = VIRTUAL_ENV={envdir} @@ -20,6 +21,7 @@ passenv = HOME TERM AMULET_* CS_API_* basepython = python2.7 deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt +commands = /bin/true [testenv:py35] basepython = python3.5 diff --git a/unit_tests/__init__.py b/unit_tests/__init__.py index 41211056..f45bce9a 100644 --- a/unit_tests/__init__.py +++ b/unit_tests/__init__.py @@ -11,20 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import os + import sys -_path = os.path.dirname(os.path.realpath(__file__)) -_parent = os.path.abspath(os.path.join(_path, "..")) -_hooks = os.path.abspath(os.path.join(_parent, "hooks")) -_actions = os.path.abspath(os.path.join(_parent, "actions")) - - -def _add_path(path): - if path not in sys.path: - sys.path.insert(1, path) - - -_add_path(_parent) -_add_path(_hooks) -_add_path(_actions) +sys.path.append('actions') +sys.path.append('hooks') +sys.path.append('unit_tests') diff --git a/unit_tests/test_glance_contexts.py b/unit_tests/test_glance_contexts.py index 5b34ba97..a493236c 100644 --- a/unit_tests/test_glance_contexts.py +++ b/unit_tests/test_glance_contexts.py @@ -106,11 +106,11 @@ class TestGlanceContexts(CharmTestCase): self.os_release.return_value = 'mitaka' self.relation_ids.return_value = ['random_rid'] self.assertEqual(contexts.MultiStoreContext()(), - {'known_stores': "glance.store.filesystem.Store," + {'known_stores': "glance.store.cinder.Store," + "glance.store.filesystem.Store," "glance.store.http.Store," "glance.store.rbd.Store," - "glance.store.swift.Store," - "glance.store.cinder.Store"}) + "glance.store.swift.Store"}) def test_multistore_defaults(self): self.relation_ids.return_value = [] diff --git a/unit_tests/test_glance_relations.py b/unit_tests/test_glance_relations.py index 1f55d94d..88971705 100644 --- a/unit_tests/test_glance_relations.py +++ b/unit_tests/test_glance_relations.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import importlib import os import sys @@ -26,26 +27,32 @@ mock_apt.apt_pkg = MagicMock() os.environ['JUJU_UNIT_NAME'] = 'glance' +import glance_utils as utils # noqa -with patch('charmhelpers.contrib.openstack.utils.' - 'pausable_restart_on_change') as mock_on_change, \ - patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec, \ - patch('charmhelpers.contrib.openstack.' - 'utils.os_requires_version') as mock_os, \ - patch('glance_utils.register_configs') as mock_register, \ - patch('glance_utils.restart_map') as mock_map, \ - patch('glance_utils.config'): - mock_on_change.side_effect = (lambda *dargs, **dkwargs: lambda f: - lambda *args, **kwargs: f(*args, - **kwargs)) - mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f: - lambda *args, **kwargs: f(*args, **kwargs)) - mock_os.side_effect = (lambda *dargs, **dkwargs: lambda f: - lambda *args, **kwargs: f(*args, **kwargs)) - import glance_relations as relations +_reg = utils.register_configs +_map = utils.restart_map + +utils.register_configs = MagicMock() +utils.restart_map = MagicMock() + + +with patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec: + mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f: + lambda *args, **kwargs: f(*args, **kwargs)) + with patch('charmhelpers.contrib.openstack.' + 'utils.os_requires_version') as mock_os: + mock_os.side_effect = (lambda *dargs, **dkwargs: lambda f: + lambda *args, **kwargs: f(*args, **kwargs)) + with patch('glance_utils.register_configs') as register_configs: + with patch('glance_utils.restart_map') as restart_map: + import glance_relations as relations + importlib.reload(relations) relations.hooks._config_save = False +utils.register_configs = _reg +utils.restart_map = _map + TO_PATCH = [ # charmhelpers.core.hookenv 'Hooks', @@ -343,8 +350,11 @@ class GlanceRelationTests(CharmTestCase): self.test_config.set('ceph-osd-replication-count', 3) self.test_config.set('ceph-pool-weight', 6) relations.get_ceph_request() - mock_create_pool.assert_called_with(name='glance', replica_count=3, - weight=6, group='images') + mock_create_pool.assert_called_once_with( + name='glance', + replica_count=3, + weight=6, + group='images') mock_request_access.assert_not_called() self.test_config.set('restrict-ceph-pools', True) diff --git a/unit_tests/test_utils.py b/unit_tests/test_utils.py index c58acb6a..2802705b 100644 --- a/unit_tests/test_utils.py +++ b/unit_tests/test_utils.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import io import os import logging import unittest @@ -52,7 +53,7 @@ def get_default_config(): ''' default_config = {} config = load_config() - for k, v in config.iteritems(): + for k, v in config.items(): if 'default' in v: default_config[k] = v['default'] else: @@ -141,8 +142,8 @@ def patch_open(): yielded. Yields the mock for "open" and "file", respectively. ''' - mock_open = MagicMock(spec=open) - mock_file = MagicMock(spec=file) + mock_open = MagicMock(spec='builtins.open') + mock_file = MagicMock(spec=io.FileIO) @contextmanager def stub_open(*args, **kwargs):