Browse Source

Merge branch 'master' into tower_install

Matt Woodson 10 years ago
parent
commit
2a8f7ab951
6 changed files with 253 additions and 37 deletions
  1. 8 4
      bin/README_SHELL_COMPLETION
  2. 3 5
      bin/ansibleutil.py
  3. 220 0
      bin/oscp
  4. 20 26
      bin/ossh
  5. 1 1
      bin/ossh_bash_completion
  6. 1 1
      bin/ossh_zsh_completion

+ 8 - 4
bin/README_SHELL_COMPLETION

@@ -1,8 +1,8 @@
-# ossh is an ssh replacement.
+# completion is available for ossh/oscp
 
 
-
-ossh uses a dynamic inventory cache in order to lookup hostnames and translate them
-to something meaningful such as an IP address or dns name.
+ossh/oscp uses a dynamic inventory cache in order to lookup
+hostnames and translate them to something meaningful
+such as an IP address or dns name.
 
 
 This allows us to treat our servers as cattle and not as pets.
 This allows us to treat our servers as cattle and not as pets.
 
 
@@ -31,3 +31,7 @@ Once $fpath includes the _ossh_zsh_completion script then you should
 run `exec zsh`.  This will then allow you to call `ossh host[TAB]`
 run `exec zsh`.  This will then allow you to call `ossh host[TAB]`
 for a list of completions.
 for a list of completions.
 
 
+Before completing the final step, zsh keeps its own cache in
+~/.zcompdump of the known functions and variables.  In order to
+refresh with new variables and completion arrays you might need
+to `rm ~/.zcompdump` before running `exec zsh`.

+ 3 - 5
bin/ansibleutil.py

@@ -17,7 +17,8 @@ class AnsibleUtil(object):
         if args:
         if args:
             cmd.extend(args)
             cmd.extend(args)
 
 
-        env = {}
+        env = os.environ
+
         p = subprocess.Popen(cmd, stderr=subprocess.PIPE,
         p = subprocess.Popen(cmd, stderr=subprocess.PIPE,
                          stdout=subprocess.PIPE, env=env)
                          stdout=subprocess.PIPE, env=env)
 
 
@@ -52,7 +53,7 @@ class AnsibleUtil(object):
 
 
         return groups
         return groups
 
 
-    def build_host_dict(self, args=[]):
+    def build_host_dict_by_env(self, args=[]):
         inv = self.get_inventory(args)
         inv = self.get_inventory(args)
 
 
         inst_by_env = {}
         inst_by_env = {}
@@ -62,8 +63,5 @@ class AnsibleUtil(object):
             host_id = "%s:%s" % (host['ec2_tag_Name'],host['ec2_id'])
             host_id = "%s:%s" % (host['ec2_tag_Name'],host['ec2_id'])
             inst_by_env[host['ec2_tag_environment']][host_id] = host
             inst_by_env[host['ec2_tag_environment']][host_id] = host
 
 
-
         return inst_by_env
         return inst_by_env
 
 
-
-

+ 220 - 0
bin/oscp

@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+# vim: expandtab:tabstop=4:shiftwidth=4
+
+import argparse
+import ansibleutil
+import traceback
+import sys
+import os
+import re
+
+class Oscp(object):
+    def __init__(self):
+        self.file_path = os.path.join(os.path.dirname(os.path.realpath(__file__)))
+        self.parse_cli_args()
+
+        # parse host and user
+        self.process_host()
+
+        self.ansible = ansibleutil.AnsibleUtil()
+
+        # get a dict of host inventory
+        if self.args.list:
+            self.get_hosts()
+        else:
+            self.get_hosts(True)
+
+        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_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('--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, cache_only=False):
+        '''Query our host inventory and return a dict where the format
+           equals:
+
+           dict['environment'] = [{'servername' : {}}, ]
+        '''
+        if cache_only:
+            self.host_inventory = self.ansible.build_host_dict_by_env(['--cache-only'])
+        else:
+            self.host_inventory = self.ansible.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 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 "{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']
+
+            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()
+

+ 20 - 26
bin/ossh

@@ -24,15 +24,10 @@ class Ossh(object):
         # parse host and user
         # parse host and user
         self.process_host()
         self.process_host()
 
 
-        if not self.args.list and not self.env:
-            print "Please specify an environment."
-            return
-
         if self.args.host == '' and not self.args.list:
         if self.args.host == '' and not self.args.list:
             self.parser.print_help()
             self.parser.print_help()
             return
             return
 
 
-
         if self.args.debug:
         if self.args.debug:
             print self.args
             print self.args
 
 
@@ -99,31 +94,28 @@ class Ossh(object):
            dict['servername'] = dns_name
            dict['servername'] = dns_name
         '''
         '''
         if cache_only:
         if cache_only:
-            self.host_inventory = self.ansible.build_host_dict(['--cache-only'])
+            self.host_inventory = self.ansible.build_host_dict_by_env(['--cache-only'])
         else:
         else:
-            self.host_inventory = self.ansible.build_host_dict()
+            self.host_inventory = self.ansible.build_host_dict_by_env()
 
 
-    def select_host(self, regex=False):
+    def select_host(self):
         '''select host attempts to match the host specified
         '''select host attempts to match the host specified
            on the command line with a list of hosts.
            on the command line with a list of hosts.
-
-           if regex is specified then we will attempt to match
-           all *{host_string}* equivalents.
         '''
         '''
-        re_host = re.compile(self.host)
-
         results = []
         results = []
-        for hostname, server_info in self.host_inventory[self.env].items():
-            if hostname.split(':')[0] == self.host:
-                # an exact match, return it!
-                return [(hostname, server_info)]
-            elif re_host.search(hostname):
-                results.append((hostname, server_info))
+        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:
         if results:
             return results
             return results
         else:
         else:
-            print "Could not find specified host: %s in %s" % (self.host, self.env)
+            print "Could not find specified host: %s." % self.host
 
 
         # default - no results found.
         # default - no results found.
         return None
         return None
@@ -135,7 +127,7 @@ class Ossh(object):
         '''
         '''
 
 
         if self.env:
         if self.env:
-            results = self.select_host(True)
+            results = self.select_host()
             if len(results) == 1:
             if len(results) == 1:
                 hostname, server_info = results[0]
                 hostname, server_info = results[0]
                 sorted_keys = server_info.keys()
                 sorted_keys = server_info.keys()
@@ -179,16 +171,18 @@ class Ossh(object):
                 for arg in self.args.ssh_opts.split(","):
                 for arg in self.args.ssh_opts.split(","):
                     ssh_args.append("-o%s" % arg)
                     ssh_args.append("-o%s" % arg)
 
 
-            result = self.select_host()
-            if not result:
+            results = self.select_host()
+            if not results:
                 return # early exit, no results
                 return # early exit, no results
 
 
-            if len(result) > 1:
-                self.list_hosts(10)
+            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
                 return # early exit, too many results
 
 
             # Assume we have one and only one.
             # Assume we have one and only one.
-            hostname, server_info = result[0]
+            hostname, server_info = results[0]
             dns = server_info['ec2_public_dns_name']
             dns = server_info['ec2_public_dns_name']
 
 
             ssh_args.append(dns)
             ssh_args.append(dns)

+ 1 - 1
bin/ossh_bash_completion

@@ -15,4 +15,4 @@ _ossh()
 
 
     return 0
     return 0
 }
 }
-complete -F _ossh ossh
+complete -F _ossh ossh oscp

+ 1 - 1
bin/ossh_zsh_completion

@@ -1,4 +1,4 @@
-#compdef ossh
+#compdef ossh oscp
 
 
 _ossh_known_hosts(){
 _ossh_known_hosts(){
   if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then
   if [[ -f ~/.ansible/tmp/multi_ec2_inventory.cache ]]; then