diff options
57 files changed, 1343 insertions, 303 deletions
diff --git a/.gitignore b/.gitignore index dcea26d60..48507c5d1 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ multi_inventory.yaml .tags* ansible.cfg *.retry +.vscode/* diff --git a/README_AWS.md b/README_AWS.md index cccb122f6..650a921a4 100644 --- a/README_AWS.md +++ b/README_AWS.md @@ -1,4 +1,4 @@ -:warning: **WARNING** :warning: This feature is community supported and has not been tested by Red Hat. Visit [docs.openshift.com](https://docs.openshift.com) for [OpenShift Enterprise](https://docs.openshift.com/enterprise/latest/install_config/install/index.html) or [OpenShift Origin](https://docs.openshift.org/latest/install_config/install/index.html) supported installation docs. +:warning: **WARNING** :warning: This feature is community supported and has not been tested by Red Hat. Visit [docs.openshift.com](https://docs.openshift.com) for [OpenShift Enterprise](https://docs.openshift.com/enterprise/latest/install_config/install/planning.html) or [OpenShift Origin](https://docs.openshift.org/latest/install_config/install/planning.html) supported installation docs. AWS Setup Instructions ====================== @@ -196,5 +196,5 @@ You should now be ready to follow the **What's Next?** section of the advanced i Refer to the advanced installation guide for your deployment type: -* [OpenShift Enterprise](https://docs.openshift.com/enterprise/3.0/install_config/install/advanced_install.html#what-s-next) +* [OpenShift Enterprise](https://docs.openshift.com/enterprise/latest/install_config/install/advanced_install.html#what-s-next) * [OpenShift Origin](https://docs.openshift.org/latest/install_config/install/advanced_install.html#what-s-next) diff --git a/README_CONTAINERIZED_INSTALLATION.md b/README_CONTAINERIZED_INSTALLATION.md index 56f25546c..c615154ef 100644 --- a/README_CONTAINERIZED_INSTALLATION.md +++ b/README_CONTAINERIZED_INSTALLATION.md @@ -1,8 +1,8 @@ # Overview Users may now deploy containerized versions of OpenShift Origin, OpenShift -Enterprise, or Atomic Enterprise Platform on Atomic -Host[https://projectatomic.io] or RHEL, Centos, and Fedora. This includes +Enterprise, or Atomic Enterprise Platform on [Atomic +Host](https://projectatomic.io) or RHEL, Centos, and Fedora. This includes OpenvSwitch based SDN. diff --git a/bin/cluster b/bin/cluster index 92174954f..68d2a7cd4 100755 --- a/bin/cluster +++ b/bin/cluster @@ -73,9 +73,16 @@ class Cluster(object): cluster['openshift_cloudprovider_openstack_auth_url'] = os.getenv('OS_AUTH_URL') cluster['openshift_cloudprovider_openstack_username'] = os.getenv('OS_USERNAME') cluster['openshift_cloudprovider_openstack_password'] = os.getenv('OS_PASSWORD') - cluster['openshift_cloudprovider_openstack_tenant_id'] = os.getenv('OS_PROJECT_ID',os.getenv('OS_TENANT_ID')) - cluster['openshift_cloudprovider_openstack_tenant_name'] = os.getenv('OS_PROJECT_NAME',os.getenv('OS_TENANT_NAME')) - cluster['openshift_cloudprovider_openstack_region'] = os.getenv('OS_REGION_NAME') + if 'OS_USER_DOMAIN_ID' in os.environ: + cluster['openshift_cloudprovider_openstack_domain_id'] = os.getenv('OS_USER_DOMAIN_ID') + if 'OS_USER_DOMAIN_NAME' in os.environ: + cluster['openshift_cloudprovider_openstack_domain_name'] = os.getenv('OS_USER_DOMAIN_NAME') + if 'OS_PROJECT_ID' in os.environ or 'OS_TENANT_ID' in os.environ: + cluster['openshift_cloudprovider_openstack_tenant_id'] = os.getenv('OS_PROJECT_ID',os.getenv('OS_TENANT_ID')) + if 'OS_PROJECT_NAME' is os.environ or 'OS_TENANT_NAME' in os.environ: + cluster['openshift_cloudprovider_openstack_tenant_name'] = os.getenv('OS_PROJECT_NAME',os.getenv('OS_TENANT_NAME')) + if 'OS_REGION_NAME' in os.environ: + cluster['openshift_cloudprovider_openstack_region'] = os.getenv('OS_REGION_NAME') self.action(args, inventory, cluster, playbook) diff --git a/callback_plugins/openshift_quick_installer.py b/callback_plugins/openshift_quick_installer.py new file mode 100644 index 000000000..e2f125df9 --- /dev/null +++ b/callback_plugins/openshift_quick_installer.py @@ -0,0 +1,291 @@ +# pylint: disable=invalid-name,protected-access,import-error,line-too-long + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +"""This file is a stdout callback plugin for the OpenShift Quick +Installer. The purpose of this callback plugin is to reduce the amount +of produced output for customers and enable simpler progress checking. + +What's different: + +* Playbook progress is expressed as: Play <current_play>/<total_plays> (Play Name) + Ex: Play 3/30 (Initialize Megafrobber) + +* The Tasks and Handlers in each play (and included roles) are printed + as a series of .'s following the play progress line. + +* Many of these methods include copy and paste code from the upstream + default.py callback. We do that to give us control over the stdout + output while allowing Ansible to handle the file logging + normally. The biggest changes here are that we are manually setting + `log_only` to True in the Display.display method and we redefine the + Display.banner method locally so we can set log_only on that call as + well. + +""" + +from __future__ import (absolute_import, print_function) +import imp +import os +import sys +from ansible import constants as C +from ansible.utils.color import colorize, hostcolor +ANSIBLE_PATH = imp.find_module('ansible')[1] +DEFAULT_PATH = os.path.join(ANSIBLE_PATH, 'plugins/callback/default.py') +DEFAULT_MODULE = imp.load_source( + 'ansible.plugins.callback.default', + DEFAULT_PATH +) + +try: + from ansible.plugins.callback import CallbackBase + BASECLASS = CallbackBase +except ImportError: # < ansible 2.1 + BASECLASS = DEFAULT_MODULE.CallbackModule + + +reload(sys) +sys.setdefaultencoding('utf-8') + + +class CallbackModule(DEFAULT_MODULE.CallbackModule): + + """ + Ansible callback plugin + """ + CALLBACK_VERSION = 2.2 + CALLBACK_TYPE = 'stdout' + CALLBACK_NAME = 'openshift_quick_installer' + CALLBACK_NEEDS_WHITELIST = False + plays_count = 0 + plays_total_ran = 0 + + def banner(self, msg, color=None): + '''Prints a header-looking line with stars taking up to 80 columns + of width (3 columns, minimum) + + Overrides the upstream banner method so that display is called + with log_only=True + ''' + msg = msg.strip() + star_len = (79 - len(msg)) + if star_len < 0: + star_len = 3 + stars = "*" * star_len + self._display.display("\n%s %s" % (msg, stars), color=color, log_only=True) + + def v2_playbook_on_start(self, playbook): + """This is basically the start of it all""" + self.plays_count = len(playbook.get_plays()) + self.plays_total_ran = 0 + + if self._display.verbosity > 1: + from os.path import basename + self.banner("PLAYBOOK: %s" % basename(playbook._file_name)) + + def v2_playbook_on_play_start(self, play): + """Each play calls this once before running any tasks + +We could print the number of tasks here as well by using +`play.get_tasks()` but that is not accurate when a play includes a +role. Only the tasks directly assigned to a play are exposed in the +`play` object. + """ + self.plays_total_ran += 1 + print("") + print("Play %s/%s (%s)" % (self.plays_total_ran, self.plays_count, play.get_name())) + + name = play.get_name().strip() + if not name: + msg = "PLAY" + else: + msg = "PLAY [%s]" % name + + self.banner(msg) + + # pylint: disable=unused-argument,no-self-use + def v2_playbook_on_task_start(self, task, is_conditional): + """This prints out the task header. For example: + +TASK [openshift_facts : Ensure PyYaml is installed] ***... + +Rather than print out all that for every task, we print a dot +character to indicate a task has been started. + """ + sys.stdout.write('.') + + args = '' + # args can be specified as no_log in several places: in the task or in + # the argument spec. We can check whether the task is no_log but the + # argument spec can't be because that is only run on the target + # machine and we haven't run it thereyet at this time. + # + # So we give people a config option to affect display of the args so + # that they can secure this if they feel that their stdout is insecure + # (shoulder surfing, logging stdout straight to a file, etc). + if not task.no_log and C.DISPLAY_ARGS_TO_STDOUT: + args = ', '.join(('%s=%s' % a for a in task.args.items())) + args = ' %s' % args + self.banner("TASK [%s%s]" % (task.get_name().strip(), args)) + if self._display.verbosity >= 2: + path = task.get_path() + if path: + self._display.display("task path: %s" % path, color=C.COLOR_DEBUG, log_only=True) + + # pylint: disable=unused-argument,no-self-use + def v2_playbook_on_handler_task_start(self, task): + """Print out task header for handlers + +Rather than print out a header for every handler, we print a dot +character to indicate a handler task has been started. +""" + sys.stdout.write('.') + + self.banner("RUNNING HANDLER [%s]" % task.get_name().strip()) + + # pylint: disable=unused-argument,no-self-use + def v2_playbook_on_cleanup_task_start(self, task): + """Print out a task header for cleanup tasks + +Rather than print out a header for every handler, we print a dot +character to indicate a handler task has been started. +""" + sys.stdout.write('.') + + self.banner("CLEANUP TASK [%s]" % task.get_name().strip()) + + def v2_playbook_on_include(self, included_file): + """Print out paths to statically included files""" + msg = 'included: %s for %s' % (included_file._filename, ", ".join([h.name for h in included_file._hosts])) + self._display.display(msg, color=C.COLOR_SKIP, log_only=True) + + def v2_runner_on_ok(self, result): + """This prints out task results in a fancy format + +The only thing we change here is adding `log_only=True` to the +.display() call + """ + delegated_vars = result._result.get('_ansible_delegated_vars', None) + self._clean_results(result._result, result._task.action) + if result._task.action in ('include', 'include_role'): + return + elif result._result.get('changed', False): + if delegated_vars: + msg = "changed: [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host']) + else: + msg = "changed: [%s]" % result._host.get_name() + color = C.COLOR_CHANGED + else: + if delegated_vars: + msg = "ok: [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host']) + else: + msg = "ok: [%s]" % result._host.get_name() + color = C.COLOR_OK + + if result._task.loop and 'results' in result._result: + self._process_items(result) + else: + + if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result: + msg += " => %s" % (self._dump_results(result._result),) + self._display.display(msg, color=color, log_only=True) + + self._handle_warnings(result._result) + + def v2_runner_item_on_ok(self, result): + """Print out task results for items you're iterating over""" + delegated_vars = result._result.get('_ansible_delegated_vars', None) + if result._task.action in ('include', 'include_role'): + return + elif result._result.get('changed', False): + msg = 'changed' + color = C.COLOR_CHANGED + else: + msg = 'ok' + color = C.COLOR_OK + + if delegated_vars: + msg += ": [%s -> %s]" % (result._host.get_name(), delegated_vars['ansible_host']) + else: + msg += ": [%s]" % result._host.get_name() + + msg += " => (item=%s)" % (self._get_item(result._result),) + + if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result: + msg += " => %s" % self._dump_results(result._result) + self._display.display(msg, color=color, log_only=True) + + def v2_runner_item_on_skipped(self, result): + """Print out task results when an item is skipped""" + if C.DISPLAY_SKIPPED_HOSTS: + msg = "skipping: [%s] => (item=%s) " % (result._host.get_name(), self._get_item(result._result)) + if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result: + msg += " => %s" % self._dump_results(result._result) + self._display.display(msg, color=C.COLOR_SKIP, log_only=True) + + def v2_runner_on_skipped(self, result): + """Print out task results when a task (or something else?) is skipped""" + if C.DISPLAY_SKIPPED_HOSTS: + if result._task.loop and 'results' in result._result: + self._process_items(result) + else: + msg = "skipping: [%s]" % result._host.get_name() + if (self._display.verbosity > 0 or '_ansible_verbose_always' in result._result) and '_ansible_verbose_override' not in result._result: + msg += " => %s" % self._dump_results(result._result) + self._display.display(msg, color=C.COLOR_SKIP, log_only=True) + + def v2_playbook_on_notify(self, res, handler): + """What happens when a task result is 'changed' and the task has a +'notify' list attached. + """ + self._display.display("skipping: no hosts matched", color=C.COLOR_SKIP, log_only=True) + + def v2_playbook_on_stats(self, stats): + """Print the final playbook run stats""" + self._display.display("", screen_only=True) + self.banner("PLAY RECAP") + + hosts = sorted(stats.processed.keys()) + for h in hosts: + t = stats.summarize(h) + + self._display.display( + u"%s : %s %s %s %s" % ( + hostcolor(h, t), + colorize(u'ok', t['ok'], C.COLOR_OK), + colorize(u'changed', t['changed'], C.COLOR_CHANGED), + colorize(u'unreachable', t['unreachable'], C.COLOR_UNREACHABLE), + colorize(u'failed', t['failures'], C.COLOR_ERROR)), + screen_only=True + ) + + self._display.display( + u"%s : %s %s %s %s" % ( + hostcolor(h, t, False), + colorize(u'ok', t['ok'], None), + colorize(u'changed', t['changed'], None), + colorize(u'unreachable', t['unreachable'], None), + colorize(u'failed', t['failures'], None)), + log_only=True + ) + + self._display.display("", screen_only=True) + self._display.display("", screen_only=True) + + # Some plays are conditional and won't run (such as load + # balancers) if they aren't required. Let the user know about + # this to avoid potential confusion. + if self.plays_total_ran != self.plays_count: + print("Installation Complete: Note: Play count is an estimate and some were skipped because your install does not require them") + self._display.display("", screen_only=True) diff --git a/filter_plugins/oo_filters.py b/filter_plugins/oo_filters.py index 1c12f2e07..39e6b0a0b 100644 --- a/filter_plugins/oo_filters.py +++ b/filter_plugins/oo_filters.py @@ -17,9 +17,17 @@ import re import json import yaml from ansible.parsing.yaml.dumper import AnsibleDumper -from ansible.utils.unicode import to_unicode from urlparse import urlparse +try: + # ansible-2.2 + # ansible.utils.unicode.to_unicode is deprecated in ansible-2.2, + # ansible.module_utils._text.to_text should be used instead. + from ansible.module_utils._text import to_text +except ImportError: + # ansible-2.1 + from ansible.utils.unicode import to_unicode as to_text + # Disabling too-many-public-methods, since filter methods are necessarily # public # pylint: disable=too-many-public-methods @@ -626,7 +634,7 @@ class FilterModule(object): default_flow_style=False, Dumper=AnsibleDumper, **kw) padded = "\n".join([" " * level * indent + line for line in transformed.splitlines()]) - return to_unicode("\n{0}".format(padded)) + return to_text("\n{0}".format(padded)) except Exception as my_e: raise errors.AnsibleFilterError('Failed to convert: %s' % my_e) diff --git a/inventory/byo/hosts.origin.example b/inventory/byo/hosts.origin.example index 200918853..df963bf05 100644 --- a/inventory/byo/hosts.origin.example +++ b/inventory/byo/hosts.origin.example @@ -65,10 +65,6 @@ openshift_release=v1.2 # See: https://docs.openshift.org/latest/install_config/web_console_customization.html#serving-static-files #openshift_master_oauth_template=/path/to/login-template.html -# Configure loggingPublicURL in the master config for aggregate logging -# See: https://docs.openshift.org/latest/install_config/aggregate_logging.html -#openshift_master_logging_public_url=https://kibana.example.com - # Configure imagePolicyConfig in the master config # See: https://godoc.org/github.com/openshift/origin/pkg/cmd/server/api#ImagePolicyConfig #openshift_master_image_policy_config={"maxImagesBulkImportedPerRepository": 3, "disableScheduledImport": true} @@ -144,6 +140,8 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', #openshift_cloudprovider_openstack_auth_url=http://openstack.example.com:35357/v2.0/ #openshift_cloudprovider_openstack_username=username #openshift_cloudprovider_openstack_password=password +#openshift_cloudprovider_openstack_domain_id=domain_id +#openshift_cloudprovider_openstack_domain_name=domain_name #openshift_cloudprovider_openstack_tenant_id=tenant_id #openshift_cloudprovider_openstack_tenant_name=tenant_name #openshift_cloudprovider_openstack_region=region @@ -370,6 +368,55 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', # `/hawkular/metrics` path will break installation of metrics. #openshift_hosted_metrics_public_url=https://hawkular-metrics.example.com/hawkular/metrics +# Logging deployment +# +# Currently logging deployment is disabled by default, enable it by setting this +#openshift_hosted_logging_deploy=true +# +# Logging storage config +# Option A - NFS Host Group +# An NFS volume will be created with path "nfs_directory/volume_name" +# on the host within the [nfs] host group. For example, the volume +# path using these options would be "/exports/logging" +#openshift_hosted_logging_storage_kind=nfs +#openshift_hosted_logging_storage_access_modes=['ReadWriteOnce'] +#openshift_hosted_logging_storage_nfs_directory=/exports +#openshift_hosted_logging_storage_nfs_options='*(rw,root_squash)' +#openshift_hosted_logging_storage_volume_name=logging +#openshift_hosted_logging_storage_volume_size=10Gi +# +# Option B - External NFS Host +# NFS volume must already exist with path "nfs_directory/_volume_name" on +# the storage_host. For example, the remote volume path using these +# options would be "nfs.example.com:/exports/logging" +#openshift_hosted_logging_storage_kind=nfs +#openshift_hosted_logging_storage_access_modes=['ReadWriteOnce'] +#openshift_hosted_logging_storage_host=nfs.example.com +#openshift_hosted_logging_storage_nfs_directory=/exports +#openshift_hosted_logging_storage_volume_name=logging +#openshift_hosted_logging_storage_volume_size=10Gi +# +# Option C - Dynamic -- If openshift supports dynamic volume provisioning for +# your cloud platform use this. +#openshift_hosted_logging_storage_kind=dynamic +# +# Option D - none -- Logging will use emptydir volumes which are destroyed when +# pods are deleted +# +# Other Logging Options -- Common items you may wish to reconfigure, for the complete +# list of options please see roles/openshift_hosted_logging/README.md +# +# Configure loggingPublicURL in the master config for aggregate logging, defaults +# to https://kibana.{{ openshift_master_default_subdomain }} +#openshift_master_logging_public_url=https://kibana.example.com +# Configure the number of elastic search nodes, unless you're using dynamic provisioning +# this value must be 1 +#openshift_hosted_logging_elasticsearch_cluster_size=1 +#openshift_hosted_logging_hostname=logging.apps.example.com +# Configure the prefix and version for the deployer image +#openshift_hosted_logging_deployer_prefix=registry.example.com:8888/openshift3/ +#openshift_hosted_logging_deployer_version=3.3.0 + # Configure the multi-tenant SDN plugin (default is 'redhat/openshift-ovs-subnet') # os_sdn_network_plugin_name='redhat/openshift-ovs-multitenant' @@ -516,8 +563,7 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', #openshift_builddefaults_git_http_proxy=http://USER:PASSWORD@HOST:PORT #openshift_builddefaults_git_https_proxy=https://USER:PASSWORD@HOST:PORT # Or you may optionally define your own serialized as json -#openshift_builddefaults_json='{"BuildDefaults":{"configuration":{"apiVersion":"v1","env":[{"name":"HTTP_PROXY","value":"http://proxy.example.com.redhat.com:3128"},{"name":"NO_PROXY","value":"ose3-master.example.com"}],"gitHTTPProxy":"http://proxy.example.com:3128","kind":"BuildDefaultsConfig"}}}' - +#openshift_builddefaults_json='{"BuildDefaults":{"configuration":{"kind":"BuildDefaultsConfig","apiVersion":"v1","gitHTTPSProxy":"http://proxy.example.com.redhat.com:3128","gitHTTPProxy":"http://proxy.example.com.redhat.com:3128","env":[{"name":"HTTP_PROXY","value":"http://proxy.example.com.redhat.com:3128"},{"name":"NO_PROXY","value":"ose3-master.example.com"}]}}' # masterConfig.volumeConfig.dynamicProvisioningEnabled, configurable as of 1.2/3.2, enabled by default #openshift_master_dynamic_provisioning_enabled=False diff --git a/inventory/byo/hosts.ose.example b/inventory/byo/hosts.ose.example index af653f850..19519da50 100644 --- a/inventory/byo/hosts.ose.example +++ b/inventory/byo/hosts.ose.example @@ -65,10 +65,6 @@ openshift_release=v3.2 # See: https://docs.openshift.org/latest/install_config/web_console_customization.html#serving-static-files #openshift_master_oauth_template=/path/to/login-template.html -# Configure loggingPublicURL in the master config for aggregate logging -# See: https://docs.openshift.com/enterprise/latest/install_config/aggregate_logging.html -#openshift_master_logging_public_url=https://kibana.example.com -# # Configure imagePolicyConfig in the master config # See: https://godoc.org/github.com/openshift/origin/pkg/cmd/server/api#ImagePolicyConfig #openshift_master_image_policy_config={"maxImagesBulkImportedPerRepository": 3, "disableScheduledImport": true} @@ -144,6 +140,8 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', #openshift_cloudprovider_openstack_auth_url=http://openstack.example.com:35357/v2.0/ #openshift_cloudprovider_openstack_username=username #openshift_cloudprovider_openstack_password=password +#openshift_cloudprovider_openstack_domain_id=domain_id +#openshift_cloudprovider_openstack_domain_name=domain_name #openshift_cloudprovider_openstack_tenant_id=tenant_id #openshift_cloudprovider_openstack_tenant_name=tenant_name #openshift_cloudprovider_openstack_region=region @@ -370,6 +368,54 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', # `/hawkular/metrics` path will break installation of metrics. #openshift_hosted_metrics_public_url=https://hawkular-metrics.example.com/hawkular/metrics +# Logging deployment +# +# Currently logging deployment is disabled by default, enable it by setting this +#openshift_hosted_logging_deploy=true +# +# Logging storage config +# Option A - NFS Host Group +# An NFS volume will be created with path "nfs_directory/volume_name" +# on the host within the [nfs] host group. For example, the volume +# path using these options would be "/exports/logging" +#openshift_hosted_logging_storage_kind=nfs +#openshift_hosted_logging_storage_access_modes=['ReadWriteOnce'] +#openshift_hosted_logging_storage_nfs_directory=/exports +#openshift_hosted_logging_storage_nfs_options='*(rw,root_squash)' +#openshift_hosted_logging_storage_volume_name=logging +#openshift_hosted_logging_storage_volume_size=10Gi +# +# Option B - External NFS Host +# NFS volume must already exist with path "nfs_directory/_volume_name" on +# the storage_host. For example, the remote volume path using these +# options would be "nfs.example.com:/exports/logging" +#openshift_hosted_logging_storage_kind=nfs +#openshift_hosted_logging_storage_access_modes=['ReadWriteOnce'] +#openshift_hosted_logging_storage_host=nfs.example.com +#openshift_hosted_logging_storage_nfs_directory=/exports +#openshift_hosted_logging_storage_volume_name=logging +#openshift_hosted_logging_storage_volume_size=10Gi +# +# Option C - Dynamic -- If openshift supports dynamic volume provisioning for +# your cloud platform use this. +#openshift_hosted_logging_storage_kind=dynamic +# +# Option D - none -- Logging will use emptydir volumes which are destroyed when +# pods are deleted +# +# Other Logging Options -- Common items you may wish to reconfigure, for the complete +# list of options please see roles/openshift_hosted_logging/README.md +# +# Configure loggingPublicURL in the master config for aggregate logging, defaults +# to https://kibana.{{ openshift_master_default_subdomain }} +#openshift_master_logging_public_url=https://kibana.example.com +# Configure the number of elastic search nodes, unless you're using dynamic provisioning +# this value must be 1 +#openshift_hosted_logging_elasticsearch_cluster_size=1 +#openshift_hosted_logging_hostname=logging.apps.example.com +# Configure the prefix and version for the deployer image +#openshift_hosted_logging_deployer_prefix=registry.example.com:8888/openshift3/ +#openshift_hosted_logging_deployer_version=3.3.0 # Configure the multi-tenant SDN plugin (default is 'redhat/openshift-ovs-subnet') # os_sdn_network_plugin_name='redhat/openshift-ovs-multitenant' @@ -517,8 +563,7 @@ openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', #openshift_builddefaults_git_http_proxy=http://USER:PASSWORD@HOST:PORT #openshift_builddefaults_git_https_proxy=https://USER:PASSWORD@HOST:PORT # Or you may optionally define your own serialized as json -#openshift_builddefaults_json='{"BuildDefaults":{"configuration":{"apiVersion":"v1","env":[{"name":"HTTP_PROXY","value":"http://proxy.example.com.redhat.com:3128"},{"name":"NO_PROXY","value":"ose3-master.example.com"}],"gitHTTPProxy":"http://proxy.example.com:3128","kind":"BuildDefaultsConfig"}}}' - +#openshift_builddefaults_json='{"BuildDefaults":{"configuration":{"kind":"BuildDefaultsConfig","apiVersion":"v1","gitHTTPSProxy":"http://proxy.example.com.redhat.com:3128","gitHTTPProxy":"http://proxy.example.com.redhat.com:3128","env":[{"name":"HTTP_PROXY","value":"http://proxy.example.com.redhat.com:3128"},{"name":"NO_PROXY","value":"ose3-master.example.com"}]}}' # masterConfig.volumeConfig.dynamicProvisioningEnabled, configurable as of 1.2/3.2, enabled by default #openshift_master_dynamic_provisioning_enabled=False diff --git a/openshift-ansible.spec b/openshift-ansible.spec index e57dbfb1b..d31447d7a 100644 --- a/openshift-ansible.spec +++ b/openshift-ansible.spec @@ -70,6 +70,9 @@ cp -rp filter_plugins %{buildroot}%{_datadir}/ansible_plugins/ # openshift-ansible-lookup-plugins install cp -rp lookup_plugins %{buildroot}%{_datadir}/ansible_plugins/ +# openshift-ansible-callback-plugins install +cp -rp callback_plugins %{buildroot}%{_datadir}/ansible_plugins/ + # create symlinks from /usr/share/ansible/plugins/lookup -> # /usr/share/ansible_plugins/lookup_plugins pushd %{buildroot}%{_datadir} @@ -77,6 +80,7 @@ mkdir -p ansible/plugins pushd ansible/plugins ln -s ../../ansible_plugins/lookup_plugins lookup ln -s ../../ansible_plugins/filter_plugins filter +ln -s ../../ansible_plugins/callback_plugins callback popd popd @@ -87,6 +91,9 @@ pushd utils mv -f %{buildroot}%{_bindir}/oo-install %{buildroot}%{_bindir}/atomic-openshift-installer mkdir -p %{buildroot}%{_datadir}/atomic-openshift-utils/ cp etc/ansible.cfg %{buildroot}%{_datadir}/atomic-openshift-utils/ansible.cfg +mkdir -p %{buildroot}%{_mandir}/man1/ +cp -v docs/man/man1/atomic-openshift-installer.1 %{buildroot}%{_mandir}/man1/ +cp etc/ansible-quiet.cfg %{buildroot}%{_datadir}/atomic-openshift-utils/ansible-quiet.cfg popd # Base openshift-ansible files @@ -120,6 +127,7 @@ Requires: %{name} = %{version} Requires: %{name}-roles = %{version} Requires: %{name}-lookup-plugins = %{version} Requires: %{name}-filter-plugins = %{version} +Requires: %{name}-callback-plugins = %{version} BuildArch: noarch %description playbooks @@ -156,6 +164,7 @@ Summary: Openshift and Atomic Enterprise Ansible roles Requires: %{name} = %{version} Requires: %{name}-lookup-plugins = %{version} Requires: %{name}-filter-plugins = %{version} +Requires: %{name}-callback-plugins = %{version} BuildArch: noarch %description roles @@ -197,6 +206,22 @@ BuildArch: noarch %{_datadir}/ansible_plugins/lookup_plugins %{_datadir}/ansible/plugins/lookup + +# ---------------------------------------------------------------------------------- +# openshift-ansible-callback-plugins subpackage +# ---------------------------------------------------------------------------------- +%package callback-plugins +Summary: Openshift and Atomic Enterprise Ansible callback plugins +Requires: %{name} = %{version} +BuildArch: noarch + +%description callback-plugins +%{summary}. + +%files callback-plugins +%{_datadir}/ansible_plugins/callback_plugins +%{_datadir}/ansible/plugins/callback + # ---------------------------------------------------------------------------------- # atomic-openshift-utils subpackage # ---------------------------------------------------------------------------------- @@ -219,6 +244,8 @@ Atomic OpenShift Utilities includes %{python_sitelib}/ooinstall* %{_bindir}/atomic-openshift-installer %{_datadir}/atomic-openshift-utils/ansible.cfg +%{_mandir}/man1/* +%{_datadir}/atomic-openshift-utils/ansible-quiet.cfg %changelog @@ -2384,4 +2411,3 @@ Atomic OpenShift Utilities includes * Mon Oct 19 2015 Troy Dawson <tdawson@redhat.com> 3.0.2-1 - Initial Package - diff --git a/playbooks/byo/openshift-cluster/config.yml b/playbooks/byo/openshift-cluster/config.yml index 0b85b2485..fccb03982 100644 --- a/playbooks/byo/openshift-cluster/config.yml +++ b/playbooks/byo/openshift-cluster/config.yml @@ -1,7 +1,8 @@ --- - include: ../../common/openshift-cluster/verify_ansible_version.yml -- hosts: localhost +- name: Create initial host groups for localhost + hosts: localhost connection: local become: no gather_facts: no @@ -14,7 +15,8 @@ groups: l_oo_all_hosts with_items: "{{ g_all_hosts | default([]) }}" -- hosts: l_oo_all_hosts +- name: Create initial host groups for all hosts + hosts: l_oo_all_hosts gather_facts: no tags: - always diff --git a/playbooks/common/openshift-cluster/config.yml b/playbooks/common/openshift-cluster/config.yml index d6a99fcda..801c8065d 100644 --- a/playbooks/common/openshift-cluster/config.yml +++ b/playbooks/common/openshift-cluster/config.yml @@ -13,7 +13,7 @@ - include: initialize_openshift_version.yml -- name: Set oo_options +- name: Set oo_option facts hosts: oo_all_hosts tags: - always diff --git a/playbooks/common/openshift-cluster/openshift_hosted.yml b/playbooks/common/openshift-cluster/openshift_hosted.yml index 4aca4daf4..2ba7fded5 100644 --- a/playbooks/common/openshift-cluster/openshift_hosted.yml +++ b/playbooks/common/openshift-cluster/openshift_hosted.yml @@ -19,6 +19,12 @@ openshift_hosted_router_registryurl: "{{ hostvars[groups.oo_first_master.0].openshift.master.registry_url }}" openshift_hosted_registry_registryurl: "{{ hostvars[groups.oo_first_master.0].openshift.master.registry_url }}" when: "'master' in hostvars[groups.oo_first_master.0].openshift and 'registry_url' in hostvars[groups.oo_first_master.0].openshift.master" + - set_fact: + logging_hostname: "{{ openshift_hosted_logging_hostname | default('kibana.' ~ (openshift.master.default_subdomain | default('router.default.svc.cluster.local', true))) }}" + logging_ops_hostname: "{{ openshift_hosted_logging_ops_hostname | default('kibana-ops.' ~ (openshift.master.default_subdomain | default('router.default.svc.cluster.local', true))) }}" + logging_master_public_url: "{{ openshift_hosted_logging_master_public_url | default(openshift.master.public_api_url) }}" + logging_elasticsearch_cluster_size: "{{ openshift_hosted_logging_elasticsearch_cluster_size | default(1) }}" + logging_elasticsearch_ops_cluster_size: "{{ openshift_hosted_logging_elasticsearch_ops_cluster_size | default(1) }}" roles: - role: openshift_cli - role: openshift_hosted_facts @@ -43,88 +49,20 @@ when: not openshift.common.version_gte_3_2_or_1_2 - role: openshift_hosted - role: openshift_metrics - when: openshift.hosted.metrics.deploy | bool - - role: cockpit-ui - when: openshift.common.deployment_subtype == 'registry' + when: openshift_hosted_metrics_deploy | default(false) | bool + - role: openshift_hosted_logging + when: openshift_hosted_logging_deploy | default(false) | bool + openshift_hosted_logging_hostname: "{{ logging_hostname }}" + openshift_hosted_logging_ops_hostname: "{{ logging_ops_hostname }}" + openshift_hosted_logging_master_public_url: "{{ logging_master_public_url }}" + openshift_hosted_logging_elasticsearch_cluster_size: "{{ logging_elasticsearch_cluster_size }}" + openshift_hosted_logging_elasticsearch_pvc_dynamic: "{{ 'true' if openshift.hosted.logging.storage_kind | default(none) == 'dynamic' else 'false' }}" + openshift_hosted_logging_elasticsearch_pvc_size: "{{ openshift.hosted.logging.storage.volume.size if openshift.hosted.logging.storage_kind | default(none) == 'dynamic' else '' }}" + openshift_hosted_logging_elasticsearch_pvc_prefix: "{{ 'logging-es' if openshift.hosted.logging.storage_kind | default(none) is not none else '' }}" + openshift_hosted_logging_elasticsearch_ops_cluster_size: "{{ logging_elasticsearch_ops_cluster_size }}" + openshift_hosted_logging_elasticsearch_ops_pvc_dynamic: "{{ 'true' if openshift.hosted.logging.storage_kind | default(none) == 'dynamic' else 'false' }}" + openshift_hosted_logging_elasticsearch_ops_pvc_size: "{{ openshift.hosted.logging.storage.volume.size if openshift.hosted.logging.storage_kind | default(none) == 'dynamic' else '' }}" + openshift_hosted_logging_elasticsearch_ops_pvc_prefix: "{{ 'logging-es' if openshift.hosted.logging.storage_kind | default(none) is not none else '' }}" -- name: Configure CA certificate for secure registry - hosts: oo_nodes_to_config - tags: - - hosted - tasks: - - name: Create temp directory for kubeconfig - command: mktemp -d /tmp/openshift-ansible-XXXXXX - register: mktemp - when: openshift.common.deployment_subtype == 'registry' - changed_when: false - delegate_to: "{{ groups.oo_first_master.0 }}" - run_once: true - - set_fact: - openshift_hosted_kubeconfig: "{{ mktemp.stdout }}/admin.kubeconfig" - when: openshift.common.deployment_subtype == 'registry' - delegate_to: "{{ groups.oo_first_master.0 }}" - run_once: true - - name: Copy the admin client config(s) - command: > - cp {{ openshift.common.config_base }}/master/admin.kubeconfig {{ openshift_hosted_kubeconfig }} - when: openshift.common.deployment_subtype == 'registry' - changed_when: false - delegate_to: "{{ groups.oo_first_master.0 }}" - run_once: true - - name: Retrieve docker-registry route - command: > - {{ openshift.common.client_binary }} get route docker-registry - --template='{{ '{{' }} .spec.host {{ '}}' }}' - --config={{ openshift_hosted_kubeconfig }} - -n default - register: docker_registry_route - when: openshift.common.deployment_subtype == 'registry' - changed_when: false - delegate_to: "{{ groups.oo_first_master.0 }}" - run_once: true - - name: Retrieve registry service IP - command: > - {{ openshift.common.client_binary }} get service docker-registry - --template='{{ '{{' }} .spec.clusterIP {{ '}}' }}' - --config={{ openshift_hosted_kubeconfig }} - -n default - register: docker_registry_service_ip - when: openshift.common.deployment_subtype == 'registry' - changed_when: false - delegate_to: "{{ groups.oo_first_master.0 }}" - run_once: true - - name: Create registry CA directories - file: - path: "/etc/docker/certs.d/{{ item }}" - state: directory - with_items: - - "{{ docker_registry_service_ip.stdout }}:5000" - - "{{ docker_registry_route.stdout }}" - - "docker-registry.default.svc.cluster.local:5000" - when: openshift.common.deployment_subtype == 'registry' - - name: Copy CA to registry CA directories - copy: - src: "{{ openshift.common.config_base }}/node/ca.crt" - dest: "/etc/docker/certs.d/{{ item }}" - remote_src: yes - force: yes - with_items: - - "{{ docker_registry_service_ip.stdout }}:5000" - - "{{ docker_registry_route.stdout }}" - - "docker-registry.default.svc.cluster.local:5000" - when: openshift.common.deployment_subtype == 'registry' - notify: - - Restart docker - - name: Delete temp directory - file: - name: "{{ mktemp.stdout }}" - state: absent - when: openshift.common.deployment_subtype == 'registry' - changed_when: False - delegate_to: "{{ groups.oo_first_master.0 }}" - run_once: true - handlers: - - name: Restart docker - service: - name: docker - state: restarted + - role: cockpit-ui + when: ( openshift.common.version_gte_3_3_or_1_3 | bool ) and ( openshift_hosted_manage_registry | default(true) | bool ) diff --git a/playbooks/common/openshift-cluster/verify_ansible_version.yml b/playbooks/common/openshift-cluster/verify_ansible_version.yml index 2a143b065..d75b23bf7 100644 --- a/playbooks/common/openshift-cluster/verify_ansible_version.yml +++ b/playbooks/common/openshift-cluster/verify_ansible_version.yml @@ -1,5 +1,6 @@ --- -- hosts: localhost +- name: Verify Ansible version is greater than or equal to 2.1.0.0 + hosts: localhost connection: local become: no gather_facts: no diff --git a/playbooks/common/openshift-master/config.yml b/playbooks/common/openshift-master/config.yml index 7f60cd9e4..a53c55c14 100644 --- a/playbooks/common/openshift-master/config.yml +++ b/playbooks/common/openshift-master/config.yml @@ -1,5 +1,5 @@ --- -- name: Set master facts +- name: Gather and set facts for master hosts hosts: oo_masters_to_config vars: t_oo_option_master_debug_level: "{{ lookup('oo_option', 'openshift_master_debug_level') }}" @@ -91,7 +91,7 @@ register: g_master_mktemp changed_when: False -- name: Check for cached session secrets +- name: Determine if session secrets must be generated hosts: oo_first_master roles: - role: openshift_facts diff --git a/playbooks/common/openshift-master/scaleup.yml b/playbooks/common/openshift-master/scaleup.yml index 7304fca56..56ed09e1b 100644 --- a/playbooks/common/openshift-master/scaleup.yml +++ b/playbooks/common/openshift-master/scaleup.yml @@ -40,6 +40,10 @@ --cacert {{ openshift.common.config_base }}/master/ca.crt {% endif %} {{ openshift.master.api_url }}/healthz/ready + args: + # Disables the following warning: + # Consider using get_url or uri module rather than running curl + warn: no register: api_available_output until: api_available_output.stdout == 'ok' retries: 120 diff --git a/playbooks/common/openshift-nfs/config.yml b/playbooks/common/openshift-nfs/config.yml index ba7530ed7..000e46e80 100644 --- a/playbooks/common/openshift-nfs/config.yml +++ b/playbooks/common/openshift-nfs/config.yml @@ -1,5 +1,5 @@ --- -- name: Configure nfs hosts +- name: Configure nfs hosts: oo_nfs_to_config roles: - role: openshift_facts diff --git a/playbooks/common/openshift-node/config.yml b/playbooks/common/openshift-node/config.yml index 66eb293e5..364a62dd0 100644 --- a/playbooks/common/openshift-node/config.yml +++ b/playbooks/common/openshift-node/config.yml @@ -45,7 +45,7 @@ with_items: "{{ groups.oo_nodes_to_config | default([]) }}" when: hostvars[item].openshift.common is defined and hostvars[item].openshift.common.is_containerized | bool and (item in groups.oo_nodes_to_config and item in groups.oo_masters_to_config) -- name: Configure node instances +- name: Configure containerized nodes hosts: oo_containerized_master_nodes serial: 1 vars: @@ -60,12 +60,12 @@ when: "{{ (openshift_http_proxy is defined or openshift_https_proxy is defined) and openshift_generate_no_proxy_hosts | default(True) | bool }}" roles: + - role: openshift_common - role: openshift_clock - role: openshift_docker - role: openshift_node_certificates openshift_ca_host: "{{ groups.oo_first_master.0 }}" - role: openshift_cloud_provider - - role: openshift_common - role: openshift_node_dnsmasq when: openshift.common.use_dnsmasq - role: os_firewall @@ -85,7 +85,7 @@ when: openshift.node.use_openshift_sdn | bool - role: openshift_node -- name: Configure node instances +- name: Configure nodes hosts: oo_nodes_to_config:!oo_containerized_master_nodes vars: openshift_node_master_api_url: "{{ hostvars[groups.oo_first_master.0].openshift.master.api_url }}" @@ -99,12 +99,12 @@ when: "{{ (openshift_http_proxy is defined or openshift_https_proxy is defined) and openshift_generate_no_proxy_hosts | default(True) | bool }}" roles: + - role: openshift_common - role: openshift_clock - role: openshift_docker - role: openshift_node_certificates openshift_ca_host: "{{ groups.oo_first_master.0 }}" - role: openshift_cloud_provider - - role: openshift_common - role: openshift_node_dnsmasq when: openshift.common.use_dnsmasq - role: os_firewall @@ -153,7 +153,7 @@ - file: name={{ mktemp.stdout }} state=absent changed_when: False -- name: Set schedulability +- name: Set node schedulability hosts: oo_first_master vars: openshift_nodes: "{{ groups.oo_nodes_to_config | default([]) }}" @@ -172,6 +172,10 @@ --cacert {{ openshift.common.config_base }}/master/ca.crt {% endif %} {{ openshift.master.api_url }}/healthz/ready + args: + # Disables the following warning: + # Consider using get_url or uri module rather than running curl + warn: no register: api_available_output until: api_available_output.stdout == 'ok' retries: 120 diff --git a/roles/cockpit-ui/tasks/main.yml b/roles/cockpit-ui/tasks/main.yml index 9fc15ee8b..c573da6d6 100644 --- a/roles/cockpit-ui/tasks/main.yml +++ b/roles/cockpit-ui/tasks/main.yml @@ -36,7 +36,7 @@ - name: Retrieve docker-registry route command: > {{ openshift.common.client_binary }} get route docker-registry - --template='{{ '{{' }} .spec.host {{ '}}' }}' + -o jsonpath='{.spec.host}' --config={{ openshift_hosted_kubeconfig }} -n default register: docker_registry_route @@ -45,18 +45,15 @@ - name: Retrieve cockpit kube url command: > {{ openshift.common.client_binary }} get route registry-console - --template='https://{{ '{{' }} .spec.host {{ '}}' }}' + -o jsonpath='https://{.spec.host}' -n default register: registry_console_cockpit_kube_url changed_when: false -- set_fact: - cockpit_image_prefix: "{{ '-p IMAGE_PREFIX=' ~ openshift_cockpit_deployer_prefix | default('') }}" - - name: Deploy registry-console command: > {{ openshift.common.client_binary }} new-app --template=registry-console - {{ cockpit_image_prefix }} + {% if openshift_cockpit_deployer_prefix is defined %}-p IMAGE_PREFIX="{{ openshift_cockpit_deployer_prefix }}"{% endif %} -p OPENSHIFT_OAUTH_PROVIDER_URL="{{ openshift.master.public_api_url }}" -p REGISTRY_HOST="{{ docker_registry_route.stdout }}" -p COCKPIT_KUBE_URL="{{ registry_console_cockpit_kube_url.stdout }}" diff --git a/roles/etcd_client_certificates/tasks/main.yml b/roles/etcd_client_certificates/tasks/main.yml index 275aa0a63..93f4fd53c 100644 --- a/roles/etcd_client_certificates/tasks/main.yml +++ b/roles/etcd_client_certificates/tasks/main.yml @@ -93,6 +93,9 @@ -C {{ etcd_generated_certs_dir }}/{{ etcd_cert_subdir }} . args: creates: "{{ etcd_generated_certs_dir }}/{{ etcd_cert_subdir }}.tgz" + # Disables the following warning: + # Consider using unarchive module rather than running tar + warn: no when: etcd_client_certs_missing | bool delegate_to: "{{ etcd_ca_host }}" diff --git a/roles/etcd_server_certificates/tasks/main.yml b/roles/etcd_server_certificates/tasks/main.yml index 718515023..d66a0a7bf 100644 --- a/roles/etcd_server_certificates/tasks/main.yml +++ b/roles/etcd_server_certificates/tasks/main.yml @@ -114,6 +114,9 @@ -C {{ etcd_generated_certs_dir }}/{{ etcd_cert_subdir }} . args: creates: "{{ etcd_generated_certs_dir }}/{{ etcd_cert_subdir }}.tgz" + # Disables the following warning: + # Consider using unarchive module rather than running tar + warn: no when: etcd_server_certs_missing | bool delegate_to: "{{ etcd_ca_host }}" diff --git a/roles/openshift_cloud_provider/templates/openstack.conf.j2 b/roles/openshift_cloud_provider/templates/openstack.conf.j2 index ce452db24..313ee02b4 100644 --- a/roles/openshift_cloud_provider/templates/openstack.conf.j2 +++ b/roles/openshift_cloud_provider/templates/openstack.conf.j2 @@ -2,6 +2,11 @@ auth-url = {{ openshift_cloudprovider_openstack_auth_url }} username = {{ openshift_cloudprovider_openstack_username }} password = {{ openshift_cloudprovider_openstack_password }} +{% if openshift_cloudprovider_openstack_domain_id is defined %} +domain-id = {{ openshift_cloudprovider_openstack_domain_id }} +{% elif openshift_cloudprovider_openstack_domain_name is defined %} +domain-name = {{ openshift_cloudprovider_openstack_domain_name }} +{% endif %} {% if openshift_cloudprovider_openstack_tenant_id is defined %} tenant-id = {{ openshift_cloudprovider_openstack_tenant_id }} {% else %} diff --git a/roles/openshift_docker_facts/tasks/main.yml b/roles/openshift_docker_facts/tasks/main.yml index 0ce142983..0c8a36d65 100644 --- a/roles/openshift_docker_facts/tasks/main.yml +++ b/roles/openshift_docker_facts/tasks/main.yml @@ -13,7 +13,7 @@ log_options: "{{ openshift_docker_log_options | default(None) }}" options: "{{ openshift_docker_options | default(None) }}" disable_push_dockerhub: "{{ openshift_disable_push_dockerhub | default(None) }}" - hosted_registry_insecure: "{{ openshift_docker_hosted_registry_insecure | default(openshift.common.deployment_subtype != 'registry') }}" + hosted_registry_insecure: "{{ openshift_docker_hosted_registry_insecure | default(False) }}" hosted_registry_network: "{{ openshift_docker_hosted_registry_network | default(None) }}" - set_fact: diff --git a/roles/openshift_examples/tasks/main.yml b/roles/openshift_examples/tasks/main.yml index 058ad8888..82536e8af 100644 --- a/roles/openshift_examples/tasks/main.yml +++ b/roles/openshift_examples/tasks/main.yml @@ -19,6 +19,10 @@ - name: Create tar of OpenShift examples local_action: command tar -C "{{ role_path }}/files/examples/{{ content_version }}/" -cvf "{{ copy_examples_mktemp.stdout }}/openshift-examples.tar" . + args: + # Disables the following warning: + # Consider using unarchive module rather than running tar + warn: no become: False register: copy_examples_tar diff --git a/roles/openshift_facts/library/openshift_facts.py b/roles/openshift_facts/library/openshift_facts.py index e94cb0952..d36926e08 100755 --- a/roles/openshift_facts/library/openshift_facts.py +++ b/roles/openshift_facts/library/openshift_facts.py @@ -1821,10 +1821,25 @@ class OpenShiftFacts(object): ), nfs=dict( directory='/exports', - options='*(rw,root_squash)'), - openstack=dict( - filesystem='ext4', - volumeID='123'), + options='*(rw,root_squash)' + ), + host=None, + access_modes=['ReadWriteOnce'], + create_pv=True, + create_pvc=False + ) + ), + logging=dict( + storage=dict( + kind=None, + volume=dict( + name='logging-es', + size='10Gi' + ), + nfs=dict( + directory='/exports', + options='*(rw,root_squash)' + ), host=None, access_modes=['ReadWriteOnce'], create_pv=True, diff --git a/roles/openshift_hosted/tasks/registry/registry.yml b/roles/openshift_hosted/tasks/registry/registry.yml index d5077932b..ed0a2b38d 100644 --- a/roles/openshift_hosted/tasks/registry/registry.yml +++ b/roles/openshift_hosted/tasks/registry/registry.yml @@ -53,7 +53,6 @@ - include: secure.yml static: no - when: openshift.common.deployment_subtype == 'registry' - include: storage/object_storage.yml static: no diff --git a/roles/openshift_hosted/tasks/registry/secure.yml b/roles/openshift_hosted/tasks/registry/secure.yml index 4cb85df04..664edef41 100644 --- a/roles/openshift_hosted/tasks/registry/secure.yml +++ b/roles/openshift_hosted/tasks/registry/secure.yml @@ -1,5 +1,15 @@ --- -- name: Determine if registry certificates must be created +- name: Create passthrough route for docker-registry + command: > + {{ openshift.common.client_binary }} create route passthrough + --service docker-registry + --config={{ openshift_hosted_kubeconfig }} + -n default + register: create_docker_registry_route + changed_when: "'already exists' not in create_docker_registry_route.stderr" + failed_when: "'already exists' not in create_docker_registry_route.stderr and create_docker_registry_route.rc != 0" + +- name: Determine if registry certificate must be created stat: path: "{{ openshift_master_config_dir }}/{{ item }}" with_items: @@ -12,7 +22,7 @@ - name: Retrieve registry service IP command: > {{ openshift.common.client_binary }} get service docker-registry - --template='{{ '{{' }} .spec.clusterIP {{ '}}' }}' + -o jsonpath='{.spec.clusterIP}' --config={{ openshift_hosted_kubeconfig }} -n default register: docker_registry_service_ip @@ -45,8 +55,8 @@ - name: "Add the secret to the registry's pod service accounts" command: > - {{ openshift.common.client_binary }} secrets link {{ item }} registry-certificates - --config={{ openshift_hosted_kubeconfig }} + {{ openshift.common.client_binary }} secrets add {{ item }} registry-certificates + --config={{ openshift_hosted_kubeconfig }} -n default with_items: - registry @@ -55,12 +65,12 @@ - name: Determine if registry-certificates secret volume attached command: > {{ openshift.common.client_binary }} get dc/docker-registry - --template='{{ '{{' }} range .spec.template.spec.volumes {{ '}}' }}{{ '{{' }} .secret.secretName {{ '}}' }}{{ '{{' }} end {{ '}}' }}' + -o jsonpath='{.spec.template.spec.volumes[*].secret.secretName}' --config={{ openshift_hosted_kubeconfig }} -n default register: docker_registry_volumes changed_when: false - failed_when: false + failed_when: "'secretName is not found' not in docker_registry_volumes.stdout and docker_registry_volumes.rc != 0" - name: Attach registry-certificates secret volume command: > @@ -71,17 +81,48 @@ -n default when: "'registry-certificates' not in docker_registry_volumes.stdout" -- name: Set registry environment variables for TLS certificate +- name: Determine if registry environment variables must be set + command: > + {{ openshift.common.client_binary }} env dc/docker-registry + --list + --config={{ openshift_hosted_kubeconfig }} + -n default + register: docker_registry_env + changed_when: false + +- name: Configure certificates in registry deplomentConfig command: > {{ openshift.common.client_binary }} env dc/docker-registry REGISTRY_HTTP_TLS_CERTIFICATE=/etc/secrets/registry.crt REGISTRY_HTTP_TLS_KEY=/etc/secrets/registry.key --config={{ openshift_hosted_kubeconfig }} -n default + when: "'REGISTRY_HTTP_TLS_CERTIFICATE=/etc/secrets/registry.crt' not in docker_registry_env.stdout or 'REGISTRY_HTTP_TLS_KEY=/etc/secrets/registry.key' not in docker_registry_env.stdout" -# These commands are on a single line to preserve patch json. +- name: Determine if registry liveness probe scheme is HTTPS + command: > + {{ openshift.common.client_binary }} get dc/docker-registry + -o jsonpath='{.spec.template.spec.containers[*].livenessProbe.httpGet.scheme}' + --config={{ openshift_hosted_kubeconfig }} + -n default + register: docker_registry_liveness_probe + changed_when: false + +# This command is on a single line to preserve patch json. - name: Update registry liveness probe from HTTP to HTTPS command: "{{ openshift.common.client_binary }} patch dc/docker-registry --api-version=v1 -p '{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"registry\",\"livenessProbe\":{\"httpGet\":{\"scheme\":\"HTTPS\"}}}]}}}}' --config={{ openshift_hosted_kubeconfig }} -n default" + when: "'HTTPS' not in docker_registry_liveness_probe.stdout" + +- name: Determine if registry readiness probe scheme is HTTPS + command: > + {{ openshift.common.client_binary }} get dc/docker-registry + -o jsonpath='{.spec.template.spec.containers[*].readinessProbe.httpGet.scheme}' + --config={{ openshift_hosted_kubeconfig }} + -n default + register: docker_registry_readiness_probe + changed_when: false +# This command is on a single line to preserve patch json. - name: Update registry readiness probe from HTTP to HTTPS command: "{{ openshift.common.client_binary }} patch dc/docker-registry --api-version=v1 -p '{\"spec\":{\"template\":{\"spec\":{\"containers\":[{\"name\":\"registry\",\"readinessProbe\":{\"httpGet\":{\"scheme\":\"HTTPS\"}}}]}}}}' --config={{ openshift_hosted_kubeconfig }} -n default" + when: "'HTTPS' not in docker_registry_readiness_probe.stdout" diff --git a/roles/openshift_hosted/templates/registry_config.j2 b/roles/openshift_hosted/templates/registry_config.j2 index 092b0fb35..cfe7ac81c 100644 --- a/roles/openshift_hosted/templates/registry_config.j2 +++ b/roles/openshift_hosted/templates/registry_config.j2 @@ -4,6 +4,8 @@ log: http: addr: :5000 storage: + delete: + enabled: true cache: blobdescriptor: inmemory {% if openshift.hosted.registry.storage.provider == 's3' %} diff --git a/roles/openshift_hosted_logging/README.md b/roles/openshift_hosted_logging/README.md index 03db1c4b1..12ffe777d 100644 --- a/roles/openshift_hosted_logging/README.md +++ b/roles/openshift_hosted_logging/README.md @@ -17,7 +17,8 @@ - openshift_hosted_logging_elasticsearch_pvc_dynamic: Set to `true` to have created PersistentVolumeClaims annotated such that their backing storage can be dynamically provisioned (if that is available for your cluster). - openshift_hosted_logging_elasticsearch_storage_group: Number of a supplemental group ID for access to Elasticsearch storage volumes; backing volumes should allow access by this group ID (defaults to 65534). - openshift_hosted_logging_elasticsearch_nodeselector: Specify the nodeSelector that Elasticsearch should be use (label=value) -- openshift_hosted_logging_fluentd_nodeselector: The nodeSelector to use for the Fluentd DaemonSet. Defaults to "logging-infra-fluentd=true". +- openshift_hosted_logging_fluentd_nodeselector: The nodeSelector used to determine which nodes to apply the `openshift_hosted_logging_fluentd_nodeselector_label` label to. +- openshift_hosted_logging_fluentd_nodeselector_label: The label applied to nodes included in the Fluentd DaemonSet. Defaults to "logging-infra-fluentd=true". - openshift_hosted_logging_kibana_nodeselector: Specify the nodeSelector that Kibana should be use (label=value) - openshift_hosted_logging_curator_nodeselector: Specify the nodeSelector that Curator should be use (label=value) - openshift_hosted_logging_enable_ops_cluster: If "true", configure a second ES cluster and Kibana for ops logs. diff --git a/roles/openshift_hosted_logging/defaults/main.yml b/roles/openshift_hosted_logging/defaults/main.yml new file mode 100644 index 000000000..e357899e5 --- /dev/null +++ b/roles/openshift_hosted_logging/defaults/main.yml @@ -0,0 +1,2 @@ +--- +examples_base: "{{ openshift.common.config_base if openshift.common.is_containerized | bool else '/usr/share/openshift' }}/examples" diff --git a/roles/openshift_hosted_logging/tasks/deploy_logging.yaml b/roles/openshift_hosted_logging/tasks/deploy_logging.yaml index 082bb6ea2..f64c56248 100644 --- a/roles/openshift_hosted_logging/tasks/deploy_logging.yaml +++ b/roles/openshift_hosted_logging/tasks/deploy_logging.yaml @@ -40,7 +40,7 @@ - name: "Create templates for logging accounts and the deployer" command: > - {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig create -f /usr/share/openshift/examples/infrastructure-templates/enterprise/logging-deployer.yaml + {{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig create -f {{ examples_base }}/infrastructure-templates/{{ 'enterprise' if openshift_deployment_type == 'openshift-enterprise' else 'origin' }}/logging-deployer.yaml register: template_output failed_when: "template_output.rc == 1 and 'exists' not in template_output.stderr" @@ -82,8 +82,8 @@ shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get pods | grep logging-deployer.*Completed" register: result until: result.rc == 0 - retries: 15 - delay: 10 + retries: 20 + delay: 15 - name: "Process imagestream template" shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig new-app logging-imagestream-template {{ oc_new_app_values }}" @@ -102,7 +102,7 @@ until: result.rc == 0 failed_when: result.rc == 1 and 'not found' not in result.stderr retries: 20 - delay: 10 + delay: 5 - name: "Wait for component pods to be running" shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get pods -l component={{ item }} | grep Running" @@ -114,7 +114,7 @@ until: result.rc == 0 failed_when: result.rc == 1 or 'Error' in result.stderr retries: 20 - delay: 10 + delay: 15 - name: "Wait for ops component pods to be running" shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get pods -l component={{ item }} | grep Running" @@ -127,7 +127,7 @@ until: result.rc == 0 failed_when: result.rc == 1 or 'Error' in result.stderr retries: 20 - delay: 10 + delay: 15 - name: "Wait for fluentd DaemonSet to exist" shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get daemonset logging-fluentd" @@ -135,10 +135,10 @@ until: result.rc == 0 failed_when: result.rc == 1 or 'Error' in result.stderr retries: 20 - delay: 10 + delay: 5 - name: "Deploy fluentd by labeling the node" - shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig label node {{ openshift_hostname }} {{ openshift_hosted_logging_fluentd_nodeselector if openshift_hosted_logging_fluentd_nodeselector is defined else 'logging-infra-fluentd=true' }}" + shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig label node --overwrite=true {{ '-l openshift_hosted_logging_fluentd_nodeselector' if openshift_hosted_logging_fluentd_nodeselector is defined else '--all' }} {{ openshift_hosted_logging_fluentd_nodeselector_label if openshift_hosted_logging_fluentd_nodeselector_label is defined else 'logging-infra-fluentd=true' }}" - name: "Wait for fluentd to be running" shell: "{{ openshift.common.client_binary }} --config={{ mktemp.stdout }}/admin.kubeconfig get pods -l component=fluentd | grep Running" @@ -146,7 +146,7 @@ until: result.rc == 0 failed_when: result.rc == 1 or 'Error' in result.stderr retries: 20 - delay: 10 + delay: 15 - debug: msg: "Logging components deployed. Note persistent volume for elasticsearch must be setup manually" diff --git a/roles/openshift_hosted_logging/vars/main.yaml b/roles/openshift_hosted_logging/vars/main.yaml index 2ef3164e1..11412733b 100644 --- a/roles/openshift_hosted_logging/vars/main.yaml +++ b/roles/openshift_hosted_logging/vars/main.yaml @@ -1,32 +1,32 @@ -tr_or_ohlip: "{{ openshift_hosted_logging_image_prefix or target_registry or none }}" -ip_kv: "{{ '-p IMAGE_PREFIX=' ~ tr_or_ohlip | quote if tr_or_ohlip is defined else '' }}" -iv_kv: "{{ '-p IMAGE_VERSION=' ~ openshift_hosted_logging_image_version | quote if openshift_hosted_logging_image_version is defined else '' }}" +tr_or_ohlip: "{{ openshift_hosted_logging_deployer_prefix | default(target_registry) | default(None) }}" +ip_kv: "{{ '-p IMAGE_PREFIX=' ~ tr_or_ohlip | quote if tr_or_ohlip != '' else '' }}" +iv_kv: "{{ '-p IMAGE_VERSION=' ~ openshift_hosted_logging_deployer_version | quote if openshift_hosted_logging_deployer_version | default(none) is not none else '' }}" oc_new_app_values: "{{ ip_kv }} {{ iv_kv }}" openshift_master_config_dir: "{{ openshift.common.config_base }}/master" -kh_cmap_param: "{{ '--from-literal kibana-hostname=' ~ openshift_hosted_logging_hostname | quote if openshift_hosted_logging_hostname is defined else '' }}" -kh_ops_cmap_param: "{{ '--from-literal kibana-ops-hostname=' ~ openshift_hosted_logging_ops_hostname | quote if openshift_hosted_logging_ops_hostname is defined else '' }}" -pmu_cmap_param: "{{ '--from-literal public-master-url=' ~ openshift_hosted_logging_master_public_url | quote if openshift_hosted_logging_master_public_url is defined else '' }}" -es_cs_cmap_param: "{{ '--from-literal es-cluster-size=' ~ openshift_hosted_logging_elasticsearch_cluster_size | string | quote if openshift_hosted_logging_elasticsearch_cluster_size is defined else '' }}" -es_ops_cs_cmap_param: "{{ '--from-literal es-ops-cluster-size=' ~ openshift_hosted_logging_elasticsearch_ops_cluster_size | string | quote if openshift_hosted_logging_elasticsearch_ops_cluster_size is defined else '' }}" -es_ir_cmap_param: "{{ '--from-literal es-instance-ram=' ~ openshift_hosted_logging_elasticsearch_instance_ram | quote if openshift_hosted_logging_elasticsearch_instance_ram is defined else '' }}" -es_ops_ir_cmap_param: "{{ '--from-literal es-ops-instance-ram=' ~ openshift_hosted_logging_elasticsearch_ops_instance_ram | quote if openshift_hosted_logging_elasticsearch_ops_instance_ram is defined else '' }}" -es_pvcs_cmap_param: "{{ '--from-literal es-pvc-size=' ~ openshift_hosted_logging_elasticsearch_pvc_size | quote if openshift_hosted_logging_elasticsearch_pvc_size is defined else '' }}" -es_ops_pvcs_cmap_param: "{{ '--from-literal es-ops-pvc-size=' ~ openshift_hosted_logging_elasticsearch_ops_pvc_size | quote if openshift_hosted_logging_elasticsearch_ops_pvc_size is defined else '' }}" -es_pvcp_cmap_param: "{{ '--from-literal es-pvc-prefix=' ~ openshift_hosted_logging_elasticsearch_pvc_prefix | quote if openshift_hosted_logging_elasticsearch_pvc_prefix is defined else '' }}" -es_ops_pvcp_cmap_param: "{{ '--from-literal es-ops-pvc-prefix=' ~ openshift_hosted_logging_elasticsearch_ops_pvc_prefix | quote if openshift_hosted_logging_elasticsearch_ops_pvc_prefix is defined else '' }}" -es_pvcd_cmap_param: "{{ '--from-literal es-pvc-dynamic=' ~ openshift_hosted_logging_elasticsearch_pvc_dynamic | quote if openshift_hosted_logging_elasticsearch_pvc_dynamic is defined else '' }}" -es_ops_pvcd_cmap_param: "{{ '--from-literal es-ops-pvc-dynamic=' ~ openshift_hosted_logging_elasticsearch_ops_pvc_dynamic | quote if openshift_hosted_logging_elasticsearch_ops_pvc_dynamic is defined else '' }}" -es_sg_cmap_param: "{{ '--from-literal storage-group=' ~ openshift_hosted_logging_elasticsearch_storage_group | string | quote if openshift_hosted_logging_elasticsearch_storage_group is defined else '' }}" -es_ns_cmap_param: "{{ '--from-literal es-nodeselector=' ~ openshift_hosted_logging_elasticsearch_nodeselector | quote if openshift_hosted_logging_elasticsearch_nodeselector is defined else '' }}" -es_ops_ns_cmap_param: "{{ '--from-literal es-ops-nodeselector=' ~ openshift_hosted_logging_elasticsearch_ops_nodeselector | quote if openshift_hosted_logging_elasticsearch_ops_nodeselector is defined else '' }}" -fd_ns_cmap_param: "{{ '--from-literal fluentd-nodeselector=' ~ openshift_hosted_logging_fluentd_nodeselector | quote if openshift_hosted_logging_fluentd_nodeselector is defined else 'logging-infra-fluentd=true' }}" -kb_ns_cmap_param: "{{ '--from-literal kibana-nodeselector=' ~ openshift_hosted_logging_kibana_nodeselector | quote if openshift_hosted_logging_kibana_nodeselector is defined else '' }}" -kb_ops_ns_cmap_param: "{{ '--from-literal kibana-ops-nodeselector=' ~ openshift_hosted_logging_kibana_ops_nodeselector | quote if openshift_hosted_logging_kibana_ops_nodeselector is defined else '' }}" -cr_ns_cmap_param: "{{ '--from-literal curator-nodeselector=' ~ openshift_hosted_logging_curator_nodeselector | quote if openshift_hosted_logging_curator_nodeselector is defined else '' }}" -cr_ops_ns_cmap_param: "{{ '--from-literal curator-ops-nodeselector=' ~ openshift_hosted_logging_curator_ops_nodeselector | quote if openshift_hosted_logging_curator_ops_nodeselector is defined else '' }}" -ops_cmap_param: "{{ '--from-literal enable-ops-cluster=' ~ openshift_hosted_logging_enable_ops_cluster | string | lower | quote if openshift_hosted_logging_enable_ops_cluster is defined else '' }}" -use_journal_cmap_param: "{{ '--from-literal use-journal=' ~ openshift_hosted_logging_use_journal | string | lower | quote if openshift_hosted_logging_use_journal is defined else '' }}" -journal_source_cmap_param: "{{ '--from-literal journal-source=' ~ openshift_hosted_logging_journal_source | quote if openshift_hosted_logging_journal_source is defined else '' }}" -journal_read_from_head_cmap_param: "{{ '--from-literal journal-read-from-head=' ~ openshift_hosted_logging_journal_read_from_head | string | lower | quote if openshift_hosted_logging_journal_read_from_head is defined else '' }}" -ips_cmap_param: "{{ '--from-literal image-pull-secret=' ~ openshift_hosted_logging_image_pull_secret | quote if openshift_hosted_logging_image_pull_secret is defined else '' }}" +kh_cmap_param: "{{ '--from-literal kibana-hostname=' ~ openshift_hosted_logging_hostname | quote if openshift_hosted_logging_hostname | default(none) is not none else '' }}" +kh_ops_cmap_param: "{{ '--from-literal kibana-ops-hostname=' ~ openshift_hosted_logging_ops_hostname | quote if openshift_hosted_logging_ops_hostname | default(none) is not none else '' }}" +pmu_cmap_param: "{{ '--from-literal public-master-url=' ~ openshift_hosted_logging_master_public_url | quote if openshift_hosted_logging_master_public_url | default(none) is not none else '' }}" +es_cs_cmap_param: "{{ '--from-literal es-cluster-size=' ~ openshift_hosted_logging_elasticsearch_cluster_size | string | quote if openshift_hosted_logging_elasticsearch_cluster_size | default(none) is not none else '' }}" +es_ops_cs_cmap_param: "{{ '--from-literal es-ops-cluster-size=' ~ openshift_hosted_logging_elasticsearch_ops_cluster_size | string | quote if openshift_hosted_logging_elasticsearch_ops_cluster_size | default(none) is not none else '' }}" +es_ir_cmap_param: "{{ '--from-literal es-instance-ram=' ~ openshift_hosted_logging_elasticsearch_instance_ram | quote if openshift_hosted_logging_elasticsearch_instance_ram | default(none) is not none else '' }}" +es_ops_ir_cmap_param: "{{ '--from-literal es-ops-instance-ram=' ~ openshift_hosted_logging_elasticsearch_ops_instance_ram | quote if openshift_hosted_logging_elasticsearch_ops_instance_ram | default(none) is not none else '' }}" +es_pvcs_cmap_param: "{{ '--from-literal es-pvc-size=' ~ openshift_hosted_logging_elasticsearch_pvc_size | quote if openshift_hosted_logging_elasticsearch_pvc_size | default(none) is not none else '' }}" +es_ops_pvcs_cmap_param: "{{ '--from-literal es-ops-pvc-size=' ~ openshift_hosted_logging_elasticsearch_ops_pvc_size | quote if openshift_hosted_logging_elasticsearch_ops_pvc_size | default(none) is not none else '' }}" +es_pvcp_cmap_param: "{{ '--from-literal es-pvc-prefix=' ~ openshift_hosted_logging_elasticsearch_pvc_prefix | quote if openshift_hosted_logging_elasticsearch_pvc_prefix | default(none) is not none else '' }}" +es_ops_pvcp_cmap_param: "{{ '--from-literal es-ops-pvc-prefix=' ~ openshift_hosted_logging_elasticsearch_ops_pvc_prefix | quote if openshift_hosted_logging_elasticsearch_ops_pvc_prefix | default(none) is not none else '' }}" +es_pvcd_cmap_param: "{{ '--from-literal es-pvc-dynamic=' ~ openshift_hosted_logging_elasticsearch_pvc_dynamic | quote if openshift_hosted_logging_elasticsearch_pvc_dynamic | default(none) is not none else '' }}" +es_ops_pvcd_cmap_param: "{{ '--from-literal es-ops-pvc-dynamic=' ~ openshift_hosted_logging_elasticsearch_ops_pvc_dynamic | quote if openshift_hosted_logging_elasticsearch_ops_pvc_dynamic | default(none) is not none else '' }}" +es_sg_cmap_param: "{{ '--from-literal storage-group=' ~ openshift_hosted_logging_elasticsearch_storage_group | string | quote if openshift_hosted_logging_elasticsearch_storage_group | default(none) is not none else '' }}" +es_ns_cmap_param: "{{ '--from-literal es-nodeselector=' ~ openshift_hosted_logging_elasticsearch_nodeselector | quote if openshift_hosted_logging_elasticsearch_nodeselector | default(none) is not none else '' }}" +es_ops_ns_cmap_param: "{{ '--from-literal es-ops-nodeselector=' ~ openshift_hosted_logging_elasticsearch_ops_nodeselector | quote if openshift_hosted_logging_elasticsearch_ops_nodeselector | default(none) is not none else '' }}" +fd_ns_cmap_param: "{{ '--from-literal fluentd-nodeselector=' ~ openshift_hosted_logging_fluentd_nodeselector_label | quote if openshift_hosted_logging_fluentd_nodeselector_label | default(none) is not none else 'logging-infra-fluentd=true' }}" +kb_ns_cmap_param: "{{ '--from-literal kibana-nodeselector=' ~ openshift_hosted_logging_kibana_nodeselector | quote if openshift_hosted_logging_kibana_nodeselector | default(none) is not none else '' }}" +kb_ops_ns_cmap_param: "{{ '--from-literal kibana-ops-nodeselector=' ~ openshift_hosted_logging_kibana_ops_nodeselector | quote if openshift_hosted_logging_kibana_ops_nodeselector | default(none) is not none else '' }}" +cr_ns_cmap_param: "{{ '--from-literal curator-nodeselector=' ~ openshift_hosted_logging_curator_nodeselector | quote if openshift_hosted_logging_curator_nodeselector | default(none) is not none else '' }}" +cr_ops_ns_cmap_param: "{{ '--from-literal curator-ops-nodeselector=' ~ openshift_hosted_logging_curator_ops_nodeselector | quote if openshift_hosted_logging_curator_ops_nodeselector | default(none) is not none else '' }}" +ops_cmap_param: "{{ '--from-literal enable-ops-cluster=' ~ openshift_hosted_logging_enable_ops_cluster | string | lower | quote if openshift_hosted_logging_enable_ops_cluster | default(none) is not none else '' }}" +use_journal_cmap_param: "{{ '--from-literal use-journal=' ~ openshift_hosted_logging_use_journal | string | lower | quote if openshift_hosted_logging_use_journal | default(none) is not none else '' }}" +journal_source_cmap_param: "{{ '--from-literal journal-source=' ~ openshift_hosted_logging_journal_source | quote if openshift_hosted_logging_journal_source | default(none) is not none else '' }}" +journal_read_from_head_cmap_param: "{{ '--from-literal journal-read-from-head=' ~ openshift_hosted_logging_journal_read_from_head | string | lower | quote if openshift_hosted_logging_journal_read_from_head | default(none) is not none else '' }}" +ips_cmap_param: "{{ '--from-literal image-pull-secret=' ~ openshift_hosted_logging_image_pull_secret | quote if openshift_hosted_logging_image_pull_secret | default(none) is not none else '' }}" deployer_cmap_params: "{{ kh_cmap_param }} {{ kh_ops_cmap_param }} {{ pmu_cmap_param }} {{ es_cs_cmap_param }} {{ es_ir_cmap_param }} {{ es_pvcs_cmap_param }} {{ es_pvcp_cmap_param }} {{ es_pvcd_cmap_param }} {{ es_ops_cs_cmap_param }} {{ es_ops_ir_cmap_param }} {{ es_ops_pvcs_cmap_param }} {{ es_ops_pvcp_cmap_param }} {{ es_ops_pvcd_cmap_param }} {{ es_sg_cmap_param }} {{ es_ns_cmap_param }} {{ es_ops_ns_cmap_param }} {{ fd_ns_cmap_param }} {{ kb_ns_cmap_param }} {{ kb_ops_ns_cmap_param }} {{ cr_ns_cmap_param }} {{ cr_ops_ns_cmap_param }} {{ ops_cmap_param }} {{ use_journal_cmap_param }} {{ journal_source_cmap_param }} {{ journal_read_from_head_cmap_param }} {{ ips_cmap_param }}" diff --git a/roles/openshift_master/handlers/main.yml b/roles/openshift_master/handlers/main.yml index edb7369de..913f3b0ae 100644 --- a/roles/openshift_master/handlers/main.yml +++ b/roles/openshift_master/handlers/main.yml @@ -24,6 +24,10 @@ --cacert {{ openshift.common.config_base }}/master/ca.crt {% endif %} {{ openshift.master.api_url }}/healthz/ready + args: + # Disables the following warning: + # Consider using get_url or uri module rather than running curl + warn: no register: api_available_output until: api_available_output.stdout == 'ok' retries: 120 diff --git a/roles/openshift_metrics/handlers/main.yml b/roles/openshift_metrics/handlers/main.yml index edb7369de..913f3b0ae 100644 --- a/roles/openshift_metrics/handlers/main.yml +++ b/roles/openshift_metrics/handlers/main.yml @@ -24,6 +24,10 @@ --cacert {{ openshift.common.config_base }}/master/ca.crt {% endif %} {{ openshift.master.api_url }}/healthz/ready + args: + # Disables the following warning: + # Consider using get_url or uri module rather than running curl + warn: no register: api_available_output until: api_available_output.stdout == 'ok' retries: 120 diff --git a/roles/openshift_named_certificates/tasks/main.yml b/roles/openshift_named_certificates/tasks/main.yml index 7f20cf401..1bcf9ef67 100644 --- a/roles/openshift_named_certificates/tasks/main.yml +++ b/roles/openshift_named_certificates/tasks/main.yml @@ -28,19 +28,19 @@ - name: Land named certificates copy: src: "{{ item.certfile }}" - dest: "{{ named_certs_dir }}" + dest: "{{ named_certs_dir }}/{{ item.certfile | basename }}" with_items: "{{ named_certificates }}" - name: Land named certificate keys copy: src: "{{ item.keyfile }}" - dest: "{{ named_certs_dir }}" + dest: "{{ named_certs_dir }}/{{ item.keyfile | basename }}" mode: 0600 with_items: "{{ named_certificates }}" - name: Land named CA certificates copy: src: "{{ item }}" - dest: "{{ named_certs_dir }}" + dest: "{{ named_certs_dir }}/{{ item | basename }}" mode: 0600 with_items: "{{ named_certificates | oo_collect('cafile') }}" diff --git a/roles/openshift_node/tasks/main.yml b/roles/openshift_node/tasks/main.yml index 995169dd6..be07bd2d3 100644 --- a/roles/openshift_node/tasks/main.yml +++ b/roles/openshift_node/tasks/main.yml @@ -93,9 +93,9 @@ create: true with_items: - regex: '^AWS_ACCESS_KEY_ID=' - line: "AWS_ACCESS_KEY_ID={{ openshift_cloudprovider_aws_access_key }}" + line: "AWS_ACCESS_KEY_ID={{ openshift_cloudprovider_aws_access_key | default('') }}" - regex: '^AWS_SECRET_ACCESS_KEY=' - line: "AWS_SECRET_ACCESS_KEY={{ openshift_cloudprovider_aws_secret_key }}" + line: "AWS_SECRET_ACCESS_KEY={{ openshift_cloudprovider_aws_secret_key | default('') }}" when: "openshift_cloudprovider_kind is defined and openshift_cloudprovider_kind == 'aws' and openshift_cloudprovider_aws_access_key is defined and openshift_cloudprovider_aws_secret_key is defined" notify: - restart node @@ -134,6 +134,10 @@ command: > curl --silent --cacert {{ openshift.common.config_base }}/node/ca.crt {{ openshift_node_master_api_url }}/healthz/ready + args: + # Disables the following warning: + # Consider using get_url or uri module rather than running curl + warn: no register: api_available_output until: api_available_output.stdout == 'ok' retries: 120 diff --git a/roles/openshift_node/tasks/systemd_units.yml b/roles/openshift_node/tasks/systemd_units.yml index 98ef1ffd4..a2192a4d0 100644 --- a/roles/openshift_node/tasks/systemd_units.yml +++ b/roles/openshift_node/tasks/systemd_units.yml @@ -56,12 +56,12 @@ create: true with_items: - regex: '^HTTP_PROXY=' - line: "HTTP_PROXY={{ openshift.common.http_proxy }}" + line: "HTTP_PROXY={{ openshift.common.http_proxy | default('') }}" - regex: '^HTTPS_PROXY=' - line: "HTTPS_PROXY={{ openshift.common.https_proxy }}" + line: "HTTPS_PROXY={{ openshift.common.https_proxy | default('') }}" - regex: '^NO_PROXY=' - line: "NO_PROXY={{ openshift.common.no_proxy | join(',') }},{{ openshift.common.portal_net }},{{ hostvars[groups.oo_first_master.0].openshift.master.sdn_cluster_network_cidr }}" - when: "{{ openshift.common.http_proxy is defined and openshift.common.http_proxy != '' }}" + line: "NO_PROXY={{ openshift.common.no_proxy | default([]) | join(',') }},{{ openshift.common.portal_net }},{{ hostvars[groups.oo_first_master.0].openshift.master.sdn_cluster_network_cidr }}" + when: ('http_proxy' in openshift.common and openshift.common.http_proxy != '') notify: - restart node diff --git a/roles/openshift_node_certificates/handlers/main.yml b/roles/openshift_node_certificates/handlers/main.yml new file mode 100644 index 000000000..f2299cecf --- /dev/null +++ b/roles/openshift_node_certificates/handlers/main.yml @@ -0,0 +1,10 @@ +--- +- name: update ca trust + command: update-ca-trust + notify: + - restart docker after updating ca trust + +- name: restart docker after updating ca trust + service: + name: docker + state: restarted diff --git a/roles/openshift_node_certificates/tasks/main.yml b/roles/openshift_node_certificates/tasks/main.yml index fef7caab8..80ab4bb1d 100644 --- a/roles/openshift_node_certificates/tasks/main.yml +++ b/roles/openshift_node_certificates/tasks/main.yml @@ -91,6 +91,9 @@ -C {{ openshift_node_generated_config_dir }} . args: creates: "{{ openshift_node_generated_config_dir }}.tgz" + # Disables the following warning: + # Consider using unarchive module rather than running tar + warn: no when: node_certs_missing | bool delegate_to: "{{ openshift_ca_host }}" @@ -121,3 +124,14 @@ when: node_certs_missing | bool delegate_to: localhost become: no + +- name: Copy OpenShift CA to system CA trust + copy: + src: "{{ item.cert }}" + dest: "/etc/pki/ca-trust/source/anchors/{{ item.id }}-{{ item.cert | basename }}" + remote_src: yes + with_items: + - id: openshift + cert: "{{ openshift_node_cert_dir }}/ca.crt" + notify: + - update ca trust diff --git a/roles/openshift_repos/handlers/main.yml b/roles/openshift_repos/handlers/main.yml index 198fc7d6e..cdb0d8a48 100644 --- a/roles/openshift_repos/handlers/main.yml +++ b/roles/openshift_repos/handlers/main.yml @@ -1,3 +1,7 @@ --- - name: refresh cache command: "{{ ansible_pkg_mgr }} clean all" + args: + # Disables the following warning: + # Consider using yum module rather than running yum + warn: no diff --git a/roles/openshift_storage_nfs/tasks/main.yml b/roles/openshift_storage_nfs/tasks/main.yml index 08d0b8540..4716c77ae 100644 --- a/roles/openshift_storage_nfs/tasks/main.yml +++ b/roles/openshift_storage_nfs/tasks/main.yml @@ -28,6 +28,8 @@ with_items: - "{{ openshift.hosted.registry }}" - "{{ openshift.hosted.metrics }}" + - "{{ openshift.hosted.logging }}" + - name: Configure exports template: diff --git a/roles/openshift_storage_nfs/templates/exports.j2 b/roles/openshift_storage_nfs/templates/exports.j2 index d6d936b72..2d6dd85e3 100644 --- a/roles/openshift_storage_nfs/templates/exports.j2 +++ b/roles/openshift_storage_nfs/templates/exports.j2 @@ -1,2 +1,3 @@ {{ openshift.hosted.registry.storage.nfs.directory }}/{{ openshift.hosted.registry.storage.volume.name }} {{ openshift.hosted.registry.storage.nfs.options }} {{ openshift.hosted.metrics.storage.nfs.directory }}/{{ openshift.hosted.metrics.storage.volume.name }} {{ openshift.hosted.metrics.storage.nfs.options }} +{{ openshift.hosted.logging.storage.nfs.directory }}/{{ openshift.hosted.logging.storage.volume.name }} {{ openshift.hosted.logging.storage.nfs.options }} diff --git a/roles/os_firewall/tasks/firewall/iptables.yml b/roles/os_firewall/tasks/firewall/iptables.yml index 774916798..470d4f4f9 100644 --- a/roles/os_firewall/tasks/firewall/iptables.yml +++ b/roles/os_firewall/tasks/firewall/iptables.yml @@ -1,6 +1,10 @@ --- - name: Check if firewalld is installed command: rpm -q firewalld + args: + # Disables the following warning: + # Consider using yum, dnf or zypper module rather than running rpm + warn: no register: pkg_check failed_when: pkg_check.rc > 1 changed_when: no diff --git a/roles/rhel_subscribe/tasks/enterprise.yml b/roles/rhel_subscribe/tasks/enterprise.yml index 8d11276d0..291df6822 100644 --- a/roles/rhel_subscribe/tasks/enterprise.yml +++ b/roles/rhel_subscribe/tasks/enterprise.yml @@ -7,7 +7,7 @@ when: deployment_type == 'enterprise' - set_fact: - default_ose_version: '3.2' + default_ose_version: '3.3' when: deployment_type in ['atomic-enterprise', 'openshift-enterprise'] - set_fact: @@ -16,7 +16,7 @@ - fail: msg: "{{ ose_version }} is not a valid version for {{ deployment_type }} deployment type" when: ( deployment_type == 'enterprise' and ose_version not in ['3.0'] ) or - ( deployment_type in ['atomic-enterprise', 'openshift-enterprise'] and ose_version not in ['3.1', '3.2'] ) + ( deployment_type in ['atomic-enterprise', 'openshift-enterprise'] and ose_version not in ['3.1', '3.2', '3.3'] ) - name: Enable RHEL repositories command: subscription-manager repos \ diff --git a/roles/rhel_subscribe/tasks/main.yml b/roles/rhel_subscribe/tasks/main.yml index 343020dce..ba3b9a923 100644 --- a/roles/rhel_subscribe/tasks/main.yml +++ b/roles/rhel_subscribe/tasks/main.yml @@ -4,7 +4,7 @@ # to make it able to enable repositories - set_fact: - rhel_subscription_pool: "{{ lookup('oo_option', 'rhel_subscription_pool') | default(rhsub_pool, True) | default('OpenShift Enterprise, Premium*', True) }}" + rhel_subscription_pool: "{{ lookup('oo_option', 'rhel_subscription_pool') | default(rhsub_pool, True) | default('Red Hat OpenShift Container Platform, Premium*', True) }}" rhel_subscription_user: "{{ lookup('oo_option', 'rhel_subscription_user') | default(rhsub_user, True) | default(omit, True) }}" rhel_subscription_pass: "{{ lookup('oo_option', 'rhel_subscription_pass') | default(rhsub_pass, True) | default(omit, True) }}" rhel_subscription_server: "{{ lookup('oo_option', 'rhel_subscription_server') | default(rhsub_server) }}" diff --git a/utils/Makefile b/utils/Makefile index 79c27626a..59aff92fd 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -25,6 +25,12 @@ NAME := oo-install TESTPACKAGE := oo-install SHORTNAME := ooinstall +# This doesn't evaluate until it's called. The -D argument is the +# directory of the target file ($@), kinda like `dirname`. +ASCII2MAN = a2x -D $(dir $@) -d manpage -f manpage $< +MANPAGES := docs/man/man1/atomic-openshift-installer.1 +VERSION := 1.3 + sdist: clean python setup.py sdist rm -fR $(SHORTNAME).egg-info @@ -35,6 +41,21 @@ clean: @rm -fR build dist rpm-build MANIFEST htmlcov .coverage cover ooinstall.egg-info oo-install @rm -fR $(NAME)env + +# To force a rebuild of the docs run 'touch' on any *.in file under +# docs/man/man1/ +docs: $(MANPAGES) + +# Regenerate %.1.asciidoc if %.1.asciidoc.in has been modified more +# recently than %.1.asciidoc. +%.1.asciidoc: %.1.asciidoc.in + sed "s/%VERSION%/$(VERSION)/" $< > $@ + +# Regenerate %.1 if %.1.asciidoc or VERSION has been modified more +# recently than %.1. (Implicitly runs the %.1.asciidoc recipe) +%.1: %.1.asciidoc + $(ASCII2MAN) + viewcover: xdg-open cover/index.html @@ -59,7 +80,7 @@ ci-pylint: @echo "#############################################" @echo "# Running PyLint Tests in virtualenv" @echo "#############################################" - . $(NAME)env/bin/activate && python -m pylint --rcfile ../git/.pylintrc src/ooinstall/cli_installer.py src/ooinstall/oo_config.py src/ooinstall/openshift_ansible.py src/ooinstall/variants.py + . $(NAME)env/bin/activate && python -m pylint --rcfile ../git/.pylintrc src/ooinstall/cli_installer.py src/ooinstall/oo_config.py src/ooinstall/openshift_ansible.py src/ooinstall/variants.py ../callback_plugins/openshift_quick_installer.py ci-list-deps: @echo "#############################################" @@ -72,12 +93,14 @@ ci-pyflakes: @echo "# Running Pyflakes Compliance Tests in virtualenv" @echo "#################################################" . $(NAME)env/bin/activate && pyflakes src/ooinstall/*.py + . $(NAME)env/bin/activate && pyflakes ../callback_plugins/openshift_quick_installer.py ci-pep8: @echo "#############################################" @echo "# Running PEP8 Compliance Tests in virtualenv" @echo "#############################################" . $(NAME)env/bin/activate && pep8 --ignore=E501,E121,E124 src/$(SHORTNAME)/ + . $(NAME)env/bin/activate && pep8 --ignore=E501,E121,E124 ../callback_plugins/openshift_quick_installer.py ci: clean virtualenv ci-list-deps ci-pep8 ci-pylint ci-pyflakes ci-unittests : diff --git a/utils/docs/man/man1/atomic-openshift-installer.1 b/utils/docs/man/man1/atomic-openshift-installer.1 new file mode 100644 index 000000000..4da82191b --- /dev/null +++ b/utils/docs/man/man1/atomic-openshift-installer.1 @@ -0,0 +1,186 @@ +'\" t +.\" Title: atomic-openshift-installer +.\" Author: [see the "AUTHOR" section] +.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> +.\" Date: 09/28/2016 +.\" Manual: atomic-openshift-installer +.\" Source: atomic-openshift-utils 1.3 +.\" Language: English +.\" +.TH "ATOMIC\-OPENSHIFT\-I" "1" "09/28/2016" "atomic\-openshift\-utils 1\&.3" "atomic\-openshift\-installer" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +atomic-openshift-installer \- Interactive OpenShift Container Platform (OCP) installer +.SH "SYNOPSIS" +.sp +atomic\-openshift\-installer [OPTIONS] COMMAND [OPTS] +.SH "DESCRIPTION" +.sp +\fBatomic\-openshift\-installer\fR makes the process for installing OCP easier by interactively gathering the data needed to run on each host\&. It can also be run in unattended mode if provided with a configuration file\&. +.SH "OPTIONS" +.sp +The following options are common to all commands\&. +.PP +\fB\-u\fR, \fB\-\-unattended\fR +.RS 4 +Run installer in +\fBunattended\fR +mode\&. You will not be prompted to answer any questions\&. +.RE +.PP +\fB\-c\fR, \fB\-\-configuration\fR \fIPATH\fR +.RS 4 +Provide an alternate +\fIPATH\fR +to an +\fIinstaller\&.cfg\&.yml\fR +file\&. +.RE +.PP +\fB\-a\fR \fIDIRECTORY\fR, \fB\-\-ansible\-playbook\-directory\fR \fIDIRECTORY\fR +.RS 4 +Manually set the +\fIDIRECTORY\fR +in which to look for Ansible playbooks\&. +.RE +.PP +\fB\-\-ansible\-log\-path\fR \fIPATH\fR +.RS 4 +Specify the +\fIPATH\fR +of the directory in which to save Ansible logs\&. +.RE +.PP +\fB\-v\fR, \fB\-\-verbose\fR +.RS 4 +Run the installer with more verbosity\&. +.RE +.PP +\fB\-d\fR, \fB\-\-debug\fR +.RS 4 +Enable installer debugging\&. Logs are saved in +\fI/tmp/installer\&.txt\fR\&. +.RE +.PP +\fB\-h\fR, \fB\-\-help\fR +.RS 4 +Show the usage help and exit\&. +.RE +.SH "COMMANDS" +.sp +\fBatomic\-openshift\-installer\fR has three modes of operation: +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fBinstall\fR +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fBuninstall\fR +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +\fBupgrade\fR +.RE +.sp +The options specific to each command are described in the following sections\&. +.SH "INSTALL" +.sp +The \fBinstall\fR command will guide you through steps required to install an OCP cluster\&. After all of the required information has been collected (target hosts, storage options, high\-availability), the installation will begin\&. +.PP +\fB\-f\fR, \fB\-\-force\fR +.RS 4 +Forces an installation\&. This means that hosts with existing installations will be reinstalled if required\&. +.RE +.PP +\fB\-\-gen\-inventory\fR +.RS 4 +Generate an Ansible inventory file and exit\&. The default location for the inventory file is +\fI~/\&.config/openshift/hosts\fR\&. +.RE +.SH "UNINSTALL" +.sp +The \fBuninstall\fR command will uninstall OCP from your target hosts\&. This command has no additional options\&. +.SH "UPGRADE" +.sp +The \fBupgrade\fR command will upgrade a cluster of hosts to a newer version of OCP\&. +.PP +\fB\-l\fR, \fB\-\-latest\-minor\fR +.RS 4 +Upgrade to the latest minor version\&. For example, if you are running version +\fB3\&.2\&.1\fR +then this could upgrade you to +\fB3\&.2\&.2\fR\&. +.RE +.PP +\fB\-n\fR, \fB\-\-next\-major\fR +.RS 4 +Upgrade to the latest major version\&. For example, if you are running version +\fB3\&.2\fR +then this could upgrade you to +\fB3\&.3\fR\&. +.RE +.SH "FILES" +.sp +\fB~/\&.config/openshift/installer\&.cfg\&.yml\fR \(em Installer configuration file\&. Can be used to generate an inventory later or start an unattended installation\&. +.sp +\fB~/\&.config/openshift/hosts\fR \(em Generated Ansible inventory file\&. Used to run the Ansible playbooks for install, uninstall, and upgrades\&. +.sp +\fB/tmp/ansible\&.log\fR \(em The default location of the ansible log file\&. +.sp +\fB/tmp/installer\&.txt\fR \(em The location of the log file for debugging the installer\&. +.SH "AUTHOR" +.sp +Red Hat OpenShift Productization team +.sp +For a complete list of contributors, please visit the GitHub charts page\&. +.SH "COPYRIGHT" +.sp +Copyright \(co 2016 Red Hat, Inc\&. +.sp +\fBatomic\-openshift\-installer\fR is released under the terms of the ASL 2\&.0 license\&. +.SH "SEE ALSO" +.sp +\fBansible\fR(1), \fBansible\-playbook\fR(1) +.sp +\fBThe openshift\-ansible GitHub Project\fR \(em https://github\&.com/openshift/openshift\-ansible/ +.sp +\fBThe atomic\-openshift\-installer Documentation\fR \(em https://docs\&.openshift\&.com/container\-platform/3\&.3/install_config/install/quick_install\&.html diff --git a/utils/docs/man/man1/atomic-openshift-installer.1.asciidoc.in b/utils/docs/man/man1/atomic-openshift-installer.1.asciidoc.in new file mode 100644 index 000000000..64e5d14a3 --- /dev/null +++ b/utils/docs/man/man1/atomic-openshift-installer.1.asciidoc.in @@ -0,0 +1,167 @@ +atomic-openshift-installer(1) +============================= +:man source: atomic-openshift-utils +:man version: %VERSION% +:man manual: atomic-openshift-installer + + +NAME +---- +atomic-openshift-installer - Interactive OpenShift Container Platform (OCP) installer + + +SYNOPSIS +-------- +atomic-openshift-installer [OPTIONS] COMMAND [OPTS] + + +DESCRIPTION +----------- + +**atomic-openshift-installer** makes the process for installing OCP +easier by interactively gathering the data needed to run on each +host. It can also be run in unattended mode if provided with a +configuration file. + + +OPTIONS +------- + +The following options are common to all commands. + +*-u*, *--unattended*:: + +Run installer in **unattended** mode. You will not be prompted to +answer any questions. + + +*-c*, *--configuration* 'PATH':: + +Provide an alternate 'PATH' to an 'installer.cfg.yml' file. + + +*-a* 'DIRECTORY', *--ansible-playbook-directory* 'DIRECTORY':: + +Manually set the 'DIRECTORY' in which to look for Ansible playbooks. + + +*--ansible-log-path* 'PATH':: + +Specify the 'PATH' of the directory in which to save Ansible logs. + + +*-v*, *--verbose*:: + +Run the installer with more verbosity. + + +*-d*, *--debug*:: + +Enable installer debugging. Logs are saved in '/tmp/installer.txt'. + + +*-h*, *--help*:: + +Show the usage help and exit. + + +COMMANDS +-------- + +**atomic-openshift-installer** has three modes of operation: + +* **install** +* **uninstall** +* **upgrade** + +The options specific to each command are described in the following +sections. + + + +INSTALL +------- + +The **install** command will guide you through steps required to +install an OCP cluster. After all of the required information has been +collected (target hosts, storage options, high-availability), the +installation will begin. + +*-f*, *--force*:: + +Forces an installation. This means that hosts with existing +installations will be reinstalled if required. + +*--gen-inventory*:: + +Generate an Ansible inventory file and exit. The default location for +the inventory file is '~/.config/openshift/hosts'. + + +UNINSTALL +--------- + +The **uninstall** command will uninstall OCP from your target +hosts. This command has no additional options. + + +UPGRADE +------- + +The **upgrade** command will upgrade a cluster of hosts to a newer +version of OCP. + +*-l*, *--latest-minor*:: + +Upgrade to the latest minor version. For example, if you are running +version **3.2.1** then this could upgrade you to **3.2.2**. + +*-n*, *--next-major*:: + +Upgrade to the latest major version. For example, if you are running +version **3.2** then this could upgrade you to **3.3**. + + + +FILES +----- + +*~/.config/openshift/installer.cfg.yml* -- Installer configuration + file. Can be used to generate an inventory later or start an + unattended installation. + +*~/.config/openshift/hosts* -- Generated Ansible inventory file. Used + to run the Ansible playbooks for install, uninstall, and upgrades. + +*/tmp/ansible.log* -- The default location of the ansible log file. + +*/tmp/installer.txt* -- The location of the log file for debugging the + installer. + + +AUTHOR +------ + +Red Hat OpenShift Productization team + +For a complete list of contributors, please visit the GitHub charts +page. + + + +COPYRIGHT +--------- +Copyright © 2016 Red Hat, Inc. + +**atomic-openshift-installer** is released under the terms of the ASL +2.0 license. + + + +SEE ALSO +-------- +*ansible*(1), *ansible-playbook*(1) + +*The openshift-ansible GitHub Project* -- <https://github.com/openshift/openshift-ansible/> + +*The atomic-openshift-installer Documentation* -- <https://docs.openshift.com/container-platform/3.3/install_config/install/quick_install.html> diff --git a/utils/etc/ansible-quiet.cfg b/utils/etc/ansible-quiet.cfg new file mode 100644 index 000000000..0eb0efa49 --- /dev/null +++ b/utils/etc/ansible-quiet.cfg @@ -0,0 +1,33 @@ +# config file for ansible -- http://ansible.com/ +# ============================================== + +# This config file provides examples for running +# the OpenShift playbooks with the provided +# inventory scripts. Only global defaults are +# left uncommented + +[defaults] +# Add the roles directory to the roles path +roles_path = roles/ + +# Set the log_path +log_path = /tmp/ansible.log + +forks = 10 +host_key_checking = False +nocows = 1 + +retry_files_enabled = False + +deprecation_warnings=False + +# Need to handle: +# inventory - derive from OO_ANSIBLE_DIRECTORY env var +# callback_plugins - derive from pkg_resource.resource_filename +# private_key_file - prompt if missing +# remote_tmp - set if provided by user (cli) +# ssh_args - set if provided by user (cli) +# control_path + +stdout_callback = openshift_quick_installer +callback_plugins = /usr/share/ansible_plugins/callback_plugins diff --git a/utils/etc/ansible.cfg b/utils/etc/ansible.cfg index a53ab6cb1..3425e7e62 100644 --- a/utils/etc/ansible.cfg +++ b/utils/etc/ansible.cfg @@ -19,10 +19,12 @@ nocows = 1 retry_files_enabled = False +deprecation_warnings = False + # Need to handle: # inventory - derive from OO_ANSIBLE_DIRECTORY env var # callback_plugins - derive from pkg_resource.resource_filename # private_key_file - prompt if missing # remote_tmp - set if provided by user (cli) # ssh_args - set if provided by user (cli) -# control_path
\ No newline at end of file +# control_path diff --git a/utils/setup.py b/utils/setup.py index eac1b4b2e..563897bb1 100644 --- a/utils/setup.py +++ b/utils/setup.py @@ -62,7 +62,7 @@ setup( # installed, specify them here. If using Python 2.6 or less, then these # have to be included in MANIFEST.in as well. package_data={ - 'ooinstall': ['ansible.cfg', 'ansible_plugins/*'], + 'ooinstall': ['ansible.cfg', 'ansible-quiet.cfg', 'ansible_plugins/*'], }, # Although 'package_data' is the preferred approach, in some case you may diff --git a/utils/src/MANIFEST.in b/utils/src/MANIFEST.in index d4153e738..216f57e9c 100644 --- a/utils/src/MANIFEST.in +++ b/utils/src/MANIFEST.in @@ -7,3 +7,4 @@ include DESCRIPTION.rst # it's already declared in setup.py include ooinstall/* include ansible.cfg +include ansible-quiet.cfg diff --git a/utils/src/ooinstall/cli_installer.py b/utils/src/ooinstall/cli_installer.py index 85b4d29cb..347ae7ec9 100644 --- a/utils/src/ooinstall/cli_installer.py +++ b/utils/src/ooinstall/cli_installer.py @@ -25,6 +25,7 @@ installer_file_handler.setLevel(logging.DEBUG) installer_log.addHandler(installer_file_handler) DEFAULT_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-utils/ansible.cfg' +QUIET_ANSIBLE_CONFIG = '/usr/share/atomic-openshift-utils/ansible-quiet.cfg' DEFAULT_PLAYBOOK_DIR = '/usr/share/ansible/openshift-ansible/' UPGRADE_MAPPINGS = { @@ -750,7 +751,9 @@ def get_hosts_to_run_on(oo_cfg, callback_facts, unattended, force, verbose): hosts_to_run_on.remove(host) # Handle the cases where we know about uninstalled systems - if len(uninstalled_hosts) > 0: + # TODO: This logic is getting hard to understand. + # we should revise all this to be cleaner. + if not force and len(uninstalled_hosts) > 0: for uninstalled_host in uninstalled_hosts: click.echo("{} is currently uninstalled".format(uninstalled_host)) # Fall through @@ -815,12 +818,6 @@ def set_infra_nodes(hosts): # callback=validate_ansible_dir, default=DEFAULT_PLAYBOOK_DIR, envvar='OO_ANSIBLE_PLAYBOOK_DIRECTORY') -@click.option('--ansible-config', - type=click.Path(file_okay=True, - dir_okay=False, - writable=True, - readable=True), - default=None) @click.option('--ansible-log-path', type=click.Path(file_okay=True, dir_okay=False, @@ -836,7 +833,7 @@ def set_infra_nodes(hosts): # pylint: disable=too-many-arguments # pylint: disable=line-too-long # Main CLI entrypoint, not much we can do about too many arguments. -def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_config, ansible_log_path, verbose, debug): +def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_log_path, verbose, debug): """ atomic-openshift-installer makes the process for installing OSE or AEP easier by interactively gathering the data needed to run on each host. @@ -855,7 +852,6 @@ def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_conf ctx.obj = {} ctx.obj['unattended'] = unattended ctx.obj['configuration'] = configuration - ctx.obj['ansible_config'] = ansible_config ctx.obj['ansible_log_path'] = ansible_log_path ctx.obj['verbose'] = verbose @@ -876,13 +872,13 @@ def cli(ctx, unattended, configuration, ansible_playbook_directory, ansible_conf oo_cfg.ansible_playbook_directory = ansible_playbook_directory ctx.obj['ansible_playbook_directory'] = ansible_playbook_directory - if ctx.obj['ansible_config']: - oo_cfg.settings['ansible_config'] = ctx.obj['ansible_config'] - elif 'ansible_config' not in oo_cfg.settings and \ - os.path.exists(DEFAULT_ANSIBLE_CONFIG): + if os.path.exists(DEFAULT_ANSIBLE_CONFIG): # If we're installed by RPM this file should exist and we can use it as our default: oo_cfg.settings['ansible_config'] = DEFAULT_ANSIBLE_CONFIG + if os.path.exists(QUIET_ANSIBLE_CONFIG): + oo_cfg.settings['ansible_quiet_config'] = QUIET_ANSIBLE_CONFIG + oo_cfg.settings['ansible_log_path'] = ctx.obj['ansible_log_path'] ctx.obj['oo_cfg'] = oo_cfg @@ -1084,7 +1080,6 @@ more: http://docs.openshift.com/enterprise/latest/admin_guide/overview.html """ click.echo(message) - click.pause() cli.add_command(install) cli.add_command(upgrade) diff --git a/utils/src/ooinstall/oo_config.py b/utils/src/ooinstall/oo_config.py index 393b36f6f..697ac9c08 100644 --- a/utils/src/ooinstall/oo_config.py +++ b/utils/src/ooinstall/oo_config.py @@ -12,7 +12,6 @@ installer_log = logging.getLogger('installer') CONFIG_PERSIST_SETTINGS = [ 'ansible_ssh_user', 'ansible_callback_facts_yaml', - 'ansible_config', 'ansible_inventory_path', 'ansible_log_path', 'deployment', @@ -27,6 +26,19 @@ DEPLOYMENT_VARIABLES_BLACKLIST = [ 'roles', ] +HOST_VARIABLES_BLACKLIST = [ + 'ip', + 'public_ip', + 'hostname', + 'public_hostname', + 'node_labels', + 'containerized', + 'preconfigured', + 'schedulable', + 'other_variables', + 'roles', +] + DEFAULT_REQUIRED_FACTS = ['ip', 'public_ip', 'hostname', 'public_hostname'] PRECONFIGURED_REQUIRED_FACTS = ['hostname', 'public_hostname'] @@ -67,7 +79,7 @@ class Host(object): self.containerized = kwargs.get('containerized', False) self.node_labels = kwargs.get('node_labels', '') - # allowable roles: master, node, etcd, storage, master_lb, new + # allowable roles: master, node, etcd, storage, master_lb self.roles = kwargs.get('roles', []) self.other_variables = kwargs.get('other_variables', {}) @@ -87,11 +99,13 @@ class Host(object): d = {} for prop in ['ip', 'hostname', 'public_ip', 'public_hostname', 'connect_to', - 'preconfigured', 'containerized', 'schedulable', 'roles', 'node_labels', - 'other_variables']: + 'preconfigured', 'containerized', 'schedulable', 'roles', 'node_labels', ]: # If the property is defined (not None or False), export it: if getattr(self, prop): d[prop] = getattr(self, prop) + for variable, value in self.other_variables.iteritems(): + d[variable] = value + return d def is_master(self): @@ -203,7 +217,6 @@ class OOConfig(object): role_list = loaded_config['deployment']['roles'] except KeyError as e: print_read_config_error("No such key: {}".format(e), self.config_path) - print "Error loading config, required key missing: {}".format(e) sys.exit(0) for setting in CONFIG_PERSIST_SETTINGS: @@ -238,6 +251,10 @@ class OOConfig(object): # Parse the hosts into DTO objects: for host in host_list: + host['other_variables'] = {} + for variable, value in host.iteritems(): + if variable not in HOST_VARIABLES_BLACKLIST: + host['other_variables'][variable] = value self.deployment.hosts.append(Host(**host)) # Parse the roles into Objects @@ -308,6 +325,12 @@ class OOConfig(object): if 'ansible_plugins_directory' not in self.settings: self.settings['ansible_plugins_directory'] = \ resource_filename(__name__, 'ansible_plugins') + installer_log.debug("We think the ansible plugins directory should be: %s (it is not already set)", + self.settings['ansible_plugins_directory']) + else: + installer_log.debug("The ansible plugins directory is already set: %s", + self.settings['ansible_plugins_directory']) + if 'version' not in self.settings: self.settings['version'] = 'v2' diff --git a/utils/src/ooinstall/openshift_ansible.py b/utils/src/ooinstall/openshift_ansible.py index 75d26c10a..80a79a6d2 100644 --- a/utils/src/ooinstall/openshift_ansible.py +++ b/utils/src/ooinstall/openshift_ansible.py @@ -7,6 +7,7 @@ import os import logging import yaml from ooinstall.variants import find_variant +from ooinstall.utils import debug_env installer_log = logging.getLogger('installer') @@ -30,6 +31,14 @@ VARIABLES_MAP = { 'proxy_exclude_hosts': 'openshift_no_proxy', } +HOST_VARIABLES_MAP = { + 'ip': 'openshift_ip', + 'public_ip': 'openshift_public_ip', + 'hostname': 'openshift_hostname', + 'public_hostname': 'openshift_public_hostname', + 'containerized': 'containerized', +} + def set_config(cfg): global CFG @@ -175,7 +184,6 @@ def write_proxy_settings(base_inventory): pass -# pylint: disable=too-many-branches def write_host(host, role, inventory, schedulable=None): global CFG @@ -183,22 +191,16 @@ def write_host(host, role, inventory, schedulable=None): return facts = '' - if host.ip: - facts += ' openshift_ip={}'.format(host.ip) - if host.public_ip: - facts += ' openshift_public_ip={}'.format(host.public_ip) - if host.hostname: - facts += ' openshift_hostname={}'.format(host.hostname) - if host.public_hostname: - facts += ' openshift_public_hostname={}'.format(host.public_hostname) - if host.containerized: - facts += ' containerized={}'.format(host.containerized) + for prop in HOST_VARIABLES_MAP: + if getattr(host, prop): + facts += ' {}={}'.format(HOST_VARIABLES_MAP.get(prop), getattr(host, prop)) + if host.other_variables: for variable, value in host.other_variables.iteritems(): facts += " {}={}".format(variable, value) - if host.node_labels: - if role == 'node': - facts += ' openshift_node_labels="{}"'.format(host.node_labels) + + if host.node_labels and role == 'node': + facts += ' openshift_node_labels="{}"'.format(host.node_labels) # Distinguish between three states, no schedulability specified (use default), # explicitly set to True, or explicitly set to False: @@ -225,6 +227,9 @@ def load_system_facts(inventory_file, os_facts_path, env_vars, verbose=False): Retrieves system facts from the remote systems. """ installer_log.debug("Inside load_system_facts") + installer_log.debug("load_system_facts will run with Ansible/Openshift environment variables:") + debug_env(env_vars) + FNULL = open(os.devnull, 'w') args = ['ansible-playbook', '-v'] if verbose \ else ['ansible-playbook'] @@ -232,6 +237,8 @@ def load_system_facts(inventory_file, os_facts_path, env_vars, verbose=False): '--inventory-file={}'.format(inventory_file), os_facts_path]) installer_log.debug("Going to subprocess out to ansible now with these args: %s", ' '.join(args)) + installer_log.debug("Subprocess will run with Ansible/Openshift environment variables:") + debug_env(env_vars) status = subprocess.call(args, env=env_vars, stdout=FNULL) if status != 0: installer_log.debug("Exit status from subprocess was not 0") @@ -280,17 +287,24 @@ def run_main_playbook(inventory_file, hosts, hosts_to_run_on, verbose=False): facts_env = os.environ.copy() if 'ansible_log_path' in CFG.settings: facts_env['ANSIBLE_LOG_PATH'] = CFG.settings['ansible_log_path'] - if 'ansible_config' in CFG.settings: - facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_config'] + + # override the ansible config for our main playbook run + if 'ansible_quiet_config' in CFG.settings: + facts_env['ANSIBLE_CONFIG'] = CFG.settings['ansible_quiet_config'] + return run_ansible(main_playbook_path, inventory_file, facts_env, verbose) def run_ansible(playbook, inventory, env_vars, verbose=False): + installer_log.debug("run_ansible will run with Ansible/Openshift environment variables:") + debug_env(env_vars) + args = ['ansible-playbook', '-v'] if verbose \ else ['ansible-playbook'] args.extend([ '--inventory-file={}'.format(inventory), playbook]) + installer_log.debug("Going to subprocess out to ansible now with these args: %s", ' '.join(args)) return subprocess.call(args, env=env_vars) diff --git a/utils/src/ooinstall/utils.py b/utils/src/ooinstall/utils.py new file mode 100644 index 000000000..eb27a57e4 --- /dev/null +++ b/utils/src/ooinstall/utils.py @@ -0,0 +1,10 @@ +import logging + +installer_log = logging.getLogger('installer') + + +def debug_env(env): + for k in sorted(env.keys()): + if k.startswith("OPENSHIFT") or k.startswith("ANSIBLE") or k.startswith("OO"): + installer_log.debug("{key}: {value}".format( + key=k, value=env[k])) diff --git a/utils/test/cli_installer_tests.py b/utils/test/cli_installer_tests.py index 6d9d443ff..34392777b 100644 --- a/utils/test/cli_installer_tests.py +++ b/utils/test/cli_installer_tests.py @@ -599,82 +599,96 @@ class UnattendedCliTests(OOCliFixture): self.assertEquals('openshift-enterprise', inventory.get('OSEv3:vars', 'deployment_type')) - @patch('ooinstall.openshift_ansible.run_ansible') - @patch('ooinstall.openshift_ansible.load_system_facts') - def test_no_ansible_config_specified(self, load_facts_mock, run_ansible_mock): - load_facts_mock.return_value = (MOCK_FACTS, 0) - run_ansible_mock.return_value = 0 - - config = SAMPLE_CONFIG % 'openshift-enterprise' - - self._ansible_config_test(load_facts_mock, run_ansible_mock, - config, None, None) - - @patch('ooinstall.openshift_ansible.run_ansible') - @patch('ooinstall.openshift_ansible.load_system_facts') - def test_ansible_config_specified_cli(self, load_facts_mock, run_ansible_mock): - load_facts_mock.return_value = (MOCK_FACTS, 0) - run_ansible_mock.return_value = 0 - - config = SAMPLE_CONFIG % 'openshift-enterprise' - ansible_config = os.path.join(self.work_dir, 'ansible.cfg') - - self._ansible_config_test(load_facts_mock, run_ansible_mock, - config, ansible_config, ansible_config) - - @patch('ooinstall.openshift_ansible.run_ansible') - @patch('ooinstall.openshift_ansible.load_system_facts') - def test_ansible_config_specified_in_installer_config(self, - load_facts_mock, run_ansible_mock): - - load_facts_mock.return_value = (MOCK_FACTS, 0) - run_ansible_mock.return_value = 0 - - ansible_config = os.path.join(self.work_dir, 'ansible.cfg') - config = SAMPLE_CONFIG % 'openshift-enterprise' - config = "%s\nansible_config: %s" % (config, ansible_config) - self._ansible_config_test(load_facts_mock, run_ansible_mock, - config, None, ansible_config) - - #pylint: disable=too-many-arguments - # This method allows for drastically simpler tests to write, and the args - # are all useful. - def _ansible_config_test(self, load_facts_mock, run_ansible_mock, - installer_config, ansible_config_cli=None, expected_result=None): - """ - Utility method for testing the ways you can specify the ansible config. - """ - - load_facts_mock.return_value = (MOCK_FACTS, 0) - run_ansible_mock.return_value = 0 - - config_file = self.write_config(os.path.join(self.work_dir, - 'ooinstall.conf'), installer_config) - - self.cli_args.extend(["-c", config_file]) - if ansible_config_cli: - self.cli_args.extend(["--ansible-config", ansible_config_cli]) - self.cli_args.append("install") - result = self.runner.invoke(cli.cli, self.cli_args) - self.assert_result(result, 0) - - # Test the env vars for facts playbook: - facts_env_vars = load_facts_mock.call_args[0][2] - if expected_result: - self.assertEquals(expected_result, facts_env_vars['ANSIBLE_CONFIG']) - else: - # If user running test has rpm installed, this might be set to default: - self.assertTrue('ANSIBLE_CONFIG' not in facts_env_vars or - facts_env_vars['ANSIBLE_CONFIG'] == cli.DEFAULT_ANSIBLE_CONFIG) - - # Test the env vars for main playbook: - env_vars = run_ansible_mock.call_args[0][2] - if expected_result: - self.assertEquals(expected_result, env_vars['ANSIBLE_CONFIG']) - else: - # If user running test has rpm installed, this might be set to default: - self.assertTrue('ANSIBLE_CONFIG' not in env_vars or - env_vars['ANSIBLE_CONFIG'] == cli.DEFAULT_ANSIBLE_CONFIG) + # 2016-09-26 - tbielawa - COMMENTING OUT these tests FOR NOW while + # we wait to see if anyone notices that we took away their ability + # to set the ansible_config parameter in the command line options + # and in the installer config file. + # + # We have removed the ability to set the ansible config file + # manually so that our new quieter output mode is the default and + # only output mode. + # + # RE: https://trello.com/c/DSwwizwP - atomic-openshift-install + # should only output relevant information. + + # @patch('ooinstall.openshift_ansible.run_ansible') + # @patch('ooinstall.openshift_ansible.load_system_facts') + # def test_no_ansible_config_specified(self, load_facts_mock, run_ansible_mock): + # load_facts_mock.return_value = (MOCK_FACTS, 0) + # run_ansible_mock.return_value = 0 + + # config = SAMPLE_CONFIG % 'openshift-enterprise' + + # self._ansible_config_test(load_facts_mock, run_ansible_mock, + # config, None, None) + + # @patch('ooinstall.openshift_ansible.run_ansible') + # @patch('ooinstall.openshift_ansible.load_system_facts') + # def test_ansible_config_specified_cli(self, load_facts_mock, run_ansible_mock): + # load_facts_mock.return_value = (MOCK_FACTS, 0) + # run_ansible_mock.return_value = 0 + + # config = SAMPLE_CONFIG % 'openshift-enterprise' + # ansible_config = os.path.join(self.work_dir, 'ansible.cfg') + + # self._ansible_config_test(load_facts_mock, run_ansible_mock, + # config, ansible_config, ansible_config) + + # @patch('ooinstall.openshift_ansible.run_ansible') + # @patch('ooinstall.openshift_ansible.load_system_facts') + # def test_ansible_config_specified_in_installer_config(self, + # load_facts_mock, run_ansible_mock): + + # load_facts_mock.return_value = (MOCK_FACTS, 0) + # run_ansible_mock.return_value = 0 + + # ansible_config = os.path.join(self.work_dir, 'ansible.cfg') + # config = SAMPLE_CONFIG % 'openshift-enterprise' + # config = "%s\nansible_config: %s" % (config, ansible_config) + # self._ansible_config_test(load_facts_mock, run_ansible_mock, + # config, None, ansible_config) + + # #pylint: disable=too-many-arguments + # # This method allows for drastically simpler tests to write, and the args + # # are all useful. + # def _ansible_config_test(self, load_facts_mock, run_ansible_mock, + # installer_config, ansible_config_cli=None, expected_result=None): + # """ + # Utility method for testing the ways you can specify the ansible config. + # """ + + # load_facts_mock.return_value = (MOCK_FACTS, 0) + # run_ansible_mock.return_value = 0 + + # config_file = self.write_config(os.path.join(self.work_dir, + # 'ooinstall.conf'), installer_config) + + # self.cli_args.extend(["-c", config_file]) + # if ansible_config_cli: + # self.cli_args.extend(["--ansible-config", ansible_config_cli]) + # self.cli_args.append("install") + # result = self.runner.invoke(cli.cli, self.cli_args) + # self.assert_result(result, 0) + + # # Test the env vars for facts playbook: + # facts_env_vars = load_facts_mock.call_args[0][2] + # if expected_result: + # self.assertEquals(expected_result, facts_env_vars['ANSIBLE_CONFIG']) + # else: + # # If user running test has rpm installed, this might be set to default: + # self.assertTrue('ANSIBLE_CONFIG' not in facts_env_vars or + # facts_env_vars['ANSIBLE_CONFIG'] == cli.DEFAULT_ANSIBLE_CONFIG) + + # # Test the env vars for main playbook: + # env_vars = run_ansible_mock.call_args[0][2] + # if expected_result: + # self.assertEquals(expected_result, env_vars['ANSIBLE_CONFIG']) + # else: + # # If user running test has rpm installed, this might be set to default: + # # + # # By default we will use the quiet config + # self.assertTrue('ANSIBLE_CONFIG' not in env_vars or + # env_vars['ANSIBLE_CONFIG'] == cli.QUIET_ANSIBLE_CONFIG) # unattended with bad config file and no installed hosts (without --force) @patch('ooinstall.openshift_ansible.run_main_playbook') diff --git a/utils/test/oo_config_tests.py b/utils/test/oo_config_tests.py index b5068cc14..56fd82408 100644 --- a/utils/test/oo_config_tests.py +++ b/utils/test/oo_config_tests.py @@ -2,6 +2,7 @@ # repo. We will work on these over time. # pylint: disable=bad-continuation,missing-docstring,no-self-use,invalid-name +import cStringIO import os import unittest import tempfile @@ -9,6 +10,7 @@ import shutil import yaml from ooinstall.oo_config import OOConfig, Host, OOConfigInvalidHostError +import ooinstall.openshift_ansible SAMPLE_CONFIG = """ variant: openshift-enterprise @@ -224,3 +226,81 @@ class HostTests(OOInstallFixture): 'public_hostname': 'a.example.com', } self.assertRaises(OOConfigInvalidHostError, Host, **yaml_props) + + def test_inventory_file_quotes_node_labels(self): + """Verify a host entry wraps openshift_node_labels value in double quotes""" + yaml_props = { + 'ip': '192.168.0.1', + 'hostname': 'a.example.com', + 'connect_to': 'a-private.example.com', + 'public_ip': '192.168.0.1', + 'public_hostname': 'a.example.com', + 'new_host': True, + 'roles': ['node'], + 'node_labels': { + 'region': 'infra' + }, + + } + + new_node = Host(**yaml_props) + inventory = cStringIO.StringIO() + # This is what the 'write_host' function generates. write_host + # has no return value, it just writes directly to the file + # 'inventory' which in this test-case is a StringIO object + ooinstall.openshift_ansible.write_host( + new_node, + 'node', + inventory, + schedulable=True) + # read the value of what was written to the inventory "file" + legacy_inventory_line = inventory.getvalue() + + # Given the `yaml_props` above we should see a line like this: + # openshift_node_labels="{'region': 'infra'}" + node_labels_expected = '''openshift_node_labels="{'region': 'infra'}"''' # Quotes around the hash + node_labels_bad = '''openshift_node_labels={'region': 'infra'}''' # No quotes around the hash + + # The good line is present in the written inventory line + self.assertIn(node_labels_expected, legacy_inventory_line) + # An unquoted version is not present + self.assertNotIn(node_labels_bad, legacy_inventory_line) + + + # def test_new_write_inventory_same_as_legacy(self): + # """Verify the original write_host function produces the same output as the new method""" + # yaml_props = { + # 'ip': '192.168.0.1', + # 'hostname': 'a.example.com', + # 'connect_to': 'a-private.example.com', + # 'public_ip': '192.168.0.1', + # 'public_hostname': 'a.example.com', + # 'new_host': True, + # 'roles': ['node'], + # 'other_variables': { + # 'zzz': 'last', + # 'foo': 'bar', + # 'aaa': 'first', + # }, + # } + + # new_node = Host(**yaml_props) + # inventory = cStringIO.StringIO() + + # # This is what the original 'write_host' function will + # # generate. write_host has no return value, it just writes + # # directly to the file 'inventory' which in this test-case is + # # a StringIO object + # ooinstall.openshift_ansible.write_host( + # new_node, + # 'node', + # inventory, + # schedulable=True) + # legacy_inventory_line = inventory.getvalue() + + # # This is what the new method in the Host class generates + # new_inventory_line = new_node.inventory_string('node', schedulable=True) + + # self.assertEqual( + # legacy_inventory_line, + # new_inventory_line) |