#!/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 Ossh(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()
self.aws = awsutil.AwsUtil()
if self.args.refresh_cache:
self.get_hosts(True)
else:
self.get_hosts()
# parse host and user
self.process_host()
if self.args.host == '' and not self.args.list:
self.parser.print_help()
return
if self.args.debug:
print self.args
# perform the SSH
if self.args.list:
self.list_hosts()
else:
self.ssh()
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="Which environment to search for the host ")
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('-c', '--command', action='store',
help='Command to run on remote host')
parser.add_argument('-l', '--login_name', action='store',
help='User in which to ssh as')
parser.add_argument('-o', '--ssh_opts', action='store',
help='options to pass to SSH.\n \
"-oForwardX11=yes,TCPKeepAlive=yes"')
parser.add_argument('host', nargs='?', default='')
self.args = parser.parse_args()
self.parser = parser
def process_host(self):
'''Determine host name and user name for SSH.
'''
self.env = None
self.user = None
re_env = re.compile("\.(" + "|".join(self.host_inventory.keys()) + ")")
search = re_env.search(self.args.host)
if self.args.env:
self.env = self.args.env
elif search:
# take the first?
self.env = search.groups()[0]
# remove env from hostname command line arg if found
if search:
self.args.host = re_env.split(self.args.host)[0]
# parse username if passed
if '@' in self.args.host:
self.user, self.host = self.args.host.split('@')
else:
self.host = self.args.host
if self.args.login_name:
self.user = self.args.login_name
def get_hosts(self, refresh_cache=False):
'''Query our host inventory and return a dict where the format
equals:
dict['servername'] = dns_name
'''
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]['ec2_tag_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]:
name = server_info['ec2_tag_Name']
ec2_id = server_info['ec2_id']
ip = server_info['ec2_ip_address']
print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address}'.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():
name = server_info['ec2_tag_Name']
ec2_id = server_info['ec2_id']
ip = server_info['ec2_ip_address']
print '{ec2_tag_Name:<35} {ec2_tag_environment:<5} {ec2_id:<15} {ec2_ip_address}'.format(**server_info)
def ssh(self):
'''SSH to a specified host
'''
try:
# shell args start with the program name in position 1
ssh_args = ['/usr/bin/ssh']
if self.user:
ssh_args.append('-l%s' % self.user)
if self.args.verbose:
ssh_args.append('-vvv')
if self.args.ssh_opts:
for arg in self.args.ssh_opts.split(","):
ssh_args.append("-o%s" % arg)
results = self.select_host()
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 "{ec2_tag_Name:<35} {ec2_tag_environment:<5} {ec2_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['ec2_public_dns_name']
ssh_args.append(dns)
#last argument
if self.args.command:
ssh_args.append("%s" % self.args.command)
print "Running: %s\n" % ' '.join(ssh_args)
os.execve('/usr/bin/ssh', ssh_args, os.environ)
except:
print traceback.print_exc()
print sys.exc_info()
if __name__ == '__main__':
ossh = Ossh()