From 7c7cb82fdd5583784fd5832b92886abf86934325 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Fri, 6 Mar 2015 13:52:20 -0700 Subject: Use ansible playbook to initialize openshift cluster * Added playbooks/gce/openshift-cluster * Added bin/cluster (will replace cluster.sh) --- bin/cluster | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100755 bin/cluster (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster new file mode 100755 index 000000000..7afdce0e5 --- /dev/null +++ b/bin/cluster @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# vim: expandtab:tabstop=4:shiftwidth=4 + +import argparse +import ConfigParser +import sys +import os + + +class Cluster(object): + """Python wrapper to ensure environment is correct for running ansible playbooks + """ + + def __init__(self, args): + self.args = args + + # setup ansible ssh environment + if 'ANSIBLE_SSH_ARGS' not in os.environ: + os.environ['ANSIBLE_SSH_ARGS'] = ( + '-o ForwardAgent=yes' + '-o StrictHostKeyChecking=no' + '-o UserKnownHostsFile=/dev/null' + '-o ControlMaster=auto' + '-o ControlPersist=600s' + ) + + def apply(self): + # setup ansible playbook environment + config = ConfigParser.ConfigParser() + if 'gce' == self.args.provider: + config.readfp(open('inventory/gce/gce.ini')) + + for key in config.options('gce'): + os.environ[key] = config.get('gce', key) + + inventory = '-i inventory/gce/gce.py' + elif 'aws' == self.args.provider: + config.readfp(open('inventory/aws/ec2.ini')) + + for key in config.options('ec2'): + os.environ[key] = config.get('ec2', key) + + inventory = '-i inventory/aws/ec2.py' + else: + assert False, "invalid PROVIDER {}".format(self.args.provider) + + env = {'cluster_id': self.args.cluster_id} + + if 'create' == self.args.action: + playbook = "playbooks/{}/openshift-cluster/launch.yml".format(self.args.provider) + env['masters'] = self.args.masters + env['nodes'] = self.args.nodes + + elif 'terminate' == self.args.action: + playbook = "playbooks/{}/openshift-cluster/terminate.yml".format(self.args.provider) + elif 'list' == self.args.action: + # todo: implement cluster list + argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) + elif 'update' == self.args.action: + # todo: implement cluster update + argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) + else: + assert False, "invalid ACTION {}".format(self.args.action) + + verbose = '' + if self.args.verbose > 0: + verbose = '-{}'.format('v' * self.args.verbose) + + ansible_env = '-e \'{}\''.format( + ' '.join(['%s=%s' % (key, value) for (key, value) in env.items()]) + ) + + command = 'ansible-playbook {} {} {} {}'.format( + verbose, inventory, ansible_env, playbook + ) + + if self.args.verbose > 1: + command = 'time {}'.format(command) + + if self.args.verbose > 0: + sys.stderr.write('RUN [{}]\n'.format(command)) + sys.stderr.flush() + + os.system(command) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Manage OpenShift Cluster') + parser.add_argument('-p', '--provider', default='gce', choices=['gce', 'aws'], + help='One of the supported cloud providers') + parser.add_argument('-m', '--masters', default=1, type=int, help='number of masters to create in cluster') + parser.add_argument('-n', '--nodes', default=2, type=int, help='number of nodes to create in cluster') + parser.add_argument('-v', '--verbose', action='count', help='Multiple -v options increase the verbosity') + parser.add_argument('--version', action='version', version='%(prog)s 0.1') + parser.add_argument('action', choices=['create', 'terminate', 'update', 'list']) + parser.add_argument('provider', choices=['gce', 'aws']) + parser.add_argument('cluster_id', help='prefix for cluster VM names') + args = parser.parse_args() + + Cluster(args).apply() -- cgit v1.2.3 From f6b2eaf7d12ff1f74551662cea46a8bad6beac33 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Fri, 13 Mar 2015 03:02:29 -0400 Subject: Add spacing to implicit string concatenation for python backwards compatibility --- bin/cluster | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster index 7afdce0e5..ad6e74577 100755 --- a/bin/cluster +++ b/bin/cluster @@ -18,10 +18,10 @@ class Cluster(object): if 'ANSIBLE_SSH_ARGS' not in os.environ: os.environ['ANSIBLE_SSH_ARGS'] = ( '-o ForwardAgent=yes' - '-o StrictHostKeyChecking=no' - '-o UserKnownHostsFile=/dev/null' - '-o ControlMaster=auto' - '-o ControlPersist=600s' + ' -o StrictHostKeyChecking=no' + ' -o UserKnownHostsFile=/dev/null' + ' -o ControlMaster=auto' + ' -o ControlPersist=600s' ) def apply(self): -- cgit v1.2.3 From 2147b1608140f2688ac9781b394824c04e55d07e Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Fri, 20 Mar 2015 09:31:05 -0700 Subject: * Updates from code reviews --- bin/cluster | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster index ad6e74577..ce17ee6d7 100755 --- a/bin/cluster +++ b/bin/cluster @@ -42,6 +42,7 @@ class Cluster(object): inventory = '-i inventory/aws/ec2.py' else: + # this code should never be reached assert False, "invalid PROVIDER {}".format(self.args.provider) env = {'cluster_id': self.args.cluster_id} @@ -55,11 +56,12 @@ class Cluster(object): playbook = "playbooks/{}/openshift-cluster/terminate.yml".format(self.args.provider) elif 'list' == self.args.action: # todo: implement cluster list - argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) + raise argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) elif 'update' == self.args.action: # todo: implement cluster update - argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) + raise argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) else: + # this code should never be reached assert False, "invalid ACTION {}".format(self.args.action) verbose = '' @@ -81,13 +83,14 @@ class Cluster(object): sys.stderr.write('RUN [{}]\n'.format(command)) sys.stderr.flush() - os.system(command) + error = os.system(command) + if error != 0: + raise Exception("Ansible run failed with exit code %d".format(error)) + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Manage OpenShift Cluster') - parser.add_argument('-p', '--provider', default='gce', choices=['gce', 'aws'], - help='One of the supported cloud providers') parser.add_argument('-m', '--masters', default=1, type=int, help='number of masters to create in cluster') parser.add_argument('-n', '--nodes', default=2, type=int, help='number of nodes to create in cluster') parser.add_argument('-v', '--verbose', action='count', help='Multiple -v options increase the verbosity') -- cgit v1.2.3 From 14b19e665b118349327a5c8c219cc49c96ae1d52 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Fri, 20 Mar 2015 09:36:34 -0700 Subject: * Replace asserts with raises --- bin/cluster | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster index ce17ee6d7..af908155c 100755 --- a/bin/cluster +++ b/bin/cluster @@ -43,7 +43,7 @@ class Cluster(object): inventory = '-i inventory/aws/ec2.py' else: # this code should never be reached - assert False, "invalid PROVIDER {}".format(self.args.provider) + raise argparse.ArgumentError("invalid PROVIDER {}".format(self.args.provider)) env = {'cluster_id': self.args.cluster_id} @@ -62,7 +62,7 @@ class Cluster(object): raise argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) else: # this code should never be reached - assert False, "invalid ACTION {}".format(self.args.action) + raise argparse.ArgumentError("invalid ACTION {}".format(self.args.action)) verbose = '' if self.args.verbose > 0: -- cgit v1.2.3 From 557cc0ca9ecc22a9d90f9cf9ce549186fe286492 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Mon, 23 Mar 2015 09:15:08 -0700 Subject: * Updates from code reviews --- bin/cluster | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster index af908155c..823f50671 100755 --- a/bin/cluster +++ b/bin/cluster @@ -83,9 +83,10 @@ class Cluster(object): sys.stderr.write('RUN [{}]\n'.format(command)) sys.stderr.flush() - error = os.system(command) - if error != 0: - raise Exception("Ansible run failed with exit code %d".format(error)) + status = os.system(command) + if status != 0: + sys.stderr.write("RUN [{}] failed with exit status %d".format(command, status)) + exit(status) @@ -100,4 +101,11 @@ if __name__ == '__main__': parser.add_argument('cluster_id', help='prefix for cluster VM names') args = parser.parse_args() + if 'terminate' == args.action: + sys.stderr.write("This will terminate the ENTIRE {} environment. Are you sure? [y/N] ".format(args.cluster_id)) + sys.stderr.flush() + answer = sys.stdin.read(1) + if answer not in ['y', 'Y']: + exit(0) + Cluster(args).apply() -- cgit v1.2.3 From 16cac480197bfe1738b785aed55204b53d06ad57 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Tue, 24 Mar 2015 17:05:13 -0700 Subject: * Refactor bin/cluster to use argparse.subparsers --- bin/cluster | 182 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 126 insertions(+), 56 deletions(-) (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster index 823f50671..b99286b46 100755 --- a/bin/cluster +++ b/bin/cluster @@ -8,33 +8,79 @@ import os class Cluster(object): - """Python wrapper to ensure environment is correct for running ansible playbooks """ - - def __init__(self, args): - self.args = args - + Control and Configuration Interface for OpenShift Clusters + """ + def __init__(self): # setup ansible ssh environment if 'ANSIBLE_SSH_ARGS' not in os.environ: os.environ['ANSIBLE_SSH_ARGS'] = ( - '-o ForwardAgent=yes' - ' -o StrictHostKeyChecking=no' - ' -o UserKnownHostsFile=/dev/null' - ' -o ControlMaster=auto' - ' -o ControlPersist=600s' + '-o ForwardAgent=yes ' + '-o StrictHostKeyChecking=no ' + '-o UserKnownHostsFile=/dev/null ' + '-o ControlMaster=auto ' + '-o ControlPersist=600s ' ) - def apply(self): - # setup ansible playbook environment + def create(self, args): + """ + Create an OpenShift cluster for given provider + :param args: command line arguments provided by user + :return: exit status from run command + """ + env = {'cluster_id': args.cluster_id} + playbook = "playbooks/{}/openshift-cluster/launch.yml".format(args.provider) + inventory = self.setup_provider(args.provider) + + env['masters'] = args.masters + env['nodes'] = args.nodes + + return self.action(args, inventory, env, playbook) + + def terminate(self, args): + """ + Destroy OpenShift cluster + :param args: command line arguments provided by user + :return: exit status from run command + """ + env = {'cluster_id': args.cluster_id} + playbook = "playbooks/{}/openshift-cluster/terminate.yml".format(args.provider) + inventory = self.setup_provider(args.provider) + + return self.action(args, inventory, env, playbook) + + def list(self, args): + """ + List VMs in cluster + :param args: command line arguments provided by user + :return: exit status from run command + """ + raise NotImplementedError("ACTION [{}] not implemented".format(sys._getframe().f_code.co_name)) + + def update(self, args): + """ + Update OpenShift across clustered VMs + :param args: command line arguments provided by user + :return: exit status from run command + """ + raise NotImplementedError("ACTION [{}] not implemented".format(sys._getframe().f_code.co_name)) + + + def setup_provider(self, provider): + """ + Setup ansible playbook environment + :param provider: command line arguments provided by user + :return: path to inventory for given provider + """ config = ConfigParser.ConfigParser() - if 'gce' == self.args.provider: + if 'gce' == provider: config.readfp(open('inventory/gce/gce.ini')) for key in config.options('gce'): os.environ[key] = config.get('gce', key) inventory = '-i inventory/gce/gce.py' - elif 'aws' == self.args.provider: + elif 'aws' == provider: config.readfp(open('inventory/aws/ec2.ini')) for key in config.options('ec2'): @@ -43,30 +89,23 @@ class Cluster(object): inventory = '-i inventory/aws/ec2.py' else: # this code should never be reached - raise argparse.ArgumentError("invalid PROVIDER {}".format(self.args.provider)) - - env = {'cluster_id': self.args.cluster_id} - - if 'create' == self.args.action: - playbook = "playbooks/{}/openshift-cluster/launch.yml".format(self.args.provider) - env['masters'] = self.args.masters - env['nodes'] = self.args.nodes - - elif 'terminate' == self.args.action: - playbook = "playbooks/{}/openshift-cluster/terminate.yml".format(self.args.provider) - elif 'list' == self.args.action: - # todo: implement cluster list - raise argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) - elif 'update' == self.args.action: - # todo: implement cluster update - raise argparse.ArgumentError("ACTION {} not implemented".format(self.args.action)) - else: - # this code should never be reached - raise argparse.ArgumentError("invalid ACTION {}".format(self.args.action)) + raise ValueError("invalid PROVIDER {}".format(provider)) + + return inventory + + def action(self, args, inventory, env, playbook): + """ + Build ansible-playbook command line and execute + :param args: command line arguments provided by user + :param inventory: derived provider library + :param env: environment variables for kubernetes + :param playbook: ansible playbook to execute + :return: exit status from ansible-playbook command + """ verbose = '' - if self.args.verbose > 0: - verbose = '-{}'.format('v' * self.args.verbose) + if args.verbose > 0: + verbose = '-{}'.format('v' * args.verbose) ansible_env = '-e \'{}\''.format( ' '.join(['%s=%s' % (key, value) for (key, value) in env.items()]) @@ -76,36 +115,67 @@ class Cluster(object): verbose, inventory, ansible_env, playbook ) - if self.args.verbose > 1: + if args.verbose > 1: command = 'time {}'.format(command) - if self.args.verbose > 0: + if args.verbose > 0: sys.stderr.write('RUN [{}]\n'.format(command)) sys.stderr.flush() - status = os.system(command) - if status != 0: - sys.stderr.write("RUN [{}] failed with exit status %d".format(command, status)) - exit(status) - + return os.system(command) if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Manage OpenShift Cluster') - parser.add_argument('-m', '--masters', default=1, type=int, help='number of masters to create in cluster') - parser.add_argument('-n', '--nodes', default=2, type=int, help='number of nodes to create in cluster') + """ + Implemented to support writing unit tests + """ + + cluster = Cluster() + + providers = ['gce', 'aws'] + parser = argparse.ArgumentParser( + description='Python wrapper to ensure proper environment for OpenShift ansible playbooks', + ) parser.add_argument('-v', '--verbose', action='count', help='Multiple -v options increase the verbosity') - parser.add_argument('--version', action='version', version='%(prog)s 0.1') - parser.add_argument('action', choices=['create', 'terminate', 'update', 'list']) - parser.add_argument('provider', choices=['gce', 'aws']) - parser.add_argument('cluster_id', help='prefix for cluster VM names') + parser.add_argument('--version', action='version', version='%(prog)s 0.2') + + meta_parser = argparse.ArgumentParser(add_help=False) + meta_parser.add_argument('provider', choices=providers, help='provider') + meta_parser.add_argument('cluster_id', help='prefix for cluster VM names') + + action_parser = parser.add_subparsers(dest='action', title='actions', description='Choose from valid actions') + + create_parser = action_parser.add_parser('create', help='Create a cluster', parents=[meta_parser]) + create_parser.add_argument('-m', '--masters', default=1, type=int, help='number of masters to create in cluster') + create_parser.add_argument('-n', '--nodes', default=2, type=int, help='number of nodes to create in cluster') + create_parser.set_defaults(func=cluster.create) + + terminate_parser = action_parser.add_parser('terminate', help='Destroy a cluster', parents=[meta_parser]) + terminate_parser.add_argument('-f', '--force', action='store_true', help='Destroy cluster without confirmation') + terminate_parser.set_defaults(func=cluster.terminate) + + update_parser = action_parser.add_parser('update', help='Update OpenShift across cluster', parents=[meta_parser]) + update_parser.add_argument('-f', '--force', action='store_true', help='Update cluster without confirmation') + update_parser.set_defaults(func=cluster.update) + + list_parser = action_parser.add_parser('list', help='List VMs in cluster', parents=[meta_parser]) + list_parser.set_defaults(func=cluster.list) + args = parser.parse_args() - if 'terminate' == args.action: - sys.stderr.write("This will terminate the ENTIRE {} environment. Are you sure? [y/N] ".format(args.cluster_id)) - sys.stderr.flush() - answer = sys.stdin.read(1) + if 'terminate' == args.action and not args.force: + answer = raw_input("This will destroy the ENTIRE {} environment. Are you sure? [y/N] ".format(args.cluster_id)) + if answer not in ['y', 'Y']: + sys.stderr.write('\nACTION [terminate] aborted by user!\n') + exit(1) + + if 'update' == args.action and not args.force: + answer = raw_input("This is destructive and could corrupt {} environment. Continue? [y/N] ".format(args.cluster_id)) if answer not in ['y', 'Y']: - exit(0) + sys.stderr.write('\nACTION [update] aborted by user!\n') + exit(1) - Cluster(args).apply() + status = args.func(args) + if status != 0: + sys.stderr.write("ACTION [{}] failed with exit status {}\n".format(args.action, status)) + exit(status) -- cgit v1.2.3 From 4712e72c912a1102bff0508c98bd97da3f33ae95 Mon Sep 17 00:00:00 2001 From: Jason DeTiberus Date: Mon, 23 Mar 2015 23:53:17 -0400 Subject: openshift_facts role/module refactor default settings - Add openshift_facts role and module - Created new role openshift_facts that contains an openshift_facts module - Refactor openshift_* roles to use openshift_facts instead of relying on defaults - Refactor playbooks to use openshift_facts - Cleanup inventory group_vars - Update defaults - update openshift_master role firewall defaults - remove etcd peer port, since we will not be supporting clustered embedded etcd - remove 8444 since console now runs on the api port by default - add 8444 and 7001 to disabled services to ensure removal if updating - Add new role os_env_extras_node that is a subset of the docker role - previously, we were starting/enabling docker which was causing issues with some installations - Does not install or start docker, since the openshift-node role will handle that for us - Only adds root to the dockerroot group - Update playbooks to use ops_env_extras_node role instead of docker role - os_firewall bug fixes - ignore ip6tables for now, since we are not configuring any ipv6 rules - if installing package do a daemon-reload before starting/enabling service - Add aws support to bin/cluster - Add list action to bin/cluster - Add update action to bin/cluster - cleanup some stray debug statements - some variable renaming for clarity --- bin/cluster | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster index b99286b46..36ab1da1b 100755 --- a/bin/cluster +++ b/bin/cluster @@ -32,8 +32,8 @@ class Cluster(object): playbook = "playbooks/{}/openshift-cluster/launch.yml".format(args.provider) inventory = self.setup_provider(args.provider) - env['masters'] = args.masters - env['nodes'] = args.nodes + env['num_masters'] = args.masters + env['num_nodes'] = args.nodes return self.action(args, inventory, env, playbook) @@ -55,16 +55,23 @@ class Cluster(object): :param args: command line arguments provided by user :return: exit status from run command """ - raise NotImplementedError("ACTION [{}] not implemented".format(sys._getframe().f_code.co_name)) + env = {'cluster_id': args.cluster_id} + playbook = "playbooks/{}/openshift-cluster/list.yml".format(args.provider) + inventory = self.setup_provider(args.provider) + + return self.action(args, inventory, env, playbook) def update(self, args): """ - Update OpenShift across clustered VMs + Update to latest OpenShift across clustered VMs :param args: command line arguments provided by user :return: exit status from run command """ - raise NotImplementedError("ACTION [{}] not implemented".format(sys._getframe().f_code.co_name)) + env = {'cluster_id': args.cluster_id} + playbook = "playbooks/{}/openshift-cluster/update.yml".format(args.provider) + inventory = self.setup_provider(args.provider) + return self.action(args, inventory, env, playbook) def setup_provider(self, provider): """ -- cgit v1.2.3 From 9fbec064d28a72963b1566258b4bcabcd63b2c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9na=C3=AFc=20Huard?= Date: Wed, 8 Apr 2015 16:33:55 +0200 Subject: Add libvirt as a provider --- bin/cluster | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'bin/cluster') diff --git a/bin/cluster b/bin/cluster index 36ab1da1b..ca227721e 100755 --- a/bin/cluster +++ b/bin/cluster @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # vim: expandtab:tabstop=4:shiftwidth=4 import argparse @@ -94,6 +94,8 @@ class Cluster(object): os.environ[key] = config.get('ec2', key) inventory = '-i inventory/aws/ec2.py' + elif 'libvirt' == provider: + inventory = '-i inventory/libvirt/hosts' else: # this code should never be reached raise ValueError("invalid PROVIDER {}".format(provider)) @@ -139,7 +141,7 @@ if __name__ == '__main__': cluster = Cluster() - providers = ['gce', 'aws'] + providers = ['gce', 'aws', 'libvirt'] parser = argparse.ArgumentParser( description='Python wrapper to ensure proper environment for OpenShift ansible playbooks', ) -- cgit v1.2.3