summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/setup.py2
-rw-r--r--utils/src/ooinstall/cli_installer.py170
-rw-r--r--utils/src/ooinstall/install_transactions.py27
-rw-r--r--utils/src/ooinstall/oo_config.py41
-rw-r--r--utils/src/ooinstall/variants.py5
-rw-r--r--utils/test/cli_installer_tests.py30
-rw-r--r--utils/test/oo_config_tests.py61
7 files changed, 270 insertions, 66 deletions
diff --git a/utils/setup.py b/utils/setup.py
index 6e2fdd9c0..eac1b4b2e 100644
--- a/utils/setup.py
+++ b/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',
],
},
)
diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index c2ae00bd1..c39eb5cac 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -12,6 +12,7 @@ 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:
@@ -190,7 +191,7 @@ Notes:
facts_confirmed = click.confirm("Do the above facts look correct?")
if not facts_confirmed:
message = """
-Edit %s with the desired values and rerun oo-install with --unattended .
+Edit %s with the desired values and re-run with --unattended .
""" % oo_cfg.config_path
click.echo(message)
# Make sure we actually write out the config file.
@@ -367,58 +368,142 @@ 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
+ ctx.obj['oo_cfg'] = oo_cfg
install_transactions.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)
+
+ install_transactions.run_uninstall_playbook()
+
+
+@click.command()
+@click.pass_context
+def upgrade(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)
+
+ # Update config to reflect the version we're targetting, we'll write
+ # to disk once ansible completes successfully, not before.
+ old_variant = oo_cfg.settings['variant']
+ old_version = oo_cfg.settings['variant_version']
+ if oo_cfg.settings['variant'] == 'enterprise':
+ oo_cfg.settings['variant'] = 'openshift-enterprise'
+ variant, version = find_variant(oo_cfg.settings['variant'])
+ oo_cfg.settings['variant_version'] = version.name
+ click.echo("Openshift will be upgraded from %s %s to %s %s on the following hosts:\n" % (
+ old_variant, old_version, oo_cfg.settings['variant'],
+ oo_cfg.settings['variant_version']))
+ for host in oo_cfg.hosts:
+ click.echo(" * %s" % host.name)
+
+ if not ctx.obj['unattended']:
+ # Prompt interactively to confirm:
+ proceed = click.confirm("\nDo you wish to proceed?")
+ if not proceed:
+ click.echo("Upgrade cancelled.")
+ sys.exit(0)
+
+ retcode = install_transactions.run_upgrade_playbook()
+ if retcode > 0:
+ click.echo("Errors encountered during upgrade, please check %s." %
+ oo_cfg.settings['ansible_log_path'])
+ else:
+ click.echo("Upgrade completed! Rebooting all hosts is recommended.")
+
+
+@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)
@@ -430,8 +515,7 @@ def main(configuration, ansible_playbook_directory, ansible_config, ansible_log_
"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,7 +533,7 @@ 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,
@@ -475,5 +559,11 @@ http://docs.openshift.com/enterprise/latest/admin_guide/overview.html
click.echo(message)
click.pause()
+cli.add_command(install)
+cli.add_command(upgrade)
+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={})
diff --git a/utils/src/ooinstall/install_transactions.py b/utils/src/ooinstall/install_transactions.py
index cef6662d7..0754b8ab6 100644
--- a/utils/src/ooinstall/install_transactions.py
+++ b/utils/src/ooinstall/install_transactions.py
@@ -14,7 +14,6 @@ def set_config(cfg):
CFG = cfg
def generate_inventory(hosts):
- print hosts
global CFG
base_inventory_path = CFG.settings['ansible_inventory_path']
base_inventory = open(base_inventory_path, 'w')
@@ -126,8 +125,34 @@ 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)
+
+
+def run_upgrade_playbook():
+ playbook = os.path.join(CFG.settings['ansible_playbook_directory'],
+ 'playbooks/adhoc/upgrades/upgrade.yml')
+ # TODO: Upgrade inventory for upgrade?
+ 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)
+
diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py
index a2f53cf78..aa63180b5 100644
--- a/utils/src/ooinstall/oo_config.py
+++ b/utils/src/ooinstall/oo_config.py
@@ -73,7 +73,6 @@ class Host(object):
class OOConfig(object):
- new_config = True
default_dir = os.path.normpath(
os.environ.get('XDG_CONFIG_HOME',
os.environ['HOME'] + '/.config/') + '/openshift/')
@@ -86,19 +85,22 @@ class OOConfig(object):
self.config_path = os.path.normpath(self.default_dir +
self.default_file)
self.settings = {}
- self.read_config()
- self.set_defaults()
+ self._read_config()
+ self._set_defaults()
- def read_config(self, is_new=False):
+ def _read_config(self):
self.hosts = []
try:
- new_settings = None
if os.path.exists(self.config_path):
cfgfile = open(self.config_path, 'r')
- new_settings = yaml.safe_load(cfgfile.read())
+ self.settings = yaml.safe_load(cfgfile.read())
cfgfile.close()
- if new_settings:
- self.settings = new_settings
+
+ # Use the presence of a Description as an indicator this is
+ # a legacy config file:
+ if 'Description' in self.settings:
+ self._upgrade_legacy_config()
+
# Parse the hosts into DTO objects:
if 'hosts' in self.settings:
for host in self.settings['hosts']:
@@ -114,9 +116,28 @@ class OOConfig(object):
ferr.strerror))
except yaml.scanner.ScannerError:
raise OOConfigFileError('Config file "{}" is not a valid YAML document'.format(self.config_path))
- self.new_config = is_new
- def set_defaults(self):
+ def _upgrade_legacy_config(self):
+ new_hosts = []
+ if 'validated_facts' in self.settings:
+ for key, value in self.settings['validated_facts'].iteritems():
+ if 'masters' in self.settings and key in self.settings['masters']:
+ value['master'] = True
+ if 'nodes' in self.settings and key in self.settings['nodes']:
+ value['node'] = True
+ new_hosts.append(value)
+ self.settings['hosts'] = new_hosts
+
+ remove_settings = ['validated_facts', 'Description', 'Name',
+ 'Subscription', 'Vendor', 'Version', 'masters', 'nodes']
+ for s in remove_settings:
+ del self.settings[s]
+
+ # A legacy config implies openshift-enterprise 3.0:
+ self.settings['variant'] = 'openshift-enterprise'
+ self.settings['variant_version'] = '3.0'
+
+ def _set_defaults(self):
if 'ansible_inventory_directory' not in self.settings:
self.settings['ansible_inventory_directory'] = \
diff --git a/utils/src/ooinstall/variants.py b/utils/src/ooinstall/variants.py
index ed98429fc..219af6cd2 100644
--- a/utils/src/ooinstall/variants.py
+++ b/utils/src/ooinstall/variants.py
@@ -29,6 +29,9 @@ class Variant(object):
self.versions = versions
+ def latest_version(self):
+ return self.versions[-1]
+
# WARNING: Keep the versions ordered, most recent last:
OSE = Variant('openshift-enterprise', 'OpenShift Enterprise',
@@ -58,7 +61,7 @@ def find_variant(name, version=None):
for prod in SUPPORTED_VARIANTS:
if prod.name == name:
if version is None:
- return (prod, prod.versions[-1])
+ return (prod, prod.latest_version())
for v in prod.versions:
if v.name == version:
return (prod, v)
diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py
index 076fe5dc9..1f74b5b15 100644
--- a/utils/test/cli_installer_tests.py
+++ b/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:
@@ -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]
@@ -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:
@@ -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)
@@ -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)
@@ -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:
@@ -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)
@@ -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)
@@ -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)
diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py
index 01af33fd9..b88218459 100644
--- a/utils/test/oo_config_tests.py
+++ b/utils/test/oo_config_tests.py
@@ -32,6 +32,26 @@ hosts:
node: true
"""
+# Used to test automatic upgrading of config:
+LEGACY_CONFIG = """
+Description: This is the configuration file for the OpenShift Ansible-Based Installer.
+Name: OpenShift Ansible-Based Installer Configuration
+Subscription: {type: none}
+Vendor: OpenShift Community
+Version: 0.0.1
+ansible_config: /home/dgoodwin/.python-eggs/ooinstall-3.0.0-py2.7.egg-tmp/ooinstall/ansible.cfg
+ansible_inventory_directory: /home/dgoodwin/.config/openshift/.ansible
+ansible_log_path: /tmp/ansible.log
+ansible_plugins_directory: /home/dgoodwin/.python-eggs/ooinstall-3.0.0-py2.7.egg-tmp/ooinstall/ansible_plugins
+masters: [10.0.0.1]
+nodes: [10.0.0.2, 10.0.0.3]
+validated_facts:
+ 10.0.0.1: {hostname: master-private.example.com, ip: 10.0.0.1, public_hostname: master.example.com, public_ip: 24.222.0.1}
+ 10.0.0.2: {hostname: node1-private.example.com, ip: 10.0.0.2, public_hostname: node1.example.com, public_ip: 24.222.0.2}
+ 10.0.0.3: {hostname: node2-private.example.com, ip: 10.0.0.3, public_hostname: node2.example.com, public_ip: 24.222.0.3}
+"""
+
+
CONFIG_INCOMPLETE_FACTS = """
hosts:
- ip: 10.0.0.1
@@ -74,6 +94,47 @@ class OOInstallFixture(unittest.TestCase):
return path
+class LegacyOOConfigTests(OOInstallFixture):
+
+ def setUp(self):
+ OOInstallFixture.setUp(self)
+ self.cfg_path = self.write_config(os.path.join(self.work_dir,
+ 'ooinstall.conf'), LEGACY_CONFIG)
+ self.cfg = OOConfig(self.cfg_path)
+
+ def test_load_config_memory(self):
+ self.assertEquals('openshift-enterprise', self.cfg.settings['variant'])
+ self.assertEquals('3.0', self.cfg.settings['variant_version'])
+
+ self.assertEquals(3, len(self.cfg.hosts))
+ h1 = self.cfg.get_host('10.0.0.1')
+ self.assertEquals('10.0.0.1', h1.ip)
+ self.assertEquals('24.222.0.1', h1.public_ip)
+ self.assertEquals('master-private.example.com', h1.hostname)
+ self.assertEquals('master.example.com', h1.public_hostname)
+
+ h2 = self.cfg.get_host('10.0.0.2')
+ self.assertEquals('10.0.0.2', h2.ip)
+ self.assertEquals('24.222.0.2', h2.public_ip)
+ self.assertEquals('node1-private.example.com', h2.hostname)
+ self.assertEquals('node1.example.com', h2.public_hostname)
+
+ h3 = self.cfg.get_host('10.0.0.3')
+ self.assertEquals('10.0.0.3', h3.ip)
+ self.assertEquals('24.222.0.3', h3.public_ip)
+ self.assertEquals('node2-private.example.com', h3.hostname)
+ self.assertEquals('node2.example.com', h3.public_hostname)
+
+ self.assertFalse('masters' in self.cfg.settings)
+ self.assertFalse('nodes' in self.cfg.settings)
+ self.assertFalse('Description' in self.cfg.settings)
+ self.assertFalse('Name' in self.cfg.settings)
+ self.assertFalse('Subscription' in self.cfg.settings)
+ self.assertFalse('Vendor' in self.cfg.settings)
+ self.assertFalse('Version' in self.cfg.settings)
+ self.assertFalse('validates_facts' in self.cfg.settings)
+
+
class OOConfigTests(OOInstallFixture):
def test_load_config(self):