diff options
Diffstat (limited to 'utils/test')
| -rw-r--r-- | utils/test/__init__.py | 0 | ||||
| -rw-r--r-- | utils/test/cli_installer_tests.py | 471 | ||||
| -rw-r--r-- | utils/test/oo_config_tests.py | 158 | 
3 files changed, 629 insertions, 0 deletions
| diff --git a/utils/test/__init__.py b/utils/test/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/utils/test/__init__.py diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py new file mode 100644 index 000000000..076fe5dc9 --- /dev/null +++ b/utils/test/cli_installer_tests.py @@ -0,0 +1,471 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name + +import copy +import os +import ConfigParser +import yaml + +import ooinstall.cli_installer as cli + +from click.testing import CliRunner +from test.oo_config_tests import OOInstallFixture +from mock import patch + + +MOCK_FACTS = { +    '10.0.0.1': { +        'common': { +            'ip': '10.0.0.1', +            'public_ip': '10.0.0.1', +            'hostname': 'master-private.example.com', +            'public_hostname': 'master.example.com' +        } +    }, +    '10.0.0.2': { +        'common': { +            'ip': '10.0.0.2', +            'public_ip': '10.0.0.2', +            'hostname': 'node1-private.example.com', +            'public_hostname': 'node1.example.com' +        } +    }, +    '10.0.0.3': { +        'common': { +            'ip': '10.0.0.3', +            'public_ip': '10.0.0.3', +            'hostname': 'node2-private.example.com', +            'public_hostname': 'node2.example.com' +        } +    }, +} + +# Substitute in a product name before use: +SAMPLE_CONFIG = """ +variant: %s +ansible_ssh_user: root +hosts: +  - ip: 10.0.0.1 +    hostname: master-private.example.com +    public_ip: 24.222.0.1 +    public_hostname: master.example.com +    master: true +    node: true +  - ip: 10.0.0.2 +    hostname: node1-private.example.com +    public_ip: 24.222.0.2 +    public_hostname: node1.example.com +    node: true +  - ip: 10.0.0.3 +    hostname: node2-private.example.com +    public_ip: 24.222.0.3 +    public_hostname: node2.example.com +    node: true +""" + + +class OOCliFixture(OOInstallFixture): + +    def setUp(self): +        OOInstallFixture.setUp(self) +        self.runner = CliRunner() + +        # Add any arguments you would like to test here, the defaults ensure +        # we only do unattended invocations here, and using temporary files/dirs. +        self.cli_args = ["-a", self.work_dir] + +    def run_cli(self): +        return self.runner.invoke(cli.main, self.cli_args) + +    def assert_result(self, result, exit_code): +        if result.exception is not None or 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 +            import traceback +            traceback.print_exception(*result.exc_info) +            print "Output:\n%s" % result.output +            self.fail("Exception during CLI execution") + +    def _read_yaml(self, config_file_path): +        f = open(config_file_path, 'r') +        config = yaml.safe_load(f.read()) +        f.close() +        return config + + +class UnattendedCliTests(OOCliFixture): + +    def setUp(self): +        OOCliFixture.setUp(self) +        self.cli_args.append("-u") + +    @patch('ooinstall.install_transactions.run_main_playbook') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_cfg_full_run(self, load_facts_mock, run_playbook_mock): +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_playbook_mock.return_value = 0 + +        config_file = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), SAMPLE_CONFIG % 'openshift-enterprise') + +        self.cli_args.extend(["-c", config_file]) +        result = self.runner.invoke(cli.main, self.cli_args) +        self.assert_result(result, 0) + +        load_facts_args = load_facts_mock.call_args[0] +        self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"), +            load_facts_args[0]) +        self.assertEquals(os.path.join(self.work_dir, +            "playbooks/byo/openshift_facts.yml"), load_facts_args[1]) +        env_vars = load_facts_args[2] +        self.assertEquals(os.path.join(self.work_dir, +            '.ansible/callback_facts.yaml'), +            env_vars['OO_INSTALL_CALLBACK_FACTS_YAML']) +        self.assertEqual('/tmp/ansible.log', env_vars['ANSIBLE_LOG_PATH']) +        self.assertTrue('ANSIBLE_CONFIG' not in env_vars) + +        # Make sure we ran on the expected masters and nodes: +        hosts = run_playbook_mock.call_args[0][0] +        hosts_to_run_on = run_playbook_mock.call_args[0][1] +        self.assertEquals(3, len(hosts)) +        self.assertEquals(3, len(hosts_to_run_on)) + +    @patch('ooinstall.install_transactions.run_main_playbook') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_inventory_write(self, load_facts_mock, run_playbook_mock): + +        # Add an ssh user so we can verify it makes it to the inventory file: +        merged_config = "%s\n%s" % (SAMPLE_CONFIG % 'openshift-enterprise', +            "ansible_ssh_user: bob") +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_playbook_mock.return_value = 0 + +        config_file = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), merged_config) + +        self.cli_args.extend(["-c", config_file]) +        result = self.runner.invoke(cli.main, self.cli_args) +        self.assert_result(result, 0) + +        # Check the inventory file looks as we would expect: +        inventory = ConfigParser.ConfigParser(allow_no_value=True) +        inventory.read(os.path.join(self.work_dir, '.ansible/hosts')) +        self.assertEquals('bob', +            inventory.get('OSEv3:vars', 'ansible_ssh_user')) +        self.assertEquals('openshift-enterprise', +            inventory.get('OSEv3:vars', 'deployment_type')) + +        # Check the masters: +        self.assertEquals(1, len(inventory.items('masters'))) +        self.assertEquals(3, len(inventory.items('nodes'))) + +        for item in inventory.items('masters'): +            # ansible host lines do NOT parse nicely: +            master_line = item[0] +            if item[1] is not None: +                master_line = "%s=%s" % (master_line, item[1]) +            self.assertTrue('openshift_ip' in master_line) +            self.assertTrue('openshift_public_ip' in master_line) +            self.assertTrue('openshift_hostname' in master_line) +            self.assertTrue('openshift_public_hostname' in master_line) + +    @patch('ooinstall.install_transactions.run_main_playbook') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_variant_version_latest_assumed(self, load_facts_mock, +        run_playbook_mock): +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_playbook_mock.return_value = 0 + +        config_file = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), SAMPLE_CONFIG % 'openshift-enterprise') + +        self.cli_args.extend(["-c", config_file]) +        result = self.runner.invoke(cli.main, self.cli_args) +        self.assert_result(result, 0) + +        written_config = self._read_yaml(config_file) + +        self.assertEquals('openshift-enterprise', written_config['variant']) +        # We didn't specify a version so the latest should have been assumed, +        # and written to disk: +        self.assertEquals('3.1', written_config['variant_version']) + +        # Make sure the correct value was passed to ansible: +        inventory = ConfigParser.ConfigParser(allow_no_value=True) +        inventory.read(os.path.join(self.work_dir, '.ansible/hosts')) +        self.assertEquals('openshift-enterprise', +            inventory.get('OSEv3:vars', 'deployment_type')) + +    @patch('ooinstall.install_transactions.run_main_playbook') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_variant_version_preserved(self, load_facts_mock, +        run_playbook_mock): +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_playbook_mock.return_value = 0 + +        config = SAMPLE_CONFIG % 'openshift-enterprise' +        config = '%s\n%s' % (config, 'variant_version: 3.0') +        config_file = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), config) + +        self.cli_args.extend(["-c", config_file]) +        result = self.runner.invoke(cli.main, self.cli_args) +        self.assert_result(result, 0) + +        written_config = self._read_yaml(config_file) + +        self.assertEquals('openshift-enterprise', written_config['variant']) +        # Make sure our older version was preserved: +        # and written to disk: +        self.assertEquals('3.0', written_config['variant_version']) + +        inventory = ConfigParser.ConfigParser(allow_no_value=True) +        inventory.read(os.path.join(self.work_dir, '.ansible/hosts')) +        self.assertEquals('enterprise', +            inventory.get('OSEv3:vars', 'deployment_type')) + +    @patch('ooinstall.install_transactions.run_ansible') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_no_ansible_config_specified(self, load_facts_mock, run_ansible_mock): +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_ansible_mock.return_value = 0 + +        config = SAMPLE_CONFIG % 'openshift-enterprise' + +        self._ansible_config_test(load_facts_mock, run_ansible_mock, +            config, None, None) + +    @patch('ooinstall.install_transactions.run_ansible') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_ansible_config_specified_cli(self, load_facts_mock, run_ansible_mock): +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_ansible_mock.return_value = 0 + +        config = SAMPLE_CONFIG % 'openshift-enterprise' +        ansible_config = os.path.join(self.work_dir, 'ansible.cfg') + +        self._ansible_config_test(load_facts_mock, run_ansible_mock, +            config, ansible_config, ansible_config) + +    @patch('ooinstall.install_transactions.run_ansible') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_ansible_config_specified_in_installer_config(self, +        load_facts_mock, run_ansible_mock): + +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_ansible_mock.return_value = 0 + +        ansible_config = os.path.join(self.work_dir, 'ansible.cfg') +        config = SAMPLE_CONFIG % 'openshift-enterprise' +        config = "%s\nansible_config: %s" % (config, ansible_config) +        self._ansible_config_test(load_facts_mock, run_ansible_mock, +            config, None, ansible_config) + +    #pylint: disable=too-many-arguments +    # This method allows for drastically simpler tests to write, and the args +    # are all useful. +    def _ansible_config_test(self, load_facts_mock, run_ansible_mock, +        installer_config, ansible_config_cli=None, expected_result=None): +        """ +        Utility method for testing the ways you can specify the ansible config. +        """ + +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_ansible_mock.return_value = 0 + +        config_file = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), installer_config) + +        self.cli_args.extend(["-c", config_file]) +        if ansible_config_cli: +            self.cli_args.extend(["--ansible-config", ansible_config_cli]) +        result = self.runner.invoke(cli.main, self.cli_args) +        self.assert_result(result, 0) + +        # Test the env vars for facts playbook: +        facts_env_vars = load_facts_mock.call_args[0][2] +        if expected_result: +            self.assertEquals(expected_result, facts_env_vars['ANSIBLE_CONFIG']) +        else: +            self.assertFalse('ANSIBLE_CONFIG' in facts_env_vars) + +        # Test the env vars for main playbook: +        env_vars = run_ansible_mock.call_args[0][2] +        if expected_result: +            self.assertEquals(expected_result, env_vars['ANSIBLE_CONFIG']) +        else: +            self.assertFalse('ANSIBLE_CONFIG' in env_vars) + + +class AttendedCliTests(OOCliFixture): + +    def setUp(self): +        OOCliFixture.setUp(self) +        # Doesn't exist but keeps us from reading the local users config: +        self.config_file = os.path.join(self.work_dir, 'config.yml') +        self.cli_args.extend(["-c", self.config_file]) + +    #pylint: disable=too-many-arguments +    def _build_input(self, ssh_user=None, hosts=None, variant_num=None, +        add_nodes=None, confirm_facts=None): +        """ +        Builds a CLI input string with newline characters to simulate +        the full run. +        This gives us only one place to update when the input prompts change. +        """ + +        inputs = [ +            'y',  # let's proceed +        ] +        if ssh_user: +            inputs.append(ssh_user) + +        if hosts: +            i = 0 +            for (host, is_master) in hosts: +                inputs.append(host) +                inputs.append('y' if is_master else 'n') +                inputs.append('rpm') +                if i < len(hosts) - 1: +                    inputs.append('y')  # Add more hosts +                else: +                    inputs.append('n')  # Done adding hosts +                i += 1 + +        if variant_num: +            inputs.append(str(variant_num))  # Choose variant + version + +        # TODO: support option 2, fresh install +        if add_nodes: +            inputs.append('1')  # Add more nodes +            i = 0 +            for (host, is_master) in add_nodes: +                inputs.append(host) +                inputs.append('y' if is_master else 'n') +                inputs.append('rpm') +                if i < len(add_nodes) - 1: +                    inputs.append('y')  # Add more hosts +                else: +                    inputs.append('n')  # Done adding hosts +                i += 1 + +        inputs.extend([ +            confirm_facts, +            'y',  # lets do this +        ]) + +        return '\n'.join(inputs) + +    def _verify_load_facts(self, load_facts_mock): +        """ Check that we ran load facts with expected inputs. """ +        load_facts_args = load_facts_mock.call_args[0] +        self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"), +            load_facts_args[0]) +        self.assertEquals(os.path.join(self.work_dir, +            "playbooks/byo/openshift_facts.yml"), load_facts_args[1]) +        env_vars = load_facts_args[2] +        self.assertEquals(os.path.join(self.work_dir, +            '.ansible/callback_facts.yaml'), +            env_vars['OO_INSTALL_CALLBACK_FACTS_YAML']) +        self.assertEqual('/tmp/ansible.log', env_vars['ANSIBLE_LOG_PATH']) + +    def _verify_run_playbook(self, run_playbook_mock, exp_hosts_len, exp_hosts_to_run_on_len): +        """ Check that we ran playbook with expected inputs. """ +        hosts = run_playbook_mock.call_args[0][0] +        hosts_to_run_on = run_playbook_mock.call_args[0][1] +        self.assertEquals(exp_hosts_len, len(hosts)) +        self.assertEquals(exp_hosts_to_run_on_len, len(hosts_to_run_on)) + +    def _verify_config_hosts(self, written_config, host_count): +        self.assertEquals(host_count, len(written_config['hosts'])) +        for h in written_config['hosts']: +            self.assertTrue(h['node']) +            self.assertTrue('ip' in h) +            self.assertTrue('hostname' in h) +            self.assertTrue('public_ip' in h) +            self.assertTrue('public_hostname' in h) + +    @patch('ooinstall.install_transactions.run_main_playbook') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_full_run(self, load_facts_mock, run_playbook_mock): +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_playbook_mock.return_value = 0 + +        cli_input = self._build_input(hosts=[ +            ('10.0.0.1', True), +            ('10.0.0.2', False), +            ('10.0.0.3', False)], +                                      ssh_user='root', +                                      variant_num=1, +                                      confirm_facts='y') +        result = self.runner.invoke(cli.main, self.cli_args, +            input=cli_input) +        self.assert_result(result, 0) + +        self._verify_load_facts(load_facts_mock) +        self._verify_run_playbook(run_playbook_mock, 3, 3) + +        written_config = self._read_yaml(self.config_file) +        self._verify_config_hosts(written_config, 3) + +    @patch('ooinstall.install_transactions.run_main_playbook') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_add_nodes(self, load_facts_mock, run_playbook_mock): + +        # Modify the mock facts to return a version indicating OpenShift +        # is already installed on our master, and the first node. +        mock_facts = copy.deepcopy(MOCK_FACTS) +        mock_facts['10.0.0.1']['common']['version'] = "3.0.0" +        mock_facts['10.0.0.2']['common']['version'] = "3.0.0" + +        load_facts_mock.return_value = (mock_facts, 0) +        run_playbook_mock.return_value = 0 + +        cli_input = self._build_input(hosts=[ +            ('10.0.0.1', True), +            ('10.0.0.2', False), +            ], +                                      add_nodes=[('10.0.0.3', False)], +                                      ssh_user='root', +                                      variant_num=1, +                                      confirm_facts='y') +        result = self.runner.invoke(cli.main, +                                    self.cli_args, +                                    input=cli_input) +        self.assert_result(result, 0) + +        self._verify_load_facts(load_facts_mock) +        self._verify_run_playbook(run_playbook_mock, 3, 2) + +        written_config = self._read_yaml(self.config_file) +        self._verify_config_hosts(written_config, 3) + +    @patch('ooinstall.install_transactions.run_main_playbook') +    @patch('ooinstall.install_transactions.load_system_facts') +    def test_fresh_install_with_config(self, load_facts_mock, run_playbook_mock): +        load_facts_mock.return_value = (MOCK_FACTS, 0) +        run_playbook_mock.return_value = 0 + +        config_file = self.write_config(os.path.join(self.work_dir, +                                                     'ooinstall.conf'), +                                        SAMPLE_CONFIG % 'openshift-enterprise') +        cli_input = self._build_input(confirm_facts='y') +        self.cli_args.extend(["-c", config_file]) +        result = self.runner.invoke(cli.main, +                                    self.cli_args, +                                    input=cli_input) +        self.assert_result(result, 0) + +        self._verify_load_facts(load_facts_mock) +        self._verify_run_playbook(run_playbook_mock, 3, 3) + +        written_config = self._read_yaml(config_file) +        self._verify_config_hosts(written_config, 3) + +# TODO: test with config file, attended add node +# TODO: test with config file, attended new node already in config file +# TODO: test with config file, attended new node already in config file, plus manually added nodes +# TODO: test with config file, attended reject facts diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py new file mode 100644 index 000000000..01af33fd9 --- /dev/null +++ b/utils/test/oo_config_tests.py @@ -0,0 +1,158 @@ +# TODO: Temporarily disabled due to importing old code into openshift-ansible +# repo. We will work on these over time. +# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name + +import os +import unittest +import tempfile +import shutil +import yaml + +from ooinstall.oo_config import OOConfig, Host, OOConfigInvalidHostError + +SAMPLE_CONFIG = """ +variant: openshift-enterprise +ansible_ssh_user: root +hosts: +  - ip: 10.0.0.1 +    hostname: master-private.example.com +    public_ip: 24.222.0.1 +    public_hostname: master.example.com +    master: true +    node: true +  - ip: 10.0.0.2 +    hostname: node1-private.example.com +    public_ip: 24.222.0.2 +    public_hostname: node1.example.com +    node: true +  - ip: 10.0.0.3 +    hostname: node2-private.example.com +    public_ip: 24.222.0.3 +    public_hostname: node2.example.com +    node: true +""" + +CONFIG_INCOMPLETE_FACTS = """ +hosts: +  - ip: 10.0.0.1 +    hostname: master-private.example.com +    public_ip: 24.222.0.1 +    public_hostname: master.example.com +    master: true +  - ip: 10.0.0.2 +    hostname: node1-private.example.com +    public_ip: 24.222.0.2 +    node: true +  - ip: 10.0.0.3 +    node: true +""" + + +class OOInstallFixture(unittest.TestCase): + +    def setUp(self): +        self.tempfiles = [] +        self.work_dir = tempfile.mkdtemp(prefix='ooconfigtests') +        self.tempfiles.append(self.work_dir) + +    def tearDown(self): +        for path in self.tempfiles: +            if os.path.isdir(path): +                shutil.rmtree(path) +            else: +                os.remove(path) + +    def write_config(self, path, config_str): +        """ +        Write given config to a temporary file which will be cleaned +        up in teardown. +        Returns full path to the file. +        """ +        cfg_file = open(path, 'w') +        cfg_file.write(config_str) +        cfg_file.close() +        return path + + +class OOConfigTests(OOInstallFixture): + +    def test_load_config(self): + +        cfg_path = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), SAMPLE_CONFIG) +        ooconfig = OOConfig(cfg_path) + +        self.assertEquals(3, len(ooconfig.hosts)) +        self.assertEquals("10.0.0.1", ooconfig.hosts[0].name) +        self.assertEquals("10.0.0.1", ooconfig.hosts[0].ip) +        self.assertEquals("master-private.example.com", ooconfig.hosts[0].hostname) + +        self.assertEquals(["10.0.0.1", "10.0.0.2", "10.0.0.3"], +                          [host['ip'] for host in ooconfig.settings['hosts']]) + +        self.assertEquals('openshift-enterprise', ooconfig.settings['variant']) + +    def test_load_complete_facts(self): +        cfg_path = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), SAMPLE_CONFIG) +        ooconfig = OOConfig(cfg_path) +        missing_host_facts = ooconfig.calc_missing_facts() +        self.assertEquals(0, len(missing_host_facts)) + +    # Test missing optional facts the user must confirm: +    def test_load_host_incomplete_facts(self): +        cfg_path = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), CONFIG_INCOMPLETE_FACTS) +        ooconfig = OOConfig(cfg_path) +        missing_host_facts = ooconfig.calc_missing_facts() +        self.assertEquals(2, len(missing_host_facts)) +        self.assertEquals(1, len(missing_host_facts['10.0.0.2'])) +        self.assertEquals(3, len(missing_host_facts['10.0.0.3'])) + +    def test_write_config(self): +        cfg_path = self.write_config(os.path.join(self.work_dir, +            'ooinstall.conf'), SAMPLE_CONFIG) +        ooconfig = OOConfig(cfg_path) +        ooconfig.save_to_disk() + +        f = open(cfg_path, 'r') +        written_config = yaml.safe_load(f.read()) +        f.close() + +        self.assertEquals(3, len(written_config['hosts'])) +        for h in written_config['hosts']: +            self.assertTrue('ip' in h) +            self.assertTrue('public_ip' in h) +            self.assertTrue('hostname' in h) +            self.assertTrue('public_hostname' in h) + +        self.assertTrue('ansible_ssh_user' in written_config) +        self.assertTrue('variant' in written_config) + +        # Some advanced settings should not get written out if they +        # were not specified by the user: +        self.assertFalse('ansible_inventory_directory' in written_config) + + +class HostTests(OOInstallFixture): + +    def test_load_host_no_ip_or_hostname(self): +        yaml_props = { +            'public_ip': '192.168.0.1', +            'public_hostname': 'a.example.com', +            'master': True +        } +        self.assertRaises(OOConfigInvalidHostError, Host, **yaml_props) + +    def test_load_host_no_master_or_node_specified(self): +        yaml_props = { +            'ip': '192.168.0.1', +            'hostname': 'a.example.com', +            'public_ip': '192.168.0.1', +            'public_hostname': 'a.example.com', +        } +        self.assertRaises(OOConfigInvalidHostError, Host, **yaml_props) + + + + | 
