ossh 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #!/usr/bin/env python2
  2. # vim: expandtab:tabstop=4:shiftwidth=4
  3. import argparse
  4. import traceback
  5. import sys
  6. import os
  7. import re
  8. import ConfigParser
  9. from openshift_ansible import awsutil
  10. CONFIG_MAIN_SECTION = 'main'
  11. CONFIG_INVENTORY_OPTION = 'inventory'
  12. class Ossh(object):
  13. def __init__(self):
  14. self.inventory = None
  15. self.file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)))
  16. # Default the config path to /etc
  17. self.config_path = os.path.join(os.path.sep, 'etc', \
  18. 'openshift_ansible', \
  19. 'openshift_ansible.conf')
  20. self.parse_cli_args()
  21. self.parse_config_file()
  22. self.aws = awsutil.AwsUtil(self.inventory)
  23. if self.args.refresh_cache:
  24. self.get_hosts(True)
  25. else:
  26. self.get_hosts()
  27. # parse host and user
  28. self.process_host()
  29. if self.args.host == '' and not self.args.list:
  30. self.parser.print_help()
  31. return
  32. if self.args.debug:
  33. print self.args
  34. # perform the SSH
  35. if self.args.list:
  36. self.list_hosts()
  37. else:
  38. self.ssh()
  39. def parse_config_file(self):
  40. if os.path.isfile(self.config_path):
  41. config = ConfigParser.ConfigParser()
  42. config.read(self.config_path)
  43. if config.has_section(CONFIG_MAIN_SECTION) and \
  44. config.has_option(CONFIG_MAIN_SECTION, CONFIG_INVENTORY_OPTION):
  45. self.inventory = config.get(CONFIG_MAIN_SECTION, CONFIG_INVENTORY_OPTION)
  46. def parse_cli_args(self):
  47. parser = argparse.ArgumentParser(description='Openshift Online SSH Tool.')
  48. parser.add_argument('-e', '--env', action="store",
  49. help="Which environment to search for the host ")
  50. parser.add_argument('-d', '--debug', default=False,
  51. action="store_true", help="debug mode")
  52. parser.add_argument('-v', '--verbose', default=False,
  53. action="store_true", help="Verbose?")
  54. parser.add_argument('--refresh-cache', default=False,
  55. action="store_true", help="Force a refresh on the host cache.")
  56. parser.add_argument('--list', default=False,
  57. action="store_true", help="list out hosts")
  58. parser.add_argument('-c', '--command', action='store',
  59. help='Command to run on remote host')
  60. parser.add_argument('-l', '--login_name', action='store',
  61. help='User in which to ssh as')
  62. parser.add_argument('-o', '--ssh_opts', action='store',
  63. help='options to pass to SSH.\n \
  64. "-oForwardX11=yes,TCPKeepAlive=yes"')
  65. parser.add_argument('host', nargs='?', default='')
  66. self.args = parser.parse_args()
  67. self.parser = parser
  68. def process_host(self):
  69. '''Determine host name and user name for SSH.
  70. '''
  71. self.env = None
  72. self.user = None
  73. re_env = re.compile("\.(" + "|".join(self.host_inventory.keys()) + ")")
  74. search = re_env.search(self.args.host)
  75. if self.args.env:
  76. self.env = self.args.env
  77. elif search:
  78. # take the first?
  79. self.env = search.groups()[0]
  80. # remove env from hostname command line arg if found
  81. if search:
  82. self.args.host = re_env.split(self.args.host)[0]
  83. # parse username if passed
  84. if '@' in self.args.host:
  85. self.user, self.host = self.args.host.split('@')
  86. else:
  87. self.host = self.args.host
  88. if self.args.login_name:
  89. self.user = self.args.login_name
  90. def get_hosts(self, refresh_cache=False):
  91. '''Query our host inventory and return a dict where the format
  92. equals:
  93. dict['servername'] = dns_name
  94. '''
  95. if refresh_cache:
  96. self.host_inventory = self.aws.build_host_dict_by_env(['--refresh-cache'])
  97. else:
  98. self.host_inventory = self.aws.build_host_dict_by_env()
  99. def select_host(self):
  100. '''select host attempts to match the host specified
  101. on the command line with a list of hosts.
  102. '''
  103. results = []
  104. for env in self.host_inventory.keys():
  105. for hostname, server_info in self.host_inventory[env].items():
  106. if hostname.split(':')[0] == self.host:
  107. results.append((hostname, server_info))
  108. # attempt to select the correct environment if specified
  109. if self.env:
  110. results = filter(lambda result: result[1]['ec2_tag_environment'] == self.env, results)
  111. if results:
  112. return results
  113. else:
  114. print "Could not find specified host: %s." % self.host
  115. # default - no results found.
  116. return None
  117. def list_hosts(self, limit=None):
  118. '''Function to print out the host inventory.
  119. Takes a single parameter to limit the number of hosts printed.
  120. '''
  121. if self.env:
  122. results = self.select_host()
  123. if len(results) == 1:
  124. hostname, server_info = results[0]
  125. sorted_keys = server_info.keys()
  126. sorted_keys.sort()
  127. for key in sorted_keys:
  128. print '{0:<35} {1}'.format(key, server_info[key])
  129. else:
  130. for host_id, server_info in results[:limit]:
  131. name = server_info['ec2_tag_Name']
  132. ec2_id = server_info['ec2_id']
  133. ip = server_info['ec2_ip_address']
  134. print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address}'.format(**server_info)
  135. if limit:
  136. print
  137. print 'Showing only the first %d results...' % limit
  138. print
  139. else:
  140. for env, host_ids in self.host_inventory.items():
  141. for host_id, server_info in host_ids.items():
  142. name = server_info['ec2_tag_Name']
  143. ec2_id = server_info['ec2_id']
  144. ip = server_info['ec2_ip_address']
  145. print '{ec2_tag_Name:<35} {ec2_tag_environment:<5} {ec2_id:<15} {ec2_ip_address}'.format(**server_info)
  146. def ssh(self):
  147. '''SSH to a specified host
  148. '''
  149. try:
  150. # shell args start with the program name in position 1
  151. ssh_args = ['/usr/bin/ssh']
  152. if self.user:
  153. ssh_args.append('-l%s' % self.user)
  154. if self.args.verbose:
  155. ssh_args.append('-vvv')
  156. if self.args.ssh_opts:
  157. for arg in self.args.ssh_opts.split(","):
  158. ssh_args.append("-o%s" % arg)
  159. results = self.select_host()
  160. if not results:
  161. return # early exit, no results
  162. if len(results) > 1:
  163. print "Multiple results found for %s." % self.host
  164. for result in results:
  165. print "{ec2_tag_Name:<35} {ec2_tag_environment:<5} {ec2_id:<10}".format(**result[1])
  166. return # early exit, too many results
  167. # Assume we have one and only one.
  168. hostname, server_info = results[0]
  169. dns = server_info['ec2_public_dns_name']
  170. ssh_args.append(dns)
  171. #last argument
  172. if self.args.command:
  173. ssh_args.append("%s" % self.args.command)
  174. print "Running: %s\n" % ' '.join(ssh_args)
  175. os.execve('/usr/bin/ssh', ssh_args, os.environ)
  176. except:
  177. print traceback.print_exc()
  178. print sys.exc_info()
  179. if __name__ == '__main__':
  180. ossh = Ossh()