From 4cdc771f8e04f88ac47dd194da03dadfa2fdba2d Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Tue, 20 Dec 2016 14:54:43 -0500 Subject: python3 support, add tox for better local testing against multiple python versions --- utils/.coveragerc | 1 + utils/Makefile | 18 ++++++++----- utils/setup.cfg | 4 +-- utils/src/ooinstall/cli_installer.py | 2 +- utils/src/ooinstall/oo_config.py | 27 ++++++++++---------- utils/src/ooinstall/openshift_ansible.py | 20 ++++++++------- utils/src/ooinstall/variants.py | 44 +++++++++++++------------------- utils/test-requirements.txt | 2 +- utils/test/cli_installer_tests.py | 21 +++++++-------- utils/test/fixture.py | 10 ++++---- utils/test/oo_config_tests.py | 7 ++--- utils/test/test_utils.py | 12 ++++----- utils/tox.ini | 17 ++++++++++++ 13 files changed, 102 insertions(+), 83 deletions(-) create mode 100644 utils/tox.ini (limited to 'utils') diff --git a/utils/.coveragerc b/utils/.coveragerc index 0c870af42..e1d918755 100644 --- a/utils/.coveragerc +++ b/utils/.coveragerc @@ -1,4 +1,5 @@ [run] omit= */lib/python*/site-packages/* + */lib/python*/* /usr/* diff --git a/utils/Makefile b/utils/Makefile index c061edd8c..0e1cd79dd 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -33,8 +33,8 @@ MANPAGES := docs/man/man1/atomic-openshift-installer.1 VERSION := 1.3 # YAMLFILES: Skipping all '/files/' folders due to conflicting yaml file definitions -YAMLFILES = $(shell find ../ -name $(VENV) -prune -o \( -name '*.yml' -o -name '*.yaml' \) ! -path "*/files/*" 2>&1) -PYFILES = $(shell find ../ -name $(VENV) -prune -o -name ooinstall.egg-info -prune -o -name test -prune -o -name "*.py" -print) +YAMLFILES = $(shell find ../ -name $(VENV) -prune -o -name .tox -prune -o \( -name '*.yml' -o -name '*.yaml' \) ! -path "*/files/*" -print 2>&1) +PYFILES = $(shell find ../ -name $(VENV) -prune -o -name ooinstall.egg-info -prune -o -name test -prune -o -name .tox -prune -o -name "*.py" -print) sdist: clean python setup.py sdist @@ -83,7 +83,8 @@ ci-unittests: $(VENV) @echo "#############################################" @echo "# Running Unit Tests in virtualenv" @echo "#############################################" - . $(VENV)/bin/activate && python setup.py nosetests + . $(VENV)/bin/activate && tox -e py27-unit + . $(VENV)/bin/activate && tox -e py35-unit @echo "VIEW CODE COVERAGE REPORT WITH 'xdg-open cover/index.html' or run 'make viewcover'" ci-pylint: $(VENV) @@ -108,12 +109,15 @@ ci-flake8: $(VENV) @echo "#############################################" @echo "# Running Flake8 Compliance Tests in virtualenv" @echo "#############################################" - . $(VENV)/bin/activate && flake8 --config=setup.cfg ../ --exclude="utils,../inventory" - . $(VENV)/bin/activate && python setup.py flake8 + . $(VENV)/bin/activate && tox -e py27-flake8 + . $(VENV)/bin/activate && tox -e py35-flake8 -ci: ci-list-deps ci-unittests ci-flake8 ci-pylint ci-yamllint +ci-tox: + . $(VENV)/bin/activate && tox + +ci: ci-list-deps ci-tox ci-pylint ci-yamllint @echo @echo "##################################################################################" @echo "VIEW CODE COVERAGE REPORT WITH 'xdg-open cover/index.html' or run 'make viewcover'" @echo "To clean your test environment run 'make clean'" - @echo "Other targets you may run with 'make': 'ci-pylint', 'ci-unittests', 'ci-flake8', 'ci-yamllint'" + @echo "Other targets you may run with 'make': 'ci-pylint', 'ci-tox', 'ci-unittests', 'ci-flake8', 'ci-yamllint'" diff --git a/utils/setup.cfg b/utils/setup.cfg index ee3288fc5..ea07eea9f 100644 --- a/utils/setup.cfg +++ b/utils/setup.cfg @@ -17,5 +17,5 @@ cover-branches=1 [flake8] max-line-length=120 -exclude=tests/*,setup.py -ignore=E501,E121,E124 +exclude=test/*,setup.py,oo-installenv +ignore=E501 diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 7e5ad4144..b70bd1817 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -501,7 +501,7 @@ def get_variant_and_version(multi_master=False): i = 1 combos = get_variant_version_combos() - for (variant, version) in combos: + for (variant, _) in combos: message = "%s\n(%s) %s" % (message, i, variant.description) i = i + 1 message = "%s\n" % message diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py index 64eb340f3..cf14105af 100644 --- a/utils/src/ooinstall/oo_config.py +++ b/utils/src/ooinstall/oo_config.py @@ -1,5 +1,7 @@ # pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,too-many-instance-attributes,too-few-public-methods +from __future__ import (absolute_import, print_function) + import os import sys import logging @@ -50,7 +52,7 @@ Error loading config. {}. See https://docs.openshift.com/enterprise/latest/install_config/install/quick_install.html#defining-an-installation-configuration-file for information on creating a configuration file or delete {} and re-run the installer. """ - print message.format(error, path) + print(message.format(error, path)) class OOConfigFileError(Exception): @@ -103,7 +105,7 @@ class Host(object): # If the property is defined (not None or False), export it: if getattr(self, prop): d[prop] = getattr(self, prop) - for variable, value in self.other_variables.iteritems(): + for variable, value in self.other_variables.items(): d[variable] = value return d @@ -256,16 +258,16 @@ class OOConfig(object): # Parse the hosts into DTO objects: for host in host_list: host['other_variables'] = {} - for variable, value in host.iteritems(): + for variable, value in host.items(): if variable not in HOST_VARIABLES_BLACKLIST: host['other_variables'][variable] = value self.deployment.hosts.append(Host(**host)) # Parse the roles into Objects - for name, variables in role_list.iteritems(): + for name, variables in role_list.items(): self.deployment.roles.update({name: Role(name, variables)}) - except IOError, ferr: + except IOError as ferr: raise OOConfigFileError('Cannot open config file "{}": {}'.format(ferr.filename, ferr.strerror)) except yaml.scanner.ScannerError: @@ -354,14 +356,13 @@ class OOConfig(object): self.settings['ansible_inventory_path'] = \ '{}/hosts'.format(os.path.dirname(self.config_path)) - # pylint: disable=consider-iterating-dictionary - # Disabled because we shouldn't alter the container we're - # iterating over - # # clean up any empty sets - for setting in self.settings.keys(): + empty_keys = [] + for setting in self.settings: if not self.settings[setting]: - self.settings.pop(setting) + empty_keys.append(setting) + for key in empty_keys: + self.settings.pop(key) installer_log.debug("Updated OOConfig settings: %s", self.settings) @@ -410,7 +411,7 @@ class OOConfig(object): for host in self.deployment.hosts: p_settings['deployment']['hosts'].append(host.to_dict()) - for name, role in self.deployment.roles.iteritems(): + for name, role in self.deployment.roles.items(): p_settings['deployment']['roles'][name] = role.variables for setting in self.deployment.variables: @@ -424,7 +425,7 @@ class OOConfig(object): if self.settings['ansible_inventory_directory'] != self._default_ansible_inv_dir(): p_settings['ansible_inventory_directory'] = self.settings['ansible_inventory_directory'] except KeyError as e: - print "Error persisting settings: {}".format(e) + print("Error persisting settings: {}".format(e)) sys.exit(0) return p_settings diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index f542fb376..113aca0e1 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -1,5 +1,7 @@ # pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,global-statement,global-variable-not-assigned +from __future__ import (absolute_import, print_function) + import socket import subprocess import sys @@ -107,12 +109,12 @@ def write_inventory_vars(base_inventory, lb): global CFG base_inventory.write('\n[OSEv3:vars]\n') - for variable, value in CFG.settings.iteritems(): + for variable, value in CFG.settings.items(): inventory_var = VARIABLES_MAP.get(variable, None) if inventory_var and value: base_inventory.write('{}={}\n'.format(inventory_var, value)) - for variable, value in CFG.deployment.variables.iteritems(): + for variable, value in CFG.deployment.variables.items(): inventory_var = VARIABLES_MAP.get(variable, variable) if value: base_inventory.write('{}={}\n'.format(inventory_var, value)) @@ -152,11 +154,11 @@ def write_inventory_vars(base_inventory, lb): "'baseurl': '{}', " "'enabled': 1, 'gpgcheck': 0}}]\n".format(os.environ['OO_INSTALL_PUDDLE_REPO'])) - for name, role_obj in CFG.deployment.roles.iteritems(): + for name, role_obj in CFG.deployment.roles.items(): if role_obj.variables: group_name = ROLES_TO_GROUPS_MAP.get(name, name) base_inventory.write("\n[{}:vars]\n".format(group_name)) - for variable, value in role_obj.variables.iteritems(): + for variable, value in role_obj.variables.items(): inventory_var = VARIABLES_MAP.get(variable, variable) if value: base_inventory.write('{}={}\n'.format(inventory_var, value)) @@ -193,7 +195,7 @@ def write_host(host, role, inventory, schedulable=None): facts += ' {}={}'.format(HOST_VARIABLES_MAP.get(prop), getattr(host, prop)) if host.other_variables: - for variable, value in host.other_variables.iteritems(): + for variable, value in host.other_variables.items(): facts += " {}={}".format(variable, value) if host.node_labels and role == 'node': @@ -212,7 +214,7 @@ def write_host(host, role, inventory, schedulable=None): if os.geteuid() != 0: no_pwd_sudo = subprocess.call(['sudo', '-n', 'echo', 'openshift']) if no_pwd_sudo == 1: - print 'The atomic-openshift-installer requires sudo access without a password.' + print('The atomic-openshift-installer requires sudo access without a password.') sys.exit(1) facts += ' ansible_become=yes' @@ -245,9 +247,9 @@ def load_system_facts(inventory_file, os_facts_path, env_vars, verbose=False): installer_log.debug("Going to try to read this file: %s", CFG.settings['ansible_callback_facts_yaml']) try: callback_facts = yaml.safe_load(callback_facts_file) - except yaml.YAMLError, exc: - print "Error in {}".format(CFG.settings['ansible_callback_facts_yaml']), exc - print "Try deleting and rerunning the atomic-openshift-installer" + except yaml.YAMLError as exc: + print("Error in {}".format(CFG.settings['ansible_callback_facts_yaml']), exc) + print("Try deleting and rerunning the atomic-openshift-installer") sys.exit(1) return callback_facts, 0 diff --git a/utils/src/ooinstall/variants.py b/utils/src/ooinstall/variants.py index 39772bb2e..a45be98bf 100644 --- a/utils/src/ooinstall/variants.py +++ b/utils/src/ooinstall/variants.py @@ -38,32 +38,24 @@ class Variant(object): # WARNING: Keep the versions ordered, most recent first: -OSE = Variant('openshift-enterprise', 'OpenShift Container Platform', - [ - Version('3.4', 'openshift-enterprise'), - ] -) - -REG = Variant('openshift-enterprise', 'Registry', - [ - Version('3.4', 'openshift-enterprise', 'registry'), - ] -) - -origin = Variant('origin', 'OpenShift Origin', - [ - Version('1.4', 'origin'), - ] -) - -LEGACY = Variant('openshift-enterprise', 'OpenShift Container Platform', - [ - Version('3.3', 'openshift-enterprise'), - Version('3.2', 'openshift-enterprise'), - Version('3.1', 'openshift-enterprise'), - Version('3.0', 'openshift-enterprise'), - ] -) +OSE = Variant('openshift-enterprise', 'OpenShift Container Platform', [ + Version('3.4', 'openshift-enterprise'), +]) + +REG = Variant('openshift-enterprise', 'Registry', [ + Version('3.4', 'openshift-enterprise', 'registry'), +]) + +origin = Variant('origin', 'OpenShift Origin', [ + Version('1.4', 'origin'), +]) + +LEGACY = Variant('openshift-enterprise', 'OpenShift Container Platform', [ + Version('3.3', 'openshift-enterprise'), + Version('3.2', 'openshift-enterprise'), + Version('3.1', 'openshift-enterprise'), + Version('3.0', 'openshift-enterprise'), +]) # Ordered list of variants we can install, first is the default. SUPPORTED_VARIANTS = (OSE, REG, origin, LEGACY) diff --git a/utils/test-requirements.txt b/utils/test-requirements.txt index b70a03563..e5c5360c3 100644 --- a/utils/test-requirements.txt +++ b/utils/test-requirements.txt @@ -1,5 +1,4 @@ ansible -enum configparser pylint nose @@ -11,3 +10,4 @@ click backports.functools_lru_cache pyOpenSSL yamllint +tox diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py index 36dc18034..0cb37eaff 100644 --- a/utils/test/cli_installer_tests.py +++ b/utils/test/cli_installer_tests.py @@ -4,7 +4,8 @@ import copy import os -import ConfigParser + +from six.moves import configparser import ooinstall.cli_installer as cli @@ -408,7 +409,7 @@ class UnattendedCliTests(OOCliFixture): result = self.runner.invoke(cli.cli, self.cli_args) if result.exception is None or result.exit_code != 1: - print "Exit code: %s" % result.exit_code + print("Exit code: %s" % result.exit_code) self.fail("Unexpected CLI return") # unattended with config file and all installed hosts (with --force) @@ -523,7 +524,7 @@ class UnattendedCliTests(OOCliFixture): self.assert_result(result, 0) # Check the inventory file looks as we would expect: - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assertEquals('root', inventory.get('OSEv3:vars', 'ansible_ssh_user')) @@ -566,7 +567,7 @@ class UnattendedCliTests(OOCliFixture): self.assertEquals('3.3', written_config['variant_version']) # Make sure the correct value was passed to ansible: - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assertEquals('openshift-enterprise', inventory.get('OSEv3:vars', 'deployment_type')) @@ -594,7 +595,7 @@ class UnattendedCliTests(OOCliFixture): # and written to disk: self.assertEquals('3.3', written_config['variant_version']) - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assertEquals('openshift-enterprise', inventory.get('OSEv3:vars', 'deployment_type')) @@ -830,7 +831,7 @@ class AttendedCliTests(OOCliFixture): written_config = read_yaml(self.config_file) self._verify_config_hosts(written_config, 4) - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1', 'openshift_schedulable=False') @@ -949,7 +950,7 @@ class AttendedCliTests(OOCliFixture): written_config = read_yaml(self.config_file) self._verify_config_hosts(written_config, 6) - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1', 'openshift_schedulable=False') @@ -990,7 +991,7 @@ class AttendedCliTests(OOCliFixture): written_config = read_yaml(self.config_file) self._verify_config_hosts(written_config, 5) - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1', 'openshift_schedulable=True') @@ -1082,7 +1083,7 @@ class AttendedCliTests(OOCliFixture): written_config = read_yaml(self.config_file) self._verify_config_hosts(written_config, 1) - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1', 'openshift_schedulable=True') @@ -1116,7 +1117,7 @@ class AttendedCliTests(OOCliFixture): written_config = read_yaml(self.config_file) self._verify_config_hosts(written_config, 4) - inventory = ConfigParser.ConfigParser(allow_no_value=True) + inventory = configparser.ConfigParser(allow_no_value=True) inventory.read(os.path.join(self.work_dir, 'hosts')) self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1', 'openshift_schedulable=False') diff --git a/utils/test/fixture.py b/utils/test/fixture.py index 62135c761..5200d275d 100644 --- a/utils/test/fixture.py +++ b/utils/test/fixture.py @@ -65,13 +65,13 @@ class OOCliFixture(OOInstallFixture): def assert_result(self, result, exit_code): if result.exit_code != exit_code: - print "Unexpected result from CLI execution" - print "Exit code: %s" % result.exit_code - print "Exception: %s" % result.exception - print result.exc_info + print("Unexpected result from CLI execution") + print("Exit code: %s" % result.exit_code) + print("Exception: %s" % result.exception) + print(result.exc_info) import traceback traceback.print_exception(*result.exc_info) - print "Output:\n%s" % result.output + print("Output:\n%s" % result.output) self.fail("Exception during CLI execution") def _verify_load_facts(self, load_facts_mock): diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py index 56fd82408..2b4fce512 100644 --- a/utils/test/oo_config_tests.py +++ b/utils/test/oo_config_tests.py @@ -2,13 +2,14 @@ # repo. We will work on these over time. # pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name -import cStringIO import os import unittest import tempfile import shutil import yaml +from six.moves import cStringIO + from ooinstall.oo_config import OOConfig, Host, OOConfigInvalidHostError import ooinstall.openshift_ansible @@ -244,7 +245,7 @@ class HostTests(OOInstallFixture): } new_node = Host(**yaml_props) - inventory = cStringIO.StringIO() + inventory = cStringIO() # This is what the 'write_host' function generates. write_host # has no return value, it just writes directly to the file # 'inventory' which in this test-case is a StringIO object @@ -285,7 +286,7 @@ class HostTests(OOInstallFixture): # } # new_node = Host(**yaml_props) - # inventory = cStringIO.StringIO() + # inventory = cStringIO() # # This is what the original 'write_host' function will # # generate. write_host has no return value, it just writes diff --git a/utils/test/test_utils.py b/utils/test/test_utils.py index 2e59d86f2..b18f85692 100644 --- a/utils/test/test_utils.py +++ b/utils/test/test_utils.py @@ -2,6 +2,7 @@ Unittests for ooinstall utils. """ +import six import unittest import logging import sys @@ -28,9 +29,6 @@ class TestUtils(unittest.TestCase): mock.call('OO_FOO: bar'), ] - # python 2.x has assertItemsEqual, python 3.x has assertCountEqual - if sys.version_info.major > 3: - self.assertItemsEqual = self.assertCountEqual ###################################################################### # Validate ooinstall.utils.debug_env functionality @@ -40,7 +38,7 @@ class TestUtils(unittest.TestCase): with mock.patch('ooinstall.utils.installer_log') as _il: debug_env(self.debug_all_params) - print _il.debug.call_args_list + print(_il.debug.call_args_list) # Debug was called for each item we expect self.assertEqual( @@ -48,7 +46,8 @@ class TestUtils(unittest.TestCase): _il.debug.call_count) # Each item we expect was logged - self.assertItemsEqual( + six.assertCountEqual( + self, self.expected, _il.debug.call_args_list) @@ -67,7 +66,8 @@ class TestUtils(unittest.TestCase): _il.debug.call_count, len(debug_some_params)) - self.assertItemsEqual( + six.assertCountEqual( + self, self.expected, _il.debug.call_args_list) diff --git a/utils/tox.ini b/utils/tox.ini new file mode 100644 index 000000000..747d79dfe --- /dev/null +++ b/utils/tox.ini @@ -0,0 +1,17 @@ +[tox] +minversion=2.3.1 +envlist = + py{27,35}-{flake8,unit} +skipsdist=True +skip_missing_interpreters=True + +[testenv] +usedevelop=True +deps = + -rtest-requirements.txt + py35-flake8: flake8-bugbear + +commands = + flake8: flake8 --config=setup.cfg ../ --exclude="../utils,.tox,../inventory" + flake8: python setup.py flake8 + unit: python setup.py nosetests -- cgit v1.2.1