123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- #!/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)
|