#!/usr/bin/env python2 # vim: expandtab:tabstop=4:shiftwidth=4 import argparse import traceback import sys import os import re import ConfigParser from openshift_ansible import awsutil CONFIG_MAIN_SECTION = 'main' class Oscp(object): def __init__(self): self.file_path = os.path.join(os.path.dirname(os.path.realpath(__file__))) # Default the config path to /etc self.config_path = os.path.join(os.path.sep, 'etc', \ 'openshift_ansible', \ 'openshift_ansible.conf') self.parse_cli_args() self.parse_config_file() # parse host and user self.process_host() self.aws = awsutil.AwsUtil() # get a dict of host inventory if self.args.refresh_cache: self.get_hosts(True) else: self.get_hosts() if (self.args.src == '' or self.args.dest == '') and not self.args.list: self.parser.print_help() return if self.args.debug: print self.host print self.args # perform the scp if self.args.list: self.list_hosts() else: self.scp() def parse_config_file(self): if os.path.isfile(self.config_path): config = ConfigParser.ConfigParser() config.read(self.config_path) def parse_cli_args(self): parser = argparse.ArgumentParser(description='OpenShift Online SSH Tool.') parser.add_argument('-e', '--env', action="store", help="Environment where this server exists.") parser.add_argument('-d', '--debug', default=False, action="store_true", help="debug mode") parser.add_argument('-v', '--verbose', default=False, action="store_true", help="Verbose?") parser.add_argument('--refresh-cache', default=False, action="store_true", help="Force a refresh on the host cache.") parser.add_argument('--list', default=False, action="store_true", help="list out hosts") parser.add_argument('-r', '--recurse', action='store_true', default=False, help='Recursively copy files to or from destination.') parser.add_argument('-o', '--ssh_opts', action='store', help='options to pass to SSH.\n \ "-oPort=22,TCPKeepAlive=yes"') parser.add_argument('src', nargs='?', default='') parser.add_argument('dest',nargs='?', default='') self.args = parser.parse_args() self.parser = parser def process_host(self): '''Determine host name and user name for SSH. ''' self.user = '' # is the first param passed a valid file? if os.path.isfile(self.args.src) or os.path.isdir(self.args.src): self.local_src = True self.host = self.args.dest else: self.local_src = False self.host = self.args.src if '@' in self.host: re_host = re.compile("(.*@)(.*)(:.*$)") else: re_host = re.compile("(.*)(:.*$)") search = re_host.search(self.host) if search: if len(search.groups()) > 2: self.user = search.groups()[0] self.host = search.groups()[1] self.path = search.groups()[2] else: self.host = search.groups()[0] self.path = search.groups()[1] if self.args.env: self.env = self.args.env elif "." in self.host: self.host, self.env = self.host.split(".") else: self.env = None def get_hosts(self, refresh_cache=False): '''Query our host inventory and return a dict where the format equals: dict['environment'] = [{'servername' : {}}, ] ''' if refresh_cache: self.host_inventory = self.aws.build_host_dict_by_env(['--refresh-cache']) else: self.host_inventory = self.aws.build_host_dict_by_env() def select_host(self): '''select host attempts to match the host specified on the command line with a list of hosts. ''' results = [] for env in self.host_inventory.keys(): for hostname, server_info in self.host_inventory[env].items(): if hostname.split(':')[0] == self.host: results.append((hostname, server_info)) # attempt to select the correct environment if specified if self.env: results = filter(lambda result: result[1]['oo_environment'] == self.env, results) if results: return results else: print "Could not find specified host: %s." % self.host # default - no results found. return None def list_hosts(self, limit=None): '''Function to print out the host inventory. Takes a single parameter to limit the number of hosts printed. ''' if self.env: results = self.select_host() if len(results) == 1: hostname, server_info = results[0] sorted_keys = server_info.keys() sorted_keys.sort() for key in sorted_keys: print '{0:<35} {1}'.format(key, server_info[key]) else: for host_id, server_info in results[:limit]: print '{oo_name:<35} {oo_clusterid:<10} {oo_environment:<8} ' \ '{oo_id:<15} {oo_public_ip:<18} {oo_private_ip:<18}'.format(**server_info) if limit: print print 'Showing only the first %d results...' % limit print else: for env, host_ids in self.host_inventory.items(): for host_id, server_info in host_ids.items(): print '{oo_name:<35} {oo_clusterid:<10} {oo_environment:<8} ' \ '{oo_id:<15} {oo_public_ip:<18} {oo_private_ip:<18}'.format(**server_info) def scp(self): '''scp files to or from a specified host ''' try: # shell args start with the program name in position 1 scp_args = ['/usr/bin/scp'] if self.args.verbose: scp_args.append('-v') if self.args.recurse: scp_args.append('-r') if self.args.ssh_opts: for arg in self.args.ssh_opts.split(","): scp_args.append("-o%s" % arg) results = self.select_host() if self.args.debug: print results if not results: return # early exit, no results if len(results) > 1: print "Multiple results found for %s." % self.host for result in results: print "{oo_name:<35} {oo_clusterid:<5} {oo_environment:<5} {oo_id:<10}".format(**result[1]) return # early exit, too many results # Assume we have one and only one. hostname, server_info = results[0] dns = server_info['oo_public_ip'] host_str = "%s%s%s" % (self.user, dns, self.path) if self.local_src: scp_args.append(self.args.src) scp_args.append(host_str) else: scp_args.append(host_str) scp_args.append(self.args.dest) print "Running: %s\n" % ' '.join(scp_args) os.execve('/usr/bin/scp', scp_args, os.environ) except: print traceback.print_exc() print sys.exc_info() if __name__ == '__main__': oscp = Oscp()