From 0ee19018001ed6a0a578aa5b7b75e096d6c014d6 Mon Sep 17 00:00:00 2001
From: Samuel Munilla <smunilla@redhat.com>
Date: Wed, 18 Nov 2015 10:59:04 -0500
Subject: atomic-openshift-installer: HA for quick installer

This adds the ability to quickly set up a multi-master environment.
---
 utils/src/ooinstall/cli_installer.py     | 82 ++++++++++++++++++++++++++++----
 utils/src/ooinstall/oo_config.py         |  9 +++-
 utils/src/ooinstall/openshift_ansible.py | 36 ++++++++++++--
 3 files changed, 110 insertions(+), 17 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index 0b3af8829..1b4a67259 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -72,7 +72,7 @@ def delete_hosts(hosts):
                 click.echo("\"{}\" doesn't coorespond to any valid input.".format(del_idx))
     return hosts, None
 
-def collect_hosts(master_set=False):
+def collect_hosts(masters_set=False):
     """
         Collect host information from user. This will later be filled in using
         ansible.
@@ -102,17 +102,20 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
 
     hosts = []
     more_hosts = True
+    num_masters = 0
     while more_hosts:
         host_props = {}
-        hostname_or_ip = click.prompt('Enter hostname or IP address:',
-                                      default='',
-                                      value_proc=validate_prompt_hostname)
-
-        host_props['connect_to'] = hostname_or_ip
-        if not master_set:
-            is_master = click.confirm('Will this host be an OpenShift Master?')
-            host_props['master'] = is_master
-            master_set = is_master
+        host_props['connect_to'] = click.prompt('Enter hostname or IP address:',
+                                                default='',
+                                                value_proc=validate_prompt_hostname)
+
+        if not masters_set:
+            if click.confirm('Will this host be an OpenShift Master?'):
+                host_props['master'] = True
+                num_masters += 1
+                if num_masters >= 3:
+                    masters_set = True
+                    hosts.append(collect_ha_proxy())
         host_props['node'] = True
 
         #TODO: Reenable this option once container installs are out of tech preview
@@ -132,6 +135,29 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
         more_hosts = click.confirm('Do you want to add additional hosts?')
     return hosts
 
+def collect_ha_proxy():
+    """
+    Get an HA proxy from the user
+    """
+    message = """
+Setting up High Availability Masters requires a load balancing solution.
+Please provide a host that will be configured as a proxy. This can either be
+an existing load balancer configured to balance all masters on port 8443 or a
+new host that will have HAProxy installed on it.
+"""
+    click.echo(message)
+    host_props = {}
+    host_props['connect_to'] = click.prompt('Enter hostname or IP address:',
+                                            default='',
+                                            value_proc=validate_prompt_hostname)
+    host_props['run_on'] = click.confirm('Is this a clean host you want to install HAProxy on?')
+    host_props['master'] = False
+    host_props['node'] = False
+    host_props['ha_proxy'] = True
+    ha_proxy = Host(**host_props)
+
+    return ha_proxy
+
 def confirm_hosts_facts(oo_cfg, callback_facts):
     hosts = oo_cfg.hosts
     click.clear()
@@ -199,6 +225,40 @@ Edit %s with the desired values and run `atomic-openshift-installer --unattended
         sys.exit(0)
     return default_facts
 
+
+
+def check_hosts_config(oo_cfg):
+    click.clear()
+    masters = [host for host in oo_cfg.hosts if host.master]
+    if len(masters) > 1:
+        ha_proxy = [host for host in oo_cfg.hosts if host.ha_proxy]
+        click.echo(ha_proxy)
+        if len(ha_proxy) > 1:
+            click.echo('More than one HAProxy specified. Only one proxy is allowed.')
+            sys.exit(0)
+        elif len(ha_proxy) == 1:
+            if ha_proxy[0].master or ha_proxy[0].node:
+                click.echo('HAProxy is configured as a master or node. Please correct this.')
+                sys.exit(0)
+        else:
+            message = """
+No HAProxy given in config. Either specify one or provide a load balancing solution
+of your choice to balance the master API (port 8443) on all master hosts.
+
+https://docs.openshift.org/latest/install_config/install/advanced_install.html#multiple-masters
+"""
+            confirm_continue(message)
+
+    nodes = [host.node for host in oo_cfg.hosts]
+    if len(masters) == len(nodes):
+        message = """
+No dedicated Nodes specified. By default, colocated Masters have their Nodes set to unscheduleable.
+Would you like to label the colocated masters as scheduleable?
+"""
+        confirm_continue(message)
+
+    return
+
 def get_variant_and_version():
     message = "\nWhich variant would you like to install?\n\n"
 
@@ -555,6 +615,8 @@ def install(ctx, force):
     else:
         oo_cfg = get_missing_info_from_user(oo_cfg)
 
+    check_hosts_config(oo_cfg)
+
     click.echo('Gathering information from hosts...')
     callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts,
         verbose)
diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py
index 9c97e6e93..6b4f36204 100644
--- a/utils/src/ooinstall/oo_config.py
+++ b/utils/src/ooinstall/oo_config.py
@@ -36,19 +36,24 @@ class Host(object):
         self.public_ip = kwargs.get('public_ip', None)
         self.public_hostname = kwargs.get('public_hostname', None)
         self.connect_to = kwargs.get('connect_to', None)
+        self.run_on = kwargs.get('run_on', None)
 
         # Should this host run as an OpenShift master:
         self.master = kwargs.get('master', False)
 
         # Should this host run as an OpenShift node:
         self.node = kwargs.get('node', False)
+
+        # Should this host run as an HAProxy:
+        self.ha_proxy = kwargs.get('ha_proxy', False)
+
         self.containerized = kwargs.get('containerized', False)
 
         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:
+        if self.master is False and self.node is False and self.ha_proxy is False:
             raise OOConfigInvalidHostError(
                 "You must specify each host as either a master or a node.")
 
@@ -62,7 +67,7 @@ class Host(object):
         """ Used when exporting to yaml. """
         d = {}
         for prop in ['ip', 'hostname', 'public_ip', 'public_hostname',
-                     'master', 'node', 'containerized', 'connect_to']:
+                     'master', 'node', 'ha_proxy', 'containerized', 'connect_to', 'run_on']:
             # If the property is defined (not None or False), export it:
             if getattr(self, prop):
                 d[prop] = getattr(self, prop)
diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index 372f27bda..ec97c4144 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -17,14 +17,31 @@ def set_config(cfg):
 
 def generate_inventory(hosts):
     global CFG
+    masters = [host for host in hosts if host.master]
+    nodes = [host for host in hosts if host.node]
+    proxy = next((host for host in hosts if host.ha_proxy), None)
+    multiple_masters = len(masters) > 1
 
     base_inventory_path = CFG.settings['ansible_inventory_path']
     base_inventory = open(base_inventory_path, 'w')
-    base_inventory.write('\n[OSEv3:children]\nmasters\nnodes\n')
+
+    base_inventory.write('\n[OSEv3:children]\n')
+    base_inventory.write('masters\n')
+    base_inventory.write('nodes\n')
+    if multiple_masters:
+        base_inventory.write('etcd\n')
+    if getattr(proxy, 'run_on', False):
+        base_inventory.write('lb\n')
+
     base_inventory.write('\n[OSEv3:vars]\n')
     base_inventory.write('ansible_ssh_user={}\n'.format(CFG.settings['ansible_ssh_user']))
     if CFG.settings['ansible_ssh_user'] != 'root':
         base_inventory.write('ansible_become=true\n')
+    if multiple_masters:
+        base_inventory.write('openshift_master_cluster_method=native\n')
+        base_inventory.write("openshift_master_cluster_hostname={}\n".format(proxy.hostname))
+        base_inventory.write("openshift_master_cluster_public_hostname={}\n".format(proxy.public_hostname))
+
 
     # Find the correct deployment type for ansible:
     ver = find_variant(CFG.settings['variant'],
@@ -45,19 +62,28 @@ def generate_inventory(hosts):
             "'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)
     for master in masters:
         write_host(master, base_inventory)
+
+    if len(masters) > 1:
+        base_inventory.write('\n[etcd]\n')
+        for master in masters:
+            write_host(master, base_inventory)
+
     base_inventory.write('\n[nodes]\n')
-    nodes = (host for host in hosts if host.node)
     for node in nodes:
         # TODO: Until the Master can run the SDN itself we have to configure the Masters
         # as Nodes too.
         scheduleable = True
         # If there's only one Node and it's also a Master we want it to be scheduleable:
-        if node in masters and len(masters) != 1:
+        if node in masters and len(masters) != len(nodes):
             scheduleable = False
         write_host(node, base_inventory, scheduleable)
+
+    if getattr(proxy, 'run_on', False):
+        base_inventory.write('\n[lb]\n')
+        write_host(proxy, base_inventory)
+
     base_inventory.close()
     return base_inventory_path
 
@@ -118,6 +144,7 @@ def default_facts(hosts, verbose=False):
     facts_env = os.environ.copy()
     facts_env["OO_INSTALL_CALLBACK_FACTS_YAML"] = CFG.settings['ansible_callback_facts_yaml']
     facts_env["ANSIBLE_CALLBACK_PLUGINS"] = CFG.settings['ansible_plugins_directory']
+    facts_env["OPENSHIFT_MASTER_CLUSTER_METHOD"] = 'native'
     if 'ansible_log_path' in CFG.settings:
         facts_env["ANSIBLE_LOG_PATH"] = CFG.settings['ansible_log_path']
     if 'ansible_config' in CFG.settings:
@@ -176,4 +203,3 @@ def run_upgrade_playbook(verbose=False):
     if 'ansible_config' in CFG.settings:
         facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config']
     return run_ansible(playbook, inventory_file, facts_env, verbose)
-
-- 
cgit v1.2.3


From d446b2fe458444a88ceffd1d1966d6814b5185b5 Mon Sep 17 00:00:00 2001
From: Samuel Munilla <smunilla@redhat.com>
Date: Fri, 20 Nov 2015 10:41:42 -0500
Subject: Enforce 1 or 3 masters

---
 utils/src/ooinstall/cli_installer.py | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index 1b4a67259..fce8f9b22 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -113,9 +113,12 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
             if click.confirm('Will this host be an OpenShift Master?'):
                 host_props['master'] = True
                 num_masters += 1
+
+                if num_masters > 1:
+                    hosts.append(collect_ha_proxy())
+
                 if num_masters >= 3:
                     masters_set = True
-                    hosts.append(collect_ha_proxy())
         host_props['node'] = True
 
         #TODO: Reenable this option once container installs are out of tech preview
@@ -132,7 +135,8 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
 
         hosts.append(host)
 
-        more_hosts = click.confirm('Do you want to add additional hosts?')
+        if num_masters <= 1 or num_masters >= 3:
+            more_hosts = click.confirm('Do you want to add additional hosts?')
     return hosts
 
 def collect_ha_proxy():
@@ -144,6 +148,8 @@ Setting up High Availability Masters requires a load balancing solution.
 Please provide a host that will be configured as a proxy. This can either be
 an existing load balancer configured to balance all masters on port 8443 or a
 new host that will have HAProxy installed on it.
+
+This will also require you to set a third master.
 """
     click.echo(message)
     host_props = {}
-- 
cgit v1.2.3


From 296d1283202fe92de3045eab8bbc60db192f3a46 Mon Sep 17 00:00:00 2001
From: Samuel Munilla <smunilla@redhat.com>
Date: Fri, 20 Nov 2015 10:56:19 -0500
Subject: Breakup inventory writing

---
 utils/src/ooinstall/openshift_ansible.py | 40 +++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 16 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index ec97c4144..ff674153d 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -25,23 +25,9 @@ def generate_inventory(hosts):
     base_inventory_path = CFG.settings['ansible_inventory_path']
     base_inventory = open(base_inventory_path, 'w')
 
-    base_inventory.write('\n[OSEv3:children]\n')
-    base_inventory.write('masters\n')
-    base_inventory.write('nodes\n')
-    if multiple_masters:
-        base_inventory.write('etcd\n')
-    if getattr(proxy, 'run_on', False):
-        base_inventory.write('lb\n')
-
-    base_inventory.write('\n[OSEv3:vars]\n')
-    base_inventory.write('ansible_ssh_user={}\n'.format(CFG.settings['ansible_ssh_user']))
-    if CFG.settings['ansible_ssh_user'] != 'root':
-        base_inventory.write('ansible_become=true\n')
-    if multiple_masters:
-        base_inventory.write('openshift_master_cluster_method=native\n')
-        base_inventory.write("openshift_master_cluster_hostname={}\n".format(proxy.hostname))
-        base_inventory.write("openshift_master_cluster_public_hostname={}\n".format(proxy.public_hostname))
+    write_inventory_children(base_inventory, multiple_masters, proxy)
 
+    write_inventory_vars(base_inventory, multiple_masters, proxy)
 
     # Find the correct deployment type for ansible:
     ver = find_variant(CFG.settings['variant'],
@@ -87,6 +73,28 @@ def generate_inventory(hosts):
     base_inventory.close()
     return base_inventory_path
 
+def write_inventory_children(base_inventory, multiple_masters, proxy):
+    global CFG
+
+    base_inventory.write('\n[OSEv3:children]\n')
+    base_inventory.write('masters\n')
+    base_inventory.write('nodes\n')
+    if multiple_masters:
+        base_inventory.write('etcd\n')
+    if getattr(proxy, 'run_on', False):
+        base_inventory.write('lb\n')
+
+def write_inventory_vars(base_inventory, multiple_masters, proxy):
+    global CFG
+    base_inventory.write('\n[OSEv3:vars]\n')
+    base_inventory.write('ansible_ssh_user={}\n'.format(CFG.settings['ansible_ssh_user']))
+    if CFG.settings['ansible_ssh_user'] != 'root':
+        base_inventory.write('ansible_become=true\n')
+    if multiple_masters:
+        base_inventory.write('openshift_master_cluster_method=native\n')
+        base_inventory.write("openshift_master_cluster_hostname={}\n".format(proxy.hostname))
+        base_inventory.write("openshift_master_cluster_public_hostname={}\n".format(proxy.public_hostname))
+
 
 def write_host(host, inventory, scheduleable=True):
     global CFG
-- 
cgit v1.2.3


From 16e373e9c71f929e3eaf5d747e1f1ad9057c0184 Mon Sep 17 00:00:00 2001
From: Samuel Munilla <smunilla@redhat.com>
Date: Fri, 20 Nov 2015 15:34:35 -0500
Subject: atomic-openshift-installer: Reverse version and host collection

Reverse the order we ask two questions: What variant the user wants
to install and which hosts to install on. This lets us avoid asking
for multiple masters for 3.0 installs.
---
 utils/src/ooinstall/cli_installer.py | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index fce8f9b22..01093379f 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -72,7 +72,7 @@ def delete_hosts(hosts):
                 click.echo("\"{}\" doesn't coorespond to any valid input.".format(del_idx))
     return hosts, None
 
-def collect_hosts(masters_set=False):
+def collect_hosts(version=None, masters_set=False):
     """
         Collect host information from user. This will later be filled in using
         ansible.
@@ -117,7 +117,7 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
                 if num_masters > 1:
                     hosts.append(collect_ha_proxy())
 
-                if num_masters >= 3:
+                if num_masters >= 3 or version == '3.0':
                     masters_set = True
         host_props['node'] = True
 
@@ -265,7 +265,7 @@ Would you like to label the colocated masters as scheduleable?
 
     return
 
-def get_variant_and_version():
+def get_variant_and_version(multi_master=False):
     message = "\nWhich variant would you like to install?\n\n"
 
     i = 1
@@ -277,6 +277,8 @@ def get_variant_and_version():
     message = "%s\n" % message
 
     click.echo(message)
+    if multi_master:
+        click.echo('NOTE: 3.0 installations are not')
     response = click.prompt("Choose a variant from above: ", default=1)
     product, version = combos[response - 1]
 
@@ -358,16 +360,16 @@ https://docs.openshift.com/enterprise/latest/admin_guide/install/prerequisites.h
         oo_cfg.settings['ansible_ssh_user'] = get_ansible_ssh_user()
         click.clear()
 
-    if not oo_cfg.hosts:
-        oo_cfg.hosts = collect_hosts()
-        click.clear()
-
     if 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(version=oo_cfg.settings['variant_version'])
+        click.clear()
+
     return oo_cfg
 
 
@@ -378,7 +380,7 @@ def collect_new_nodes():
 Add new nodes here
     """
     click.echo(message)
-    return collect_hosts(True)
+    return collect_hosts(masters_set=True)
 
 def get_installed_hosts(hosts, callback_facts):
     installed_hosts = []
-- 
cgit v1.2.3


From ac6bc198d469315e7fec2452211c13d37abca795 Mon Sep 17 00:00:00 2001
From: Samuel Munilla <smunilla@redhat.com>
Date: Fri, 20 Nov 2015 15:58:05 -0500
Subject: atomic-openshift-installer: Rename ha_proxy

Rename ha_proxy variables and methods to 'master_lb' to better
future-proof things.
---
 utils/src/ooinstall/cli_installer.py     | 20 ++++++++++----------
 utils/src/ooinstall/oo_config.py         |  6 +++---
 utils/src/ooinstall/openshift_ansible.py |  2 +-
 3 files changed, 14 insertions(+), 14 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index 01093379f..ac9d884d9 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -115,7 +115,7 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
                 num_masters += 1
 
                 if num_masters > 1:
-                    hosts.append(collect_ha_proxy())
+                    hosts.append(collect_master_lb())
 
                 if num_masters >= 3 or version == '3.0':
                     masters_set = True
@@ -139,7 +139,7 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
             more_hosts = click.confirm('Do you want to add additional hosts?')
     return hosts
 
-def collect_ha_proxy():
+def collect_master_lb():
     """
     Get an HA proxy from the user
     """
@@ -159,10 +159,10 @@ This will also require you to set a third master.
     host_props['run_on'] = click.confirm('Is this a clean host you want to install HAProxy on?')
     host_props['master'] = False
     host_props['node'] = False
-    host_props['ha_proxy'] = True
-    ha_proxy = Host(**host_props)
+    host_props['master_lb'] = True
+    master_lb = Host(**host_props)
 
-    return ha_proxy
+    return master_lb
 
 def confirm_hosts_facts(oo_cfg, callback_facts):
     hosts = oo_cfg.hosts
@@ -237,13 +237,13 @@ def check_hosts_config(oo_cfg):
     click.clear()
     masters = [host for host in oo_cfg.hosts if host.master]
     if len(masters) > 1:
-        ha_proxy = [host for host in oo_cfg.hosts if host.ha_proxy]
-        click.echo(ha_proxy)
-        if len(ha_proxy) > 1:
+        master_lb = [host for host in oo_cfg.hosts if host.master_lb]
+        click.echo(master_lb)
+        if len(master_lb) > 1:
             click.echo('More than one HAProxy specified. Only one proxy is allowed.')
             sys.exit(0)
-        elif len(ha_proxy) == 1:
-            if ha_proxy[0].master or ha_proxy[0].node:
+        elif len(master_lb) == 1:
+            if master_lb[0].master or master_lb[0].node:
                 click.echo('HAProxy is configured as a master or node. Please correct this.')
                 sys.exit(0)
         else:
diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py
index 6b4f36204..243a75b09 100644
--- a/utils/src/ooinstall/oo_config.py
+++ b/utils/src/ooinstall/oo_config.py
@@ -45,7 +45,7 @@ class Host(object):
         self.node = kwargs.get('node', False)
 
         # Should this host run as an HAProxy:
-        self.ha_proxy = kwargs.get('ha_proxy', False)
+        self.master_lb = kwargs.get('master_lb', False)
 
         self.containerized = kwargs.get('containerized', False)
 
@@ -53,7 +53,7 @@ class Host(object):
             raise OOConfigInvalidHostError("You must specify either and 'ip' " \
                                            "or 'hostname' to connect to.")
 
-        if self.master is False and self.node is False and self.ha_proxy is False:
+        if self.master is False and self.node is False and self.master_lb is False:
             raise OOConfigInvalidHostError(
                 "You must specify each host as either a master or a node.")
 
@@ -67,7 +67,7 @@ class Host(object):
         """ Used when exporting to yaml. """
         d = {}
         for prop in ['ip', 'hostname', 'public_ip', 'public_hostname',
-                     'master', 'node', 'ha_proxy', 'containerized', 'connect_to', 'run_on']:
+                     'master', 'node', 'master_lb', 'containerized', 'connect_to', 'run_on']:
             # If the property is defined (not None or False), export it:
             if getattr(self, prop):
                 d[prop] = getattr(self, prop)
diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index ff674153d..86c707b17 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -19,7 +19,7 @@ def generate_inventory(hosts):
     global CFG
     masters = [host for host in hosts if host.master]
     nodes = [host for host in hosts if host.node]
-    proxy = next((host for host in hosts if host.ha_proxy), None)
+    proxy = next((host for host in hosts if host.master_lb), None)
     multiple_masters = len(masters) > 1
 
     base_inventory_path = CFG.settings['ansible_inventory_path']
-- 
cgit v1.2.3


From c148283d1731d08fbfd4446af88450c5983c7b7a Mon Sep 17 00:00:00 2001
From: Brenton Leanhardt <bleanhar@redhat.com>
Date: Mon, 23 Nov 2015 11:56:27 -0500
Subject: Handling preconfigured load balancers

The preconfigured load balancers, previously denoted by having 'run_on' set to
false, cannot have their facts gathered which results in a stack trace.  Later
when we write out the inventory we have to fake out the hostname and just use
'connect_to'.

We're likely going to have the concept of other types of "plug-in" hosts where
we don't run ansible.  We should make sure we abstract this properly so it's
easy to add additional types of hosts.

Also in the commit:
- Renamed 'run_on' to 'preconfigured' and inverted the logic as needed
- Output tally of Masters and Nodes as well as remaining Masters required for
  HA
- Minor rewording in a few places
- Currently only prompting for the load balancer after all other hosts have
  been entered
- Removed spurious echo
---
 utils/src/ooinstall/cli_installer.py     | 34 ++++++++++++++++++++++----------
 utils/src/ooinstall/oo_config.py         |  4 ++--
 utils/src/ooinstall/openshift_ansible.py | 17 +++++++++++++---
 3 files changed, 40 insertions(+), 15 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index ac9d884d9..9abea0683 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -79,6 +79,7 @@ def collect_hosts(version=None, masters_set=False):
 
         Returns: a list of host information collected from the user
     """
+    min_masters_for_ha = 3
     click.clear()
     click.echo('***Host Configuration***')
     message = """
@@ -114,10 +115,7 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
                 host_props['master'] = True
                 num_masters += 1
 
-                if num_masters > 1:
-                    hosts.append(collect_master_lb())
-
-                if num_masters >= 3 or version == '3.0':
+                if num_masters >= min_masters_for_ha or version == '3.0':
                     masters_set = True
         host_props['node'] = True
 
@@ -135,8 +133,18 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
 
         hosts.append(host)
 
-        if num_masters <= 1 or num_masters >= 3:
+        click.echo('')
+        click.echo('Current Masters: {}'.format(num_masters))
+        click.echo('Current Nodes: {}'.format(len(hosts)))
+        click.echo('Additional Masters required for HA: {}'.format(max(min_masters_for_ha - num_masters, 0)))
+        click.echo('')
+
+        if num_masters <= 1 or num_masters >= min_masters_for_ha:
             more_hosts = click.confirm('Do you want to add additional hosts?')
+
+    if num_masters > 1:
+        hosts.append(collect_master_lb())
+
     return hosts
 
 def collect_master_lb():
@@ -149,14 +157,19 @@ Please provide a host that will be configured as a proxy. This can either be
 an existing load balancer configured to balance all masters on port 8443 or a
 new host that will have HAProxy installed on it.
 
-This will also require you to set a third master.
+If the host provided does is not yet configured a reference haproxy load
+balancer will be installed.  It's important to note that while the rest of the
+environment will be fault tolerant this reference load balancer will not be.
+It can be replaced post-installation with a load balancer with the same
+hostname.
 """
     click.echo(message)
     host_props = {}
     host_props['connect_to'] = click.prompt('Enter hostname or IP address:',
                                             default='',
                                             value_proc=validate_prompt_hostname)
-    host_props['run_on'] = click.confirm('Is this a clean host you want to install HAProxy on?')
+    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
@@ -201,6 +214,8 @@ Notes:
     default_facts_lines = []
     default_facts = {}
     for h in hosts:
+        if h.preconfigured == True:
+            continue
         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"]
@@ -238,13 +253,12 @@ def check_hosts_config(oo_cfg):
     masters = [host for host in oo_cfg.hosts if host.master]
     if len(masters) > 1:
         master_lb = [host for host in oo_cfg.hosts if host.master_lb]
-        click.echo(master_lb)
         if len(master_lb) > 1:
-            click.echo('More than one HAProxy specified. Only one proxy is allowed.')
+            click.echo('More than one Master load balancer specified. Only one is allowed.')
             sys.exit(0)
         elif len(master_lb) == 1:
             if master_lb[0].master or master_lb[0].node:
-                click.echo('HAProxy is configured as a master or node. Please correct this.')
+                click.echo('The Master load balancer is configured as a master or node. Please correct this.')
                 sys.exit(0)
         else:
             message = """
diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py
index 243a75b09..b6f0cdce3 100644
--- a/utils/src/ooinstall/oo_config.py
+++ b/utils/src/ooinstall/oo_config.py
@@ -36,7 +36,7 @@ class Host(object):
         self.public_ip = kwargs.get('public_ip', None)
         self.public_hostname = kwargs.get('public_hostname', None)
         self.connect_to = kwargs.get('connect_to', None)
-        self.run_on = kwargs.get('run_on', None)
+        self.preconfigured = kwargs.get('preconfigured', None)
 
         # Should this host run as an OpenShift master:
         self.master = kwargs.get('master', False)
@@ -67,7 +67,7 @@ class Host(object):
         """ Used when exporting to yaml. """
         d = {}
         for prop in ['ip', 'hostname', 'public_ip', 'public_hostname',
-                     'master', 'node', 'master_lb', 'containerized', 'connect_to', 'run_on']:
+                     'master', 'node', 'master_lb', 'containerized', 'connect_to', 'preconfigured']:
             # If the property is defined (not None or False), export it:
             if getattr(self, prop):
                 d[prop] = getattr(self, prop)
diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index 86c707b17..ed1ba2c77 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -19,7 +19,7 @@ def generate_inventory(hosts):
     global CFG
     masters = [host for host in hosts if host.master]
     nodes = [host for host in hosts if host.node]
-    proxy = next((host for host in hosts if host.master_lb), None)
+    proxy = determine_proxy_configuration(hosts)
     multiple_masters = len(masters) > 1
 
     base_inventory_path = CFG.settings['ansible_inventory_path']
@@ -66,13 +66,24 @@ def generate_inventory(hosts):
             scheduleable = False
         write_host(node, base_inventory, scheduleable)
 
-    if getattr(proxy, 'run_on', False):
+    if not getattr(proxy, 'preconfigured', True):
         base_inventory.write('\n[lb]\n')
         write_host(proxy, base_inventory)
 
     base_inventory.close()
     return base_inventory_path
 
+def determine_proxy_configuration(hosts):
+    proxy = next((host for host in hosts if host.master_lb), None)
+    if proxy:
+        if proxy.hostname == None:
+            proxy.hostname = proxy.connect_to
+            proxy.public_hostname = proxy.connect_to
+        print('asd09o')
+        return proxy
+
+    return None
+
 def write_inventory_children(base_inventory, multiple_masters, proxy):
     global CFG
 
@@ -81,7 +92,7 @@ def write_inventory_children(base_inventory, multiple_masters, proxy):
     base_inventory.write('nodes\n')
     if multiple_masters:
         base_inventory.write('etcd\n')
-    if getattr(proxy, 'run_on', False):
+    if not getattr(proxy, 'preconfigured', True):
         base_inventory.write('lb\n')
 
 def write_inventory_vars(base_inventory, multiple_masters, proxy):
-- 
cgit v1.2.3


From 54ba429f37454b7ed7564ae53fe266da9f955ba4 Mon Sep 17 00:00:00 2001
From: Samuel Munilla <smunilla@redhat.com>
Date: Mon, 23 Nov 2015 18:08:26 -0500
Subject: atomic-openshift-installer: Fix lint issue

---
 utils/src/ooinstall/openshift_ansible.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index ed1ba2c77..d098a5593 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -79,7 +79,7 @@ def determine_proxy_configuration(hosts):
         if proxy.hostname == None:
             proxy.hostname = proxy.connect_to
             proxy.public_hostname = proxy.connect_to
-        print('asd09o')
+        print 'asd09o'
         return proxy
 
     return None
-- 
cgit v1.2.3


From 6a988e92ff6d63229cecf9b2d571ce114af820d5 Mon Sep 17 00:00:00 2001
From: Brenton Leanhardt <bleanhar@redhat.com>
Date: Tue, 24 Nov 2015 08:32:46 -0500
Subject: Removing a debug line

---
 utils/src/ooinstall/openshift_ansible.py | 1 -
 1 file changed, 1 deletion(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index d098a5593..66b9ead93 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -79,7 +79,6 @@ def determine_proxy_configuration(hosts):
         if proxy.hostname == None:
             proxy.hostname = proxy.connect_to
             proxy.public_hostname = proxy.connect_to
-        print 'asd09o'
         return proxy
 
     return None
-- 
cgit v1.2.3


From 1c326a03caf06e388ecb9a2c3d140445f60005ba Mon Sep 17 00:00:00 2001
From: Brenton Leanhardt <bleanhar@redhat.com>
Date: Tue, 24 Nov 2015 09:48:42 -0500
Subject: Fixing tests for quick_ha

Also:
* minor rewording of the text that informs the admin about scheduleable
  masters.
---
 utils/src/ooinstall/cli_installer.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index 9abea0683..3eee0c32b 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -272,8 +272,9 @@ https://docs.openshift.org/latest/install_config/install/advanced_install.html#m
     nodes = [host.node for host in oo_cfg.hosts]
     if len(masters) == len(nodes):
         message = """
-No dedicated Nodes specified. By default, colocated Masters have their Nodes set to unscheduleable.
-Would you like to label the colocated masters as scheduleable?
+No dedicated Nodes specified. By default, colocated Masters have their Nodes
+set to unscheduleable.  Continuing at this point will lable all nodes as
+scheduleable.
 """
         confirm_continue(message)
 
-- 
cgit v1.2.3


From ba47106f21fd18c64c3a3bb89980a3e857fbd034 Mon Sep 17 00:00:00 2001
From: Brenton Leanhardt <bleanhar@redhat.com>
Date: Tue, 24 Nov 2015 10:34:51 -0500
Subject: Avoid printing the master and node totals in the add-a-node scenario

---
 utils/src/ooinstall/cli_installer.py | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index 3eee0c32b..812a42795 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -72,7 +72,7 @@ def delete_hosts(hosts):
                 click.echo("\"{}\" doesn't coorespond to any valid input.".format(del_idx))
     return hosts, None
 
-def collect_hosts(version=None, masters_set=False):
+def collect_hosts(version=None, masters_set=False, print_summary=True):
     """
         Collect host information from user. This will later be filled in using
         ansible.
@@ -133,11 +133,12 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
 
         hosts.append(host)
 
-        click.echo('')
-        click.echo('Current Masters: {}'.format(num_masters))
-        click.echo('Current Nodes: {}'.format(len(hosts)))
-        click.echo('Additional Masters required for HA: {}'.format(max(min_masters_for_ha - num_masters, 0)))
-        click.echo('')
+        if print_summary:
+            click.echo('')
+            click.echo('Current Masters: {}'.format(num_masters))
+            click.echo('Current Nodes: {}'.format(len(hosts)))
+            click.echo('Additional Masters required for HA: {}'.format(max(min_masters_for_ha - num_masters, 0)))
+            click.echo('')
 
         if num_masters <= 1 or num_masters >= min_masters_for_ha:
             more_hosts = click.confirm('Do you want to add additional hosts?')
@@ -395,7 +396,7 @@ def collect_new_nodes():
 Add new nodes here
     """
     click.echo(message)
-    return collect_hosts(masters_set=True)
+    return collect_hosts(masters_set=True, print_summary=False)
 
 def get_installed_hosts(hosts, callback_facts):
     installed_hosts = []
-- 
cgit v1.2.3


From ed650557aef9bb1d18b755ffdf891fcb26bb20cb Mon Sep 17 00:00:00 2001
From: Brenton Leanhardt <bleanhar@redhat.com>
Date: Tue, 24 Nov 2015 15:05:27 -0500
Subject: Properly setting scheduleability for HA Master scenarios

If the only Nodes we have are also on Masters we set the scheduleable.
---
 utils/src/ooinstall/cli_installer.py     |  4 ++--
 utils/src/ooinstall/openshift_ansible.py | 22 ++++++++++++++--------
 2 files changed, 16 insertions(+), 10 deletions(-)

(limited to 'utils/src/ooinstall')

diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index 812a42795..c62461ad3 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -270,11 +270,11 @@ https://docs.openshift.org/latest/install_config/install/advanced_install.html#m
 """
             confirm_continue(message)
 
-    nodes = [host.node for host in oo_cfg.hosts]
+    nodes = [host for host in oo_cfg.hosts if host.node]
     if len(masters) == len(nodes):
         message = """
 No dedicated Nodes specified. By default, colocated Masters have their Nodes
-set to unscheduleable.  Continuing at this point will lable all nodes as
+set to unscheduleable.  Continuing at this point will label all nodes as
 scheduleable.
 """
         confirm_continue(message)
diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index 66b9ead93..75125084c 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -57,14 +57,20 @@ def generate_inventory(hosts):
             write_host(master, base_inventory)
 
     base_inventory.write('\n[nodes]\n')
-    for node in nodes:
-        # TODO: Until the Master can run the SDN itself we have to configure the Masters
-        # as Nodes too.
-        scheduleable = True
-        # If there's only one Node and it's also a Master we want it to be scheduleable:
-        if node in masters and len(masters) != len(nodes):
-            scheduleable = False
-        write_host(node, base_inventory, scheduleable)
+
+    # TODO: It would be much better to calculate the scheduleability elsewhere
+    # and store it on the Node object.
+    if set(nodes) == set(masters):
+        for node in nodes:
+            write_host(node, base_inventory)
+    else:
+        for node in nodes:
+            # TODO: Until the Master can run the SDN itself we have to configure the Masters
+            # as Nodes too.
+            scheduleable = True
+            if node in masters:
+                scheduleable = False
+            write_host(node, base_inventory, scheduleable)
 
     if not getattr(proxy, 'preconfigured', True):
         base_inventory.write('\n[lb]\n')
-- 
cgit v1.2.3