소스 검색

Merge pull request #751 from dgoodwin/uninstall

Add Uninstall Subcommand And Assume Location of Packaged Ansible Playbooks
Brenton Leanhardt 9 년 전
부모
커밋
65d86727dc
5개의 변경된 파일149개의 추가작업 그리고 79개의 파일을 삭제
  1. 2 0
      openshift-ansible.spec
  2. 1 1
      utils/setup.py
  3. 97 45
      utils/src/ooinstall/cli_installer.py
  4. 12 0
      utils/src/ooinstall/install_transactions.py
  5. 37 33
      utils/test/cli_installer_tests.py

+ 2 - 0
openshift-ansible.spec

@@ -230,6 +230,8 @@ BuildArch:     noarch
 %package -n atomic-openshift-utils
 Summary:       Atomic OpenShift Utilities
 BuildRequires: python-setuptools
+Requires:      openshift-ansible-playbooks
+Requires:      openshift-ansible-roles
 Requires:      ansible
 Requires:      python-click
 Requires:      python-setuptools

+ 1 - 1
utils/setup.py

@@ -79,7 +79,7 @@ setup(
     # pip to create the appropriate form of executable for the target platform.
     entry_points={
         'console_scripts': [
-            'oo-install=ooinstall.cli_installer:main',
+            'oo-install=ooinstall.cli_installer:cli',
         ],
     },
 )

+ 97 - 45
utils/src/ooinstall/cli_installer.py

@@ -6,12 +6,13 @@ import click
 import os
 import re
 import sys
-from ooinstall import install_transactions
+from ooinstall import openshift_ansible
 from ooinstall import OOConfig
 from ooinstall.oo_config import Host
 from ooinstall.variants import find_variant, get_variant_version_combos
 
 DEFAULT_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-util/ansible.cfg'
+DEFAULT_PLAYBOOK_DIR = '/usr/share/ansible/openshift-ansible/'
 
 def validate_ansible_dir(path):
     if not path:
@@ -356,8 +357,8 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force):
                 hosts_to_run_on.extend(new_nodes)
                 oo_cfg.hosts.extend(new_nodes)
 
-                install_transactions.set_config(oo_cfg)
-                callback_facts, error = install_transactions.default_facts(oo_cfg.hosts)
+                openshift_ansible.set_config(oo_cfg)
+                callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts)
                 if error:
                     click.echo("There was a problem fetching the required information. " \
                                "See {} for details.".format(oo_cfg.settings['ansible_log_path']))
@@ -367,71 +368,117 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force):
 
     return hosts_to_run_on, callback_facts
 
-@click.command()
+
+@click.group()
+@click.pass_context
+@click.option('--unattended', '-u', is_flag=True, default=False)
 @click.option('--configuration', '-c',
-              type=click.Path(file_okay=True,
-                              dir_okay=False,
-                              writable=True,
-                              readable=True),
-              default=None)
+    type=click.Path(file_okay=True,
+        dir_okay=False,
+        writable=True,
+        readable=True),
+    default=None)
 @click.option('--ansible-playbook-directory',
-              '-a',
-              type=click.Path(exists=True,
-                              file_okay=False,
-                              dir_okay=True,
-                              writable=True,
-                              readable=True),
-              # callback=validate_ansible_dir,
-              envvar='OO_ANSIBLE_PLAYBOOK_DIRECTORY')
+    '-a',
+    type=click.Path(exists=True,
+        file_okay=False,
+        dir_okay=True,
+        writable=False,
+        readable=True),
+    # callback=validate_ansible_dir,
+    envvar='OO_ANSIBLE_PLAYBOOK_DIRECTORY')
 @click.option('--ansible-config',
-              type=click.Path(file_okay=True,
-                              dir_okay=False,
-                              writable=True,
-                              readable=True),
-              default=None)
+    type=click.Path(file_okay=True,
+        dir_okay=False,
+        writable=True,
+        readable=True),
+    default=None)
 @click.option('--ansible-log-path',
-              type=click.Path(file_okay=True,
-                              dir_okay=False,
-                              writable=True,
-                              readable=True),
-              default="/tmp/ansible.log")
-@click.option('--unattended', '-u', is_flag=True, default=False)
-@click.option('--force', '-f', is_flag=True, default=False)
+    type=click.Path(file_okay=True,
+        dir_okay=False,
+        writable=True,
+        readable=True),
+    default="/tmp/ansible.log")
 #pylint: disable=too-many-arguments
 # Main CLI entrypoint, not much we can do about too many arguments.
-def main(configuration, ansible_playbook_directory, ansible_config, ansible_log_path, unattended, force):
-    oo_cfg = OOConfig(configuration)
+def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_config, ansible_log_path):
+    """
+    The main click CLI module. Responsible for handling most common CLI options,
+    assigning any defaults and adding to the context for the sub-commands.
+    """
+    ctx.obj = {}
+    ctx.obj['unattended'] = unattended
+    ctx.obj['configuration'] = configuration
+    ctx.obj['ansible_config'] = ansible_config
+    ctx.obj['ansible_log_path'] = ansible_log_path
 
+    oo_cfg = OOConfig(ctx.obj['configuration'])
+
+    # If no playbook dir on the CLI, check the config:
     if not ansible_playbook_directory:
         ansible_playbook_directory = oo_cfg.settings.get('ansible_playbook_directory', '')
+    # If still no playbook dir, check for the default location:
+    if not ansible_playbook_directory and os.path.exists(DEFAULT_PLAYBOOK_DIR):
+        ansible_playbook_directory = DEFAULT_PLAYBOOK_DIR
+    validate_ansible_dir(ansible_playbook_directory)
+    oo_cfg.settings['ansible_playbook_directory'] = ansible_playbook_directory
+    oo_cfg.ansible_playbook_directory = ansible_playbook_directory
+    ctx.obj['ansible_playbook_directory'] = ansible_playbook_directory
 
-    if ansible_config:
-        oo_cfg.settings['ansible_config'] = ansible_config
+    if ctx.obj['ansible_config']:
+        oo_cfg.settings['ansible_config'] = ctx.obj['ansible_config']
     elif os.path.exists(DEFAULT_ANSIBLE_CONFIG):
         # If we're installed by RPM this file should exist and we can use it as our default:
         oo_cfg.settings['ansible_config'] = DEFAULT_ANSIBLE_CONFIG
 
-    validate_ansible_dir(ansible_playbook_directory)
-    oo_cfg.settings['ansible_playbook_directory'] = ansible_playbook_directory
-    oo_cfg.ansible_playbook_directory = ansible_playbook_directory
+    oo_cfg.settings['ansible_log_path'] = ctx.obj['ansible_log_path']
 
-    oo_cfg.settings['ansible_log_path'] = ansible_log_path
-    install_transactions.set_config(oo_cfg)
+    ctx.obj['oo_cfg'] = oo_cfg
+    openshift_ansible.set_config(oo_cfg)
 
-    if unattended:
+
+@click.command()
+@click.pass_context
+def uninstall(ctx):
+    oo_cfg = ctx.obj['oo_cfg']
+
+    if len(oo_cfg.hosts) == 0:
+        click.echo("No hosts defined in: %s" % oo_cfg['configuration'])
+        sys.exit(1)
+
+    click.echo("OpenShift will be uninstalled from the following hosts:\n")
+    if not ctx.obj['unattended']:
+        # Prompt interactively to confirm:
+        for host in oo_cfg.hosts:
+            click.echo("  * %s" % host.name)
+        proceed = click.confirm("\nDo you wish to proceed?")
+        if not proceed:
+            click.echo("Uninstall cancelled.")
+            sys.exit(0)
+
+    openshift_ansible.run_uninstall_playbook()
+
+
+
+@click.command()
+@click.option('--force', '-f', is_flag=True, default=False)
+@click.pass_context
+def install(ctx, force):
+    oo_cfg = ctx.obj['oo_cfg']
+
+    if ctx.obj['unattended']:
         error_if_missing_info(oo_cfg)
     else:
         oo_cfg = get_missing_info_from_user(oo_cfg)
 
     click.echo('Gathering information from hosts...')
-    callback_facts, error = install_transactions.default_facts(oo_cfg.hosts)
+    callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts)
     if error:
         click.echo("There was a problem fetching the required information. " \
                    "Please see {} for details.".format(oo_cfg.settings['ansible_log_path']))
         sys.exit(1)
 
-    hosts_to_run_on, callback_facts = get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force)
-
+    hosts_to_run_on, callback_facts = get_hosts_to_run_on(oo_cfg, callback_facts, ctx.obj['unattended'], force)
 
     click.echo('Writing config to: %s' % oo_cfg.config_path)
 
@@ -449,10 +496,10 @@ def main(configuration, ansible_playbook_directory, ansible_config, ansible_log_
     message = """
 If changes are needed to the values recorded by the installer please update {}.
 """.format(oo_cfg.config_path)
-    if not unattended:
+    if not ctx.obj['unattended']:
         confirm_continue(message)
 
-    error = install_transactions.run_main_playbook(oo_cfg.hosts,
+    error = openshift_ansible.run_main_playbook(oo_cfg.hosts,
                                                    hosts_to_run_on)
     if error:
         # The bootstrap script will print out the log location.
@@ -475,5 +522,10 @@ http://docs.openshift.com/enterprise/latest/admin_guide/overview.html
         click.echo(message)
         click.pause()
 
+cli.add_command(install)
+cli.add_command(uninstall)
+
 if __name__ == '__main__':
-    main()
+    # This is expected behaviour for context passing with click library:
+    # pylint: disable=unexpected-keyword-arg
+    cli(obj={})

+ 12 - 0
utils/src/ooinstall/install_transactions.py

@@ -126,8 +126,20 @@ def run_main_playbook(hosts, hosts_to_run_on):
         facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
     return run_ansible(main_playbook_path, inventory_file, facts_env)
 
+
 def run_ansible(playbook, inventory, env_vars):
     return subprocess.call(['ansible-playbook',
                              '--inventory-file={}'.format(inventory),
                              playbook],
                              env=env_vars)
+
+def run_uninstall_playbook():
+    playbook = os.path.join(CFG.settings['ansible_playbook_directory'],
+        'playbooks/adhoc/uninstall.yml')
+    inventory_file = generate_inventory(CFG.hosts)
+    facts_env = os.environ.copy()
+    if 'ansible_log_path' in CFG.settings:
+        facts_env['ANSIBLE_LOG_PATH'] = CFG.settings['ansible_log_path']
+    if 'ansible_config' in CFG.settings:
+        facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
+    return run_ansible(playbook, inventory_file, facts_env)

+ 37 - 33
utils/test/cli_installer_tests.py

@@ -76,7 +76,7 @@ class OOCliFixture(OOInstallFixture):
         self.cli_args = ["-a", self.work_dir]
 
     def run_cli(self):
-        return self.runner.invoke(cli.main, self.cli_args)
+        return self.runner.invoke(cli.cli, self.cli_args)
 
     def assert_result(self, result, exit_code):
         if result.exception is not None or result.exit_code != exit_code:
@@ -102,8 +102,8 @@ class UnattendedCliTests(OOCliFixture):
         OOCliFixture.setUp(self)
         self.cli_args.append("-u")
 
-    @patch('ooinstall.install_transactions.run_main_playbook')
-    @patch('ooinstall.install_transactions.load_system_facts')
+    @patch('ooinstall.openshift_ansible.run_main_playbook')
+    @patch('ooinstall.openshift_ansible.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
@@ -111,8 +111,8 @@ class UnattendedCliTests(OOCliFixture):
         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.cli_args.extend(["-c", config_file, "install"])
+        result = self.runner.invoke(cli.cli, self.cli_args)
         self.assert_result(result, 0)
 
         load_facts_args = load_facts_mock.call_args[0]
@@ -133,8 +133,8 @@ class UnattendedCliTests(OOCliFixture):
         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')
+    @patch('ooinstall.openshift_ansible.run_main_playbook')
+    @patch('ooinstall.openshift_ansible.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:
@@ -146,8 +146,8 @@ class UnattendedCliTests(OOCliFixture):
         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.cli_args.extend(["-c", config_file, "install"])
+        result = self.runner.invoke(cli.cli, self.cli_args)
         self.assert_result(result, 0)
 
         # Check the inventory file looks as we would expect:
@@ -172,8 +172,8 @@ class UnattendedCliTests(OOCliFixture):
             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')
+    @patch('ooinstall.openshift_ansible.run_main_playbook')
+    @patch('ooinstall.openshift_ansible.load_system_facts')
     def test_variant_version_latest_assumed(self, load_facts_mock,
         run_playbook_mock):
         load_facts_mock.return_value = (MOCK_FACTS, 0)
@@ -182,8 +182,8 @@ class UnattendedCliTests(OOCliFixture):
         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.cli_args.extend(["-c", config_file, "install"])
+        result = self.runner.invoke(cli.cli, self.cli_args)
         self.assert_result(result, 0)
 
         written_config = self._read_yaml(config_file)
@@ -199,8 +199,8 @@ class UnattendedCliTests(OOCliFixture):
         self.assertEquals('openshift-enterprise',
             inventory.get('OSEv3:vars', 'deployment_type'))
 
-    @patch('ooinstall.install_transactions.run_main_playbook')
-    @patch('ooinstall.install_transactions.load_system_facts')
+    @patch('ooinstall.openshift_ansible.run_main_playbook')
+    @patch('ooinstall.openshift_ansible.load_system_facts')
     def test_variant_version_preserved(self, load_facts_mock,
         run_playbook_mock):
         load_facts_mock.return_value = (MOCK_FACTS, 0)
@@ -211,8 +211,8 @@ class UnattendedCliTests(OOCliFixture):
         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.cli_args.extend(["-c", config_file, "install"])
+        result = self.runner.invoke(cli.cli, self.cli_args)
         self.assert_result(result, 0)
 
         written_config = self._read_yaml(config_file)
@@ -227,8 +227,8 @@ class UnattendedCliTests(OOCliFixture):
         self.assertEquals('enterprise',
             inventory.get('OSEv3:vars', 'deployment_type'))
 
-    @patch('ooinstall.install_transactions.run_ansible')
-    @patch('ooinstall.install_transactions.load_system_facts')
+    @patch('ooinstall.openshift_ansible.run_ansible')
+    @patch('ooinstall.openshift_ansible.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
@@ -238,8 +238,8 @@ class UnattendedCliTests(OOCliFixture):
         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')
+    @patch('ooinstall.openshift_ansible.run_ansible')
+    @patch('ooinstall.openshift_ansible.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
@@ -250,8 +250,8 @@ class UnattendedCliTests(OOCliFixture):
         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')
+    @patch('ooinstall.openshift_ansible.run_ansible')
+    @patch('ooinstall.openshift_ansible.load_system_facts')
     def test_ansible_config_specified_in_installer_config(self,
         load_facts_mock, run_ansible_mock):
 
@@ -282,7 +282,8 @@ class UnattendedCliTests(OOCliFixture):
         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.cli_args.append("install")
+        result = self.runner.invoke(cli.cli, self.cli_args)
         self.assert_result(result, 0)
 
         # Test the env vars for facts playbook:
@@ -388,8 +389,8 @@ class AttendedCliTests(OOCliFixture):
             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')
+    @patch('ooinstall.openshift_ansible.run_main_playbook')
+    @patch('ooinstall.openshift_ansible.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
@@ -401,7 +402,8 @@ class AttendedCliTests(OOCliFixture):
                                       ssh_user='root',
                                       variant_num=1,
                                       confirm_facts='y')
-        result = self.runner.invoke(cli.main, self.cli_args,
+        self.cli_args.append("install")
+        result = self.runner.invoke(cli.cli, self.cli_args,
             input=cli_input)
         self.assert_result(result, 0)
 
@@ -411,8 +413,8 @@ class AttendedCliTests(OOCliFixture):
         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')
+    @patch('ooinstall.openshift_ansible.run_main_playbook')
+    @patch('ooinstall.openshift_ansible.load_system_facts')
     def test_add_nodes(self, load_facts_mock, run_playbook_mock):
 
         # Modify the mock facts to return a version indicating OpenShift
@@ -432,7 +434,8 @@ class AttendedCliTests(OOCliFixture):
                                       ssh_user='root',
                                       variant_num=1,
                                       confirm_facts='y')
-        result = self.runner.invoke(cli.main,
+        self.cli_args.append("install")
+        result = self.runner.invoke(cli.cli,
                                     self.cli_args,
                                     input=cli_input)
         self.assert_result(result, 0)
@@ -443,8 +446,8 @@ class AttendedCliTests(OOCliFixture):
         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')
+    @patch('ooinstall.openshift_ansible.run_main_playbook')
+    @patch('ooinstall.openshift_ansible.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
@@ -454,7 +457,8 @@ class AttendedCliTests(OOCliFixture):
                                         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.append("install")
+        result = self.runner.invoke(cli.cli,
                                     self.cli_args,
                                     input=cli_input)
         self.assert_result(result, 0)