diff options
| author | Wesley Hearn <wesley.s.hearn@gmail.com> | 2015-04-24 14:06:12 -0400 | 
|---|---|---|
| committer | Wesley Hearn <wesley.s.hearn@gmail.com> | 2015-04-24 14:06:12 -0400 | 
| commit | 519e097df31e2148ac520ab273d0bd2fb2f7bb43 (patch) | |
| tree | 4c5413c72a2dd2ec732730b6994a104cca6a9798 /bin/cluster | |
| parent | db9cf8ef4f030f30391e021f360fe0c3db1dce74 (diff) | |
| parent | 8ce5e1de898d2fd2c4aa4620f31b57b62ed0c5d6 (diff) | |
| download | openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.tar.gz openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.tar.bz2 openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.tar.xz openshift-519e097df31e2148ac520ab273d0bd2fb2f7bb43.zip  | |
Merge pull request #188 from openshift/master
Merge master into stage
Diffstat (limited to 'bin/cluster')
| -rwxr-xr-x | bin/cluster | 241 | 
1 files changed, 241 insertions, 0 deletions
diff --git a/bin/cluster b/bin/cluster new file mode 100755 index 000000000..79f1f988f --- /dev/null +++ b/bin/cluster @@ -0,0 +1,241 @@ +#!/usr/bin/env python2 +# vim: expandtab:tabstop=4:shiftwidth=4 + +import argparse +import ConfigParser +import sys +import os + + +class Cluster(object): +    """ +    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 ' +            ) + +    def get_deployment_type(self, args): +        """ +        Get the deployment_type based on the environment variables and the +        command line arguments +        :param args: command line arguments provided by the user +        :return: string representing the deployment type +        """ +        deployment_type = 'origin' +        if args.deployment_type: +            deployment_type = args.deployment_type +        elif 'OS_DEPLOYMENT_TYPE' in os.environ: +            deployment_type = os.environ['OS_DEPLOYMENT_TYPE'] +        return deployment_type + +    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, +               'deployment_type': self.get_deployment_type(args)} +        playbook = "playbooks/{}/openshift-cluster/launch.yml".format(args.provider) +        inventory = self.setup_provider(args.provider) + +        env['num_masters'] = args.masters +        env['num_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, +               'deployment_type': self.get_deployment_type(args)} +        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 +        """ +        env = {'cluster_id': args.cluster_id, +               'deployment_type': self.get_deployment_type(args)} +        playbook = "playbooks/{}/openshift-cluster/list.yml".format(args.provider) +        inventory = self.setup_provider(args.provider) + +        return self.action(args, inventory, env, playbook) + +    def config(self, args): +        """ +        Configure or reconfigure OpenShift across clustered VMs +        :param args: command line arguments provided by user +        :return: exit status from run command +        """ +        env = {'cluster_id': args.cluster_id, +               'deployment_type': self.get_deployment_type(args)} +        playbook = "playbooks/{}/openshift-cluster/config.yml".format(args.provider) +        inventory = self.setup_provider(args.provider) + +        return self.action(args, inventory, env, playbook) + +    def update(self, args): +        """ +        Update to latest OpenShift across clustered VMs +        :param args: command line arguments provided by user +        :return: exit status from run command +        """ +        env = {'cluster_id': args.cluster_id, +               'deployment_type': self.get_deployment_type(args)} +        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): +        """ +        Setup ansible playbook environment +        :param provider: command line arguments provided by user +        :return: path to inventory for given provider +        """ +        config = ConfigParser.ConfigParser() +        if 'gce' == provider: +            config.readfp(open('inventory/gce/hosts/gce.ini')) + +            for key in config.options('gce'): +                os.environ[key] = config.get('gce', key) + +            inventory = '-i inventory/gce/hosts' +        elif 'aws' == provider: +            config.readfp(open('inventory/aws/hosts/ec2.ini')) + +            for key in config.options('ec2'): +                os.environ[key] = config.get('ec2', key) + +            inventory = '-i inventory/aws/hosts' +        elif 'libvirt' == provider: +            inventory = '-i inventory/libvirt/hosts' +        else: +            # this code should never be reached +            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 args.verbose > 0: +            verbose = '-{}'.format('v' * 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 args.verbose > 1: +            command = 'time {}'.format(command) + +        if args.verbose > 0: +            sys.stderr.write('RUN [{}]\n'.format(command)) +            sys.stderr.flush() + +        return os.system(command) + + +if __name__ == '__main__': +    """ +    Implemented to support writing unit tests +    """ + +    cluster = Cluster() + +    providers = ['gce', 'aws', 'libvirt'] +    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.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') +    meta_parser.add_argument('-t', '--deployment-type', +                             choices=['origin', 'online', 'enterprise'], +                             help='Deployment type. (default: origin)') + +    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) + +    config_parser = action_parser.add_parser('config', +                                             help='Configure or reconfigure a cluster', +                                             parents=[meta_parser]) +    config_parser.set_defaults(func=cluster.config) + +    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 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']: +            sys.stderr.write('\nACTION [update] aborted by user!\n') +            exit(1) + +    status = args.func(args) +    if status != 0: +        sys.stderr.write("ACTION [{}] failed with exit status {}\n".format(args.action, status)) +    exit(status)  | 
