summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/src/ooinstall/cli_installer.py182
-rw-r--r--utils/src/ooinstall/oo_config.py12
-rw-r--r--utils/src/ooinstall/openshift_ansible.py64
-rw-r--r--utils/src/ooinstall/variants.py3
-rw-r--r--utils/test/cli_installer_tests.py244
-rw-r--r--utils/test/fixture.py22
6 files changed, 406 insertions, 121 deletions
diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py
index ace834323..c896a74b4 100644
--- a/utils/src/ooinstall/cli_installer.py
+++ b/utils/src/ooinstall/cli_installer.py
@@ -11,6 +11,7 @@ from ooinstall import OOConfig
from ooinstall.oo_config import OOConfigInvalidHostError
from ooinstall.oo_config import Host
from ooinstall.variants import find_variant, get_variant_version_combos
+from distutils.version import LooseVersion
DEFAULT_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-utils/ansible.cfg'
DEFAULT_PLAYBOOK_DIR = '/usr/share/ansible/openshift-ansible/'
@@ -166,6 +167,9 @@ http://docs.openshift.com/enterprise/latest/architecture/infrastructure_componen
if num_masters >= 3:
collect_master_lb(hosts)
+ if not existing_env:
+ collect_storage_host(hosts)
+
return hosts
@@ -202,8 +206,9 @@ Please add one more to proceed."""
elif len(masters) >= 3:
ha_message = """
NOTE: Multiple Masters specified, this will be an HA deployment with a separate
-etcd cluster. You will be prompted to provide the FQDN of a load balancer once
-finished entering hosts."""
+etcd cluster. You will be prompted to provide the FQDN of a load balancer and
+a host for storage once finished entering hosts.
+"""
click.echo(ha_message)
dedicated_nodes_message = """
@@ -243,6 +248,8 @@ def print_host_summary(all_hosts, host):
click.echo(" - Etcd Member")
else:
click.echo(" - Etcd (Embedded)")
+ if host.storage:
+ click.echo(" - Storage")
def collect_master_lb(hosts):
@@ -291,6 +298,48 @@ hostname.
master_lb = Host(**host_props)
hosts.append(master_lb)
+def collect_storage_host(hosts):
+ """
+ Get a valid host for storage from the user and append it to the list of
+ hosts.
+ """
+ message = """
+Setting up High Availability Masters requires a storage host. Please provide a
+host that will be configured as a Registry Storage.
+
+Note: Containerized storage hosts are not currently supported.
+"""
+ click.echo(message)
+ host_props = {}
+
+ first_master = next(host for host in hosts if host.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
+ else:
+ host_props['connect_to'] = hostname_or_ip
+ host_props['preconfigured'] = False
+ host_props['master'] = False
+ host_props['node'] = False
+ host_props['storage'] = True
+ storage = Host(**host_props)
+ hosts.append(storage)
+
+def is_host_already_node_or_master(hostname, hosts):
+ is_existing = False
+ existing_host = None
+
+ for host in hosts:
+ if host.connect_to == hostname and (host.master or host.node):
+ is_existing = True
+ existing_host = host
+
+ return is_existing, existing_host
+
def confirm_hosts_facts(oo_cfg, callback_facts):
hosts = oo_cfg.hosts
click.clear()
@@ -330,11 +379,15 @@ Notes:
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"]
- h.hostname = callback_facts[h.connect_to]["common"]["hostname"]
- h.public_hostname = callback_facts[h.connect_to]["common"]["public_hostname"]
+ try:
+ 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"]
+ except KeyError:
+ click.echo("Problem fetching facts from {}".format(h.connect_to))
+ continue
default_facts_lines.append(",".join([h.connect_to,
h.ip,
@@ -468,6 +521,34 @@ def error_if_missing_info(oo_cfg):
if missing_info:
sys.exit(1)
+def get_proxy_hostnames_and_excludes():
+ message = """
+If a proxy is needed to reach HTTP and HTTPS traffic please enter the name below.
+This proxy will be configured by default for all processes needing to reach systems outside
+the cluster.
+
+More advanced configuration is possible if using ansible directly:
+
+https://docs.openshift.com/enterprise/latest/install_config/http_proxies.html
+"""
+ click.echo(message)
+
+ message = "Specify your http proxy ? (ENTER for none)"
+ http_proxy_hostname = click.prompt(message, default='')
+
+ message = "Specify your https proxy ? (ENTER for none)"
+ https_proxy_hostname = click.prompt(message, default=http_proxy_hostname)
+
+ if http_proxy_hostname or https_proxy_hostname:
+ message = """
+All hosts in your openshift inventory will automatically be added to the NO_PROXY value.
+Please provide any additional hosts to be added to NO_PROXY. (ENTER for none)
+"""
+ proxy_excludes = click.prompt(message, default='')
+ else:
+ proxy_excludes = ''
+
+ return http_proxy_hostname, https_proxy_hostname, proxy_excludes
def get_missing_info_from_user(oo_cfg):
""" Prompts the user for any information missing from the given configuration. """
@@ -514,6 +595,14 @@ https://docs.openshift.com/enterprise/latest/admin_guide/install/prerequisites.h
oo_cfg.settings['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
+ click.clear()
+
return oo_cfg
@@ -618,7 +707,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, verbose)
- if error:
+ 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']))
sys.exit(1)
@@ -732,42 +821,67 @@ def uninstall(ctx):
@click.command()
+@click.option('--latest-minor', '-l', is_flag=True, default=False)
+@click.option('--next-major', '-n', is_flag=True, default=False)
@click.pass_context
-def upgrade(ctx):
+def upgrade(ctx, latest_minor, next_major):
oo_cfg = ctx.obj['oo_cfg']
verbose = ctx.obj['verbose']
+ upgrade_mappings = {
+ '3.0':{
+ 'minor_version' :'3.0',
+ 'minor_playbook':'v3_0_minor/upgrade.yml',
+ 'major_version' :'3.1',
+ 'major_playbook':'v3_0_to_v3_1/upgrade.yml',
+ },
+ '3.1':{
+ 'minor_version' :'3.1',
+ 'minor_playbook':'v3_1_minor/upgrade.yml',
+ 'major_playbook':'v3_1_to_v3_2/upgrade.yml',
+ 'major_version' :'3.2',
+ }
+ }
+
if len(oo_cfg.hosts) == 0:
click.echo("No hosts defined in: %s" % oo_cfg.config_path)
sys.exit(1)
old_variant = oo_cfg.settings['variant']
old_version = oo_cfg.settings['variant_version']
-
+ mapping = upgrade_mappings.get(old_version)
message = """
This tool will help you upgrade your existing OpenShift installation.
"""
click.echo(message)
- click.echo("Version {} found. Do you want to update to the latest version of {} " \
- "or migrate to the next major release?".format(old_version, old_version))
- resp = click.prompt("(1) Update to latest {} (2) Migrate to next relese".format(old_version))
- if resp == "2":
- # TODO: Make this a lot more flexible
- new_version = "3.1"
+ if not (latest_minor or next_major):
+ click.echo("Version {} found. Do you want to update to the latest version of {} " \
+ "or migrate to the next major release?".format(old_version, old_version))
+ response = click.prompt("(1) Update to latest {} " \
+ "(2) Migrate to next release".format(old_version),
+ type=click.Choice(['1', '2']),)
+ if response == "1":
+ latest_minor = True
+ if response == "2":
+ next_major = True
+
+ if next_major:
+ playbook = mapping['major_playbook']
+ new_version = mapping['major_version']
# Update config to reflect the version we're targetting, we'll write
# to disk once ansible completes successfully, not before.
+ oo_cfg.settings['variant_version'] = new_version
if oo_cfg.settings['variant'] == 'enterprise':
oo_cfg.settings['variant'] = 'openshift-enterprise'
- version = find_variant(oo_cfg.settings['variant'])[1]
- oo_cfg.settings['variant_version'] = version.name
- else:
- new_version = old_version
+
+ if latest_minor:
+ playbook = mapping['minor_playbook']
+ new_version = mapping['minor_version']
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']))
+ old_variant, old_version, oo_cfg.settings['variant'], new_version))
for host in oo_cfg.hosts:
click.echo(" * %s" % host.connect_to)
@@ -778,7 +892,7 @@ def upgrade(ctx):
click.echo("Upgrade cancelled.")
sys.exit(0)
- retcode = openshift_ansible.run_upgrade_playbook(old_version, new_version, verbose)
+ retcode = openshift_ansible.run_upgrade_playbook(playbook, verbose)
if retcode > 0:
click.echo("Errors encountered during upgrade, please check %s." %
oo_cfg.settings['ansible_log_path'])
@@ -789,8 +903,10 @@ def upgrade(ctx):
@click.command()
@click.option('--force', '-f', is_flag=True, default=False)
+@click.option('--gen-inventory', is_flag=True, default=False,
+ help="Generate an ansible inventory file and exit.")
@click.pass_context
-def install(ctx, force):
+def install(ctx, force, gen_inventory):
oo_cfg = ctx.obj['oo_cfg']
verbose = ctx.obj['verbose']
@@ -805,7 +921,7 @@ def install(ctx, force):
click.echo('Gathering information from hosts...')
callback_facts, error = openshift_ansible.default_facts(oo_cfg.hosts,
verbose)
- if error:
+ 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']))
sys.exit(1)
@@ -813,7 +929,6 @@ def install(ctx, 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)
# We already verified this is not the case for unattended installs, so this can
# only trigger for live CLI users:
@@ -823,7 +938,18 @@ def install(ctx, force):
if len(oo_cfg.calc_missing_facts()) > 0:
confirm_hosts_facts(oo_cfg, callback_facts)
+ # 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)
+
+ click.echo()
+ click.echo('Wrote atomic-openshift-installer config: %s' % oo_cfg.config_path)
+ click.echo("Wrote ansible inventory: %s" % inventory_file)
+ click.echo()
+
+ if gen_inventory:
+ sys.exit(0)
click.echo('Ready to run installation process.')
message = """
@@ -832,8 +958,8 @@ 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(oo_cfg.hosts,
- hosts_to_run_on, verbose)
+ error = openshift_ansible.run_main_playbook(inventory_file, oo_cfg.hosts,
+ hosts_to_run_on, verbose)
if error:
# The bootstrap script will print out the log location.
message = """
diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py
index b1af21773..24dfbe013 100644
--- a/utils/src/ooinstall/oo_config.py
+++ b/utils/src/ooinstall/oo_config.py
@@ -11,6 +11,8 @@ PERSIST_SETTINGS = [
'ansible_config',
'ansible_log_path',
'master_routingconfig_subdomain',
+ 'proxy',
+ 'proxy_exclude_hosts',
'variant',
'variant_version',
'version',
@@ -50,13 +52,17 @@ class Host(object):
# Should this host run as an HAProxy:
self.master_lb = kwargs.get('master_lb', False)
+ # Should this host run as an HAProxy:
+ self.storage = kwargs.get('storage', False)
+
self.containerized = kwargs.get('containerized', False)
if self.connect_to is None:
raise OOConfigInvalidHostError("You must specify either an ip " \
"or hostname as 'connect_to'")
- if self.master is False and self.node is False and self.master_lb is False:
+ if self.master is False and self.node is False and \
+ self.master_lb is False and self.storage is False:
raise OOConfigInvalidHostError(
"You must specify each host as either a master or a node.")
@@ -70,7 +76,7 @@ class Host(object):
""" Used when exporting to yaml. """
d = {}
for prop in ['ip', 'hostname', 'public_ip', 'public_hostname',
- 'master', 'node', 'master_lb', 'containerized',
+ 'master', 'node', 'master_lb', 'storage', 'containerized',
'connect_to', 'preconfigured', 'new_host']:
# If the property is defined (not None or False), export it:
if getattr(self, prop):
@@ -194,7 +200,7 @@ class OOConfig(object):
self.settings['ansible_ssh_user'] = ''
self.settings['ansible_inventory_path'] = \
- '{}/hosts'.format(self.settings['ansible_inventory_directory'])
+ '{}/hosts'.format(os.path.dirname(self.config_path))
# clean up any empty sets
for setting in self.settings.keys():
diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py
index 3a135139b..97aee0b53 100644
--- a/utils/src/ooinstall/openshift_ansible.py
+++ b/utils/src/ooinstall/openshift_ansible.py
@@ -21,13 +21,14 @@ def generate_inventory(hosts):
nodes = [host for host in hosts if host.node]
new_nodes = [host for host in hosts if host.node and host.new_host]
proxy = determine_proxy_configuration(hosts)
+ storage = determine_storage_configuration(hosts)
multiple_masters = len(masters) > 1
scaleup = len(new_nodes) > 0
base_inventory_path = CFG.settings['ansible_inventory_path']
base_inventory = open(base_inventory_path, 'w')
- write_inventory_children(base_inventory, multiple_masters, proxy, scaleup)
+ write_inventory_children(base_inventory, multiple_masters, proxy, storage, scaleup)
write_inventory_vars(base_inventory, multiple_masters, proxy)
@@ -37,10 +38,10 @@ def generate_inventory(hosts):
base_inventory.write('deployment_type={}\n'.format(ver.ansible_key))
if 'OO_INSTALL_ADDITIONAL_REGISTRIES' in os.environ:
- base_inventory.write('cli_docker_additional_registries={}\n'
+ base_inventory.write('openshift_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'
+ base_inventory.write('openshift_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
@@ -73,11 +74,16 @@ def generate_inventory(hosts):
base_inventory.write('\n[lb]\n')
write_host(proxy, base_inventory)
+
if scaleup:
base_inventory.write('\n[new_nodes]\n')
for node in new_nodes:
write_host(node, base_inventory)
+ if storage:
+ base_inventory.write('\n[nfs]\n')
+ write_host(storage, base_inventory)
+
base_inventory.close()
return base_inventory_path
@@ -87,11 +93,15 @@ def determine_proxy_configuration(hosts):
if proxy.hostname == None:
proxy.hostname = proxy.connect_to
proxy.public_hostname = proxy.connect_to
- return proxy
- return None
+ return proxy
+
+def determine_storage_configuration(hosts):
+ storage = next((host for host in hosts if host.storage), None)
+
+ return storage
-def write_inventory_children(base_inventory, multiple_masters, proxy, scaleup):
+def write_inventory_children(base_inventory, multiple_masters, proxy, storage, scaleup):
global CFG
base_inventory.write('\n[OSEv3:children]\n')
@@ -103,13 +113,15 @@ def write_inventory_children(base_inventory, multiple_masters, proxy, scaleup):
base_inventory.write('etcd\n')
if not getattr(proxy, 'preconfigured', True):
base_inventory.write('lb\n')
+ if storage:
+ base_inventory.write('nfs\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')
+ base_inventory.write('ansible_become=yes\n')
if multiple_masters and proxy is not None:
base_inventory.write('openshift_master_cluster_method=native\n')
base_inventory.write("openshift_master_cluster_hostname={}\n".format(proxy.hostname))
@@ -117,8 +129,21 @@ def write_inventory_vars(base_inventory, multiple_masters, proxy):
"openshift_master_cluster_public_hostname={}\n".format(proxy.public_hostname))
if CFG.settings.get('master_routingconfig_subdomain', False):
base_inventory.write(
- "openshift_master_default_subdomain={}\n".format(CFG.settings['master_routingconfig_subdomain']))
-
+ "openshift_master_default_subdomain={}\n".format(
+ CFG.settings['master_routingconfig_subdomain']))
+ if CFG.settings.get('variant_version', None) == '3.1':
+ #base_inventory.write('openshift_image_tag=v{}\n'.format(CFG.settings.get('variant_version')))
+ base_inventory.write('openshift_image_tag=v{}\n'.format('3.1.1.6'))
+
+ if CFG.settings.get('openshift_http_proxy', ''):
+ base_inventory.write("openshift_http_proxy={}\n".format(
+ CFG.settings['openshift_http_proxy']))
+ if CFG.settings.get('openshift_https_proxy', ''):
+ base_inventory.write("openshift_https_proxy={}\n".format(
+ CFG.settings['openshift_https_proxy']))
+ if CFG.settings.get('openshift_no_proxy', ''):
+ base_inventory.write("openshift_no_proxy={}\n".format(
+ CFG.settings['openshift_no_proxy']))
def write_host(host, inventory, schedulable=None):
@@ -155,7 +180,7 @@ def write_host(host, inventory, schedulable=None):
if no_pwd_sudo == 1:
print 'The atomic-openshift-installer requires sudo access without a password.'
sys.exit(1)
- facts += ' ansible_become=true'
+ facts += ' ansible_become=yes'
inventory.write('{} {}\n'.format(host.connect_to, facts))
@@ -201,9 +226,8 @@ def default_facts(hosts, verbose=False):
return load_system_facts(inventory_file, os_facts_path, facts_env, verbose)
-def run_main_playbook(hosts, hosts_to_run_on, verbose=False):
+def run_main_playbook(inventory_file, hosts, hosts_to_run_on, verbose=False):
global CFG
- 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/byo/openshift-node/scaleup.yml')
@@ -239,18 +263,10 @@ def run_uninstall_playbook(verbose=False):
return run_ansible(playbook, inventory_file, facts_env, verbose)
-def run_upgrade_playbook(old_version, new_version, verbose=False):
- # TODO: do not hardcode the upgrade playbook, add ability to select the
- # right playbook depending on the type of upgrade.
- old_version = old_version.replace('.', '_')
- new_version = old_version.replace('.', '_')
- if old_version == new_version:
- playbook = os.path.join(CFG.settings['ansible_playbook_directory'],
- 'playbooks/byo/openshift-cluster/upgrades/v{}_minor/upgrade.yml'.format(new_version))
- else:
- playbook = os.path.join(CFG.settings['ansible_playbook_directory'],
- 'playbooks/byo/openshift-cluster/upgrades/v{}_to_v{}/upgrade.yml'.format(old_version,
- new_version))
+def run_upgrade_playbook(playbook, verbose=False):
+ playbook = os.path.join(CFG.settings['ansible_playbook_directory'],
+ 'playbooks/byo/openshift-cluster/upgrades/{}'.format(playbook))
+
# TODO: Upgrade inventory for upgrade?
inventory_file = generate_inventory(CFG.hosts)
facts_env = os.environ.copy()
diff --git a/utils/src/ooinstall/variants.py b/utils/src/ooinstall/variants.py
index 571025543..9d98379bb 100644
--- a/utils/src/ooinstall/variants.py
+++ b/utils/src/ooinstall/variants.py
@@ -36,6 +36,7 @@ class Variant(object):
# WARNING: Keep the versions ordered, most recent last:
OSE = Variant('openshift-enterprise', 'OpenShift Enterprise',
[
+ Version('3.2', 'openshift-enterprise'),
Version('3.1', 'openshift-enterprise'),
Version('3.0', 'enterprise')
]
@@ -43,6 +44,7 @@ OSE = Variant('openshift-enterprise', 'OpenShift Enterprise',
AEP = Variant('atomic-enterprise', 'Atomic Enterprise Platform',
[
+ Version('3.2', 'atomic-enterprise'),
Version('3.1', 'atomic-enterprise')
]
)
@@ -74,4 +76,3 @@ def get_variant_version_combos():
for ver in variant.versions:
combos.append((variant, ver))
return combos
-
diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py
index baab5d56f..66ed66660 100644
--- a/utils/test/cli_installer_tests.py
+++ b/utils/test/cli_installer_tests.py
@@ -1,6 +1,6 @@
# TODO: Temporarily disabled due to importing old code into openshift-ansible
# repo. We will work on these over time.
-# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name
+# pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name,too-many-lines
import copy
import os
@@ -37,6 +37,14 @@ MOCK_FACTS = {
'public_hostname': 'node2.example.com'
}
},
+ '10.1.0.1': {
+ 'common': {
+ 'ip': '10.1.0.1',
+ 'public_ip': '10.1.0.1',
+ 'hostname': 'storage-private.example.com',
+ 'public_hostname': 'storage.example.com'
+ }
+ },
}
MOCK_FACTS_QUICKHA = {
@@ -72,6 +80,14 @@ MOCK_FACTS_QUICKHA = {
'public_hostname': 'proxy.example.com'
}
},
+ '10.1.0.1': {
+ 'common': {
+ 'ip': '10.1.0.1',
+ 'public_ip': '10.1.0.1',
+ 'hostname': 'storage-private.example.com',
+ 'public_hostname': 'storage.example.com'
+ }
+ },
}
# Missing connect_to on some hosts:
@@ -137,6 +153,12 @@ hosts:
public_ip: 24.222.0.5
public_hostname: proxy.example.com
master_lb: true
+ - connect_to: 10.1.0.1
+ ip: 10.1.0.1
+ hostname: storage-private.example.com
+ public_ip: 24.222.0.6
+ public_hostname: storage.example.com
+ storage: true
"""
QUICKHA_2_MASTER_CONFIG = """
@@ -169,6 +191,12 @@ hosts:
public_ip: 24.222.0.5
public_hostname: proxy.example.com
master_lb: true
+ - connect_to: 10.1.0.1
+ ip: 10.1.0.1
+ hostname: storage-private.example.com
+ public_ip: 24.222.0.6
+ public_hostname: storage.example.com
+ storage: true
"""
QUICKHA_CONFIG_REUSED_LB = """
@@ -197,6 +225,12 @@ hosts:
public_hostname: node2.example.com
node: true
master: true
+ - connect_to: 10.1.0.1
+ ip: 10.1.0.1
+ hostname: storage-private.example.com
+ public_ip: 24.222.0.6
+ public_hostname: storage.example.com
+ storage: true
"""
QUICKHA_CONFIG_NO_LB = """
@@ -224,6 +258,12 @@ hosts:
public_hostname: node2.example.com
node: true
master: true
+ - connect_to: 10.1.0.1
+ ip: 10.1.0.1
+ hostname: storage-private.example.com
+ public_ip: 24.222.0.6
+ public_hostname: storage.example.com
+ storage: true
"""
QUICKHA_CONFIG_PRECONFIGURED_LB = """
@@ -263,6 +303,12 @@ hosts:
public_hostname: proxy.example.com
master_lb: true
preconfigured: true
+ - connect_to: 10.1.0.1
+ ip: 10.1.0.1
+ hostname: storage-private.example.com
+ public_ip: 24.222.0.6
+ public_hostname: storage.example.com
+ storage: true
"""
class UnattendedCliTests(OOCliFixture):
@@ -371,7 +417,7 @@ class UnattendedCliTests(OOCliFixture):
self.assert_result(result, 0)
load_facts_args = load_facts_mock.call_args[0]
- self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"),
+ self.assertEquals(os.path.join(self.work_dir, "hosts"),
load_facts_args[0])
self.assertEquals(os.path.join(self.work_dir,
"playbooks/byo/openshift_facts.yml"), load_facts_args[1])
@@ -385,8 +431,8 @@ class UnattendedCliTests(OOCliFixture):
env_vars['ANSIBLE_CONFIG'] == cli.DEFAULT_ANSIBLE_CONFIG)
# Make sure we ran on the expected masters and nodes:
- hosts = run_playbook_mock.call_args[0][0]
- hosts_to_run_on = run_playbook_mock.call_args[0][1]
+ hosts = run_playbook_mock.call_args[0][1]
+ hosts_to_run_on = run_playbook_mock.call_args[0][2]
self.assertEquals(3, len(hosts))
self.assertEquals(3, len(hosts_to_run_on))
@@ -409,7 +455,7 @@ class UnattendedCliTests(OOCliFixture):
# Check the inventory file looks as we would expect:
inventory = ConfigParser.ConfigParser(allow_no_value=True)
- inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
self.assertEquals('bob',
inventory.get('OSEv3:vars', 'ansible_ssh_user'))
self.assertEquals('openshift-enterprise',
@@ -448,11 +494,11 @@ class UnattendedCliTests(OOCliFixture):
self.assertEquals('openshift-enterprise', written_config['variant'])
# We didn't specify a version so the latest should have been assumed,
# and written to disk:
- self.assertEquals('3.1', written_config['variant_version'])
+ self.assertEquals('3.2', written_config['variant_version'])
# Make sure the correct value was passed to ansible:
inventory = ConfigParser.ConfigParser(allow_no_value=True)
- inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
self.assertEquals('openshift-enterprise',
inventory.get('OSEv3:vars', 'deployment_type'))
@@ -480,7 +526,7 @@ class UnattendedCliTests(OOCliFixture):
self.assertEquals('3.0', written_config['variant_version'])
inventory = ConfigParser.ConfigParser(allow_no_value=True)
- inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
self.assertEquals('enterprise',
inventory.get('OSEv3:vars', 'deployment_type'))
@@ -593,10 +639,10 @@ class UnattendedCliTests(OOCliFixture):
self.assert_result(result, 0)
# Make sure we ran on the expected masters and nodes:
- hosts = run_playbook_mock.call_args[0][0]
- hosts_to_run_on = run_playbook_mock.call_args[0][1]
- self.assertEquals(5, len(hosts))
- self.assertEquals(5, len(hosts_to_run_on))
+ hosts = run_playbook_mock.call_args[0][1]
+ hosts_to_run_on = run_playbook_mock.call_args[0][2]
+ self.assertEquals(6, len(hosts))
+ self.assertEquals(6, len(hosts_to_run_on))
#unattended with two masters, one node, and haproxy
@patch('ooinstall.openshift_ansible.run_main_playbook')
@@ -663,10 +709,10 @@ class UnattendedCliTests(OOCliFixture):
self.assert_result(result, 0)
# Make sure we ran on the expected masters and nodes:
- hosts = run_playbook_mock.call_args[0][0]
- hosts_to_run_on = run_playbook_mock.call_args[0][1]
- self.assertEquals(5, len(hosts))
- self.assertEquals(5, len(hosts_to_run_on))
+ hosts = run_playbook_mock.call_args[0][1]
+ hosts_to_run_on = run_playbook_mock.call_args[0][2]
+ self.assertEquals(6, len(hosts))
+ self.assertEquals(6, len(hosts_to_run_on))
class AttendedCliTests(OOCliFixture):
@@ -688,26 +734,27 @@ class AttendedCliTests(OOCliFixture):
('10.0.0.3', False, False)],
ssh_user='root',
variant_num=1,
- confirm_facts='y')
+ confirm_facts='y',
+ storage='10.1.0.1',)
self.cli_args.append("install")
result = self.runner.invoke(cli.cli, self.cli_args,
input=cli_input)
self.assert_result(result, 0)
self._verify_load_facts(load_facts_mock)
- self._verify_run_playbook(run_playbook_mock, 3, 3)
+ self._verify_run_playbook(run_playbook_mock, 4, 4)
written_config = read_yaml(self.config_file)
- self._verify_config_hosts(written_config, 3)
+ self._verify_config_hosts(written_config, 4)
inventory = ConfigParser.ConfigParser(allow_no_value=True)
- inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
- self.assertEquals('False',
- inventory.get('nodes', '10.0.0.1 openshift_schedulable'))
- self.assertEquals(None,
- inventory.get('nodes', '10.0.0.2'))
- self.assertEquals(None,
- inventory.get('nodes', '10.0.0.3'))
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1',
+ 'openshift_schedulable=False')
+ self.assert_inventory_host_var_unset(inventory, 'nodes', '10.0.0.2',
+ 'openshift_schedulable')
+ self.assert_inventory_host_var_unset(inventory, 'nodes', '10.0.0.3',
+ 'openshift_schedulable')
# interactive with config file and some installed some uninstalled hosts
@patch('ooinstall.openshift_ansible.run_main_playbook')
@@ -730,7 +777,8 @@ class AttendedCliTests(OOCliFixture):
add_nodes=[('10.0.0.3', False, False)],
ssh_user='root',
variant_num=1,
- confirm_facts='y')
+ confirm_facts='y',
+ storage='10.0.0.1',)
self.cli_args.append("install")
result = self.runner.invoke(cli.cli,
self.cli_args,
@@ -781,7 +829,8 @@ class AttendedCliTests(OOCliFixture):
ssh_user='root',
variant_num=1,
schedulable_masters_ok=True,
- confirm_facts='y')
+ confirm_facts='y',
+ storage='10.0.0.1',)
self._verify_get_hosts_to_run_on(mock_facts, load_facts_mock,
run_playbook_mock,
@@ -805,28 +854,29 @@ class AttendedCliTests(OOCliFixture):
ssh_user='root',
variant_num=1,
confirm_facts='y',
- master_lb=('10.0.0.5', False))
+ master_lb=('10.0.0.5', False),
+ storage='10.1.0.1',)
self.cli_args.append("install")
result = self.runner.invoke(cli.cli, self.cli_args,
input=cli_input)
self.assert_result(result, 0)
self._verify_load_facts(load_facts_mock)
- self._verify_run_playbook(run_playbook_mock, 5, 5)
+ self._verify_run_playbook(run_playbook_mock, 6, 6)
written_config = read_yaml(self.config_file)
- self._verify_config_hosts(written_config, 5)
+ self._verify_config_hosts(written_config, 6)
inventory = ConfigParser.ConfigParser(allow_no_value=True)
- inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
- self.assertEquals('False',
- inventory.get('nodes', '10.0.0.1 openshift_schedulable'))
- self.assertEquals('False',
- inventory.get('nodes', '10.0.0.2 openshift_schedulable'))
- self.assertEquals('False',
- inventory.get('nodes', '10.0.0.3 openshift_schedulable'))
- self.assertEquals(None,
- inventory.get('nodes', '10.0.0.4'))
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1',
+ 'openshift_schedulable=False')
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.2',
+ 'openshift_schedulable=False')
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.3',
+ 'openshift_schedulable=False')
+ self.assert_inventory_host_var_unset(inventory, 'nodes', '10.0.0.4',
+ 'openshift_schedulable')
self.assertTrue(inventory.has_section('etcd'))
self.assertEquals(3, len(inventory.items('etcd')))
@@ -845,26 +895,64 @@ class AttendedCliTests(OOCliFixture):
ssh_user='root',
variant_num=1,
confirm_facts='y',
- master_lb=('10.0.0.5', False))
+ master_lb=('10.0.0.5', False),
+ storage='10.1.0.1',)
self.cli_args.append("install")
result = self.runner.invoke(cli.cli, self.cli_args,
input=cli_input)
self.assert_result(result, 0)
self._verify_load_facts(load_facts_mock)
- self._verify_run_playbook(run_playbook_mock, 4, 4)
+ self._verify_run_playbook(run_playbook_mock, 5, 5)
written_config = read_yaml(self.config_file)
- self._verify_config_hosts(written_config, 4)
+ self._verify_config_hosts(written_config, 5)
inventory = ConfigParser.ConfigParser(allow_no_value=True)
- inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
- self.assertEquals('True',
- inventory.get('nodes', '10.0.0.1 openshift_schedulable'))
- self.assertEquals('True',
- inventory.get('nodes', '10.0.0.2 openshift_schedulable'))
- self.assertEquals('True',
- inventory.get('nodes', '10.0.0.3 openshift_schedulable'))
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1',
+ 'openshift_schedulable=True')
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.2',
+ 'openshift_schedulable=True')
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.3',
+ 'openshift_schedulable=True')
+
+ # Checks the inventory (as a ConfigParser) for the given host, host
+ # variable, and expected value.
+ def assert_inventory_host_var(self, inventory, section, host, variable):
+ # Config parser splits on the first "=", so we end up with:
+ # 'hostname key1' -> 'val1 key2=val2 key3=val3'
+ #
+ # Convert to something easier to test:
+ for (a, b) in inventory.items(section):
+ full_line = "%s=%s" % (a, b)
+ tokens = full_line.split()
+ if tokens[0] == host:
+ found = False
+ for token in tokens:
+ if token == variable:
+ found = True
+ continue
+ self.assertTrue("Unable to find %s in line: %s" %
+ (variable, full_line), found)
+ return
+ self.fail("unable to find host %s in inventory" % host)
+
+ def assert_inventory_host_var_unset(self, inventory, section, host, variable):
+ # Config parser splits on the first "=", so we end up with:
+ # 'hostname key1' -> 'val1 key2=val2 key3=val3'
+ #
+ # Convert to something easier to test:
+ for (a, b) in inventory.items(section):
+ full_line = "%s=%s" % (a, b)
+ tokens = full_line.split()
+ if tokens[0] == host:
+ self.assertFalse(("%s=" % variable) in full_line,
+ msg='%s host variable was set: %s' %
+ (variable, full_line))
+ return
+ self.fail("unable to find host %s in inventory" % host)
+
#interactive multimaster: attempting to use a master as the load balancer should fail:
@patch('ooinstall.openshift_ansible.run_main_playbook')
@@ -881,7 +969,8 @@ class AttendedCliTests(OOCliFixture):
ssh_user='root',
variant_num=1,
confirm_facts='y',
- master_lb=(['10.0.0.2', '10.0.0.5'], False))
+ master_lb=(['10.0.0.2', '10.0.0.5'], False),
+ storage='10.1.0.1')
self.cli_args.append("install")
result = self.runner.invoke(cli.cli, self.cli_args,
input=cli_input)
@@ -898,7 +987,8 @@ class AttendedCliTests(OOCliFixture):
('10.0.0.1', True, False)],
ssh_user='root',
variant_num=1,
- confirm_facts='y')
+ confirm_facts='y',
+ storage='10.0.0.1')
self.cli_args.append("install")
result = self.runner.invoke(cli.cli, self.cli_args,
input=cli_input)
@@ -911,9 +1001,9 @@ class AttendedCliTests(OOCliFixture):
self._verify_config_hosts(written_config, 1)
inventory = ConfigParser.ConfigParser(allow_no_value=True)
- inventory.read(os.path.join(self.work_dir, '.ansible/hosts'))
- self.assertEquals('True',
- inventory.get('nodes', '10.0.0.1 openshift_schedulable'))
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1',
+ 'openshift_schedulable=True')
#interactive 3.0 install confirm no HA hints
@patch('ooinstall.openshift_ansible.run_main_playbook')
@@ -925,15 +1015,55 @@ class AttendedCliTests(OOCliFixture):
cli_input = build_input(hosts=[
('10.0.0.1', True, False)],
ssh_user='root',
- variant_num=2,
- confirm_facts='y')
+ variant_num=3,
+ confirm_facts='y',
+ storage='10.1.0.1',)
self.cli_args.append("install")
result = self.runner.invoke(cli.cli, self.cli_args,
input=cli_input)
self.assert_result(result, 0)
+ print result.output
self.assertTrue("NOTE: Add a total of 3 or more Masters to perform an HA installation."
not in result.output)
+ @patch('ooinstall.openshift_ansible.run_main_playbook')
+ @patch('ooinstall.openshift_ansible.load_system_facts')
+ def test_gen_inventory(self, load_facts_mock, run_playbook_mock):
+ load_facts_mock.return_value = (MOCK_FACTS, 0)
+ run_playbook_mock.return_value = 0
+
+ cli_input = build_input(hosts=[
+ ('10.0.0.1', True, False),
+ ('10.0.0.2', False, False),
+ ('10.0.0.3', False, False)],
+ ssh_user='root',
+ variant_num=1,
+ confirm_facts='y',
+ storage='10.1.0.1',)
+ self.cli_args.append("install")
+ self.cli_args.append("--gen-inventory")
+ result = self.runner.invoke(cli.cli, self.cli_args,
+ input=cli_input)
+ self.assert_result(result, 0)
+
+ self._verify_load_facts(load_facts_mock)
+
+ # Make sure run playbook wasn't called:
+ self.assertEquals(0, len(run_playbook_mock.mock_calls))
+
+ written_config = read_yaml(self.config_file)
+ self._verify_config_hosts(written_config, 4)
+
+ inventory = ConfigParser.ConfigParser(allow_no_value=True)
+ inventory.read(os.path.join(self.work_dir, 'hosts'))
+ self.assert_inventory_host_var(inventory, 'nodes', '10.0.0.1',
+ 'openshift_schedulable=False')
+ self.assert_inventory_host_var_unset(inventory, 'nodes', '10.0.0.2',
+ 'openshift_schedulable')
+ self.assert_inventory_host_var_unset(inventory, 'nodes', '10.0.0.3',
+ 'openshift_schedulable')
+
+
# TODO: test with config file, attended add node
# TODO: test with config file, attended new node already in config file
# TODO: test with config file, attended new node already in config file, plus manually added nodes
diff --git a/utils/test/fixture.py b/utils/test/fixture.py
index 1b1c2e5c2..e01eaebaf 100644
--- a/utils/test/fixture.py
+++ b/utils/test/fixture.py
@@ -68,7 +68,7 @@ class OOCliFixture(OOInstallFixture):
def _verify_load_facts(self, load_facts_mock):
""" Check that we ran load facts with expected inputs. """
load_facts_args = load_facts_mock.call_args[0]
- self.assertEquals(os.path.join(self.work_dir, ".ansible/hosts"),
+ self.assertEquals(os.path.join(self.work_dir, "hosts"),
load_facts_args[0])
self.assertEquals(os.path.join(self.work_dir,
"playbooks/byo/openshift_facts.yml"),
@@ -81,8 +81,8 @@ class OOCliFixture(OOInstallFixture):
def _verify_run_playbook(self, run_playbook_mock, exp_hosts_len, exp_hosts_to_run_on_len):
""" Check that we ran playbook with expected inputs. """
- hosts = run_playbook_mock.call_args[0][0]
- hosts_to_run_on = run_playbook_mock.call_args[0][1]
+ hosts = run_playbook_mock.call_args[0][1]
+ hosts_to_run_on = run_playbook_mock.call_args[0][2]
self.assertEquals(exp_hosts_len, len(hosts))
self.assertEquals(exp_hosts_to_run_on_len, len(hosts_to_run_on))
@@ -92,7 +92,7 @@ class OOCliFixture(OOInstallFixture):
self.assertTrue('hostname' in host)
self.assertTrue('public_hostname' in host)
if 'preconfigured' not in host:
- self.assertTrue(host['node'])
+ self.assertTrue('node' in host or 'storage' in host)
self.assertTrue('ip' in host)
self.assertTrue('public_ip' in host)
@@ -133,8 +133,8 @@ class OOCliFixture(OOInstallFixture):
self._verify_run_playbook(run_playbook_mock, exp_hosts_len, exp_hosts_to_run_on_len)
# Make sure we ran on the expected masters and nodes:
- hosts = run_playbook_mock.call_args[0][0]
- hosts_to_run_on = run_playbook_mock.call_args[0][1]
+ hosts = run_playbook_mock.call_args[0][1]
+ hosts_to_run_on = run_playbook_mock.call_args[0][2]
self.assertEquals(exp_hosts_len, len(hosts))
self.assertEquals(exp_hosts_to_run_on_len, len(hosts_to_run_on))
@@ -142,7 +142,7 @@ class OOCliFixture(OOInstallFixture):
#pylint: disable=too-many-arguments,too-many-branches,too-many-statements
def build_input(ssh_user=None, hosts=None, variant_num=None,
add_nodes=None, confirm_facts=None, schedulable_masters_ok=None,
- master_lb=None):
+ master_lb=None, storage=None):
"""
Build an input string simulating a user entering values in an interactive
attended install.
@@ -197,7 +197,13 @@ def build_input(ssh_user=None, hosts=None, variant_num=None,
inputs.append(master_lb[0])
inputs.append('y' if master_lb[1] else 'n')
- inputs.append('example.com')
+ if storage:
+ inputs.append(storage)
+
+ inputs.append('subdomain.example.com')
+ inputs.append('proxy.example.com')
+ inputs.append('proxy-private.example.com')
+ inputs.append('exclude.example.com')
# TODO: support option 2, fresh install
if add_nodes: