From 7197aba51d24ab2cf6cde77efa853903d7ddd5ba Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Wed, 28 Oct 2015 12:12:39 -0300 Subject: Block upgrade if targetting enterprise deployment type. enterprise is being phased out in favor of openshift-enterprise, you need to specify where you wish to go. --- utils/src/ooinstall/cli_installer.py | 21 +++++++++++++++++++++ utils/src/ooinstall/install_transactions.py | 12 ++++++++++++ 2 files changed, 33 insertions(+) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 03f86a166..e22217fdb 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -459,6 +459,26 @@ def uninstall(ctx): 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) + + click.echo("OpenShift will be upgraded on 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("Upgrade cancelled.") + sys.exit(0) + install_transactions.run_upgrade_playbook() + @click.command() @click.option('--force', '-f', is_flag=True, default=False) @@ -523,6 +543,7 @@ http://docs.openshift.com/enterprise/latest/admin_guide/overview.html click.pause() cli.add_command(install) +cli.add_command(upgrade) cli.add_command(uninstall) if __name__ == '__main__': diff --git a/utils/src/ooinstall/install_transactions.py b/utils/src/ooinstall/install_transactions.py index 3306271c8..60b0f3d9f 100644 --- a/utils/src/ooinstall/install_transactions.py +++ b/utils/src/ooinstall/install_transactions.py @@ -143,3 +143,15 @@ def run_uninstall_playbook(): 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) -- cgit v1.2.3 From 3d7c5c6fd545112d87fa09e4a8c3f3cbc1cda1ee Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Wed, 28 Oct 2015 15:29:52 -0300 Subject: First cut at checking available disk space for etcd backup. --- playbooks/adhoc/upgrades/upgrade.yml | 27 ++++++++++++++++++++++++++- utils/src/ooinstall/cli_installer.py | 15 ++++++++++++++- utils/src/ooinstall/install_transactions.py | 1 - utils/src/ooinstall/variants.py | 5 ++++- 4 files changed, 44 insertions(+), 4 deletions(-) (limited to 'utils') diff --git a/playbooks/adhoc/upgrades/upgrade.yml b/playbooks/adhoc/upgrades/upgrade.yml index e8d6a335d..c2c1d57e8 100644 --- a/playbooks/adhoc/upgrades/upgrade.yml +++ b/playbooks/adhoc/upgrades/upgrade.yml @@ -1,5 +1,5 @@ --- -- name: Verify deployment type +- name: Verify upgrade can proceed hosts: masters tasks: # Checking the global deployment type rather than host facts, this is about @@ -7,6 +7,31 @@ - fail: msg="Deployment type enterprise not supported for upgrade" when: deployment_type == "enterprise" +- name: Backup etcd + hosts: masters + vars: + embedded_etcd: "{{ openshift.master.embedded_etcd }}" + roles: + - openshift_facts + tasks: + - name: display all variables set for the current host + debug: + var: hostvars[inventory_hostname] + - debug: var=embedded_etcd + - name: Check available data dir disk space + shell: > + df --output=avail -k {{ openshift.common.data_dir }} | tail -n 1 + register: avail_disk + when: embedded_etcd | bool + - debug: var=avail_disk.stdout + - name: Check current etcd disk usage + shell: > + df --output=avail -k /var/lib/openshift/openshift.local.etcd/ | tail -n 1 + register: etc_disk_usage + when: embedded_etcd | bool + - debug: var=etc_disk_usage.stdout + - fail: msg="All done for now." + - name: Re-Run cluster configuration to apply latest configuration changes include: ../../common/openshift-cluster/config.yml vars: diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index e22217fdb..daac5e388 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -191,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. @@ -477,6 +477,19 @@ def upgrade(ctx): if not proceed: click.echo("Upgrade cancelled.") sys.exit(0) + + # 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("Upgrading from %s %s to %s %s" % ( + old_variant, old_version, oo_cfg.settings['variant'], + oo_cfg.settings['variant_version'])) + install_transactions.run_upgrade_playbook() diff --git a/utils/src/ooinstall/install_transactions.py b/utils/src/ooinstall/install_transactions.py index 60b0f3d9f..1d1dbe340 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') 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) -- cgit v1.2.3 From 7063a66354faebe143124ff275cbe04a56c03237 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Mon, 2 Nov 2015 09:27:06 -0400 Subject: Automatically upgrade legacy config files. --- utils/src/ooinstall/oo_config.py | 41 ++++++++++++++++++++------- utils/test/oo_config_tests.py | 61 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 10 deletions(-) (limited to 'utils') 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/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): -- cgit v1.2.3 From 1ddfdd136f4b22368c87ad7656faa0cccdfa4a25 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Mon, 2 Nov 2015 10:10:46 -0400 Subject: Print info after upgrade completes. --- utils/src/ooinstall/cli_installer.py | 7 ++++++- utils/src/ooinstall/install_transactions.py | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index daac5e388..978259f79 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -490,7 +490,12 @@ def upgrade(ctx): old_variant, old_version, oo_cfg.settings['variant'], oo_cfg.settings['variant_version'])) - install_transactions.run_upgrade_playbook() + 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() diff --git a/utils/src/ooinstall/install_transactions.py b/utils/src/ooinstall/install_transactions.py index 1d1dbe340..0754b8ab6 100644 --- a/utils/src/ooinstall/install_transactions.py +++ b/utils/src/ooinstall/install_transactions.py @@ -143,6 +143,7 @@ def run_uninstall_playbook(): 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') @@ -154,3 +155,4 @@ def run_upgrade_playbook(): if 'ansible_config' in CFG.settings: facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config'] return run_ansible(playbook, inventory_file, facts_env) + -- cgit v1.2.3 From ef6b36d14a00757754aaf001a8acad8354cf62ff Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Mon, 2 Nov 2015 15:17:47 -0400 Subject: Better info prior to initiating upgrade. --- utils/src/ooinstall/cli_installer.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 978259f79..c39eb5cac 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -468,16 +468,6 @@ def upgrade(ctx): click.echo("No hosts defined in: %s" % oo_cfg['configuration']) sys.exit(1) - click.echo("OpenShift will be upgraded on 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("Upgrade cancelled.") - sys.exit(0) - # 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'] @@ -486,9 +476,18 @@ def upgrade(ctx): oo_cfg.settings['variant'] = 'openshift-enterprise' variant, version = find_variant(oo_cfg.settings['variant']) oo_cfg.settings['variant_version'] = version.name - click.echo("Upgrading from %s %s to %s %s" % ( + 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: -- cgit v1.2.3 From 39250a47afca63ef0b5a73158a2c9b15443a4235 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Tue, 3 Nov 2015 08:27:26 -0400 Subject: Pylint fix. --- utils/src/ooinstall/cli_installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index c39eb5cac..21e50de6d 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -474,7 +474,7 @@ def upgrade(ctx): 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']) + version = find_variant(oo_cfg.settings['variant'])[0] 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'], -- cgit v1.2.3 From f91c0cac0b6e671d5ad70543054a17178c5f0a46 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Tue, 3 Nov 2015 08:37:31 -0400 Subject: Add a simple version for the installer config file. --- utils/src/ooinstall/oo_config.py | 3 +++ utils/test/oo_config_tests.py | 3 +++ 2 files changed, 6 insertions(+) (limited to 'utils') diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py index aa63180b5..4281947f1 100644 --- a/utils/src/ooinstall/oo_config.py +++ b/utils/src/ooinstall/oo_config.py @@ -12,6 +12,7 @@ PERSIST_SETTINGS = [ 'ansible_log_path', 'variant', 'variant_version', + 'version', ] REQUIRED_FACTS = ['ip', 'public_ip', 'hostname', 'public_hostname'] @@ -146,6 +147,8 @@ class OOConfig(object): os.makedirs(self.settings['ansible_inventory_directory']) if 'ansible_plugins_directory' not in self.settings: self.settings['ansible_plugins_directory'] = resource_filename(__name__, 'ansible_plugins') + if 'version' not in self.settings: + self.settings['version'] = 'v1' if 'ansible_callback_facts_yaml' not in self.settings: self.settings['ansible_callback_facts_yaml'] = '%s/callback_facts.yaml' % \ diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py index b88218459..480560542 100644 --- a/utils/test/oo_config_tests.py +++ b/utils/test/oo_config_tests.py @@ -105,6 +105,7 @@ class LegacyOOConfigTests(OOInstallFixture): 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('v1', self.cfg.settings['version']) self.assertEquals(3, len(self.cfg.hosts)) h1 = self.cfg.get_host('10.0.0.1') @@ -152,6 +153,7 @@ class OOConfigTests(OOInstallFixture): [host['ip'] for host in ooconfig.settings['hosts']]) self.assertEquals('openshift-enterprise', ooconfig.settings['variant']) + self.assertEquals('v1', ooconfig.settings['version']) def test_load_complete_facts(self): cfg_path = self.write_config(os.path.join(self.work_dir, @@ -189,6 +191,7 @@ class OOConfigTests(OOInstallFixture): self.assertTrue('ansible_ssh_user' in written_config) self.assertTrue('variant' in written_config) + self.assertEquals('v1', written_config['version']) # Some advanced settings should not get written out if they # were not specified by the user: -- cgit v1.2.3 From 3f28361fdf56c9e7395fcbfe5c2698569f8a5684 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Tue, 3 Nov 2015 08:57:57 -0400 Subject: Remove my username from some test data. --- utils/test/oo_config_tests.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'utils') diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py index 480560542..6dc335a0e 100644 --- a/utils/test/oo_config_tests.py +++ b/utils/test/oo_config_tests.py @@ -39,10 +39,10 @@ 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_config: /tmp/notreal/ansible.cfg +ansible_inventory_directory: /tmp/notreal/.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 +ansible_plugins_directory: /tmp/notreal/.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: -- cgit v1.2.3 From ec31736606fc280de641e8909f03416c6b74e004 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Tue, 3 Nov 2015 09:20:04 -0400 Subject: Document the new version field for installer config. --- utils/docs/config.md | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'utils') diff --git a/utils/docs/config.md b/utils/docs/config.md index 9399409dd..ee4b157c9 100644 --- a/utils/docs/config.md +++ b/utils/docs/config.md @@ -7,6 +7,7 @@ The default location this config file will be written to ~/.config/openshift/ins ## Example ``` +version: v1 variant: openshift-enterprise variant_version: 3.0 ansible_ssh_user: root @@ -32,6 +33,10 @@ hosts: ## Primary Settings +### version + +Indicates the version of configuration this file was written with. Current implementation is v1. + ### variant The OpenShift variant to install. Currently valid options are: -- cgit v1.2.3 From ab83e16dbed3eb5cf1dff96992509439d2739550 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Tue, 3 Nov 2015 09:51:10 -0400 Subject: Fix installer upgrade bug following pylint fix. --- utils/src/ooinstall/cli_installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 21e50de6d..2fc7a872f 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -474,7 +474,7 @@ def upgrade(ctx): old_version = oo_cfg.settings['variant_version'] if oo_cfg.settings['variant'] == 'enterprise': oo_cfg.settings['variant'] = 'openshift-enterprise' - version = find_variant(oo_cfg.settings['variant'])[0] + version = find_variant(oo_cfg.settings['variant'])[1] 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'], -- cgit v1.2.3 From 21f793b8aefcd680041150d0740eeed05d272c31 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Wed, 4 Nov 2015 09:13:39 -0400 Subject: Fix bug with default ansible playbook dir. --- utils/src/ooinstall/cli_installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 25705ec7a..455f56a66 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -385,7 +385,7 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): dir_okay=True, readable=True), # callback=validate_ansible_dir, - default='/usr/share/openshift-ansible/', + default=DEFAULT_PLAYBOOK_DIR, envvar='OO_ANSIBLE_PLAYBOOK_DIRECTORY') @click.option('--ansible-config', type=click.Path(file_okay=True, -- cgit v1.2.3 From 6b2644268ed1bbb1ff3f2fd85427aefef0e51e0f Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Wed, 4 Nov 2015 09:54:55 -0400 Subject: Fix bug from module rename. --- utils/src/ooinstall/cli_installer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 455f56a66..e4fda2813 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -489,7 +489,7 @@ def upgrade(ctx): click.echo("Upgrade cancelled.") sys.exit(0) - retcode = install_transactions.run_upgrade_playbook() + retcode = openshift_ansible.run_upgrade_playbook() if retcode > 0: click.echo("Errors encountered during upgrade, please check %s." % oo_cfg.settings['ansible_log_path']) -- cgit v1.2.3 From 215a7aacc2fc3df19a64a2a57910516533665423 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Wed, 4 Nov 2015 10:41:39 -0400 Subject: Fix bug with not upgrading openshift-master to atomic-openshift-master. Removing the full call to config resulted in rpms not getting upgraded. Config was doing a yum update of everything, which picks up the atomic-openshift-master obsoleting openshift-master. The actual yum call changed here would not. Instead we switch to a direct call to yum which correctly picks up the obsoletes and updates to atomic-openshift packages. --- playbooks/adhoc/upgrades/upgrade.yml | 19 +++++-------------- utils/src/ooinstall/openshift_ansible.py | 1 + 2 files changed, 6 insertions(+), 14 deletions(-) (limited to 'utils') diff --git a/playbooks/adhoc/upgrades/upgrade.yml b/playbooks/adhoc/upgrades/upgrade.yml index 8c1138797..0f505bf7d 100644 --- a/playbooks/adhoc/upgrades/upgrade.yml +++ b/playbooks/adhoc/upgrades/upgrade.yml @@ -57,9 +57,6 @@ vars: g_masters_group: "{{ 'masters' }}" tasks: - - name: display all variables set for the current host - debug: - var: hostvars[inventory_hostname] - name: Evaluate oo_first_master add_host: name: "{{ groups[g_masters_group][0] }}" @@ -93,15 +90,6 @@ - fail: msg="Deployment type 'enterprise' must be updated to 'openshift-enterprise' for upgrade to proceed" when: deployment_type == "enterprise" and (_new_version.stdout | version_compare('1.0.7', '>=') or _new_version.stdout | version_compare('3.1', '>=')) - #- name: Re-Run cluster configuration to apply latest configuration changes - # include: ../../common/openshift-cluster/config.yml - # vars: - # g_etcd_group: "{{ 'etcd' }}" - # g_masters_group: "{{ 'masters' }}" - # g_nodes_group: "{{ 'nodes' }}" - # openshift_cluster_id: "{{ cluster_id | default('default') }}" - # openshift_deployment_type: "{{ deployment_type }}" - - name: Upgrade masters hosts: masters vars: @@ -109,8 +97,11 @@ tasks: - name: Upgrade to latest available kernel yum: pkg=kernel state=latest + - name: display just the deployment_type variable for the current host + debug: + var: hostvars[inventory_hostname] - name: Upgrade master packages - yum: pkg={{ openshift.common.service_type }}-master{{ openshift_version }} state=latest + command: yum update -y {{ openshift.common.service_type }}-master{{ openshift_version }} - name: Upgrade master configuration. openshift_upgrade_config: from_version=3.0 to_version=3.1 role=master - name: Restart master services @@ -124,7 +115,7 @@ - openshift_facts tasks: - name: Upgrade node packages - yum: pkg={{ openshift.common.service_type }}-node{{ openshift_version }} state=latest + command: yum update -y {{ openshift.common.service_type }}-node{{ openshift_version }} - name: Restart node services service: name="{{ openshift.common.service_type }}-node" state=restarted diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index 9d801cabe..e33330102 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -144,6 +144,7 @@ def run_ansible(playbook, inventory, env_vars): playbook], env=env_vars) + def run_uninstall_playbook(): playbook = os.path.join(CFG.settings['ansible_playbook_directory'], 'playbooks/adhoc/uninstall.yml') -- cgit v1.2.3 From 82b4209c02c27ab0e9a6d9c016ff06d12f42a9c1 Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Thu, 5 Nov 2015 08:41:51 -0500 Subject: Bug 1274201 - Fixing sudo non-interactive test https://bugzilla.redhat.com/show_bug.cgi?id=1274201#c13 --- utils/src/ooinstall/openshift_ansible.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index e33330102..bdb9859a2 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -46,7 +46,7 @@ def generate_inventory(hosts): if any(host.hostname == installer_host or host.public_hostname == installer_host for host in hosts): - no_pwd_sudo = subprocess.call(['sudo', '-v', '--non-interactive']) + no_pwd_sudo = subprocess.call(['sudo', '-v', '-n']) if no_pwd_sudo == 1: print 'The atomic-openshift-installer requires sudo access without a password.' sys.exit(1) -- cgit v1.2.3 From cfca7b9f7894e2b427ae0753477cd13cc537e348 Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Thu, 5 Nov 2015 09:14:33 -0500 Subject: Bug 1274201 - Fixing non-root installations if using a local connection Previously we were writing out a inventory like this: ~~~ [OSEv3:children] masters nodes [OSEv3:vars] ansible_ssh_user=root deployment_type=openshift-enterprise ansible_connection=local [masters] ose3-master.example.com openshift_hostname=ose3-master.example.com [nodes] ose3-master.example.com openshift_hostname=ose3-master.example.com ose3-node1.example.com openshift_hostname=ose3-node1.example.com ose3-node2.example.com openshift_hostname=ose3-node2.example.com ~~~ The problem with that is now all the hosts are consider local connections. In addition our sudo check wasn't working as expected. We would check that we have sudo, but the playbooks were not running with root privileges. When gathering facts you'd hit: ~~~ __main__.OpenShiftFactsFileWriteError: Could not create fact file: /etc/ansible/facts.d/openshift.fact, error: [Errno 13] Permission denied: '/etc/ansible/facts.d/openshift.fact' ~~~ Instead the test for locale connections needs to be per host. Anytime we're not running as root we need `ansible_become` set: ~~~ ose3-master.example.com openshift_hostname=ose3-master.example.com ansible_connection=local ansible_become=true ~~~ --- utils/src/ooinstall/openshift_ansible.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'utils') diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index bdb9859a2..4b37be278 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -18,7 +18,6 @@ def set_config(cfg): def generate_inventory(hosts): global CFG - installer_host = socket.gethostname() base_inventory_path = CFG.settings['ansible_inventory_path'] base_inventory = open(base_inventory_path, 'w') base_inventory.write('\n[OSEv3:children]\nmasters\nnodes\n') @@ -44,14 +43,6 @@ def generate_inventory(hosts): if 'OO_INSTALL_STAGE_REGISTRY' in os.environ: base_inventory.write('oreg_url=registry.access.stage.redhat.com/openshift3/ose-${component}:${version}\n') - if any(host.hostname == installer_host or host.public_hostname == installer_host - for host in hosts): - no_pwd_sudo = subprocess.call(['sudo', '-v', '-n']) - if no_pwd_sudo == 1: - print 'The atomic-openshift-installer requires sudo access without a password.' - sys.exit(1) - base_inventory.write("ansible_connection=local\n") - base_inventory.write('\n[masters]\n') masters = (host for host in hosts if host.master) for master in masters: @@ -72,6 +63,7 @@ def generate_inventory(hosts): def write_host(host, inventory, scheduleable=True): global CFG + facts = '' if host.ip: facts += ' openshift_ip={}'.format(host.ip) @@ -85,6 +77,16 @@ def write_host(host, inventory, scheduleable=True): # Technically only nodes will ever need this. if not scheduleable: facts += ' openshift_scheduleable=False' + installer_host = socket.gethostname() + if host.hostname == installer_host or host.public_hostname == installer_host: + facts += ' ansible_connection=local' + if os.geteuid() != 0: + no_pwd_sudo = subprocess.call(['sudo', '-v', '-n']) + if no_pwd_sudo == 1: + print 'The atomic-openshift-installer requires sudo access without a password.' + sys.exit(1) + facts += ' ansible_become=true' + inventory.write('{} {}\n'.format(host, facts)) -- cgit v1.2.3 From dcd2fb0558c58fb79f9e3dd9ecd5f6687d8bed5d Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Thu, 5 Nov 2015 09:47:50 -0500 Subject: Making it easier to use pre-release content --- utils/src/ooinstall/openshift_ansible.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'utils') diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index 4b37be278..0648df0fa 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -31,17 +31,18 @@ def generate_inventory(hosts): version=CFG.settings.get('variant_version', None))[1] base_inventory.write('deployment_type={}\n'.format(ver.ansible_key)) - if 'OO_INSTALL_DEVEL_REGISTRY' in os.environ: - base_inventory.write('oreg_url=rcm-img-docker01.build.eng.bos.redhat.com:' - '5001/openshift3/ose-${component}:${version}\n') - if 'OO_INSTALL_PUDDLE_REPO_ENABLE' in os.environ: - base_inventory.write("openshift_additional_repos=[{'id': 'ose-devel', " + if 'OO_INSTALL_ADDITIONAL_REGISTRIES' in os.environ: + base_inventory.write('cli_docker_additional_registries={}\n' + .format(os.environ['OO_INSTALL_ADDITIONAL_REGISTRIES'])) + if 'OO_INSTALL_INSECURE_REGISTRIES' in os.environ: + base_inventory.write('cli_docker_insecure_registries={}\n' + .format(os.environ['OO_INSTALL_INSECURE_REGISTRIES'])) + if 'OO_INSTALL_PUDDLE_REPO' in os.environ: + # We have to double the '{' here for literals + base_inventory.write("openshift_additional_repos=[{{'id': 'ose-devel', " "'name': 'ose-devel', " - "'baseurl': 'http://buildvm-devops.usersys.redhat.com" - "/puddle/build/AtomicOpenShift/3.1/latest/RH7-RHAOS-3.1/$basearch/os', " - "'enabled': 1, 'gpgcheck': 0}]\n") - if 'OO_INSTALL_STAGE_REGISTRY' in os.environ: - base_inventory.write('oreg_url=registry.access.stage.redhat.com/openshift3/ose-${component}:${version}\n') + "'baseurl': '{}', " + "'enabled': 1, 'gpgcheck': 0}}]\n".format(os.environ['OO_INSTALL_PUDDLE_REPO'])) base_inventory.write('\n[masters]\n') masters = (host for host in hosts if host.master) -- cgit v1.2.3 From ae7757195a4230b561b14353a7024d964b5d9664 Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Thu, 5 Nov 2015 12:49:42 -0500 Subject: atomic-openshift-installer's unattended mode wasn't work with --force for all cases --- utils/src/ooinstall/cli_installer.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index e4fda2813..f675efead 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -339,7 +339,10 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): # new nodes. elif host.node: click.echo("{} is already an OpenShift Node".format(host)) - hosts_to_run_on.remove(host) + # force is only used for reinstalls so we don't want to remove + # anything. + if not force: + hosts_to_run_on.remove(host) # for unattended either continue if they force install or exit if they didn't if unattended: if not force: -- cgit v1.2.3 From a552645b05d4af2180596fb01837d0f1062b3ac5 Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Thu, 5 Nov 2015 13:11:42 -0500 Subject: Bug 1278244 - Incorrect node information gathered by atomic-openshift-installer Previously the output was a little confusing. We didn't display anything about the uninstalled hosts. --- utils/src/ooinstall/cli_installer.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index f675efead..ff740e426 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -343,6 +343,8 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): # anything. if not force: hosts_to_run_on.remove(host) + for new_host in set(hosts_to_run_on) - set(installed_hosts): + click.echo("{} is currently uninstalled".format(new_host)) # for unattended either continue if they force install or exit if they didn't if unattended: if not force: -- cgit v1.2.3 From 837ea49bba342aa1fa87736947979ee5235da727 Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Thu, 5 Nov 2015 13:37:51 -0500 Subject: Bug 1278244 - Previously there was no way to add a node in unattended mode TODO: We desparately need tests cases for: - interactive with no config file - interactive with config file and all installed hosts - interactive with config file and no installed hosts - interactive with config file and some installed some uninstalled hosts - unattended with config file and all installed hosts (with and without --force) - unattended with config file and no installed hosts (with and without --force) - unattended with config file and some installed some uninstalled hosts (with and without --force) --- utils/src/ooinstall/cli_installer.py | 69 +++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 25 deletions(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index ff740e426..9bf3bc714 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -331,7 +331,22 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): # Check if master or nodes already have something installed installed_hosts = get_installed_hosts(oo_cfg.hosts, callback_facts) if len(installed_hosts) > 0: - # present a message listing already installed hosts + click.echo('Installed environment detected.') + # This check has to happen before we start removing hosts later in this method + if not force: + if not unattended: + click.echo('By default the installer only adds new nodes to an installed environment.') + response = click.prompt('Do you want to (1) only add additional nodes or ' \ + '(2) perform a clean install?', type=int) + # TODO: this should be reworked with error handling. + # Click can certainly do this for us. + # This should be refactored as soon as we add a 3rd option. + if response == 1: + force = False + if response == 2: + force = True + + # present a message listing already installed hosts and remove hosts if needed for host in installed_hosts: if host.master: click.echo("{} is already an OpenShift Master".format(host)) @@ -343,33 +358,37 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): # anything. if not force: hosts_to_run_on.remove(host) - for new_host in set(hosts_to_run_on) - set(installed_hosts): - click.echo("{} is currently uninstalled".format(new_host)) - # for unattended either continue if they force install or exit if they didn't - if unattended: - if not force: - click.echo('Installed environment detected and no additional nodes specified: ' \ - 'aborting. If you want a fresh install, use --force') - sys.exit(1) - # for attended ask the user what to do + + # Handle the cases where we know about uninstalled systems + new_hosts = set(hosts_to_run_on) - set(installed_hosts) + if len(new_hosts) > 0: + for new_host in new_hosts: + click.echo("{} is currently uninstalled".format(new_host)) + + # Fall through + click.echo('Adding additional nodes...') else: - click.echo('Installed environment detected and no additional nodes specified. ') - response = click.prompt('Do you want to (1) add more nodes or ' \ - '(2) perform a clean install?', type=int) - if response == 1: # add more nodes - new_nodes = collect_new_nodes() - - hosts_to_run_on.extend(new_nodes) - oo_cfg.hosts.extend(new_nodes) - - 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'])) + if unattended: + if not force: + click.echo('Installed environment detected and no additional nodes specified: ' \ + 'aborting. If you want a fresh install, use --force') sys.exit(1) else: - pass # proceeding as normal should do a clean install + if not force: + new_nodes = collect_new_nodes() + + hosts_to_run_on.extend(new_nodes) + oo_cfg.hosts.extend(new_nodes) + + openshift_ansible.set_config(oo_cfg) + click.echo('Gathering information from hosts...') + 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'])) + sys.exit(1) + else: + pass # proceeding as normal should do a clean install return hosts_to_run_on, callback_facts -- cgit v1.2.3 From a2d19f85a1e501cf7be64236b851eda898f3f51b Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Thu, 5 Nov 2015 15:33:33 -0500 Subject: Bug 1278243 - Confusing prompt from atomic-openshift-installer --- utils/src/ooinstall/cli_installer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 9bf3bc714..8bee99f90 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -371,7 +371,8 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): if unattended: if not force: click.echo('Installed environment detected and no additional nodes specified: ' \ - 'aborting. If you want a fresh install, use --force') + 'aborting. If you want a fresh install, use ' \ + '`atomic-openshift-installer install --force`') sys.exit(1) else: if not force: -- cgit v1.2.3 From fe4e9a4ca7028aa877fdd3895225a67b026aea11 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Thu, 5 Nov 2015 08:35:53 -0400 Subject: Upgrade improvements - Push config dir logic out of module and use host variables instead. - Backup master config with ansible utility. - Add error handling for the upgrade config module. - Add verbose option to installer. - Return details on what we changed when upgrading config. - Cleanup use of first master. - Don't install upgrade rpms to check what version we'll upgrade to. --- .../upgrades/library/openshift_upgrade_config.py | 53 +++++++-------- playbooks/adhoc/upgrades/upgrade.yml | 78 +++++++++------------- utils/src/ooinstall/cli_installer.py | 22 ++++-- utils/src/ooinstall/openshift_ansible.py | 41 ++++++------ 4 files changed, 93 insertions(+), 101 deletions(-) (limited to 'utils') diff --git a/playbooks/adhoc/upgrades/library/openshift_upgrade_config.py b/playbooks/adhoc/upgrades/library/openshift_upgrade_config.py index 60f4fd8b8..0894efa52 100755 --- a/playbooks/adhoc/upgrades/library/openshift_upgrade_config.py +++ b/playbooks/adhoc/upgrades/library/openshift_upgrade_config.py @@ -5,11 +5,8 @@ """Ansible module for modifying OpenShift configs during an upgrade""" import os -import shutil import yaml -from datetime import datetime - DOCUMENTATION = ''' --- module: openshift_upgrade_config @@ -20,21 +17,14 @@ requirements: [ ] EXAMPLES = ''' ''' -def get_cfg_dir(): - """Return the correct config directory to use.""" - cfg_path = '/etc/origin/' - if not os.path.exists(cfg_path): - cfg_path = '/etc/openshift/' - return cfg_path - -def upgrade_master_3_0_to_3_1(backup): +def upgrade_master_3_0_to_3_1(module, config_base, backup): """Main upgrade method for 3.0 to 3.1.""" - changed = False + changes = [] # Facts do not get transferred to the hosts where custom modules run, # need to make some assumptions here. - master_config = os.path.join(get_cfg_dir(), 'master/master-config.yaml') + master_config = os.path.join(config_base, 'master/master-config.yaml') master_cfg_file = open(master_config, 'r') config = yaml.safe_load(master_cfg_file.read()) @@ -45,6 +35,7 @@ def upgrade_master_3_0_to_3_1(backup): 'v1beta3' in config['apiLevels']: config['apiLevels'].remove('v1beta3') changed = True + changes.append("master-config.yaml: removed v1beta3 from apiLevels") if 'apiLevels' in config['kubernetesMasterConfig'] and \ 'v1beta3' in config['kubernetesMasterConfig']['apiLevels']: config['kubernetesMasterConfig']['apiLevels'].remove('v1beta3') @@ -57,27 +48,26 @@ def upgrade_master_3_0_to_3_1(backup): # 'certFile': 'master.proxy-client.crt', # 'keyFile': 'master.proxy-client.key' # } +# changes.append("master-config.yaml: added proxyClientInfo") - if changed: + if len(changes) > 0: if backup: - timestamp = datetime.now().strftime('%Y%m%d%H%M%S') - basedir = os.path.split(master_config)[0] - backup_file = os.path.join(basedir, 'master-config.yaml.bak-%s' - % timestamp) - shutil.copyfile(master_config, backup_file) + # TODO: Check success: + module.backup_local(master_config) + # Write the modified config: out_file = open(master_config, 'w') out_file.write(yaml.safe_dump(config, default_flow_style=False)) out_file.close() - return changed + return changes -def upgrade_master(from_version, to_version, backup): +def upgrade_master(module, config_base, from_version, to_version, backup): """Upgrade entry point.""" if from_version == '3.0': if to_version == '3.1': - return upgrade_master_3_0_to_3_1(backup) + return upgrade_master_3_0_to_3_1(module, config_base, backup) def main(): @@ -89,6 +79,7 @@ def main(): module = AnsibleModule( argument_spec=dict( + config_base=dict(required=True), from_version=dict(required=True, choices=['3.0']), to_version=dict(required=True, choices=['3.1']), role=dict(required=True, choices=['master']), @@ -101,12 +92,18 @@ def main(): to_version = module.params['to_version'] role = module.params['role'] backup = module.params['backup'] - - changed = False - if role == 'master': - changed = upgrade_master(from_version, to_version, backup) - - return module.exit_json(changed=changed) + config_base = module.params['config_base'] + + try: + changes = [] + if role == 'master': + changes = upgrade_master(module, config_base, from_version, + to_version, backup) + + changed = len(changes) > 0 + return module.exit_json(changed=changed, changes=changes) + except Exception, e: + return module.fail_json(msg=str(e)) # ignore pylint errors related to the module_utils import # pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import diff --git a/playbooks/adhoc/upgrades/upgrade.yml b/playbooks/adhoc/upgrades/upgrade.yml index 09f991b1d..c113c7ab2 100644 --- a/playbooks/adhoc/upgrades/upgrade.yml +++ b/playbooks/adhoc/upgrades/upgrade.yml @@ -1,4 +1,12 @@ --- +- name: Verify upgrade can proceed + hosts: masters + tasks: + # Checking the global deployment type rather than host facts, this is about + # what the user is requesting. + - fail: msg="Deployment type enterprise not supported for upgrade" + when: deployment_type == "enterprise" + - name: Update deployment type hosts: OSEv3 roles: @@ -9,14 +17,6 @@ local_facts: deployment_type: "{{ deployment_type }}" -- name: Verify upgrade can proceed - hosts: masters - tasks: - # Checking the global deployment type rather than host facts, this is about - # what the user is requesting. - - fail: msg="Deployment type enterprise not supported for upgrade" - when: deployment_type == "enterprise" - - name: Backup etcd hosts: masters vars: @@ -52,48 +52,35 @@ - name: Display location of etcd backup debug: msg="Etcd backup created in {{ openshift.common.data_dir }}/etcd-backup-{{ timestamp }}" -- name: Upgrade base package on masters - hosts: masters - roles: - - openshift_facts - vars: - openshift_version: "{{ openshift_pkg_version | default('') }}" - tasks: - - name: Upgrade base package - yum: pkg={{ openshift.common.service_type }}{{ openshift_version }} state=latest - -- name: Evaluate oo_first_master - hosts: localhost - vars: - g_masters_group: "{{ 'masters' }}" - tasks: - - name: Evaluate oo_first_master - add_host: - name: "{{ groups[g_masters_group][0] }}" - groups: oo_first_master - ansible_ssh_user: "{{ g_ssh_user | default(omit) }}" - ansible_sudo: "{{ g_sudo | default(omit) }}" - when: g_masters_group in groups and (groups[g_masters_group] | length) > 0 - -# TODO: ideally we would check the new version, without installing it. (some -# kind of yum repoquery? would need to handle openshift -> atomic-openshift -# package rename) - name: Perform upgrade version checking - hosts: oo_first_master + hosts: masters[0] tasks: - - name: Determine new version + - name: Determine available version + shell: > + yum list available {{ openshift.common.service_type }} | tail -n 1 | cut -f 2 -d " " | cut -f 1 -d "-" + register: _new_version + - debug: var=_new_version + # The above check will return nothing if the package is already installed, + # and we may be re-running upgrade due to a failure. + - name: Determine installed version command: > rpm -q --queryformat '%{version}' {{ openshift.common.service_type }} register: _new_version + when: _new_version.stdout == "" + # Fail if we still don't know: + - debug: var=_new_version + - name: Verify upgrade version + fail: Unable to determine upgrade version for {{ openshift.common.service_type }} + when: _new_version.stdout == "" - name: Ensure AOS 3.0.2 or Origin 1.0.6 - hosts: oo_first_master + hosts: masters[0] tasks: fail: This playbook requires Origin 1.0.6 or Atomic OpenShift 3.0.2 or later when: _new_version.stdout | version_compare('1.0.6','<') or ( _new_version.stdout | version_compare('3.0','>=' and _new_version.stdout | version_compare('3.0.2','<') ) - name: Verify upgrade can proceed - hosts: oo_first_master + hosts: masters[0] tasks: # Checking the global deployment type rather than host facts, this is about # what the user is requesting. @@ -107,13 +94,10 @@ tasks: - name: Upgrade to latest available kernel yum: pkg=kernel state=latest - - name: display just the deployment_type variable for the current host - debug: - var: hostvars[inventory_hostname] - name: Upgrade master packages command: yum update -y {{ openshift.common.service_type }}-master{{ openshift_version }} - name: Upgrade master configuration. - openshift_upgrade_config: from_version=3.0 to_version=3.1 role=master + openshift_upgrade_config: from_version=3.0 to_version=3.1 role=master config_base={{ hostvars[inventory_hostname].openshift.common.config_base }} - name: Restart master services service: name="{{ openshift.common.service_type}}-master" state=restarted @@ -130,7 +114,7 @@ service: name="{{ openshift.common.service_type }}-node" state=restarted - name: Update cluster policy - hosts: oo_first_master + hosts: masters[0] tasks: - name: oadm policy reconcile-cluster-roles --confirm command: > @@ -138,7 +122,7 @@ policy reconcile-cluster-roles --confirm - name: Update cluster policy bindings - hosts: oo_first_master + hosts: masters[0] tasks: - name: oadm policy reconcile-cluster-role-bindings --confirm command: > @@ -151,7 +135,7 @@ when: ( _new_version.stdout | version_compare('1.0.6', '>') and _new_version.stdout | version_compare('3.0','<') ) or _new_version.stdout | version_compare('3.0.2','>') - name: Upgrade default router - hosts: oo_first_master + hosts: masters[0] vars: - router_image: "{{ openshift.master.registry_url | replace( '${component}', 'haproxy-router' ) | replace ( '${version}', 'v' + _new_version.stdout ) }}" - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" @@ -189,7 +173,7 @@ '{"spec":{"template":{"spec":{"containers":[{"name":"router","image":"{{ router_image }}"}]}}}}' - name: Upgrade default - hosts: oo_first_master + hosts: masters[0] vars: - registry_image: "{{ openshift.master.registry_url | replace( '${component}', 'docker-registry' ) | replace ( '${version}', 'v' + _new_version.stdout ) }}" - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" @@ -207,7 +191,7 @@ '{"spec":{"template":{"spec":{"containers":[{"name":"registry","image":"{{ registry_image }}"}]}}}}' - name: Update image streams and templates - hosts: oo_first_master + hosts: masters[0] vars: openshift_examples_import_command: "update" openshift_deployment_type: "{{ deployment_type }}" diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 8bee99f90..9f0861b77 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -323,7 +323,7 @@ def get_installed_hosts(hosts, callback_facts): installed_hosts.append(host) return installed_hosts -def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): +def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force, verbose): # Copy the list of existing hosts so we can remove any already installed nodes. hosts_to_run_on = list(oo_cfg.hosts) @@ -424,9 +424,11 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force): writable=True, readable=True), default="/tmp/ansible.log") +@click.option('-v', '--verbose', + is_flag=True, default=False) #pylint: disable=too-many-arguments # Main CLI entrypoint, not much we can do about too many arguments. -def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_config, ansible_log_path): +def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_config, ansible_log_path, verbose): """ The main click CLI module. Responsible for handling most common CLI options, assigning any defaults and adding to the context for the sub-commands. @@ -436,6 +438,7 @@ def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_conf ctx.obj['configuration'] = configuration ctx.obj['ansible_config'] = ansible_config ctx.obj['ansible_log_path'] = ansible_log_path + ctx.obj['verbose'] = verbose oo_cfg = OOConfig(ctx.obj['configuration']) @@ -466,6 +469,7 @@ def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_conf @click.pass_context def uninstall(ctx): oo_cfg = ctx.obj['oo_cfg'] + verbose = ctx.obj['verbose'] if len(oo_cfg.hosts) == 0: click.echo("No hosts defined in: %s" % oo_cfg['configuration']) @@ -481,13 +485,14 @@ def uninstall(ctx): click.echo("Uninstall cancelled.") sys.exit(0) - openshift_ansible.run_uninstall_playbook() + openshift_ansible.run_uninstall_playbook(verbose) @click.command() @click.pass_context def upgrade(ctx): oo_cfg = ctx.obj['oo_cfg'] + verbose = ctx.obj['verbose'] if len(oo_cfg.hosts) == 0: click.echo("No hosts defined in: %s" % oo_cfg['configuration']) @@ -514,7 +519,7 @@ def upgrade(ctx): click.echo("Upgrade cancelled.") sys.exit(0) - retcode = openshift_ansible.run_upgrade_playbook() + retcode = openshift_ansible.run_upgrade_playbook(verbose) if retcode > 0: click.echo("Errors encountered during upgrade, please check %s." % oo_cfg.settings['ansible_log_path']) @@ -527,6 +532,7 @@ def upgrade(ctx): @click.pass_context def install(ctx, force): oo_cfg = ctx.obj['oo_cfg'] + verbose = ctx.obj['verbose'] if ctx.obj['unattended']: error_if_missing_info(oo_cfg) @@ -534,13 +540,15 @@ def install(ctx, force): oo_cfg = get_missing_info_from_user(oo_cfg) click.echo('Gathering information from hosts...') - callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts) + callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts, + verbose) 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, ctx.obj['unattended'], force) + hosts_to_run_on, callback_facts = get_hosts_to_run_on( + oo_cfg, callback_facts, ctx.obj['unattended'], force, verbose) click.echo('Writing config to: %s' % oo_cfg.config_path) @@ -562,7 +570,7 @@ If changes are needed to the values recorded by the installer please update {}. confirm_continue(message) error = openshift_ansible.run_main_playbook(oo_cfg.hosts, - hosts_to_run_on) + hosts_to_run_on, verbose) if error: # The bootstrap script will print out the log location. message = """ diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index 0648df0fa..153415e8c 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -91,16 +91,17 @@ def write_host(host, inventory, scheduleable=True): inventory.write('{} {}\n'.format(host, facts)) -def load_system_facts(inventory_file, os_facts_path, env_vars): +def load_system_facts(inventory_file, os_facts_path, env_vars, verbose=False): """ Retrieves system facts from the remote systems. """ FNULL = open(os.devnull, 'w') - status = subprocess.call(['ansible-playbook', - '--inventory-file={}'.format(inventory_file), - os_facts_path], - env=env_vars, - stdout=FNULL) + args = ['ansible-playbook', '-v'] if verbose \ + else ['ansible-playbook'] + args.extend([ + '--inventory-file={}'.format(inventory_file), + os_facts_path]) + status = subprocess.call(args, env=env_vars, stdout=FNULL) if not status == 0: return [], 1 callback_facts_file = open(CFG.settings['ansible_callback_facts_yaml'], 'r') @@ -109,7 +110,7 @@ def load_system_facts(inventory_file, os_facts_path, env_vars): return callback_facts, 0 -def default_facts(hosts): +def default_facts(hosts, verbose=False): global CFG inventory_file = generate_inventory(hosts) os_facts_path = '{}/playbooks/byo/openshift_facts.yml'.format(CFG.ansible_playbook_directory) @@ -121,10 +122,10 @@ def default_facts(hosts): 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 load_system_facts(inventory_file, os_facts_path, facts_env) + return load_system_facts(inventory_file, os_facts_path, facts_env, verbose) -def run_main_playbook(hosts, hosts_to_run_on): +def run_main_playbook(hosts, hosts_to_run_on, verbose=False): global CFG inventory_file = generate_inventory(hosts) if len(hosts_to_run_on) != len(hosts): @@ -138,17 +139,19 @@ def run_main_playbook(hosts, hosts_to_run_on): 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(main_playbook_path, inventory_file, facts_env) + return run_ansible(main_playbook_path, inventory_file, facts_env, verbose) -def run_ansible(playbook, inventory, env_vars): - return subprocess.call(['ansible-playbook', - '--inventory-file={}'.format(inventory), - playbook], - env=env_vars) +def run_ansible(playbook, inventory, env_vars, verbose=False): + args = ['ansible-playbook', '-v'] if verbose \ + else ['ansible-playbook'] + args.extend([ + '--inventory-file={}'.format(inventory), + playbook]) + return subprocess.call(args, env=env_vars) -def run_uninstall_playbook(): +def run_uninstall_playbook(verbose=False): playbook = os.path.join(CFG.settings['ansible_playbook_directory'], 'playbooks/adhoc/uninstall.yml') inventory_file = generate_inventory(CFG.hosts) @@ -157,10 +160,10 @@ def run_uninstall_playbook(): 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) + return run_ansible(playbook, inventory_file, facts_env, verbose) -def run_upgrade_playbook(): +def run_upgrade_playbook(verbose=False): playbook = os.path.join(CFG.settings['ansible_playbook_directory'], 'playbooks/adhoc/upgrades/upgrade.yml') # TODO: Upgrade inventory for upgrade? @@ -170,5 +173,5 @@ def run_upgrade_playbook(): 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) + return run_ansible(playbook, inventory_file, facts_env, verbose) -- cgit v1.2.3 From 98b69946496d0b214c5bd0d384e1cea0856c4cbb Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Fri, 6 Nov 2015 11:43:25 -0400 Subject: Fix pylint errors with getting hosts to run on. --- utils/src/ooinstall/cli_installer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 9f0861b77..e63f14816 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -323,6 +323,8 @@ def get_installed_hosts(hosts, callback_facts): installed_hosts.append(host) return installed_hosts +# pylint: disable=too-many-branches +# This pylint error will be corrected shortly in separate PR. def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force, verbose): # Copy the list of existing hosts so we can remove any already installed nodes. @@ -383,7 +385,7 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force, verbose): openshift_ansible.set_config(oo_cfg) click.echo('Gathering information from hosts...') - callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts) + callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts, verbose) if error: click.echo("There was a problem fetching the required information. " \ "See {} for details.".format(oo_cfg.settings['ansible_log_path'])) -- cgit v1.2.3 From 6955b11fbed1f3d73d814d610b4a6905331406e8 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Fri, 6 Nov 2015 11:52:56 -0400 Subject: Write new config to disk after successful upgrade. --- utils/src/ooinstall/cli_installer.py | 1 + 1 file changed, 1 insertion(+) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index e63f14816..0d65f2053 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -526,6 +526,7 @@ def upgrade(ctx): click.echo("Errors encountered during upgrade, please check %s." % oo_cfg.settings['ansible_log_path']) else: + oo_cfg.save_to_disk() click.echo("Upgrade completed! Rebooting all hosts is recommended.") -- cgit v1.2.3 From eb136c6d84c762a2692ef62f0e15d4b98c723edf Mon Sep 17 00:00:00 2001 From: Samuel Munilla Date: Thu, 5 Nov 2015 13:28:24 -0500 Subject: atomic-openshift-installer: Better specification of ansible connection point Changes to installer.cfg.yaml to allow for better defaults in unattended mode. Update example in the docs. --- utils/docs/config.md | 3 +++ utils/src/ooinstall/cli_installer.py | 38 ++++++++++++++------------------ utils/src/ooinstall/oo_config.py | 22 ++++++++---------- utils/src/ooinstall/openshift_ansible.py | 2 +- 4 files changed, 29 insertions(+), 36 deletions(-) (limited to 'utils') diff --git a/utils/docs/config.md b/utils/docs/config.md index ee4b157c9..2729f8d37 100644 --- a/utils/docs/config.md +++ b/utils/docs/config.md @@ -19,16 +19,19 @@ hosts: master: true node: true containerized: true + connect_to: 24.222.0.1 - ip: 10.0.0.2 hostname: node1-private.example.com public_ip: 24.222.0.2 public_hostname: node1.example.com node: true + connect_to: 10.0.0.2 - ip: 10.0.0.3 hostname: node2-private.example.com public_ip: 24.222.0.3 public_hostname: node2.example.com node: true + connect_to: 10.0.0.3 ``` ## Primary Settings diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 8bee99f90..8c2421183 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -101,18 +101,13 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen hosts = [] more_hosts = True - ip_regex = re.compile(r'^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}$') - while more_hosts: host_props = {} hostname_or_ip = click.prompt('Enter hostname or IP address:', default='', value_proc=validate_prompt_hostname) - if ip_regex.match(hostname_or_ip): - host_props['ip'] = hostname_or_ip - else: - host_props['hostname'] = hostname_or_ip + host_props['connect_to'] = hostname_or_ip host_props['master'] = click.confirm('Will this host be an OpenShift Master?') host_props['node'] = True @@ -150,7 +145,7 @@ Plese confirm that they are correct before moving forward. notes = """ Format: -IP,public IP,hostname,public hostname +connect_to,IP,public IP,hostname,public hostname Notes: * The installation host is the hostname from the installer's perspective. @@ -168,16 +163,15 @@ Notes: default_facts_lines = [] default_facts = {} - validated_facts = {} for h in hosts: - default_facts[h] = {} - h.ip = callback_facts[str(h)]["common"]["ip"] - h.public_ip = callback_facts[str(h)]["common"]["public_ip"] - h.hostname = callback_facts[str(h)]["common"]["hostname"] - h.public_hostname = callback_facts[str(h)]["common"]["public_hostname"] - - validated_facts[h] = {} - default_facts_lines.append(",".join([h.ip, + default_facts[h.connect_to] = {} + h.ip = callback_facts[h.connect_to]["common"]["ip"] + h.public_ip = callback_facts[h.connect_to]["common"]["public_ip"] + h.hostname = callback_facts[h.connect_to]["common"]["hostname"] + h.public_hostname = callback_facts[h.connect_to]["common"]["public_hostname"] + + default_facts_lines.append(",".join([h.connect_to, + h.ip, h.public_ip, h.hostname, h.public_hostname])) @@ -316,10 +310,10 @@ Add new nodes here def get_installed_hosts(hosts, callback_facts): installed_hosts = [] for host in hosts: - if(host.name in callback_facts.keys() - and 'common' in callback_facts[host.name].keys() - and callback_facts[host.name]['common'].get('version', '') - and callback_facts[host.name]['common'].get('version', '') != 'None'): + if(host.connect_to in callback_facts.keys() + and 'common' in callback_facts[host.connect_to].keys() + and callback_facts[host.connect_to]['common'].get('version', '') + and callback_facts[host.connect_to]['common'].get('version', '') != 'None'): installed_hosts.append(host) return installed_hosts @@ -475,7 +469,7 @@ def uninstall(ctx): if not ctx.obj['unattended']: # Prompt interactively to confirm: for host in oo_cfg.hosts: - click.echo(" * %s" % host.name) + click.echo(" * %s" % host.connect_to) proceed = click.confirm("\nDo you wish to proceed?") if not proceed: click.echo("Uninstall cancelled.") @@ -505,7 +499,7 @@ def upgrade(ctx): old_variant, old_version, oo_cfg.settings['variant'], oo_cfg.settings['variant_version'])) for host in oo_cfg.hosts: - click.echo(" * %s" % host.name) + click.echo(" * %s" % host.connect_to) if not ctx.obj['unattended']: # Prompt interactively to confirm: diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py index 4281947f1..f35a8f51b 100644 --- a/utils/src/ooinstall/oo_config.py +++ b/utils/src/ooinstall/oo_config.py @@ -35,6 +35,7 @@ class Host(object): self.hostname = kwargs.get('hostname', None) self.public_ip = kwargs.get('public_ip', None) self.public_hostname = kwargs.get('public_hostname', None) + self.connect_to = kwargs.get('connect_to', None) # Should this host run as an OpenShift master: self.master = kwargs.get('master', False) @@ -43,30 +44,25 @@ class Host(object): self.node = kwargs.get('node', False) self.containerized = kwargs.get('containerized', False) - if self.ip is None and self.hostname is None: - raise OOConfigInvalidHostError("You must specify either 'ip' or 'hostname'") + if self.connect_to is None: + raise OOConfigInvalidHostError("You must specify either and 'ip' " \ + "or 'hostname' to connect to.") if self.master is False and self.node is False: raise OOConfigInvalidHostError( "You must specify each host as either a master or a node.") - # Hosts can be specified with an ip, hostname, or both. However we need - # something authoritative we can connect to and refer to the host by. - # Preference given to the IP if specified as this is more specific. - # We know one must be set by this point. - self.name = self.ip if self.ip is not None else self.hostname - def __str__(self): - return self.name + return self.connect_to def __repr__(self): - return self.name + return self.connect_to def to_dict(self): """ Used when exporting to yaml. """ d = {} for prop in ['ip', 'hostname', 'public_ip', 'public_hostname', - 'master', 'node', 'containerized']: + 'master', 'node', 'containerized', 'connect_to']: # If the property is defined (not None or False), export it: if getattr(self, prop): d[prop] = getattr(self, prop) @@ -182,7 +178,7 @@ class OOConfig(object): if not getattr(host, required_fact): missing_facts.append(required_fact) if len(missing_facts) > 0: - result[host.name] = missing_facts + result[host.connect_to] = missing_facts return result def save_to_disk(self): @@ -214,6 +210,6 @@ class OOConfig(object): def get_host(self, name): for host in self.hosts: - if host.name == name: + if host.connect_to == name: return host return None diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index 0648df0fa..d2399df5c 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -88,7 +88,7 @@ def write_host(host, inventory, scheduleable=True): sys.exit(1) facts += ' ansible_become=true' - inventory.write('{} {}\n'.format(host, facts)) + inventory.write('{} {}\n'.format(host.connect_to, facts)) def load_system_facts(inventory_file, os_facts_path, env_vars): -- cgit v1.2.3 From 0ab85bfb33a141d5b23ae85fd495cf7b487f99d4 Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Fri, 6 Nov 2015 15:47:46 -0500 Subject: Updating the atomic-openshift-isntaller local connection logic for the connect_to addition. --- utils/src/ooinstall/openshift_ansible.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index d2399df5c..0b2000a0a 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -79,7 +79,7 @@ def write_host(host, inventory, scheduleable=True): if not scheduleable: facts += ' openshift_scheduleable=False' installer_host = socket.gethostname() - if host.hostname == installer_host or host.public_hostname == installer_host: + if installer_host in [host.connect_to, host.hostname, host.public_hostname]: facts += ' ansible_connection=local' if os.geteuid() != 0: no_pwd_sudo = subprocess.call(['sudo', '-v', '-n']) -- cgit v1.2.3 From 96464d04a5b88e7fb090b286b10838a183a2758a Mon Sep 17 00:00:00 2001 From: Brenton Leanhardt Date: Mon, 9 Nov 2015 10:38:07 -0500 Subject: Various fixes related to connect_to There the tests didn't know anything about connect_to and we had a case where we weren't handling the migration from the 3.0 installer config format to 3.1 --- utils/src/ooinstall/oo_config.py | 1 + utils/test/cli_installer_tests.py | 9 ++++++--- utils/test/oo_config_tests.py | 22 ++++++++++++++-------- 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'utils') diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py index f35a8f51b..cf51bb404 100644 --- a/utils/src/ooinstall/oo_config.py +++ b/utils/src/ooinstall/oo_config.py @@ -118,6 +118,7 @@ class OOConfig(object): new_hosts = [] if 'validated_facts' in self.settings: for key, value in self.settings['validated_facts'].iteritems(): + value['connect_to'] = key 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']: diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py index b183f0acb..fcefcdff3 100644 --- a/utils/test/cli_installer_tests.py +++ b/utils/test/cli_installer_tests.py @@ -46,18 +46,21 @@ SAMPLE_CONFIG = """ variant: %s ansible_ssh_user: root hosts: - - ip: 10.0.0.1 + - connect_to: master-private.example.com + 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 + - connect_to: node1-private.example.com + 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 + - connect_to: node2-private.example.com + ip: 10.0.0.3 hostname: node2-private.example.com public_ip: 24.222.0.3 public_hostname: node2.example.com diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py index 6dc335a0e..0dd4a30e9 100644 --- a/utils/test/oo_config_tests.py +++ b/utils/test/oo_config_tests.py @@ -14,18 +14,21 @@ SAMPLE_CONFIG = """ variant: openshift-enterprise ansible_ssh_user: root hosts: - - ip: 10.0.0.1 + - connect_to: master-private.example.com + 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 + - connect_to: node1-private.example.com + 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 + - connect_to: node2-private.example.com + ip: 10.0.0.3 hostname: node2-private.example.com public_ip: 24.222.0.3 public_hostname: node2.example.com @@ -54,16 +57,19 @@ validated_facts: CONFIG_INCOMPLETE_FACTS = """ hosts: - - ip: 10.0.0.1 + - connect_to: 10.0.0.1 + 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 + - connect_to: 10.0.0.2 + ip: 10.0.0.2 + hostname: 24.222.0.2 public_ip: 24.222.0.2 node: true - - ip: 10.0.0.3 + - connect_to: 10.0.0.3 + ip: 10.0.0.3 node: true """ @@ -145,7 +151,7 @@ class OOConfigTests(OOInstallFixture): ooconfig = OOConfig(cfg_path) self.assertEquals(3, len(ooconfig.hosts)) - self.assertEquals("10.0.0.1", ooconfig.hosts[0].name) + self.assertEquals("master-private.example.com", ooconfig.hosts[0].connect_to) self.assertEquals("10.0.0.1", ooconfig.hosts[0].ip) self.assertEquals("master-private.example.com", ooconfig.hosts[0].hostname) -- cgit v1.2.3 From e109335a205a31a96611a5206947aa090a963241 Mon Sep 17 00:00:00 2001 From: Samuel Munilla Date: Mon, 9 Nov 2015 10:25:12 -0500 Subject: atomic-openshift-installer: Generate inventory off hosts_to_run_on This generates the ansible inventory based on the pruned list of non-installed hosts we've created rather than the full host list provided in installer.cfg.yaml --- utils/src/ooinstall/openshift_ansible.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'utils') diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index bac4951d5..489a0f7c1 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -127,7 +127,7 @@ def default_facts(hosts, verbose=False): def run_main_playbook(hosts, hosts_to_run_on, verbose=False): global CFG - inventory_file = generate_inventory(hosts) + inventory_file = generate_inventory(hosts_to_run_on) if len(hosts_to_run_on) != len(hosts): main_playbook_path = os.path.join(CFG.ansible_playbook_directory, 'playbooks/common/openshift-cluster/scaleup.yml') -- cgit v1.2.3 From c2f3f81d926aacbd1fe973c36931dc5ad2ebe7c5 Mon Sep 17 00:00:00 2001 From: Devan Goodwin Date: Tue, 10 Nov 2015 08:20:24 -0400 Subject: Package the default ansible.cfg with atomic-openshift-utils. If this file exists on disk, the installer will use it if the user didn't specify an ansible config file on the CLI. Rename share directory to match the rpm name. (utils vs util) --- openshift-ansible.spec | 3 +++ utils/src/ooinstall/cli_installer.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'utils') diff --git a/openshift-ansible.spec b/openshift-ansible.spec index 10a53d921..646352961 100644 --- a/openshift-ansible.spec +++ b/openshift-ansible.spec @@ -82,6 +82,8 @@ pushd utils %{__python} setup.py install --skip-build --root %{buildroot} # Remove this line once the name change has happened mv -f %{buildroot}%{_bindir}/oo-install %{buildroot}%{_bindir}/atomic-openshift-installer +mkdir -p %{buildroot}%{_datadir}/atomic-openshift-utils/ +cp etc/ansible.cfg %{buildroot}%{_datadir}/atomic-openshift-utils/ansible.cfg popd # Base openshift-ansible files @@ -252,6 +254,7 @@ Atomic OpenShift Utilities includes %files -n atomic-openshift-utils %{python_sitelib}/ooinstall* %{_bindir}/atomic-openshift-installer +%{_datadir}/atomic-openshift-utils/ansible.cfg %changelog diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index a40ff5cfc..08c2439f7 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -11,7 +11,7 @@ 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_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-utils/ansible.cfg' DEFAULT_PLAYBOOK_DIR = '/usr/share/ansible/openshift-ansible/' def validate_ansible_dir(path): -- cgit v1.2.3 From 1e28190e374aac4677394bc9b8f3e8428b15dc5a Mon Sep 17 00:00:00 2001 From: Samuel Munilla Date: Tue, 10 Nov 2015 13:35:13 -0500 Subject: atomic-openshift-installer: Remove question for container install Removing the option for a container-based install from the quick installer with it is in tech preview. --- utils/src/ooinstall/cli_installer.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'utils') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index a40ff5cfc..3322a1e62 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -112,13 +112,15 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen host_props['master'] = click.confirm('Will this host be an OpenShift Master?') host_props['node'] = True - rpm_or_container = click.prompt('Will this host be RPM or Container based (rpm/container)?', - type=click.Choice(['rpm', 'container']), - default='rpm') - if rpm_or_container == 'container': - host_props['containerized'] = True - else: - host_props['containerized'] = False + #TODO: Reenable this option once container installs are out of tech preview + #rpm_or_container = click.prompt('Will this host be RPM or Container based (rpm/container)?', + # type=click.Choice(['rpm', 'container']), + # default='rpm') + #if rpm_or_container == 'container': + # host_props['containerized'] = True + #else: + # host_props['containerized'] = False + host_props['containerized'] = False host = Host(**host_props) -- cgit v1.2.3 From 7f4cafed723058ab7e79d11a826fca031d1d2aae Mon Sep 17 00:00:00 2001 From: Samuel Munilla Date: Tue, 10 Nov 2015 13:58:24 -0500 Subject: Update tests now that cli is not asking for rpm/container install --- utils/test/cli_installer_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'utils') diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py index fcefcdff3..d58539b18 100644 --- a/utils/test/cli_installer_tests.py +++ b/utils/test/cli_installer_tests.py @@ -332,7 +332,7 @@ class AttendedCliTests(OOCliFixture): for (host, is_master) in hosts: inputs.append(host) inputs.append('y' if is_master else 'n') - inputs.append('rpm') + #inputs.append('rpm') if i < len(hosts) - 1: inputs.append('y') # Add more hosts else: @@ -349,7 +349,7 @@ class AttendedCliTests(OOCliFixture): for (host, is_master) in add_nodes: inputs.append(host) inputs.append('y' if is_master else 'n') - inputs.append('rpm') + #inputs.append('rpm') if i < len(add_nodes) - 1: inputs.append('y') # Add more hosts else: -- cgit v1.2.3 From 4c1b0dd4ab8f3a5d4fcfa4ba1501ed374793e77a Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Fri, 6 Nov 2015 16:56:37 -0500 Subject: Refactor upgrade playbook(s) - Split playbooks into two, one for 3.0 minor upgrades and one for 3.0 to 3.1 upgrades - Move upgrade playbooks to common/openshift/cluster/upgrades from adhoc - Added a byo wrapper playbooks to set the groups based on the byo conventions, other providers will need similar playbooks added eventually - installer wrapper updates for refactored upgrade playbooks - call new 3.0 to 3.1 upgrade playbook - various fixes for edge cases I hit with a really old config laying around. - fix output of host facts to show connect_to value. --- playbooks/adhoc/upgrades/README.md | 21 -- playbooks/adhoc/upgrades/files/pre-upgrade-check | 188 ---------- playbooks/adhoc/upgrades/files/versions.sh | 10 - playbooks/adhoc/upgrades/filter_plugins | 1 - .../upgrades/library/openshift_upgrade_config.py | 154 -------- playbooks/adhoc/upgrades/lookup_plugins | 1 - playbooks/adhoc/upgrades/roles | 1 - playbooks/adhoc/upgrades/upgrade.yml | 407 --------------------- playbooks/byo/openshift-cluster/upgrades/README.md | 8 + .../upgrades/v3_0_minor/README.md | 21 ++ .../upgrades/v3_0_minor/upgrade.yml | 9 + .../upgrades/v3_0_to_v3_1/README.md | 17 + .../upgrades/v3_0_to_v3_1/upgrade.yml | 9 + .../upgrades/files/pre-upgrade-check | 188 ++++++++++ .../openshift-cluster/upgrades/files/versions.sh | 10 + .../openshift-cluster/upgrades/filter_plugins | 1 + .../upgrades/library/openshift_upgrade_config.py | 154 ++++++++ .../openshift-cluster/upgrades/lookup_plugins | 1 + playbooks/common/openshift-cluster/upgrades/roles | 1 + .../upgrades/v3_0_minor/filter_plugins | 1 + .../openshift-cluster/upgrades/v3_0_minor/library | 1 + .../upgrades/v3_0_minor/lookup_plugins | 1 + .../openshift-cluster/upgrades/v3_0_minor/roles | 1 + .../upgrades/v3_0_minor/upgrade.yml | 112 ++++++ .../upgrades/v3_0_to_v3_1/filter_plugins | 1 + .../upgrades/v3_0_to_v3_1/library | 1 + .../upgrades/v3_0_to_v3_1/lookup_plugins | 1 + .../openshift-cluster/upgrades/v3_0_to_v3_1/roles | 1 + .../upgrades/v3_0_to_v3_1/upgrade.yml | 407 +++++++++++++++++++++ playbooks/common/openshift-etcd/config.yml | 2 + playbooks/common/openshift-master/config.yml | 3 + roles/openshift_facts/library/openshift_facts.py | 71 ++-- utils/src/ooinstall/cli_installer.py | 5 +- utils/src/ooinstall/oo_config.py | 8 +- utils/src/ooinstall/openshift_ansible.py | 4 +- 35 files changed, 998 insertions(+), 824 deletions(-) delete mode 100644 playbooks/adhoc/upgrades/README.md delete mode 100644 playbooks/adhoc/upgrades/files/pre-upgrade-check delete mode 100644 playbooks/adhoc/upgrades/files/versions.sh delete mode 120000 playbooks/adhoc/upgrades/filter_plugins delete mode 100755 playbooks/adhoc/upgrades/library/openshift_upgrade_config.py delete mode 120000 playbooks/adhoc/upgrades/lookup_plugins delete mode 120000 playbooks/adhoc/upgrades/roles delete mode 100644 playbooks/adhoc/upgrades/upgrade.yml create mode 100644 playbooks/byo/openshift-cluster/upgrades/README.md create mode 100644 playbooks/byo/openshift-cluster/upgrades/v3_0_minor/README.md create mode 100644 playbooks/byo/openshift-cluster/upgrades/v3_0_minor/upgrade.yml create mode 100644 playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/README.md create mode 100644 playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml create mode 100644 playbooks/common/openshift-cluster/upgrades/files/pre-upgrade-check create mode 100644 playbooks/common/openshift-cluster/upgrades/files/versions.sh create mode 120000 playbooks/common/openshift-cluster/upgrades/filter_plugins create mode 100755 playbooks/common/openshift-cluster/upgrades/library/openshift_upgrade_config.py create mode 120000 playbooks/common/openshift-cluster/upgrades/lookup_plugins create mode 120000 playbooks/common/openshift-cluster/upgrades/roles create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_minor/filter_plugins create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_minor/library create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_minor/lookup_plugins create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_minor/roles create mode 100644 playbooks/common/openshift-cluster/upgrades/v3_0_minor/upgrade.yml create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/filter_plugins create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/library create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/lookup_plugins create mode 120000 playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/roles create mode 100644 playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml (limited to 'utils') diff --git a/playbooks/adhoc/upgrades/README.md b/playbooks/adhoc/upgrades/README.md deleted file mode 100644 index 6de8a970f..000000000 --- a/playbooks/adhoc/upgrades/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# [NOTE] -This playbook will re-run installation steps overwriting any local -modifications. You should ensure that your inventory has been updated with any -modifications you've made after your initial installation. If you find any items -that cannot be configured via ansible please open an issue at -https://github.com/openshift/openshift-ansible - -# Overview -This playbook is available as a technical preview. It currently performs the -following steps. - - * Upgrade and restart master services - * Upgrade and restart node services - * Applies latest configuration by re-running the installation playbook - * Applies the latest cluster policies - * Updates the default router if one exists - * Updates the default registry if one exists - * Updates image streams and quickstarts - -# Usage -ansible-playbook -i ~/ansible-inventory openshift-ansible/playbooks/adhoc/upgrades/upgrade.yml diff --git a/playbooks/adhoc/upgrades/files/pre-upgrade-check b/playbooks/adhoc/upgrades/files/pre-upgrade-check deleted file mode 100644 index ed4ab6d1b..000000000 --- a/playbooks/adhoc/upgrades/files/pre-upgrade-check +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python -""" -Pre-upgrade checks that must be run on a master before proceeding with upgrade. -""" -# This is a script not a python module: -# pylint: disable=invalid-name - -# NOTE: This script should not require any python libs other than what is -# in the standard library. - -__license__ = "ASL 2.0" - -import json -import os -import subprocess -import re - -# The maximum length of container.ports.name -ALLOWED_LENGTH = 15 -# The valid structure of container.ports.name -ALLOWED_CHARS = re.compile('^[a-z0-9][a-z0-9\\-]*[a-z0-9]$') -AT_LEAST_ONE_LETTER = re.compile('[a-z]') -# look at OS_PATH for the full path. Default ot 'oc' -OC_PATH = os.getenv('OC_PATH', 'oc') - - -def validate(value): - """ - validate verifies that value matches required conventions - - Rules of container.ports.name validation: - - * must be less that 16 chars - * at least one letter - * only a-z0-9- - * hyphens can not be leading or trailing or next to each other - - :Parameters: - - `value`: Value to validate - """ - if len(value) > ALLOWED_LENGTH: - return False - - if '--' in value: - return False - - # We search since it can be anywhere - if not AT_LEAST_ONE_LETTER.search(value): - return False - - # We match because it must start at the beginning - if not ALLOWED_CHARS.match(value): - return False - return True - - -def list_items(kind): - """ - list_items returns a list of items from the api - - :Parameters: - - `kind`: Kind of item to access - """ - response = subprocess.check_output([OC_PATH, 'get', '--all-namespaces', '-o', 'json', kind]) - items = json.loads(response) - return items.get("items", []) - - -def get(obj, *paths): - """ - Gets an object - - :Parameters: - - `obj`: A dictionary structure - - `path`: All other non-keyword arguments - """ - ret_obj = obj - for path in paths: - if ret_obj.get(path, None) is None: - return [] - ret_obj = ret_obj[path] - return ret_obj - - -# pylint: disable=too-many-arguments -def pretty_print_errors(namespace, kind, item_name, container_name, port_name, valid): - """ - Prints out results in human friendly way. - - :Parameters: - - `namespace`: Namespace of the resource - - `kind`: Kind of the resource - - `item_name`: Name of the resource - - `container_name`: Name of the container. May be "" when kind=Service. - - `port_name`: Name of the port - - `valid`: True if the port is valid - """ - if not valid: - if len(container_name) > 0: - print('%s/%s -n %s (Container="%s" Port="%s")' % ( - kind, item_name, namespace, container_name, port_name)) - else: - print('%s/%s -n %s (Port="%s")' % ( - kind, item_name, namespace, port_name)) - - -def print_validation_header(): - """ - Prints the error header. Should run on the first error to avoid - overwhelming the user. - """ - print """\ -At least one port name does not validate. Valid port names: - - * must be less that 16 chars - * have at least one letter - * only a-z0-9- - * do not start or end with - - * Dashes may not be next to eachother ('--') -""" - - -def main(): - """ - main is the main entry point to this script - """ - try: - # the comma at the end suppresses the newline - print "Checking for oc ...", - subprocess.check_output([OC_PATH, 'whoami']) - print "found" - except: - print( - 'Unable to run "%s whoami"\n' - 'Please ensure OpenShift is running, and "oc" is on your system ' - 'path.\n' - 'You can override the path with the OC_PATH environment variable.' - % OC_PATH) - raise SystemExit(1) - - # Where the magic happens - first_error = True - for kind, path in [ - ('replicationcontrollers', ("spec", "template", "spec", "containers")), - ('pods', ("spec", "containers")), - ('deploymentconfigs', ("spec", "template", "spec", "containers"))]: - for item in list_items(kind): - namespace = item["metadata"]["namespace"] - item_name = item["metadata"]["name"] - for container in get(item, *path): - container_name = container["name"] - for port in get(container, "ports"): - port_name = port.get("name", None) - if not port_name: - # Unnamed ports are OK - continue - valid = validate(port_name) - if not valid and first_error: - first_error = False - print_validation_header() - pretty_print_errors( - namespace, kind, item_name, - container_name, port_name, valid) - - # Services follow a different flow - for item in list_items('services'): - namespace = item["metadata"]["namespace"] - item_name = item["metadata"]["name"] - for port in get(item, "spec", "ports"): - port_name = port.get("targetPort", None) - if isinstance(port_name, int) or port_name is None: - # Integer only or unnamed ports are OK - continue - valid = validate(port_name) - if not valid and first_error: - first_error = False - print_validation_header() - pretty_print_errors( - namespace, "services", item_name, "", port_name, valid) - - # If we had at least 1 error then exit with 1 - if not first_error: - raise SystemExit(1) - - -if __name__ == '__main__': - main() - diff --git a/playbooks/adhoc/upgrades/files/versions.sh b/playbooks/adhoc/upgrades/files/versions.sh deleted file mode 100644 index f90719cab..000000000 --- a/playbooks/adhoc/upgrades/files/versions.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -yum_installed=$(yum list installed "$@" 2>&1 | tail -n +2 | grep -v 'Installed Packages' | grep -v 'Red Hat Subscription Management' | grep -v 'Error:' | awk '{ print $2 }' | tr '\n' ' ') - -yum_available=$(yum list available "$@" 2>&1 | tail -n +2 | grep -v 'Available Packages' | grep -v 'Red Hat Subscription Management' | grep -v 'el7ose' | grep -v 'Error:' | awk '{ print $2 }' | tr '\n' ' ') - - -echo "---" -echo "curr_version: ${yum_installed}" -echo "avail_version: ${yum_available}" diff --git a/playbooks/adhoc/upgrades/filter_plugins b/playbooks/adhoc/upgrades/filter_plugins deleted file mode 120000 index b0b7a3414..000000000 --- a/playbooks/adhoc/upgrades/filter_plugins +++ /dev/null @@ -1 +0,0 @@ -../../../filter_plugins/ \ No newline at end of file diff --git a/playbooks/adhoc/upgrades/library/openshift_upgrade_config.py b/playbooks/adhoc/upgrades/library/openshift_upgrade_config.py deleted file mode 100755 index a6721bb92..000000000 --- a/playbooks/adhoc/upgrades/library/openshift_upgrade_config.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -# vim: expandtab:tabstop=4:shiftwidth=4 - -"""Ansible module for modifying OpenShift configs during an upgrade""" - -import os -import yaml - -DOCUMENTATION = ''' ---- -module: openshift_upgrade_config -short_description: OpenShift Upgrade Config -author: Jason DeTiberus -requirements: [ ] -''' -EXAMPLES = ''' -''' - -def modify_api_levels(level_list, remove, ensure, msg_prepend='', - msg_append=''): - """ modify_api_levels """ - changed = False - changes = [] - - if not isinstance(remove, list): - remove = [] - - if not isinstance(ensure, list): - ensure = [] - - if not isinstance(level_list, list): - new_list = [] - changed = True - changes.append("%s created missing %s" % (msg_prepend, msg_append)) - else: - new_list = level_list - for level in remove: - if level in new_list: - new_list.remove(level) - changed = True - changes.append("%s removed %s %s" % (msg_prepend, level, msg_append)) - - for level in ensure: - if level not in new_list: - new_list.append(level) - changed = True - changes.append("%s added %s %s" % (msg_prepend, level, msg_append)) - - return {'new_list': new_list, 'changed': changed, 'changes': changes} - - -def upgrade_master_3_0_to_3_1(ansible_module, config_base, backup): - """Main upgrade method for 3.0 to 3.1.""" - changes = [] - - # Facts do not get transferred to the hosts where custom modules run, - # need to make some assumptions here. - master_config = os.path.join(config_base, 'master/master-config.yaml') - - master_cfg_file = open(master_config, 'r') - config = yaml.safe_load(master_cfg_file.read()) - master_cfg_file.close() - - - # Remove unsupported api versions and ensure supported api versions from - # master config - unsupported_levels = ['v1beta1', 'v1beta2', 'v1beta3'] - supported_levels = ['v1'] - - result = modify_api_levels(config.get('apiLevels'), unsupported_levels, - supported_levels, 'master-config.yaml:', 'from apiLevels') - if result['changed']: - config['apiLevels'] = result['new_list'] - changes.append(result['changes']) - - if 'kubernetesMasterConfig' in config and 'apiLevels' in config['kubernetesMasterConfig']: - config['kubernetesMasterConfig'].pop('apiLevels') - changes.append('master-config.yaml: removed kubernetesMasterConfig.apiLevels') - - # Add proxyClientInfo to master-config - if 'proxyClientInfo' not in config['kubernetesMasterConfig']: - config['kubernetesMasterConfig']['proxyClientInfo'] = { - 'certFile': 'master.proxy-client.crt', - 'keyFile': 'master.proxy-client.key' - } - changes.append("master-config.yaml: added proxyClientInfo") - - if len(changes) > 0: - if backup: - # TODO: Check success: - ansible_module.backup_local(master_config) - - # Write the modified config: - out_file = open(master_config, 'w') - out_file.write(yaml.safe_dump(config, default_flow_style=False)) - out_file.close() - - return changes - - -def upgrade_master(ansible_module, config_base, from_version, to_version, backup): - """Upgrade entry point.""" - if from_version == '3.0': - if to_version == '3.1': - return upgrade_master_3_0_to_3_1(ansible_module, config_base, backup) - - -def main(): - """ main """ - # disabling pylint errors for global-variable-undefined and invalid-name - # for 'global module' usage, since it is required to use ansible_facts - # pylint: disable=global-variable-undefined, invalid-name, - # redefined-outer-name - global module - - module = AnsibleModule( - argument_spec=dict( - config_base=dict(required=True), - from_version=dict(required=True, choices=['3.0']), - to_version=dict(required=True, choices=['3.1']), - role=dict(required=True, choices=['master']), - backup=dict(required=False, default=True, type='bool') - ), - supports_check_mode=True, - ) - - from_version = module.params['from_version'] - to_version = module.params['to_version'] - role = module.params['role'] - backup = module.params['backup'] - config_base = module.params['config_base'] - - try: - changes = [] - if role == 'master': - changes = upgrade_master(module, config_base, from_version, - to_version, backup) - - changed = len(changes) > 0 - return module.exit_json(changed=changed, changes=changes) - - # ignore broad-except error to avoid stack trace to ansible user - # pylint: disable=broad-except - except Exception, e: - return module.fail_json(msg=str(e)) - -# ignore pylint errors related to the module_utils import -# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import -# import module snippets -from ansible.module_utils.basic import * - -if __name__ == '__main__': - main() diff --git a/playbooks/adhoc/upgrades/lookup_plugins b/playbooks/adhoc/upgrades/lookup_plugins deleted file mode 120000 index 73cafffe5..000000000 --- a/playbooks/adhoc/upgrades/lookup_plugins +++ /dev/null @@ -1 +0,0 @@ -../../../lookup_plugins/ \ No newline at end of file diff --git a/playbooks/adhoc/upgrades/roles b/playbooks/adhoc/upgrades/roles deleted file mode 120000 index e2b799b9d..000000000 --- a/playbooks/adhoc/upgrades/roles +++ /dev/null @@ -1 +0,0 @@ -../../../roles/ \ No newline at end of file diff --git a/playbooks/adhoc/upgrades/upgrade.yml b/playbooks/adhoc/upgrades/upgrade.yml deleted file mode 100644 index 324f5fba3..000000000 --- a/playbooks/adhoc/upgrades/upgrade.yml +++ /dev/null @@ -1,407 +0,0 @@ ---- -- name: Load master facts - hosts: masters - roles: - - openshift_facts - -- name: Verify upgrade can proceed - hosts: masters[0] - vars: - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - gather_facts: no - tasks: - # Pacemaker is currently the only supported upgrade path for multiple masters - - fail: - msg: "openshift_master_cluster_method must be set to 'pacemaker'" - when: openshift_master_ha | bool and ((openshift_master_cluster_method is not defined) or (openshift_master_cluster_method is defined and openshift_master_cluster_method != "pacemaker")) - -- name: Run pre-upgrade checks on first master - hosts: masters[0] - tasks: - # If this script errors out ansible will show the default stdout/stderr - # which contains details for the user: - - script: files/pre-upgrade-check - -- name: Evaluate etcd_hosts - hosts: localhost - tasks: - - name: Evaluate etcd hosts - add_host: - name: "{{ groups.masters.0 }}" - groups: etcd_hosts - when: hostvars[groups.masters.0].openshift.master.embedded_etcd | bool - - name: Evaluate etcd hosts - add_host: - name: "{{ item }}" - groups: etcd_hosts - with_items: groups.etcd - when: not hostvars[groups.masters.0].openshift.master.embedded_etcd | bool - -- name: Backup etcd - hosts: etcd_hosts - vars: - embedded_etcd: "{{ openshift.master.embedded_etcd }}" - timestamp: "{{ lookup('pipe', 'date +%Y%m%d%H%M%S') }}" - roles: - - openshift_facts - tasks: - - - stat: path=/var/lib/openshift - register: var_lib_openshift - - - stat: path=/var/lib/origin - register: var_lib_origin - - - name: Create origin symlink if necessary - file: src=/var/lib/openshift/ dest=/var/lib/origin state=link - when: var_lib_openshift.stat.exists == True and var_lib_origin.stat.exists == False - - - name: Check available disk space for etcd backup - # We assume to be using the data dir for all backups. - shell: > - df --output=avail -k {{ openshift.common.data_dir }} | tail -n 1 - register: avail_disk - - - name: Check current embedded etcd disk usage - shell: > - du -k {{ openshift.master.etcd_data_dir }} | tail -n 1 | cut -f1 - register: etcd_disk_usage - when: embedded_etcd | bool - - - name: Abort if insufficient disk space for etcd backup - fail: - msg: > - {{ etcd_disk_usage.stdout }} Kb disk space required for etcd backup, - {{ avail_disk.stdout }} Kb available. - when: (embedded_etcd | bool) and (etcd_disk_usage.stdout|int > avail_disk.stdout|int) - - - name: Install etcd (for etcdctl) - yum: - pkg: etcd - state: latest - - - name: Generate etcd backup - command: > - etcdctl backup --data-dir={{ openshift.master.etcd_data_dir }} - --backup-dir={{ openshift.common.data_dir }}/etcd-backup-{{ timestamp }} - - - name: Display location of etcd backup - debug: - msg: "Etcd backup created in {{ openshift.common.data_dir }}/etcd-backup-{{ timestamp }}" - -- name: Update deployment type - hosts: OSEv3 - roles: - - openshift_facts - post_tasks: - - openshift_facts: - role: common - local_facts: - deployment_type: "{{ deployment_type }}" - - -- name: Perform upgrade version checking - hosts: masters[0] - tasks: - - name: Clean yum cache - command: yum clean all - - - name: Determine available versions - script: files/versions.sh {{ openshift.common.service_type }} openshift - register: g_versions_result - - - set_fact: - g_aos_versions: "{{ g_versions_result.stdout | from_yaml }}" - - - set_fact: - g_new_version: "{{ g_aos_versions.curr_version.split('-', 1).0 if g_aos_versions.avail_version is none else g_aos_versions.avail_version.split('-', 1).0 }}" - - - fail: - msg: This playbook requires Origin 1.0.6 or later - when: deployment_type == 'origin' and g_aos_versions.curr_version | version_compare('1.0.6','<') - - # TODO: This should be specific to the 3.1 upgrade playbook (coming in future refactor), otherwise we are blocking 3.0.1 to 3.0.2 here. - - fail: - msg: Atomic OpenShift 3.1 packages not found - when: deployment_type in ['openshift-enterprise', 'atomic-openshift'] and g_aos_versions.curr_version | version_compare('3.0.2.900','<') and (g_aos_versions.avail_version is none or g_aos_versions.avail_version | version_compare('3.0.2.900','<')) - # Deployment type 'enterprise' is no longer valid if we're upgrading to 3.1 or beyond. - # (still valid for 3.0.x to 3.0.y however) Using the global deployment_type here as - # we're checking what was requested by the upgrade, not the current type on the system. - - fail: - msg: "Deployment type enterprise not supported for upgrade" - when: deployment_type == "enterprise" and g_aos_versions.curr_version | version_compare('3.1', '>=') - - -- name: Upgrade masters - hosts: masters - vars: - openshift_version: "{{ openshift_pkg_version | default('') }}" - tasks: - - name: Upgrade to latest available kernel - yum: - pkg: kernel - state: latest - - - name: Upgrade master packages - command: yum update -y {{ openshift.common.service_type }}-master{{ openshift_version }} - - - name: Ensure python-yaml present for config upgrade - yum: - pkg: PyYAML - state: installed - - - name: Upgrade master configuration - openshift_upgrade_config: - from_version: '3.0' - to_version: '3.1' - role: master - config_base: "{{ hostvars[inventory_hostname].openshift.common.config_base }}" - when: deployment_type in ['openshift-enterprise', 'atomic-enterprise'] and g_aos_versions.curr_version | version_compare('3.1', '>=') - - - set_fact: - master_certs_missing: True - master_cert_subdir: master-{{ openshift.common.hostname }} - master_cert_config_dir: "{{ openshift.common.config_base }}/master" - -- name: Create temp directory for syncing certs - hosts: localhost - gather_facts: no - tasks: - - name: Create local temp directory for syncing certs - local_action: command mktemp -d /tmp/openshift-ansible-XXXXXXX - register: g_master_mktemp - changed_when: False - -- name: Generate missing master certificates - hosts: masters[0] - vars: - master_hostnames: "{{ hostvars - | oo_select_keys(groups.masters) - | oo_collect('openshift.common.all_hostnames') - | oo_flatten | unique }}" - master_generated_certs_dir: "{{ openshift.common.config_base }}/generated-configs" - masters_needing_certs: "{{ hostvars - | oo_select_keys(groups.masters) - | difference([groups.masters.0]) }}" - sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" - openshift_deployment_type: "{{ deployment_type }}" - roles: - - openshift_master_certificates - post_tasks: - - name: Remove generated etcd client certs when using external etcd - file: - path: "{{ master_generated_certs_dir }}/{{ item.0.master_cert_subdir }}/{{ item.1 }}" - state: absent - when: groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config - with_nested: - - masters_needing_certs - - - master.etcd-client.crt - - master.etcd-client.key - - - name: Create a tarball of the master certs - command: > - tar -czvf {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz - -C {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }} . - with_items: masters_needing_certs - - - name: Retrieve the master cert tarball from the master - fetch: - src: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz" - dest: "{{ sync_tmpdir }}/" - flat: yes - fail_on_missing: yes - validate_checksum: yes - with_items: masters_needing_certs - -- name: Sync certs and restart masters post configuration change - hosts: masters - vars: - sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - tasks: - - name: Unarchive the tarball on the master - unarchive: - src: "{{ sync_tmpdir }}/{{ master_cert_subdir }}.tgz" - dest: "{{ master_cert_config_dir }}" - when: inventory_hostname != groups.masters.0 - - - name: Restart master services - service: name="{{ openshift.common.service_type}}-master" state=restarted - when: not openshift_master_ha | bool - -- name: Destroy cluster - hosts: masters[0] - vars: - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - openshift_deployment_type: "{{ deployment_type }}" - pre_tasks: - - name: Check for configured cluster - stat: - path: /etc/corosync/corosync.conf - register: corosync_conf - when: openshift_master_ha | bool - - name: Destroy cluster - command: pcs cluster destroy --all - when: openshift_master_ha | bool and corosync_conf.stat.exists == true - -- name: Start pcsd on masters - hosts: masters - vars: - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - tasks: - - name: Start pcsd - service: name=pcsd enabled=yes state=started - when: openshift_master_ha | bool - -- name: Re-create cluster - hosts: masters[0] - vars: - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - openshift_deployment_type: "{{ deployment_type }}" - omc_cluster_hosts: "{{ groups.masters | join(' ') }}" - roles: - - role: openshift_master_cluster - when: openshift_master_ha | bool - -- name: Delete temporary directory on localhost - hosts: localhost - gather_facts: no - tasks: - - file: name={{ g_master_mktemp.stdout }} state=absent - changed_when: False - - -- name: Upgrade nodes - hosts: nodes - vars: - openshift_version: "{{ openshift_pkg_version | default('') }}" - roles: - - openshift_facts - tasks: - - name: Upgrade node packages - command: yum update -y {{ openshift.common.service_type }}-node{{ openshift_version }} - - name: Restart node services - service: name="{{ openshift.common.service_type }}-node" state=restarted - -- name: Update cluster policy and policy bindings - hosts: masters[0] - vars: - origin_reconcile_bindings: "{{ deployment_type == 'origin' and g_new_version | version_compare('1.0.6', '>') }}" - ent_reconcile_bindings: "{{ deployment_type in ['openshift-enterprise', 'atomic-enterprise'] and g_new_version | version_compare('3.0.2','>') }}" - tasks: - - name: oadm policy reconcile-cluster-roles --confirm - command: > - {{ openshift.common.admin_binary}} --config={{ openshift.common.config_base }}/master/admin.kubeconfig - policy reconcile-cluster-roles --confirm - - - name: oadm policy reconcile-cluster-role-bindings --confirm - command: > - {{ openshift.common.admin_binary}} --config={{ openshift.common.config_base }}/master/admin.kubeconfig - policy reconcile-cluster-role-bindings - --exclude-groups=system:authenticated - --exclude-groups=system:unauthenticated - --exclude-users=system:anonymous - --additive-only=true --confirm - when: origin_reconcile_bindings | bool or ent_reconcile_bindings | bool - - -- name: Restart masters post reconcile - hosts: masters - vars: - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - tasks: - - name: Restart master services - service: name="{{ openshift.common.service_type}}-master" state=restarted - when: not openshift_master_ha | bool - -- name: Restart cluster post reconcile - hosts: masters[0] - vars: - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - tasks: - - name: Restart master cluster - command: pcs resource restart master - when: openshift_master_ha | bool - - name: Wait for the clustered master service to be available - wait_for: - host: "{{ openshift_master_cluster_vip }}" - port: 8443 - state: started - timeout: 180 - delay: 90 - when: openshift_master_ha | bool - -- name: Upgrade default router and registry - hosts: masters[0] - vars: - - registry_image: "{{ openshift.master.registry_url | replace( '${component}', 'docker-registry' ) | replace ( '${version}', 'v' + g_new_version ) }}" - - router_image: "{{ openshift.master.registry_url | replace( '${component}', 'haproxy-router' ) | replace ( '${version}', 'v' + g_new_version ) }}" - - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" - tasks: - - name: Check for default router - command: > - {{ oc_cmd }} get -n default dc/router - register: _default_router - failed_when: false - changed_when: false - - name: Check for allowHostNetwork and allowHostPorts - when: _default_router.rc == 0 - shell: > - {{ oc_cmd }} get -o yaml scc/privileged | /usr/bin/grep -e allowHostPorts -e allowHostNetwork - register: _scc - - name: Grant allowHostNetwork and allowHostPorts - when: - - _default_router.rc == 0 - - "'false' in _scc.stdout" - command: > - {{ oc_cmd }} patch scc/privileged -p '{"allowHostPorts":true,"allowHostNetwork":true}' --loglevel=9 - - name: Update deployment config to 1.0.4/3.0.1 spec - when: _default_router.rc == 0 - command: > - {{ oc_cmd }} patch dc/router -p - '{"spec":{"strategy":{"rollingParams":{"updatePercent":-10},"spec":{"serviceAccount":"router","serviceAccountName":"router"}}}}' - - name: Switch to hostNetwork=true - when: _default_router.rc == 0 - command: > - {{ oc_cmd }} patch dc/router -p '{"spec":{"template":{"spec":{"hostNetwork":true}}}}' - - name: Update router image to current version - when: _default_router.rc == 0 - command: > - {{ oc_cmd }} patch dc/router -p - '{"spec":{"template":{"spec":{"containers":[{"name":"router","image":"{{ router_image }}"}]}}}}' - - - name: Check for default registry - command: > - {{ oc_cmd }} get -n default dc/docker-registry - register: _default_registry - failed_when: false - changed_when: false - - name: Update registry image to current version - when: _default_registry.rc == 0 - command: > - {{ oc_cmd }} patch dc/docker-registry -p - '{"spec":{"template":{"spec":{"containers":[{"name":"registry","image":"{{ registry_image }}"}]}}}}' - -- name: Update image streams and templates - hosts: masters[0] - vars: - openshift_examples_import_command: "update" - openshift_deployment_type: "{{ deployment_type }}" - roles: - - openshift_examples - -- name: Ensure master services enabled - hosts: masters - vars: - openshift_master_ha: "{{ groups['masters'] | length > 1 }}" - tasks: - - name: Enable master services - service: name="{{ openshift.common.service_type}}-master" state=started enabled=yes - when: not openshift_master_ha | bool - -- name: Ensure node services enabled - hosts: nodes - tasks: - - name: Restart node services - service: name="{{ openshift.common.service_type }}-node" state=started enabled=yes - diff --git a/playbooks/byo/openshift-cluster/upgrades/README.md b/playbooks/byo/openshift-cluster/upgrades/README.md new file mode 100644 index 000000000..ce7aebf8e --- /dev/null +++ b/playbooks/byo/openshift-cluster/upgrades/README.md @@ -0,0 +1,8 @@ +# Upgrade playbooks +The playbooks provided in this directory can be used for upgrading an existing +environment. Additional notes for the associated upgrade playbooks are +provided in their respective directories. + +# Upgrades available +- [OpenShift Enterprise 3.0 to latest minor release](v3_0_minor/README.md) +- [OpenShift Enterprise 3.0 to 3.1](v3_0_to_v3_1/README.md) diff --git a/playbooks/byo/openshift-cluster/upgrades/v3_0_minor/README.md b/playbooks/byo/openshift-cluster/upgrades/v3_0_minor/README.md new file mode 100644 index 000000000..c91a6cb96 --- /dev/null +++ b/playbooks/byo/openshift-cluster/upgrades/v3_0_minor/README.md @@ -0,0 +1,21 @@ +# v3.0 minor upgrade playbook +**Note:** This playbook will re-run installation steps overwriting any local +modifications. You should ensure that your inventory has been updated with any +modifications you've made after your initial installation. If you find any items +that cannot be configured via ansible please open an issue at +https://github.com/openshift/openshift-ansible + +## Overview +This playbook is available as a technical preview. It currently performs the +following steps. + + * Upgrade and restart master services + * Upgrade and restart node services + * Applies latest configuration by re-running the installation playbook + * Applies the latest cluster policies + * Updates the default router if one exists + * Updates the default registry if one exists + * Updates image streams and quickstarts + +## Usage +ansible-playbook -i ~/ansible-inventory openshift-ansible/playbooks/byo/openshift-cluster/upgrades/v3_0_minor/upgrade.yml diff --git a/playbooks/byo/openshift-cluster/upgrades/v3_0_minor/upgrade.yml b/playbooks/byo/openshift-cluster/upgrades/v3_0_minor/upgrade.yml new file mode 100644 index 000000000..76fa9ba22 --- /dev/null +++ b/playbooks/byo/openshift-cluster/upgrades/v3_0_minor/upgrade.yml @@ -0,0 +1,9 @@ +--- +- include: ../../../../common/openshift-cluster/upgrades/v3_0_minor/upgrade.yml + vars: + g_etcd_group: "{{ 'etcd' }}" + g_masters_group: "{{ 'masters' }}" + g_nodes_group: "{{ 'nodes' }}" + g_lb_group: "{{ 'lb' }}" + openshift_cluster_id: "{{ cluster_id | default('default') }}" + openshift_deployment_type: "{{ deployment_type }}" diff --git a/playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/README.md b/playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/README.md new file mode 100644 index 000000000..c434be5b7 --- /dev/null +++ b/playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/README.md @@ -0,0 +1,17 @@ +# v3.0 to v3.1 upgrade playbook + +## Overview +This playbook currently performs the +following steps. + +**TODO: update for current steps** + * Upgrade and restart master services + * Upgrade and restart node services + * Modifies the subset of the configuration necessary + * Applies the latest cluster policies + * Updates the default router if one exists + * Updates the default registry if one exists + * Updates image streams and quickstarts + +## Usage +ansible-playbook -i ~/ansible-inventory openshift-ansible/playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml diff --git a/playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml b/playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml new file mode 100644 index 000000000..b06442366 --- /dev/null +++ b/playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml @@ -0,0 +1,9 @@ +--- +- include: ../../../../common/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml + vars: + g_etcd_group: "{{ 'etcd' }}" + g_masters_group: "{{ 'masters' }}" + g_nodes_group: "{{ 'nodes' }}" + g_lb_group: "{{ 'lb' }}" + openshift_cluster_id: "{{ cluster_id | default('default') }}" + openshift_deployment_type: "{{ deployment_type }}" diff --git a/playbooks/common/openshift-cluster/upgrades/files/pre-upgrade-check b/playbooks/common/openshift-cluster/upgrades/files/pre-upgrade-check new file mode 100644 index 000000000..ed4ab6d1b --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/files/pre-upgrade-check @@ -0,0 +1,188 @@ +#!/usr/bin/env python +""" +Pre-upgrade checks that must be run on a master before proceeding with upgrade. +""" +# This is a script not a python module: +# pylint: disable=invalid-name + +# NOTE: This script should not require any python libs other than what is +# in the standard library. + +__license__ = "ASL 2.0" + +import json +import os +import subprocess +import re + +# The maximum length of container.ports.name +ALLOWED_LENGTH = 15 +# The valid structure of container.ports.name +ALLOWED_CHARS = re.compile('^[a-z0-9][a-z0-9\\-]*[a-z0-9]$') +AT_LEAST_ONE_LETTER = re.compile('[a-z]') +# look at OS_PATH for the full path. Default ot 'oc' +OC_PATH = os.getenv('OC_PATH', 'oc') + + +def validate(value): + """ + validate verifies that value matches required conventions + + Rules of container.ports.name validation: + + * must be less that 16 chars + * at least one letter + * only a-z0-9- + * hyphens can not be leading or trailing or next to each other + + :Parameters: + - `value`: Value to validate + """ + if len(value) > ALLOWED_LENGTH: + return False + + if '--' in value: + return False + + # We search since it can be anywhere + if not AT_LEAST_ONE_LETTER.search(value): + return False + + # We match because it must start at the beginning + if not ALLOWED_CHARS.match(value): + return False + return True + + +def list_items(kind): + """ + list_items returns a list of items from the api + + :Parameters: + - `kind`: Kind of item to access + """ + response = subprocess.check_output([OC_PATH, 'get', '--all-namespaces', '-o', 'json', kind]) + items = json.loads(response) + return items.get("items", []) + + +def get(obj, *paths): + """ + Gets an object + + :Parameters: + - `obj`: A dictionary structure + - `path`: All other non-keyword arguments + """ + ret_obj = obj + for path in paths: + if ret_obj.get(path, None) is None: + return [] + ret_obj = ret_obj[path] + return ret_obj + + +# pylint: disable=too-many-arguments +def pretty_print_errors(namespace, kind, item_name, container_name, port_name, valid): + """ + Prints out results in human friendly way. + + :Parameters: + - `namespace`: Namespace of the resource + - `kind`: Kind of the resource + - `item_name`: Name of the resource + - `container_name`: Name of the container. May be "" when kind=Service. + - `port_name`: Name of the port + - `valid`: True if the port is valid + """ + if not valid: + if len(container_name) > 0: + print('%s/%s -n %s (Container="%s" Port="%s")' % ( + kind, item_name, namespace, container_name, port_name)) + else: + print('%s/%s -n %s (Port="%s")' % ( + kind, item_name, namespace, port_name)) + + +def print_validation_header(): + """ + Prints the error header. Should run on the first error to avoid + overwhelming the user. + """ + print """\ +At least one port name does not validate. Valid port names: + + * must be less that 16 chars + * have at least one letter + * only a-z0-9- + * do not start or end with - + * Dashes may not be next to eachother ('--') +""" + + +def main(): + """ + main is the main entry point to this script + """ + try: + # the comma at the end suppresses the newline + print "Checking for oc ...", + subprocess.check_output([OC_PATH, 'whoami']) + print "found" + except: + print( + 'Unable to run "%s whoami"\n' + 'Please ensure OpenShift is running, and "oc" is on your system ' + 'path.\n' + 'You can override the path with the OC_PATH environment variable.' + % OC_PATH) + raise SystemExit(1) + + # Where the magic happens + first_error = True + for kind, path in [ + ('replicationcontrollers', ("spec", "template", "spec", "containers")), + ('pods', ("spec", "containers")), + ('deploymentconfigs', ("spec", "template", "spec", "containers"))]: + for item in list_items(kind): + namespace = item["metadata"]["namespace"] + item_name = item["metadata"]["name"] + for container in get(item, *path): + container_name = container["name"] + for port in get(container, "ports"): + port_name = port.get("name", None) + if not port_name: + # Unnamed ports are OK + continue + valid = validate(port_name) + if not valid and first_error: + first_error = False + print_validation_header() + pretty_print_errors( + namespace, kind, item_name, + container_name, port_name, valid) + + # Services follow a different flow + for item in list_items('services'): + namespace = item["metadata"]["namespace"] + item_name = item["metadata"]["name"] + for port in get(item, "spec", "ports"): + port_name = port.get("targetPort", None) + if isinstance(port_name, int) or port_name is None: + # Integer only or unnamed ports are OK + continue + valid = validate(port_name) + if not valid and first_error: + first_error = False + print_validation_header() + pretty_print_errors( + namespace, "services", item_name, "", port_name, valid) + + # If we had at least 1 error then exit with 1 + if not first_error: + raise SystemExit(1) + + +if __name__ == '__main__': + main() + diff --git a/playbooks/common/openshift-cluster/upgrades/files/versions.sh b/playbooks/common/openshift-cluster/upgrades/files/versions.sh new file mode 100644 index 000000000..f90719cab --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/files/versions.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +yum_installed=$(yum list installed "$@" 2>&1 | tail -n +2 | grep -v 'Installed Packages' | grep -v 'Red Hat Subscription Management' | grep -v 'Error:' | awk '{ print $2 }' | tr '\n' ' ') + +yum_available=$(yum list available "$@" 2>&1 | tail -n +2 | grep -v 'Available Packages' | grep -v 'Red Hat Subscription Management' | grep -v 'el7ose' | grep -v 'Error:' | awk '{ print $2 }' | tr '\n' ' ') + + +echo "---" +echo "curr_version: ${yum_installed}" +echo "avail_version: ${yum_available}" diff --git a/playbooks/common/openshift-cluster/upgrades/filter_plugins b/playbooks/common/openshift-cluster/upgrades/filter_plugins new file mode 120000 index 000000000..b1213dedb --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/filter_plugins @@ -0,0 +1 @@ +../../../../filter_plugins \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/library/openshift_upgrade_config.py b/playbooks/common/openshift-cluster/upgrades/library/openshift_upgrade_config.py new file mode 100755 index 000000000..a6721bb92 --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/library/openshift_upgrade_config.py @@ -0,0 +1,154 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# vim: expandtab:tabstop=4:shiftwidth=4 + +"""Ansible module for modifying OpenShift configs during an upgrade""" + +import os +import yaml + +DOCUMENTATION = ''' +--- +module: openshift_upgrade_config +short_description: OpenShift Upgrade Config +author: Jason DeTiberus +requirements: [ ] +''' +EXAMPLES = ''' +''' + +def modify_api_levels(level_list, remove, ensure, msg_prepend='', + msg_append=''): + """ modify_api_levels """ + changed = False + changes = [] + + if not isinstance(remove, list): + remove = [] + + if not isinstance(ensure, list): + ensure = [] + + if not isinstance(level_list, list): + new_list = [] + changed = True + changes.append("%s created missing %s" % (msg_prepend, msg_append)) + else: + new_list = level_list + for level in remove: + if level in new_list: + new_list.remove(level) + changed = True + changes.append("%s removed %s %s" % (msg_prepend, level, msg_append)) + + for level in ensure: + if level not in new_list: + new_list.append(level) + changed = True + changes.append("%s added %s %s" % (msg_prepend, level, msg_append)) + + return {'new_list': new_list, 'changed': changed, 'changes': changes} + + +def upgrade_master_3_0_to_3_1(ansible_module, config_base, backup): + """Main upgrade method for 3.0 to 3.1.""" + changes = [] + + # Facts do not get transferred to the hosts where custom modules run, + # need to make some assumptions here. + master_config = os.path.join(config_base, 'master/master-config.yaml') + + master_cfg_file = open(master_config, 'r') + config = yaml.safe_load(master_cfg_file.read()) + master_cfg_file.close() + + + # Remove unsupported api versions and ensure supported api versions from + # master config + unsupported_levels = ['v1beta1', 'v1beta2', 'v1beta3'] + supported_levels = ['v1'] + + result = modify_api_levels(config.get('apiLevels'), unsupported_levels, + supported_levels, 'master-config.yaml:', 'from apiLevels') + if result['changed']: + config['apiLevels'] = result['new_list'] + changes.append(result['changes']) + + if 'kubernetesMasterConfig' in config and 'apiLevels' in config['kubernetesMasterConfig']: + config['kubernetesMasterConfig'].pop('apiLevels') + changes.append('master-config.yaml: removed kubernetesMasterConfig.apiLevels') + + # Add proxyClientInfo to master-config + if 'proxyClientInfo' not in config['kubernetesMasterConfig']: + config['kubernetesMasterConfig']['proxyClientInfo'] = { + 'certFile': 'master.proxy-client.crt', + 'keyFile': 'master.proxy-client.key' + } + changes.append("master-config.yaml: added proxyClientInfo") + + if len(changes) > 0: + if backup: + # TODO: Check success: + ansible_module.backup_local(master_config) + + # Write the modified config: + out_file = open(master_config, 'w') + out_file.write(yaml.safe_dump(config, default_flow_style=False)) + out_file.close() + + return changes + + +def upgrade_master(ansible_module, config_base, from_version, to_version, backup): + """Upgrade entry point.""" + if from_version == '3.0': + if to_version == '3.1': + return upgrade_master_3_0_to_3_1(ansible_module, config_base, backup) + + +def main(): + """ main """ + # disabling pylint errors for global-variable-undefined and invalid-name + # for 'global module' usage, since it is required to use ansible_facts + # pylint: disable=global-variable-undefined, invalid-name, + # redefined-outer-name + global module + + module = AnsibleModule( + argument_spec=dict( + config_base=dict(required=True), + from_version=dict(required=True, choices=['3.0']), + to_version=dict(required=True, choices=['3.1']), + role=dict(required=True, choices=['master']), + backup=dict(required=False, default=True, type='bool') + ), + supports_check_mode=True, + ) + + from_version = module.params['from_version'] + to_version = module.params['to_version'] + role = module.params['role'] + backup = module.params['backup'] + config_base = module.params['config_base'] + + try: + changes = [] + if role == 'master': + changes = upgrade_master(module, config_base, from_version, + to_version, backup) + + changed = len(changes) > 0 + return module.exit_json(changed=changed, changes=changes) + + # ignore broad-except error to avoid stack trace to ansible user + # pylint: disable=broad-except + except Exception, e: + return module.fail_json(msg=str(e)) + +# ignore pylint errors related to the module_utils import +# pylint: disable=redefined-builtin, unused-wildcard-import, wildcard-import +# import module snippets +from ansible.module_utils.basic import * + +if __name__ == '__main__': + main() diff --git a/playbooks/common/openshift-cluster/upgrades/lookup_plugins b/playbooks/common/openshift-cluster/upgrades/lookup_plugins new file mode 120000 index 000000000..aff753026 --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/lookup_plugins @@ -0,0 +1 @@ +../../../../lookup_plugins \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/roles b/playbooks/common/openshift-cluster/upgrades/roles new file mode 120000 index 000000000..4bdbcbad3 --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/roles @@ -0,0 +1 @@ +../../../../roles \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_minor/filter_plugins b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/filter_plugins new file mode 120000 index 000000000..27ddaa18b --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/filter_plugins @@ -0,0 +1 @@ +../../../../../filter_plugins \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_minor/library b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/library new file mode 120000 index 000000000..53bed9684 --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/library @@ -0,0 +1 @@ +../library \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_minor/lookup_plugins b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/lookup_plugins new file mode 120000 index 000000000..cf407f69b --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/lookup_plugins @@ -0,0 +1 @@ +../../../../../lookup_plugins \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_minor/roles b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/roles new file mode 120000 index 000000000..6bc1a7aef --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/roles @@ -0,0 +1 @@ +../../../../../roles \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_minor/upgrade.yml b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/upgrade.yml new file mode 100644 index 000000000..9f7e49b93 --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_minor/upgrade.yml @@ -0,0 +1,112 @@ +--- +- name: Evaluate groups + include: ../../evaluate_groups.yml + +- name: Re-Run cluster configuration to apply latest configuration changes + include: ../../config.yml + +- name: Upgrade masters + hosts: oo_masters_to_config + vars: + openshift_version: "{{ openshift_pkg_version | default('') }}" + tasks: + - name: Upgrade master packages + yum: pkg={{ openshift.common.service_type }}-master{{ openshift_version }} state=latest + - name: Restart master services + service: name="{{ openshift.common.service_type}}-master" state=restarted + +- name: Upgrade nodes + hosts: oo_nodes_to_config + vars: + openshift_version: "{{ openshift_pkg_version | default('') }}" + tasks: + - name: Upgrade node packages + yum: pkg={{ openshift.common.service_type }}-node{{ openshift_version }} state=latest + - name: Restart node services + service: name="{{ openshift.common.service_type }}-node" state=restarted + +- name: Determine new master version + hosts: oo_first_master + tasks: + - name: Determine new version + command: > + rpm -q --queryformat '%{version}' {{ openshift.common.service_type }}-master + register: _new_version + +- name: Ensure AOS 3.0.2 or Origin 1.0.6 + hosts: oo_first_master + tasks: + fail: This playbook requires Origin 1.0.6 or Atomic OpenShift 3.0.2 or later + when: _new_version.stdout | version_compare('1.0.6','<') or ( _new_version.stdout | version_compare('3.0','>=' and _new_version.stdout | version_compare('3.0.2','<') ) + +- name: Update cluster policy + hosts: oo_first_master + tasks: + - name: oadm policy reconcile-cluster-roles --confirm + command: > + {{ openshift.common.admin_binary}} --config={{ openshift.common.config_base }}/master/admin.kubeconfig + policy reconcile-cluster-roles --confirm + +- name: Upgrade default router + hosts: oo_first_master + vars: + - router_image: "{{ openshift.master.registry_url | replace( '${component}', 'haproxy-router' ) | replace ( '${version}', 'v' + _new_version.stdout ) }}" + - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" + tasks: + - name: Check for default router + command: > + {{ oc_cmd }} get -n default dc/router + register: _default_router + failed_when: false + changed_when: false + - name: Check for allowHostNetwork and allowHostPorts + when: _default_router.rc == 0 + shell: > + {{ oc_cmd }} get -o yaml scc/privileged | /usr/bin/grep -e allowHostPorts -e allowHostNetwork + register: _scc + - name: Grant allowHostNetwork and allowHostPorts + when: + - _default_router.rc == 0 + - "'false' in _scc.stdout" + command: > + {{ oc_cmd }} patch scc/privileged -p '{"allowHostPorts":true,"allowHostNetwork":true}' --loglevel=9 + - name: Update deployment config to 1.0.4/3.0.1 spec + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p + '{"spec":{"strategy":{"rollingParams":{"updatePercent":-10},"spec":{"serviceAccount":"router","serviceAccountName":"router"}}}}' + - name: Switch to hostNetwork=true + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p '{"spec":{"template":{"spec":{"hostNetwork":true}}}}' + - name: Update router image to current version + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p + '{"spec":{"template":{"spec":{"containers":[{"name":"router","image":"{{ router_image }}"}]}}}}' + +- name: Upgrade default + hosts: oo_first_master + vars: + - registry_image: "{{ openshift.master.registry_url | replace( '${component}', 'docker-registry' ) | replace ( '${version}', 'v' + _new_version.stdout ) }}" + - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" + tasks: + - name: Check for default registry + command: > + {{ oc_cmd }} get -n default dc/docker-registry + register: _default_registry + failed_when: false + changed_when: false + - name: Update registry image to current version + when: _default_registry.rc == 0 + command: > + {{ oc_cmd }} patch dc/docker-registry -p + '{"spec":{"template":{"spec":{"containers":[{"name":"registry","image":"{{ registry_image }}"}]}}}}' + +- name: Update image streams and templates + hosts: oo_first_master + vars: + openshift_examples_import_command: "update" + openshift_deployment_type: "{{ deployment_type }}" + roles: + - openshift_examples diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/filter_plugins b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/filter_plugins new file mode 120000 index 000000000..27ddaa18b --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/filter_plugins @@ -0,0 +1 @@ +../../../../../filter_plugins \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/library b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/library new file mode 120000 index 000000000..53bed9684 --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/library @@ -0,0 +1 @@ +../library \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/lookup_plugins b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/lookup_plugins new file mode 120000 index 000000000..cf407f69b --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/lookup_plugins @@ -0,0 +1 @@ +../../../../../lookup_plugins \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/roles b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/roles new file mode 120000 index 000000000..6bc1a7aef --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/roles @@ -0,0 +1 @@ +../../../../../roles \ No newline at end of file diff --git a/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml new file mode 100644 index 000000000..dd6979ab7 --- /dev/null +++ b/playbooks/common/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml @@ -0,0 +1,407 @@ +--- +- name: Evaluate host groups + include: ../../evaluate_groups.yml + +- name: Load openshift_facts from the environment + hosts: oo_masters_to_config oo_nodes_to_config oo_etcd_to_config oo_lb_to_config + roles: + - openshift_facts + +- name: Verify upgrade can proceed + hosts: oo_first_master + vars: + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + gather_facts: no + tasks: + # Pacemaker is currently the only supported upgrade path for multiple masters + - fail: + msg: "openshift_master_cluster_method must be set to 'pacemaker'" + when: openshift_master_ha | bool and ((openshift_master_cluster_method is not defined) or (openshift_master_cluster_method is defined and openshift_master_cluster_method != "pacemaker")) + - fail: + msg: > + This upgrade is only supported for origin and openshift-enterprise + deployment types + when: deployment_type not in ['origin','openshift-enterprise'] + - fail: + msg: > + openshift_pkg_version is {{ openshift_pkg_version }} which is not a + valid version for a 3.1 upgrade + when: openshift_pkg_version is defined and openshift_pkg_version.split('-',1).1 | version_compare('3.0.2.900','<') + + # If this script errors out ansible will show the default stdout/stderr + # which contains details for the user: + - script: ../files/pre-upgrade-check + +- name: Evaluate etcd_hosts_to_backup + hosts: localhost + tasks: + - name: Evaluate etcd_hosts_to_backup + add_host: + name: "{{ item }}" + groups: etcd_hosts_to_backup + with_items: groups.oo_etcd_to_config if groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config | length > 0 else groups.oo_first_master + +- name: Backup etcd + hosts: etcd_hosts_to_backup + vars: + embedded_etcd: "{{ openshift.master.embedded_etcd }}" + timestamp: "{{ lookup('pipe', 'date +%Y%m%d%H%M%S') }}" + roles: + - openshift_facts + tasks: + - openshift_facts: + role: etcd + local_facts: {} + when: "'etcd' not in openshift" + + - stat: path=/var/lib/openshift + register: var_lib_openshift + + - stat: path=/var/lib/origin + register: var_lib_origin + + - name: Create origin symlink if necessary + file: src=/var/lib/openshift/ dest=/var/lib/origin state=link + when: var_lib_openshift.stat.exists == True and var_lib_origin.stat.exists == False + + - name: Check available disk space for etcd backup + # We assume to be using the data dir for all backups. + shell: > + df --output=avail -k {{ openshift.common.data_dir }} | tail -n 1 + register: avail_disk + + - name: Check current embedded etcd disk usage + shell: > + du -k {{ openshift.etcd.etcd_data_dir }} | tail -n 1 | cut -f1 + register: etcd_disk_usage + when: embedded_etcd | bool + + - name: Abort if insufficient disk space for etcd backup + fail: + msg: > + {{ etcd_disk_usage.stdout }} Kb disk space required for etcd backup, + {{ avail_disk.stdout }} Kb available. + when: (embedded_etcd | bool) and (etcd_disk_usage.stdout|int > avail_disk.stdout|int) + + - name: Install etcd (for etcdctl) + yum: + pkg: etcd + state: latest + + - name: Generate etcd backup + command: > + etcdctl backup --data-dir={{ openshift.etcd.etcd_data_dir }} + --backup-dir={{ openshift.common.data_dir }}/etcd-backup-{{ timestamp }} + + - name: Display location of etcd backup + debug: + msg: "Etcd backup created in {{ openshift.common.data_dir }}/etcd-backup-{{ timestamp }}" + + +- name: Update deployment type + hosts: OSEv3 + roles: + - openshift_facts + post_tasks: + - openshift_facts: + role: common + local_facts: + deployment_type: "{{ deployment_type }}" + + +- name: Perform upgrade version checking + hosts: masters[0] + tasks: + - name: Clean yum cache + command: yum clean all + + - name: Determine available versions + script: ../files/versions.sh {{ openshift.common.service_type }} openshift + register: g_versions_result + + - set_fact: + g_aos_versions: "{{ g_versions_result.stdout | from_yaml }}" + + - set_fact: + g_new_version: "{{ g_aos_versions.curr_version.split('-', 1).0 if g_aos_versions.avail_version is none else g_aos_versions.avail_version.split('-', 1).0 }}" + + - fail: + msg: This playbook requires Origin 1.0.6 or later + when: deployment_type == 'origin' and g_aos_versions.curr_version | version_compare('1.0.6','<') + + - fail: + msg: Atomic OpenShift 3.1 packages not found + when: g_aos_versions.curr_version | version_compare('3.0.2.900','<') and (g_aos_versions.avail_version is none or g_aos_versions.avail_version | version_compare('3.0.2.900','<')) + +- name: Upgrade masters + hosts: masters + vars: + openshift_version: "{{ openshift_pkg_version | default('') }}" + tasks: + - name: Upgrade to latest available kernel + yum: + pkg: kernel + state: latest + + - name: Upgrade master packages + command: yum update -y {{ openshift.common.service_type }}-master{{ openshift_version }} + + - name: Ensure python-yaml present for config upgrade + yum: + pkg: PyYAML + state: installed + + - name: Upgrade master configuration + openshift_upgrade_config: + from_version: '3.0' + to_version: '3.1' + role: master + config_base: "{{ hostvars[inventory_hostname].openshift.common.config_base }}" + + - set_fact: + master_certs_missing: True + master_cert_subdir: master-{{ openshift.common.hostname }} + master_cert_config_dir: "{{ openshift.common.config_base }}/master" + +- name: Create temp directory for syncing certs + hosts: localhost + gather_facts: no + tasks: + - name: Create local temp directory for syncing certs + local_action: command mktemp -d /tmp/openshift-ansible-XXXXXXX + register: g_master_mktemp + changed_when: False + +- name: Generate missing master certificates + hosts: masters[0] + vars: + master_hostnames: "{{ hostvars + | oo_select_keys(groups.masters) + | oo_collect('openshift.common.all_hostnames') + | oo_flatten | unique }}" + master_generated_certs_dir: "{{ openshift.common.config_base }}/generated-configs" + masters_needing_certs: "{{ hostvars + | oo_select_keys(groups.masters) + | difference([groups.masters.0]) }}" + sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" + openshift_deployment_type: "{{ deployment_type }}" + roles: + - openshift_master_certificates + post_tasks: + - name: Remove generated etcd client certs when using external etcd + file: + path: "{{ master_generated_certs_dir }}/{{ item.0.master_cert_subdir }}/{{ item.1 }}" + state: absent + when: groups.oo_etcd_to_config is defined and groups.oo_etcd_to_config + with_nested: + - masters_needing_certs + - - master.etcd-client.crt + - master.etcd-client.key + + - name: Create a tarball of the master certs + command: > + tar -czvf {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz + -C {{ master_generated_certs_dir }}/{{ item.master_cert_subdir }} . + with_items: masters_needing_certs + + - name: Retrieve the master cert tarball from the master + fetch: + src: "{{ master_generated_certs_dir }}/{{ item.master_cert_subdir }}.tgz" + dest: "{{ sync_tmpdir }}/" + flat: yes + fail_on_missing: yes + validate_checksum: yes + with_items: masters_needing_certs + +- name: Sync certs and restart masters post configuration change + hosts: masters + vars: + sync_tmpdir: "{{ hostvars.localhost.g_master_mktemp.stdout }}" + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + tasks: + - name: Unarchive the tarball on the master + unarchive: + src: "{{ sync_tmpdir }}/{{ master_cert_subdir }}.tgz" + dest: "{{ master_cert_config_dir }}" + when: inventory_hostname != groups.masters.0 + + - name: Restart master services + service: name="{{ openshift.common.service_type}}-master" state=restarted + when: not openshift_master_ha | bool + +- name: Destroy cluster + hosts: masters[0] + vars: + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + openshift_deployment_type: "{{ deployment_type }}" + pre_tasks: + - name: Check for configured cluster + stat: + path: /etc/corosync/corosync.conf + register: corosync_conf + when: openshift_master_ha | bool + - name: Destroy cluster + command: pcs cluster destroy --all + when: openshift_master_ha | bool and corosync_conf.stat.exists == true + +- name: Start pcsd on masters + hosts: masters + vars: + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + tasks: + - name: Start pcsd + service: name=pcsd enabled=yes state=started + when: openshift_master_ha | bool + +- name: Re-create cluster + hosts: masters[0] + vars: + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + openshift_deployment_type: "{{ deployment_type }}" + omc_cluster_hosts: "{{ groups.masters | join(' ') }}" + roles: + - role: openshift_master_cluster + when: openshift_master_ha | bool + +- name: Delete temporary directory on localhost + hosts: localhost + gather_facts: no + tasks: + - file: name={{ g_master_mktemp.stdout }} state=absent + changed_when: False + + +- name: Upgrade nodes + hosts: nodes + vars: + openshift_version: "{{ openshift_pkg_version | default('') }}" + roles: + - openshift_facts + tasks: + - name: Upgrade node packages + command: yum update -y {{ openshift.common.service_type }}-node{{ openshift_version }} + - name: Restart node services + service: name="{{ openshift.common.service_type }}-node" state=restarted + +- name: Update cluster policy and policy bindings + hosts: masters[0] + vars: + origin_reconcile_bindings: "{{ deployment_type == 'origin' and g_new_version | version_compare('1.0.6', '>') }}" + ent_reconcile_bindings: true + tasks: + - name: oadm policy reconcile-cluster-roles --confirm + command: > + {{ openshift.common.admin_binary}} --config={{ openshift.common.config_base }}/master/admin.kubeconfig + policy reconcile-cluster-roles --confirm + + - name: oadm policy reconcile-cluster-role-bindings --confirm + command: > + {{ openshift.common.admin_binary}} --config={{ openshift.common.config_base }}/master/admin.kubeconfig + policy reconcile-cluster-role-bindings + --exclude-groups=system:authenticated + --exclude-groups=system:unauthenticated + --exclude-users=system:anonymous + --additive-only=true --confirm + when: origin_reconcile_bindings | bool or ent_reconcile_bindings | bool + + +- name: Restart masters post reconcile + hosts: masters + vars: + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + tasks: + - name: Restart master services + service: name="{{ openshift.common.service_type}}-master" state=restarted + when: not openshift_master_ha | bool + +- name: Restart cluster post reconcile + hosts: masters[0] + vars: + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + tasks: + - name: Restart master cluster + command: pcs resource restart master + when: openshift_master_ha | bool + - name: Wait for the clustered master service to be available + wait_for: + host: "{{ openshift_master_cluster_vip }}" + port: 8443 + state: started + timeout: 180 + delay: 90 + when: openshift_master_ha | bool + +- name: Upgrade default router and registry + hosts: masters[0] + vars: + - registry_image: "{{ openshift.master.registry_url | replace( '${component}', 'docker-registry' ) | replace ( '${version}', 'v' + g_new_version ) }}" + - router_image: "{{ openshift.master.registry_url | replace( '${component}', 'haproxy-router' ) | replace ( '${version}', 'v' + g_new_version ) }}" + - oc_cmd: "{{ openshift.common.client_binary }} --config={{ openshift.common.config_base }}/master/admin.kubeconfig" + tasks: + - name: Check for default router + command: > + {{ oc_cmd }} get -n default dc/router + register: _default_router + failed_when: false + changed_when: false + - name: Check for allowHostNetwork and allowHostPorts + when: _default_router.rc == 0 + shell: > + {{ oc_cmd }} get -o yaml scc/privileged | /usr/bin/grep -e allowHostPorts -e allowHostNetwork + register: _scc + - name: Grant allowHostNetwork and allowHostPorts + when: + - _default_router.rc == 0 + - "'false' in _scc.stdout" + command: > + {{ oc_cmd }} patch scc/privileged -p '{"allowHostPorts":true,"allowHostNetwork":true}' --loglevel=9 + - name: Update deployment config to 1.0.4/3.0.1 spec + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p + '{"spec":{"strategy":{"rollingParams":{"updatePercent":-10},"spec":{"serviceAccount":"router","serviceAccountName":"router"}}}}' + - name: Switch to hostNetwork=true + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p '{"spec":{"template":{"spec":{"hostNetwork":true}}}}' + - name: Update router image to current version + when: _default_router.rc == 0 + command: > + {{ oc_cmd }} patch dc/router -p + '{"spec":{"template":{"spec":{"containers":[{"name":"router","image":"{{ router_image }}"}]}}}}' + + - name: Check for default registry + command: > + {{ oc_cmd }} get -n default dc/docker-registry + register: _default_registry + failed_when: false + changed_when: false + - name: Update registry image to current version + when: _default_registry.rc == 0 + command: > + {{ oc_cmd }} patch dc/docker-registry -p + '{"spec":{"template":{"spec":{"containers":[{"name":"registry","image":"{{ registry_image }}"}]}}}}' + +- name: Update image streams and templates + hosts: masters[0] + vars: + openshift_examples_import_command: "update" + openshift_deployment_type: "{{ deployment_type }}" + roles: + - openshift_examples + +- name: Ensure master services enabled + hosts: masters + vars: + openshift_master_ha: "{{ groups['masters'] | length > 1 }}" + tasks: + - name: Enable master services + service: name="{{ openshift.common.service_type}}-master" state=started enabled=yes + when: not openshift_master_ha | bool + +- name: Ensure node services enabled + hosts: nodes + tasks: + - name: Restart node services + service: name="{{ openshift.common.service_type }}-node" state=started enabled=yes + diff --git a/playbooks/common/openshift-etcd/config.yml b/playbooks/common/openshift-etcd/config.yml index 952960652..ed23ada88 100644 --- a/playbooks/common/openshift-etcd/config.yml +++ b/playbooks/common/openshift-etcd/config.yml @@ -13,6 +13,8 @@ hostname: "{{ openshift_hostname | default(None) }}" public_hostname: "{{ openshift_public_hostname | default(None) }}" deployment_type: "{{ openshift_deployment_type }}" + - role: etcd + local_facts: {} - name: Check status of etcd certificates stat: path: "{{ item }}" diff --git a/playbooks/common/openshift-master/config.yml b/playbooks/common/openshift-master/config.yml index b1da85d5d..1b3fba3aa 100644 --- a/playbooks/common/openshift-master/config.yml +++ b/playbooks/common/openshift-master/config.yml @@ -51,6 +51,9 @@ console_url: "{{ openshift_master_console_url | default(None) }}" console_use_ssl: "{{ openshift_master_console_use_ssl | default(None) }}" public_console_url: "{{ openshift_master_public_console_url | default(None) }}" + - role: etcd + local_facts: {} + when: openshift.master.embedded_etcd | bool - name: Check status of external etcd certificatees stat: path: "{{ openshift.common.config_base }}/master/{{ item }}" diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py index c108cd422..2e1075aca 100755 --- a/roles/openshift_facts/library/openshift_facts.py +++ b/roles/openshift_facts/library/openshift_facts.py @@ -528,7 +528,6 @@ def set_aggregate_facts(facts): first_svc_ip = str(IPNetwork(facts['master']['portal_net'])[1]) all_hostnames.add(first_svc_ip) internal_hostnames.add(first_svc_ip) - _add_etcd_data_dir_fact(facts) facts['common']['all_hostnames'] = list(all_hostnames) facts['common']['internal_hostnames'] = list(internal_hostnames) @@ -536,7 +535,7 @@ def set_aggregate_facts(facts): return facts -def _add_etcd_data_dir_fact(facts): +def set_etcd_facts_if_unset(facts): """ If using embedded etcd, loads the data directory from master-config.yaml. @@ -544,38 +543,39 @@ def _add_etcd_data_dir_fact(facts): If anything goes wrong parsing these, the fact will not be set. """ - if facts['master']['embedded_etcd']: - try: - # Parse master config to find actual etcd data dir: - master_cfg_path = os.path.join(facts['common']['config_base'], - 'master/master-config.yaml') - master_cfg_f = open(master_cfg_path, 'r') - config = yaml.safe_load(master_cfg_f.read()) - master_cfg_f.close() - - facts['master']['etcd_data_dir'] = \ - config['etcdConfig']['storageDirectory'] - # We don't want exceptions bubbling up here: - # pylint: disable=broad-except - except Exception: - pass - else: - # Read ETCD_DATA_DIR from /etc/etcd/etcd.conf: - try: - # Add a fake section for parsing: - ini_str = '[root]\n' + open('/etc/etcd/etcd.conf', 'r').read() - ini_fp = StringIO.StringIO(ini_str) - config = ConfigParser.RawConfigParser() - config.readfp(ini_fp) - etcd_data_dir = config.get('root', 'ETCD_DATA_DIR') - if etcd_data_dir.startswith('"') and etcd_data_dir.endswith('"'): - etcd_data_dir = etcd_data_dir[1:-1] - facts['master']['etcd_data_dir'] = etcd_data_dir - # We don't want exceptions bubbling up here: - # pylint: disable=broad-except - except Exception: - pass - + if 'etcd' in facts: + if 'master' in facts and facts['master']['embedded_etcd']: + try: + # Parse master config to find actual etcd data dir: + master_cfg_path = os.path.join(facts['common']['config_base'], + 'master/master-config.yaml') + master_cfg_f = open(master_cfg_path, 'r') + config = yaml.safe_load(master_cfg_f.read()) + master_cfg_f.close() + + facts['etcd']['etcd_data_dir'] = \ + config['etcdConfig']['storageDirectory'] + # We don't want exceptions bubbling up here: + # pylint: disable=broad-except + except Exception: + pass + else: + # Read ETCD_DATA_DIR from /etc/etcd/etcd.conf: + try: + # Add a fake section for parsing: + ini_str = '[root]\n' + open('/etc/etcd/etcd.conf', 'r').read() + ini_fp = StringIO.StringIO(ini_str) + config = ConfigParser.RawConfigParser() + config.readfp(ini_fp) + etcd_data_dir = config.get('root', 'ETCD_DATA_DIR') + if etcd_data_dir.startswith('"') and etcd_data_dir.endswith('"'): + etcd_data_dir = etcd_data_dir[1:-1] + facts['etcd']['etcd_data_dir'] = etcd_data_dir + # We don't want exceptions bubbling up here: + # pylint: disable=broad-except + except Exception: + pass + return facts def set_deployment_facts_if_unset(facts): """ Set Facts that vary based on deployment_type. This currently @@ -939,7 +939,7 @@ class OpenShiftFacts(object): Raises: OpenShiftFactsUnsupportedRoleError: """ - known_roles = ['common', 'master', 'node', 'master_sdn', 'node_sdn', 'dns'] + known_roles = ['common', 'master', 'node', 'master_sdn', 'node_sdn', 'dns', 'etcd'] def __init__(self, role, filename, local_facts): self.changed = False @@ -982,6 +982,7 @@ class OpenShiftFacts(object): facts = set_deployment_facts_if_unset(facts) facts = set_version_facts_if_unset(facts) facts = set_aggregate_facts(facts) + facts = set_etcd_facts_if_unset(facts) return dict(openshift=facts) def get_defaults(self, roles): diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 4c55002fb..6cdc19f20 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -177,7 +177,8 @@ Notes: h.public_ip, h.hostname, h.public_hostname])) - output = "%s\n%s" % (output, ",".join([h.ip, + output = "%s\n%s" % (output, ",".join([h.connect_to, + h.ip, h.public_ip, h.hostname, h.public_hostname])) @@ -493,7 +494,7 @@ def upgrade(ctx): verbose = ctx.obj['verbose'] if len(oo_cfg.hosts) == 0: - click.echo("No hosts defined in: %s" % oo_cfg['configuration']) + click.echo("No hosts defined in: %s" % oo_cfg.config_path) sys.exit(1) # Update config to reflect the version we're targetting, we'll write diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py index cf51bb404..9c97e6e93 100644 --- a/utils/src/ooinstall/oo_config.py +++ b/utils/src/ooinstall/oo_config.py @@ -116,6 +116,9 @@ class OOConfig(object): def _upgrade_legacy_config(self): new_hosts = [] + remove_settings = ['validated_facts', 'Description', 'Name', + 'Subscription', 'Vendor', 'Version', 'masters', 'nodes'] + if 'validated_facts' in self.settings: for key, value in self.settings['validated_facts'].iteritems(): value['connect_to'] = key @@ -126,10 +129,9 @@ class OOConfig(object): 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] + if s in self.settings: + del self.settings[s] # A legacy config implies openshift-enterprise 3.0: self.settings['variant'] = 'openshift-enterprise' diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index 489a0f7c1..e4c808e85 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -164,8 +164,10 @@ def run_uninstall_playbook(verbose=False): def run_upgrade_playbook(verbose=False): + # TODO: do not hardcode the upgrade playbook, add ability to select the + # right playbook depending on the type of upgrade. playbook = os.path.join(CFG.settings['ansible_playbook_directory'], - 'playbooks/adhoc/upgrades/upgrade.yml') + 'playbooks/byo/openshift-cluster/upgrades/v3_0_to_v3_1/upgrade.yml') # TODO: Upgrade inventory for upgrade? inventory_file = generate_inventory(CFG.hosts) facts_env = os.environ.copy() -- cgit v1.2.3