ossh 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #!/usr/bin/env python
  2. import pdb
  3. import argparse
  4. import ansibleutil
  5. import traceback
  6. import sys
  7. import os
  8. import re
  9. # use dynamic inventory
  10. # list instances
  11. # symlinked to ~/bin
  12. # list instances that match pattern
  13. # python!
  14. # list environment stuff as well
  15. # 3 states:
  16. # - an exact match; return result
  17. # - a partial match; return all regex results
  18. # - no match; None
  19. class Ossh(object):
  20. def __init__(self):
  21. self.file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)))
  22. self.parse_cli_args()
  23. # parse host and user
  24. self.process_host()
  25. if not self.args.list and not self.env:
  26. print "Please specify an environment."
  27. return
  28. if self.args.host == '' and not self.args.list:
  29. self.parser.print_help()
  30. return
  31. self.ansible = ansibleutil.AnsibleUtil()
  32. # get a dict of host inventory
  33. if self.args.list:
  34. self.get_hosts()
  35. else:
  36. self.get_hosts(True)
  37. if self.args.debug:
  38. print self.args
  39. # perform the SSH
  40. if self.args.list:
  41. self.list_hosts()
  42. else:
  43. self.ssh()
  44. def parse_cli_args(self):
  45. parser = argparse.ArgumentParser(description='Openshift Online SSH Tool.')
  46. parser.add_argument('-r', '--random', action="store",
  47. help="Choose a random host")
  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('--list', default=False,
  55. action="store_true", help="list out hosts")
  56. parser.add_argument('-c', '--command', action='store',
  57. help='Command to run on remote host')
  58. parser.add_argument('-l', '--login_name', action='store',
  59. help='User in which to ssh as')
  60. parser.add_argument('-o', '--ssh_opts', action='store',
  61. help='options to pass to SSH.\n \
  62. "-o ForwardX11 yes"')
  63. parser.add_argument('host', nargs='?', default='')
  64. self.args = parser.parse_args()
  65. self.parser = parser
  66. def process_host(self):
  67. '''Determine host name and user name for SSH.
  68. '''
  69. self.env = None
  70. self.user = None
  71. re_env = re.compile('\.(int|stg|prod|ops)')
  72. search = re_env.search(self.args.host)
  73. if self.args.env:
  74. self.env = self.args.env
  75. elif search:
  76. # take the first?
  77. self.env = search.groups()[0]
  78. # remove env from hostname command line arg if found
  79. if search:
  80. self.args.host = re_env.split(self.args.host)[0]
  81. # parse username if passed
  82. if '@' in self.args.host:
  83. self.user, self.host = self.args.host.split('@')
  84. else:
  85. self.host = self.args.host
  86. if self.args.login_name:
  87. self.user = self.args.login_name
  88. def get_hosts(self, cache=False):
  89. '''Query our host inventory and return a dict where the format
  90. equals:
  91. dict['servername'] = dns_name
  92. '''
  93. # TODO: perform a numerical sort on these hosts
  94. # and display them
  95. if not cache:
  96. self.host_inventory = self.ansible.build_host_dict()
  97. else:
  98. self.host_inventory = self.ansible.build_host_dict(['--cache-only'])
  99. def select_host(self, regex=False):
  100. '''select host attempts to match the host specified
  101. on the command line with a list of hosts.
  102. if regex is specified then we will attempt to match
  103. all *{host_string}* equivalents.
  104. '''
  105. # list environment stuff as well
  106. # 3 states:
  107. # - an exact match; return result
  108. # - a partial match; return all regex results
  109. # - no match; None
  110. re_host = re.compile(self.host)
  111. exact = []
  112. results = []
  113. for hostname, server_info in self.host_inventory[self.env].items():
  114. if hostname.split(':')[0] == self.host:
  115. exact.append((hostname, server_info))
  116. break
  117. elif re_host.search(hostname):
  118. results.append((hostname, server_info))
  119. if exact:
  120. return exact
  121. elif results:
  122. return results
  123. else:
  124. print "Could not find specified host: %s in %s" % (self.host, self.env)
  125. # default - no results found.
  126. return None
  127. def list_hosts(self, limit=None):
  128. '''Function to print out the host inventory.
  129. Takes a single parameter to limit the number of hosts printed.
  130. '''
  131. if self.env:
  132. results = self.select_host(True)
  133. if len(results) == 1:
  134. hostname, server_info = results[0]
  135. sorted_keys = server_info.keys()
  136. sorted_keys.sort()
  137. for key in sorted_keys:
  138. print '{0:<35} {1}'.format(key, server_info[key])
  139. else:
  140. for host_id, server_info in results[:limit]:
  141. name = server_info['ec2_tag_Name']
  142. ec2_id = server_info['ec2_id']
  143. ip = server_info['ec2_ip_address']
  144. print '{ec2_tag_Name:<35} {ec2_tag_environment:<8} {ec2_id:<15} {ec2_ip_address}'.format(**server_info)
  145. if limit:
  146. print
  147. print 'Showing only the first %d results...' % limit
  148. print
  149. else:
  150. for env, host_ids in self.host_inventory.items():
  151. for host_id, server_info in host_ids.items():
  152. name = server_info['ec2_tag_Name']
  153. ec2_id = server_info['ec2_id']
  154. ip = server_info['ec2_ip_address']
  155. print '{ec2_tag_Name:<35} {ec2_tag_environment:<5} {ec2_id:<15} {ec2_ip_address}'.format(**server_info)
  156. def ssh(self):
  157. '''SSH to a specified host
  158. '''
  159. try:
  160. cmd = '/usr/bin/ssh'
  161. # shell args start with the program name in position 1
  162. ssh_args = [cmd, ]
  163. if self.user:
  164. ssh_args.append('-l%s' % self.user)
  165. if self.args.verbose:
  166. ssh_args.append('-vvv')
  167. if self.args.ssh_opts:
  168. ssh_args.append("-o%s" % self.args.ssh_opts)
  169. result = self.select_host()
  170. if not result:
  171. return # early exit, no results
  172. if len(result) > 1:
  173. self.list_hosts(10)
  174. return # early exit, too many results
  175. # Assume we have one and only one.
  176. hostname, server_info = result[0]
  177. dns = server_info['ec2_public_dns_name']
  178. ssh_args.append(dns)
  179. #last argument
  180. if self.args.command:
  181. ssh_args.append("%s" % self.args.command)
  182. if self.args.debug:
  183. print "SSH to %s in %s as %s" % (hostname, self.env, self.user)
  184. print "Running: %s\n" % ' '.join(ssh_args)
  185. os.execve('/usr/bin/ssh', ssh_args, os.environ)
  186. except:
  187. print traceback.print_exc()
  188. print sys.exc_info()
  189. def main():
  190. ossh = Ossh()
  191. if __name__ == '__main__':
  192. main()