diff options
Diffstat (limited to 'deployment/ocp-on-vmware.py')
-rwxr-xr-x | deployment/ocp-on-vmware.py | 463 |
1 files changed, 463 insertions, 0 deletions
diff --git a/deployment/ocp-on-vmware.py b/deployment/ocp-on-vmware.py new file mode 100755 index 00000000..3ba0a03a --- /dev/null +++ b/deployment/ocp-on-vmware.py @@ -0,0 +1,463 @@ +#!/usr/bin/env python +# set ts=4 sw=4 et +import argparse +import click +import fileinput +import json +import os +import random +import requests +import six +from six.moves import configparser +import sys +import yaml + + +class OCPOnVMWare(object): + + __name__ = 'OCPOnVMWare' + console_port=8443 + cluster_id=None + deployment_type=None + openshift_vers=None + vcenter_host=None + vcenter_username=None + vcenter_password=None + vcenter_template_name=None + vcenter_folder=None + vcenter_cluster=None + vcenter_datacenter=None + vcenter_datastore=None + vcenter_resource_pool=None + dns_zone=None + app_dns_prefix=None + vm_network=None + rhel_subscription_user=None + rhel_subscription_pass=None + rhel_subscription_server=None + rhel_subscription_pool=None + no_confirm=False + tag=None + verbose=0 + create_inventory=None + compute_nodes=None + ocp_hostname_prefix=None + create_ocp_vars=None + openshift_sdn=None + container_storage=None + openshift_disable_check=None + wildcard_zone=None + inventory_file='infrastructure.json' + vmware_ini_path=None + clean=None + cns_automation_config_file_path=None, + docker_registry_url=None + docker_additional_registries=None + docker_insecure_registries=None + docker_image_tag=None + ose_puddle_repo=None + gluster_puddle_repo=None + web_console_install=None + disable_yum_update_and_reboot=None + + def __init__(self): + self._parse_cli_args() + self._read_ini_settings() + self._create_inventory_file() + self._create_ocp_vars() + self._launch_refarch_env() + + def _parse_cli_args(self): + """Command line argument processing""" + tag_help = '''Skip to various parts of install valid tags include: + - setup create the vCenter folder and resource pool + - prod create and setup the OCP cluster + - ocp-install install OCP on the prod VMs + - ocp-config configure OCP on the prod VMs + - clean unsubscribe and remove all VMs''' + parser = argparse.ArgumentParser( + description='Deploy VMs to vSphere and install/configure OCP', + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument( + '--clean', action='store_true', + help='Delete all nodes and unregister from RHN') + parser.add_argument( + '--create_inventory', action='store_true', + help=('Deprecated and not used option. ' + 'Everything that is needed gets autocreated.')) + parser.add_argument( + '--create_ocp_vars', action='store_true', + help='Deprecated and not used option.') + parser.add_argument( + '--no_confirm', action='store_true', + help='Skip confirmation prompt') + parser.add_argument('--tag', default=None, help=tag_help) + parser.add_argument( + '--verbose', default=None, action='store_true', + help='Verbosely display commands') + self.args = parser.parse_args() + self.verbose = self.args.verbose + self.tag = self.args.tag + self.no_confirm = self.args.no_confirm + self.clean = self.args.clean + + def _is_rpm_and_image_tag_compatible(self): + if not (self.docker_image_tag and self.ose_puddle_repo): + return True + url = self.ose_puddle_repo + if url[-1] == '/': + url += 'Packages/' + else: + url += '/Packages/' + resp = requests.get(url) + if resp.ok: + v = self.docker_image_tag.split('v')[-1].strip() + return (('atomic-openshift-%s' % v) in resp.text) + raise Exception( + "Failed to pull list of packages from '%s' url." % url) + + def _read_ini_settings(self): + """Read ini file settings.""" + + scriptbasename = "ocp-on-vmware" + defaults = {'vmware': { + 'ini_path': os.path.join( + os.path.dirname(__file__), '%s.ini' % scriptbasename), + 'console_port': '8443', + 'container_storage': 'none', + 'deployment_type': 'openshift-enterprise', + 'openshift_vers': 'v3_11', + 'vcenter_username': 'administrator@vsphere.local', + 'vcenter_template_name': 'not-defined', + 'vcenter_folder': 'ocp', + 'vcenter_resource_pool': '/Resources/OCP3', + 'app_dns_prefix': 'apps', + 'vm_network':'VM Network', + 'cns_automation_config_file_path': '', + 'docker_registry_url': '', + 'docker_additional_registries': '', + 'docker_insecure_registries': '', + 'docker_image_tag': '', + 'web_console_install': '', + 'ose_puddle_repo': '', + 'gluster_puddle_repo': '', + 'rhel_subscription_pool': 'Employee SKU', + 'openshift_sdn': 'redhat/openshift-ovs-subnet', + 'compute_nodes': '2', + 'ocp_hostname_prefix': 'openshift-on-vmware', + 'tag': self.tag, + 'openshift_disable_check': ( + 'docker_storage,docker_image_availability,disk_availability'), + 'disable_yum_update_and_reboot': 'no', + }} + if six.PY3: + config = configparser.ConfigParser() + else: + config = configparser.SafeConfigParser() + + # where is the config? + self.vmware_ini_path = os.environ.get( + 'VMWARE_INI_PATH', defaults['vmware']['ini_path']) + self.vmware_ini_path = os.path.expanduser( + os.path.expandvars(self.vmware_ini_path)) + config.read(self.vmware_ini_path) + + # apply defaults + for k,v in defaults['vmware'].iteritems(): + if not config.has_option('vmware', k): + config.set('vmware', k, str(v)) + + self.console_port = config.get('vmware', 'console_port') + self.cluster_id = config.get('vmware', 'cluster_id') + self.container_storage = config.get('vmware', 'container_storage') + self.deployment_type = config.get('vmware','deployment_type') + if os.environ.get('VIRTUAL_ENV'): + self.openshift_vers = ( + 'v3_%s' % os.environ['VIRTUAL_ENV'].split('_')[-1].split( + '.')[-1]) + else: + self.openshift_vers = config.get('vmware','openshift_vers') + self.vcenter_host = config.get('vmware', 'vcenter_host') + self.vcenter_username = config.get('vmware', 'vcenter_username') + self.vcenter_password = config.get('vmware', 'vcenter_password') + self.vcenter_template_name = config.get( + 'vmware', 'vcenter_template_name') + self.vcenter_folder = config.get('vmware', 'vcenter_folder') + self.vcenter_datastore = config.get('vmware', 'vcenter_datastore') + self.vcenter_datacenter = config.get('vmware', 'vcenter_datacenter') + self.vcenter_cluster = config.get('vmware', 'vcenter_cluster') + self.vcenter_datacenter = config.get('vmware', 'vcenter_datacenter') + self.vcenter_resource_pool = config.get( + 'vmware', 'vcenter_resource_pool') + self.dns_zone= config.get('vmware', 'dns_zone') + self.app_dns_prefix = config.get('vmware', 'app_dns_prefix') + self.vm_network = config.get('vmware', 'vm_network') + self.ocp_hostname_prefix = config.get( + 'vmware', 'ocp_hostname_prefix') or 'ansible-on-vmware' + self.lb_host = '%s-master-0' % self.ocp_hostname_prefix + self.cns_automation_config_file_path = config.get( + 'vmware', 'cns_automation_config_file_path') + self.docker_registry_url = ( + config.get('vmware', 'docker_registry_url') or '').strip() + self.docker_additional_registries = config.get( + 'vmware', 'docker_additional_registries') + self.docker_insecure_registries = config.get( + 'vmware', 'docker_insecure_registries') + self.docker_image_tag = ( + config.get('vmware', 'docker_image_tag') or '').strip() + self.web_console_install = ( + config.get('vmware', 'web_console_install') or '').strip() + self.ose_puddle_repo = config.get('vmware', 'ose_puddle_repo') + self.gluster_puddle_repo = config.get('vmware', 'gluster_puddle_repo') + self.rhel_subscription_user = config.get( + 'vmware', 'rhel_subscription_user') + self.rhel_subscription_pass = config.get( + 'vmware', 'rhel_subscription_pass') + self.rhel_subscription_server = config.get( + 'vmware', 'rhel_subscription_server') + self.rhel_subscription_pool = config.get( + 'vmware', 'rhel_subscription_pool') + self.openshift_sdn = config.get('vmware', 'openshift_sdn') + self.compute_nodes = config.get('vmware', 'compute_nodes') + self.storage_nodes = config.get('vmware', 'storage_nodes') + self.openshift_disable_check = config.get( + 'vmware', 'openshift_disable_check').strip() or ( + 'docker_storage,docker_image_availability,disk_availability') + self.disable_yum_update_and_reboot = config.get( + 'vmware', 'disable_yum_update_and_reboot').strip() or 'no' + err_count=0 + + required_vars = { + 'vcenter_datacenter': self.vcenter_datacenter, + 'vcenter_host': self.vcenter_host, + 'vcenter_password': self.vcenter_password, + 'vcenter_template_name': self.vcenter_template_name, + 'dns_zone': self.dns_zone, + } + + for k, v in required_vars.items(): + if v == '': + err_count += 1 + print "Missing %s " % k + if (self.cns_automation_config_file_path and + not os.path.exists( + os.path.abspath(self.cns_automation_config_file_path))): + err_count += 1 + print ("Wrong value for 'cns_automation_config_file_path' " + "config option. It is expected to be either a relative " + "or an absolute file path.") + else: + self.cns_automation_config_file_path = os.path.abspath( + self.cns_automation_config_file_path) + if self.docker_image_tag and self.docker_registry_url: + vers_from_reg = self.docker_registry_url.split(':')[-1].strip() + if not vers_from_reg == self.docker_image_tag: + err_count += 1 + print ("If 'docker_image_tag' and 'docker_registry_url' are " + "specified, then their image tags should match. " + "docker_image_tag='%s', docker_registry_url='%s'" % ( + self.docker_image_tag, self.docker_registry_url)) + if not self._is_rpm_and_image_tag_compatible(): + err_count += 1 + print ("OCP RPM versions and docker image tag do not match. " + "Need either to change 'ose_puddle_repo' or " + "'docker_image_tag' config options.") + allowed_disable_checks = ( + 'disk_availability', + 'docker_image_availability', + 'docker_storage', + 'memory_availability', + 'package_availability', + 'package_version', + ) + self.openshift_disable_check_data = [ + el.strip() + for el in self.openshift_disable_check.strip().split(',') + if el.strip() + ] + if not all([(s in allowed_disable_checks) + for s in self.openshift_disable_check_data]): + err_count += 1 + print ("'openshift_disable_check' is allowed to have only " + "following values separated with comma: %s.\n " + "Got following value: %s" % (','.join( + allowed_disable_checks), self.openshift_disable_check)) + + if err_count > 0: + print "Please fill out the missing variables in %s " % ( + self.vmware_ini_path) + exit (1) + self.wildcard_zone="%s.%s" % (self.app_dns_prefix, self.dns_zone) + + if not self.cluster_id: + # Create a unique cluster_id first + self.cluster_id = ''.join( + random.choice('0123456789abcdefghijklmnopqrstuvwxyz') + for i in range(7)) + config.set('vmware', 'cluster_id', self.cluster_id) + for line in fileinput.input(self.vmware_ini_path, inplace=True): + if line.startswith('cluster_id'): + print "cluster_id=" + str(self.cluster_id) + else: + print line, + + print 'Configured inventory values:' + for each_section in config.sections(): + for (key, val) in config.items(each_section): + if 'pass' in key: + print '\t %s: ******' % ( key ) + else: + print '\t %s: %s' % ( key, val ) + print '\n' + + def _create_inventory_file(self): + click.echo('Configured inventory values:') + click.echo('\tcompute_nodes: %s' % self.compute_nodes) + click.echo('\tdns_zone: %s' % self.dns_zone) + click.echo('\tapp_dns_prefix: %s' % self.app_dns_prefix) + click.echo('\tocp_hostname_prefix: %s' % self.ocp_hostname_prefix) + click.echo('\tUsing values from: %s' % self.vmware_ini_path) + click.echo("") + if not self.no_confirm: + click.confirm('Continue using these values?', abort=True) + + master_name = "%s-master-0" % self.ocp_hostname_prefix + d = {'host_inventory': {master_name: { + 'guestname': master_name, + 'guesttype': 'master', + 'tag': str(self.cluster_id) + '-master', + }}} + for i in range(0, int(self.compute_nodes)): + compute_name = "%s-compute-%d" % (self.ocp_hostname_prefix, i) + d['host_inventory'][compute_name] = { + 'guestname': compute_name, + 'guesttype': 'compute', + 'tag': '%s-compute' % self.cluster_id, + } + + with open(self.inventory_file, 'w') as outfile: + json.dump(d, outfile, indent=4, sort_keys=True) + + if self.args.create_inventory: + exit(0) + + def _create_ocp_vars(self): + if self.args.create_ocp_vars: + click.echo( + "No-op run. '--create_ocp_vars' option is not used anymore. " + "Ending execution.") + exit(0) + + def _launch_refarch_env(self): + with open(self.inventory_file, 'r') as f: + print yaml.safe_dump(json.load(f), default_flow_style=False) + + if not self.args.no_confirm: + if not click.confirm('Continue adding nodes with these values?'): + sys.exit(0) + + # Add section here to modify inventory file based on input + # from user check your vmmark scripts for parsing the file and + # adding the values. + for line in fileinput.input( + "inventory/vsphere/vms/vmware_inventory.ini", inplace=True): + if line.startswith("server="): + print "server=" + self.vcenter_host + elif line.startswith("password="): + print "password=" + self.vcenter_password + elif line.startswith("username="): + print "username=" + self.vcenter_username + else: + print line, + + if self.clean is True: + tags = 'clean' + elif self.tag: + tags = self.tag + else: + tags = [ + 'setup', + 'prod', + 'ocp-install', + 'ocp-configure', + ] + tags = ",".join(tags) + + # remove any cached facts to prevent stale data during a re-run + command='rm -rf .ansible/cached_facts' + os.system(command) + + playbook_vars_dict = { + 'vcenter_host': self.vcenter_host, + 'vcenter_username': self.vcenter_username, + 'vcenter_password': self.vcenter_password, + 'vcenter_template_name': self.vcenter_template_name, + 'vcenter_folder': self.vcenter_folder, + 'vcenter_cluster': self.vcenter_cluster, + 'vcenter_datacenter': self.vcenter_datacenter, + 'vcenter_datastore': self.vcenter_datastore, + 'vcenter_resource_pool': self.vcenter_resource_pool, + 'dns_zone': self.dns_zone, + 'app_dns_prefix': self.app_dns_prefix, + 'vm_network': self.vm_network, + 'lb_host': self.lb_host, + 'cns_automation_config_file_path': ( + self.cns_automation_config_file_path), + 'ose_puddle_repo': self.ose_puddle_repo, + 'gluster_puddle_repo': self.gluster_puddle_repo, + 'wildcard_zone': self.wildcard_zone, + 'console_port': self.console_port, + 'cluster_id': self.cluster_id, + 'deployment_type': self.deployment_type, + 'openshift_vers': self.openshift_vers, + 'rhsm_user': self.rhel_subscription_user, + 'rhsm_password': self.rhel_subscription_pass, + 'rhsm_satellite': self.rhel_subscription_server, + 'rhsm_pool': self.rhel_subscription_pool, + 'openshift_sdn': self.openshift_sdn, + 'openshift_use_openshift_sdn': True, + 'container_storage': self.container_storage, + 'ocp_hostname_prefix': self.ocp_hostname_prefix, + 'disable_yum_update_and_reboot': self.disable_yum_update_and_reboot + } + if self.openshift_disable_check_data: + playbook_vars_dict["openshift_disable_check"] = ( + ','.join(self.openshift_disable_check_data)) + if self.docker_registry_url: + playbook_vars_dict['oreg_url'] = self.docker_registry_url + if self.docker_additional_registries: + playbook_vars_dict['openshift_docker_additional_registries'] = ( + self.docker_additional_registries) + playbook_vars_dict['openshift_docker_ent_reg'] = '' + if self.docker_insecure_registries: + playbook_vars_dict['openshift_docker_insecure_registries'] = ( + self.docker_insecure_registries) + if self.docker_image_tag: + playbook_vars_dict['openshift_image_tag'] = self.docker_image_tag + if self.web_console_install: + playbook_vars_dict['openshift_web_console_install'] = ( + self.web_console_install) + if self.openshift_vers in ('v3_6', 'v3_7'): + playbook_vars_dict['docker_version'] = '1.12.6' + + playbook_vars_str = ' '.join('%s=%s' % (k, v) + for (k, v) in playbook_vars_dict.items()) + + command = ( + "ansible-playbook" + " --extra-vars '@./infrastructure.json'" + " --tags %s" + " -e '%s' playbooks/ocp-end-to-end.yaml" + ) % (tags, playbook_vars_str) + + if self.verbose > 0: + command += " -vvvvvv" + + click.echo('We are running: %s' % command) + status = os.system(command) + if os.WIFEXITED(status) and os.WEXITSTATUS(status) != 0: + sys.exit(os.WEXITSTATUS(status)) + + +if __name__ == '__main__': + OCPOnVMWare() |