From 4a11a05a59348dc2875a017c67b0ed88808dc06c Mon Sep 17 00:00:00 2001 From: Samuel Munilla Date: Mon, 7 Mar 2016 13:47:05 -0500 Subject: Arbitrary Installer yaml Initial build of new, more flexible installer config file format. --- utils/src/ooinstall/cli_installer.py | 141 ++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 51 deletions(-) (limited to 'utils/src/ooinstall/cli_installer.py') diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index d6f2540bc..d052ad852 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -10,7 +10,7 @@ import click from ooinstall import openshift_ansible from ooinstall import OOConfig from ooinstall.oo_config import OOConfigInvalidHostError -from ooinstall.oo_config import Host +from ooinstall.oo_config import Host, Role from ooinstall.variants import find_variant, get_variant_version_combos DEFAULT_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-utils/ansible.cfg' @@ -121,21 +121,23 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen click.echo(message) hosts = [] + roles = set(['master', 'node', 'storage']) more_hosts = True num_masters = 0 while more_hosts: host_props = {} + host_props['roles'] = [] host_props['connect_to'] = click.prompt('Enter hostname or IP address', value_proc=validate_prompt_hostname) if not masters_set: if click.confirm('Will this host be an OpenShift Master?'): - host_props['master'] = True + host_props['roles'].append('master') num_masters += 1 if oo_cfg.settings['variant_version'] == '3.0': masters_set = True - host_props['node'] = True + host_props['roles'].append('node') host_props['containerized'] = False if oo_cfg.settings['variant_version'] != '3.0': @@ -152,6 +154,7 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen hosts.append(host) + if print_summary: print_installation_summary(hosts, oo_cfg.settings['variant_version']) @@ -163,11 +166,12 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen if num_masters >= 3: collect_master_lb(hosts) + roles.add('master_lb') if not existing_env: collect_storage_host(hosts) - return hosts + return hosts, roles def print_installation_summary(hosts, version=None): @@ -184,9 +188,9 @@ def print_installation_summary(hosts, version=None): for host in hosts: print_host_summary(hosts, host) - masters = [host for host in hosts if host.master] - nodes = [host for host in hosts if host.node] - dedicated_nodes = [host for host in hosts if host.node and not host.master] + masters = [host for host in hosts if host.is_master()] + nodes = [host for host in hosts if host.is_node()] + dedicated_nodes = [host for host in hosts if host.is_node() and not host.is_master()] click.echo('') click.echo('Total OpenShift Masters: %s' % len(masters)) click.echo('Total OpenShift Nodes: %s' % len(nodes)) @@ -226,26 +230,26 @@ deployment.""" def print_host_summary(all_hosts, host): click.echo("- %s" % host.connect_to) - if host.master: + if host.is_master(): click.echo(" - OpenShift Master") - if host.node: + if host.is_node(): if host.is_dedicated_node(): click.echo(" - OpenShift Node (Dedicated)") elif host.is_schedulable_node(all_hosts): click.echo(" - OpenShift Node") else: click.echo(" - OpenShift Node (Unscheduled)") - if host.master_lb: + if host.is_master_lb(): if host.preconfigured: click.echo(" - Load Balancer (Preconfigured)") else: click.echo(" - Load Balancer (HAProxy)") - if host.master: + if host.is_master(): if host.is_etcd_member(all_hosts): click.echo(" - Etcd Member") else: click.echo(" - Etcd (Embedded)") - if host.storage: + if host.is_storage(): click.echo(" - Storage") @@ -279,7 +283,7 @@ hostname. # Make sure this host wasn't already specified: for host in hosts: - if host.connect_to == hostname and (host.master or host.node): + if host.connect_to == hostname and (host.is_master() or host.is_node()): raise click.BadParameter('Cannot re-use "%s" as a load balancer, ' 'please specify a separate host' % hostname) return hostname @@ -289,9 +293,7 @@ hostname. install_haproxy = \ click.confirm('Should the reference haproxy load balancer be installed on this host?') host_props['preconfigured'] = not install_haproxy - host_props['master'] = False - host_props['node'] = False - host_props['master_lb'] = True + host_props['roles'] = ['master_lb'] master_lb = Host(**host_props) hosts.append(master_lb) @@ -309,14 +311,14 @@ Note: Containerized storage hosts are not currently supported. click.echo(message) host_props = {} - first_master = next(host for host in hosts if host.master) + first_master = next(host for host in hosts if host.is_master()) hostname_or_ip = click.prompt('Enter hostname or IP address', value_proc=validate_prompt_hostname, default=first_master.connect_to) existing, existing_host = is_host_already_node_or_master(hostname_or_ip, hosts) - if existing and existing_host.node: - existing_host.storage = True + if existing and existing_host.is_node(): + existing_host.roles.append('storage') else: host_props['connect_to'] = hostname_or_ip host_props['preconfigured'] = False @@ -331,14 +333,14 @@ def is_host_already_node_or_master(hostname, hosts): existing_host = None for host in hosts: - if host.connect_to == hostname and (host.master or host.node): + if host.connect_to == hostname and (host.is_master() or host.is_node()): is_existing = True existing_host = host return is_existing, existing_host def confirm_hosts_facts(oo_cfg, callback_facts): - hosts = oo_cfg.hosts + hosts = oo_cfg.deployment.hosts click.clear() message = """ A list of the facts gathered from the provided hosts follows. Because it is @@ -414,19 +416,20 @@ Edit %s with the desired values and run `atomic-openshift-installer --unattended def check_hosts_config(oo_cfg, unattended): click.clear() - masters = [host for host in oo_cfg.hosts if host.master] + masters = [host for host in oo_cfg.deployment.hosts if host.is_master()] if len(masters) == 2: click.echo("A minimum of 3 Masters are required for HA deployments.") sys.exit(1) if len(masters) > 1: - master_lb = [host for host in oo_cfg.hosts if host.master_lb] + master_lb = [host for host in oo_cfg.deployment.hosts if host.is_master_lb()] + if len(master_lb) > 1: click.echo('ERROR: More than one Master load balancer specified. Only one is allowed.') sys.exit(1) elif len(master_lb) == 1: - if master_lb[0].master or master_lb[0].node: + if master_lb[0].is_master() or master_lb[0].is_node(): click.echo('ERROR: The Master load balancer is configured as a master or node. ' \ 'Please correct this.') sys.exit(1) @@ -440,7 +443,8 @@ https://docs.openshift.org/latest/install_config/install/advanced_install.html#m click.echo(message) sys.exit(1) - dedicated_nodes = [host for host in oo_cfg.hosts if host.node and not host.master] + dedicated_nodes = [host for host in oo_cfg.deployment.hosts \ + if host.is_node() and not host.is_master()] if len(dedicated_nodes) == 0: message = """ WARNING: No dedicated Nodes specified. By default, colocated Masters have @@ -481,7 +485,7 @@ def confirm_continue(message): def error_if_missing_info(oo_cfg): missing_info = False - if not oo_cfg.hosts: + if not oo_cfg.deployment.hosts: missing_info = True click.echo('For unattended installs, hosts must be specified on the ' 'command line or in the config file: %s' % oo_cfg.config_path) @@ -515,9 +519,24 @@ def error_if_missing_info(oo_cfg): for host in missing_facts: click.echo('Host "%s" missing facts: %s' % (host, ", ".join(missing_facts[host]))) + # check that all listed host roles are included + listed_roles = get_host_roles_set(oo_cfg) + configured_roles = set([role for role in oo_cfg.deployment.roles]) + if listed_roles != configured_roles: + missing_info = True + click.echo('Any roles assigned to hosts must be defined.') + if missing_info: sys.exit(1) +def get_host_roles_set(oo_cfg): + roles_set = set() + for host in oo_cfg.deployment.hosts: + for role in host.roles: + roles_set.add(role) + + return roles_set + def get_proxy_hostnames_and_excludes(): message = """ If a proxy is needed to reach HTTP and HTTPS traffic please enter the name below. @@ -574,35 +593,51 @@ https://docs.openshift.com/enterprise/latest/admin_guide/install/prerequisites.h confirm_continue(message) click.clear() - if oo_cfg.settings.get('ansible_ssh_user', '') == '': + if not oo_cfg.settings.get('ansible_ssh_user', ''): oo_cfg.settings['ansible_ssh_user'] = get_ansible_ssh_user() click.clear() - if oo_cfg.settings.get('variant', '') == '': + if not oo_cfg.settings.get('variant', ''): variant, version = get_variant_and_version() oo_cfg.settings['variant'] = variant.name oo_cfg.settings['variant_version'] = version.name click.clear() - if not oo_cfg.hosts: - oo_cfg.hosts = collect_hosts(oo_cfg) + if not oo_cfg.deployment.hosts: + oo_cfg.deployment.hosts, roles = collect_hosts(oo_cfg) + + for role in roles: + oo_cfg.deployment.roles[role] = Role(name=role, variables={}) click.clear() - if not oo_cfg.settings.get('master_routingconfig_subdomain', None): - oo_cfg.settings['master_routingconfig_subdomain'] = get_master_routingconfig_subdomain() + if not 'master_routingconfig_subdomain' in oo_cfg.deployment.variables: + oo_cfg.deployment.variables['master_routingconfig_subdomain'] = \ + get_master_routingconfig_subdomain() click.clear() if not oo_cfg.settings.get('openshift_http_proxy', None) and \ LooseVersion(oo_cfg.settings.get('variant_version', '0.0')) >= LooseVersion('3.2'): http_proxy, https_proxy, proxy_excludes = get_proxy_hostnames_and_excludes() - oo_cfg.settings['openshift_http_proxy'] = http_proxy - oo_cfg.settings['openshift_https_proxy'] = https_proxy - oo_cfg.settings['openshift_no_proxy'] = proxy_excludes + oo_cfg.deployment.variables['proxy_http'] = http_proxy + oo_cfg.deployment.variables['proxy_https'] = https_proxy + oo_cfg.deployment.variables['proxy_exclude_hosts'] = proxy_excludes click.clear() return oo_cfg +def get_role_variable(oo_cfg, role_name, variable_name): + try: + target_role = next(role for role in oo_cfg.deployment.roles if role.name is role_name) + target_variable = target_role.variables[variable_name] + return target_variable + except (StopIteration, KeyError): + return None + +def set_role_variable(oo_cfg, role_name, variable_name, variable_value): + target_role = next(role for role in oo_cfg.deployment.roles if role.name is role_name) + target_role[variable_name] = variable_value + def collect_new_nodes(oo_cfg): click.clear() click.echo('*** New Node Configuration ***') @@ -610,14 +645,15 @@ def collect_new_nodes(oo_cfg): Add new nodes here """ click.echo(message) - return collect_hosts(oo_cfg, existing_env=True, masters_set=True, print_summary=False) + new_nodes, _ = collect_hosts(oo_cfg, existing_env=True, masters_set=True, print_summary=False) + return new_nodes def get_installed_hosts(hosts, callback_facts): installed_hosts = [] # count nativeha lb as an installed host try: - first_master = next(host for host in hosts if host.master) + first_master = next(host for host in hosts if host.is_master()) lb_hostname = callback_facts[first_master.connect_to]['master'].get('cluster_hostname', '') lb_host = \ next(host for host in hosts if host.ip == callback_facts[lb_hostname]['common']['ip']) @@ -636,17 +672,17 @@ def is_installed_host(host, callback_facts): callback_facts[host.connect_to]['common'].get('version', '') and \ callback_facts[host.connect_to]['common'].get('version', '') != 'None' - return version_found or host.master_lb or host.preconfigured + return version_found # 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. - hosts_to_run_on = list(oo_cfg.hosts) + hosts_to_run_on = list(oo_cfg.deployment.hosts) # Check if master or nodes already have something installed - installed_hosts = get_installed_hosts(oo_cfg.hosts, callback_facts) + installed_hosts = get_installed_hosts(oo_cfg.deployment.hosts, callback_facts) if len(installed_hosts) > 0: click.echo('Installed environment detected.') # This check has to happen before we start removing hosts later in this method @@ -668,11 +704,11 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force, verbose): # present a message listing already installed hosts and remove hosts if needed for host in installed_hosts: - if host.master: + if host.is_master(): click.echo("{} is already an OpenShift Master".format(host)) # Masters stay in the list, we need to run against them when adding # new nodes. - elif host.node: + elif host.is_node(): click.echo("{} is already an OpenShift Node".format(host)) # force is only used for reinstalls so we don't want to remove # anything. @@ -699,11 +735,11 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force, verbose): new_nodes = collect_new_nodes(oo_cfg) hosts_to_run_on.extend(new_nodes) - oo_cfg.hosts.extend(new_nodes) + oo_cfg.deployment.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, verbose) + callback_facts, error = openshift_ansible.default_facts(oo_cfg.deployment.hosts, verbose) if error or callback_facts is None: click.echo("There was a problem fetching the required information. See " \ "{} for details.".format(oo_cfg.settings['ansible_log_path'])) @@ -800,14 +836,14 @@ def uninstall(ctx): oo_cfg = ctx.obj['oo_cfg'] verbose = ctx.obj['verbose'] - if len(oo_cfg.hosts) == 0: + if len(oo_cfg.deployment.hosts) == 0: click.echo("No hosts defined in: %s" % oo_cfg.config_path) sys.exit(1) click.echo("OpenShift will be uninstalled from the following hosts:\n") if not ctx.obj['unattended']: # Prompt interactively to confirm: - for host in oo_cfg.hosts: + for host in oo_cfg.deployment.hosts: click.echo(" * %s" % host.connect_to) proceed = click.confirm("\nDo you wish to proceed?") if not proceed: @@ -841,7 +877,7 @@ def upgrade(ctx, latest_minor, next_major): }, } - if len(oo_cfg.hosts) == 0: + if len(oo_cfg.deployment.hosts) == 0: click.echo("No hosts defined in: %s" % oo_cfg.config_path) sys.exit(1) @@ -901,7 +937,7 @@ def upgrade(ctx, latest_minor, next_major): click.echo("Openshift will be upgraded from %s %s to latest %s %s on the following hosts:\n" % ( variant, old_version, oo_cfg.settings['variant'], new_version)) - for host in oo_cfg.hosts: + for host in oo_cfg.deployment.hosts: click.echo(" * %s" % host.connect_to) if not ctx.obj['unattended']: @@ -936,10 +972,11 @@ def install(ctx, force, gen_inventory): check_hosts_config(oo_cfg, ctx.obj['unattended']) - print_installation_summary(oo_cfg.hosts, oo_cfg.settings.get('variant_version', None)) + print_installation_summary(oo_cfg.deployment.hosts, oo_cfg.settings.get('variant_version', None)) 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.deployment.hosts, verbose) + if error or callback_facts is None: click.echo("There was a problem fetching the required information. " \ "Please see {} for details.".format(oo_cfg.settings['ansible_log_path'])) @@ -959,6 +996,7 @@ def install(ctx, force, gen_inventory): # Write quick installer config file to disk: oo_cfg.save_to_disk() + # Write ansible inventory file to disk: inventory_file = openshift_ansible.generate_inventory(hosts_to_run_on) @@ -977,8 +1015,9 @@ If changes are needed please edit the config file above and re-run. if not ctx.obj['unattended']: confirm_continue(message) - error = openshift_ansible.run_main_playbook(inventory_file, oo_cfg.hosts, + error = openshift_ansible.run_main_playbook(inventory_file, oo_cfg.deployment.hosts, hosts_to_run_on, verbose) + if error: # The bootstrap script will print out the log location. message = """ -- cgit v1.2.3