|
@@ -1,146 +1,137 @@
|
|
|
-#!/usr/bin/env python
|
|
|
+#!/bin/bash
|
|
|
# vim: expandtab:tabstop=4:shiftwidth=4
|
|
|
|
|
|
-import argparse
|
|
|
-import traceback
|
|
|
-import sys
|
|
|
-import os
|
|
|
-import re
|
|
|
-import tempfile
|
|
|
-import time
|
|
|
-import subprocess
|
|
|
-import ConfigParser
|
|
|
|
|
|
-from openshift_ansible import awsutil
|
|
|
-from openshift_ansible.awsutil import ArgumentError
|
|
|
-
|
|
|
-DEFAULT_PSSH_PAR = 200
|
|
|
-PSSH = '/usr/bin/pssh'
|
|
|
-CONFIG_MAIN_SECTION = 'main'
|
|
|
-CONFIG_HOST_TYPE_ALIAS_SECTION = 'host_type_aliases'
|
|
|
-CONFIG_INVENTORY_OPTION = 'inventory'
|
|
|
-
|
|
|
-class Opssh(object):
|
|
|
- def __init__(self):
|
|
|
- self.inventory = None
|
|
|
- self.host_type_aliases = {}
|
|
|
- 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(self.inventory, self.host_type_aliases)
|
|
|
-
|
|
|
- def run(self):
|
|
|
- if self.args.list_host_types:
|
|
|
- self.aws.print_host_types()
|
|
|
- return 0
|
|
|
-
|
|
|
- if self.args.host_type is not None or \
|
|
|
- self.args.env is not None:
|
|
|
- return self.run_pssh()
|
|
|
-
|
|
|
- # We weren't able to determine what they wanted to do
|
|
|
- raise ArgumentError("Invalid combination of arguments")
|
|
|
-
|
|
|
- def run_pssh(self):
|
|
|
- """Actually run the pssh command based off of the supplied options
|
|
|
- """
|
|
|
-
|
|
|
- # Default set of options
|
|
|
- pssh_args = [PSSH, '-t', '0', '-p', str(self.args.par), '--user', self.args.user]
|
|
|
-
|
|
|
- if self.args.inline:
|
|
|
- pssh_args.append("--inline")
|
|
|
-
|
|
|
- if self.args.outdir:
|
|
|
- pssh_args.extend(["--outdir", self.args.outdir])
|
|
|
-
|
|
|
- if self.args.errdir:
|
|
|
- pssh_args.extend(["--errdir", self.args.errdir])
|
|
|
-
|
|
|
- hosts = self.aws.get_host_list(host_type=self.args.host_type,
|
|
|
- env=self.args.env)
|
|
|
-
|
|
|
- with tempfile.NamedTemporaryFile(prefix='opssh-', delete=True) as f:
|
|
|
- for h in hosts:
|
|
|
- f.write(h + os.linesep)
|
|
|
- f.flush()
|
|
|
-
|
|
|
- pssh_args.extend(["-h", f.name])
|
|
|
- pssh_args.append(self.args.command)
|
|
|
-
|
|
|
- print
|
|
|
- print "Running: %s" % ' '.join(pssh_args)
|
|
|
- print
|
|
|
- return subprocess.call(pssh_args)
|
|
|
-
|
|
|
- return None
|
|
|
-
|
|
|
- def parse_config_file(self):
|
|
|
- if os.path.isfile(self.config_path):
|
|
|
- config = ConfigParser.ConfigParser()
|
|
|
- config.read(self.config_path)
|
|
|
-
|
|
|
- if config.has_section(CONFIG_MAIN_SECTION) and \
|
|
|
- config.has_option(CONFIG_MAIN_SECTION, CONFIG_INVENTORY_OPTION):
|
|
|
- self.inventory = config.get(CONFIG_MAIN_SECTION, CONFIG_INVENTORY_OPTION)
|
|
|
-
|
|
|
- self.host_type_aliases = {}
|
|
|
- if config.has_section(CONFIG_HOST_TYPE_ALIAS_SECTION):
|
|
|
- for alias in config.options(CONFIG_HOST_TYPE_ALIAS_SECTION):
|
|
|
- value = config.get(CONFIG_HOST_TYPE_ALIAS_SECTION, alias).split(',')
|
|
|
- self.host_type_aliases[alias] = value
|
|
|
-
|
|
|
- def parse_cli_args(self):
|
|
|
- """Setup the command line parser with the options we want
|
|
|
- """
|
|
|
-
|
|
|
- parser = argparse.ArgumentParser(description='Openshift Online PSSH Tool.')
|
|
|
-
|
|
|
- parser.add_argument('--list-host-types', default=False, action='store_true',
|
|
|
- help='List all of the host types')
|
|
|
-
|
|
|
- parser.add_argument('-e', '--env', action="store",
|
|
|
- help="Which environment to use")
|
|
|
-
|
|
|
- parser.add_argument('-t', '--host-type', action="store", default=None,
|
|
|
- help="Which host type to use")
|
|
|
-
|
|
|
- parser.add_argument('-c', '--command', action='store',
|
|
|
- help='Command to run on remote host(s)')
|
|
|
-
|
|
|
- parser.add_argument('--user', action='store', default='root',
|
|
|
- help='username')
|
|
|
-
|
|
|
- parser.add_argument('-i', '--inline', default=False, action='store_true',
|
|
|
- help='inline aggregated output and error for each server')
|
|
|
-
|
|
|
- parser.add_argument('-p', '--par', action='store', default=DEFAULT_PSSH_PAR,
|
|
|
- help=('max number of parallel threads (default %s)' % DEFAULT_PSSH_PAR))
|
|
|
-
|
|
|
- parser.add_argument('--outdir', action='store',
|
|
|
- help='output directory for stdout files')
|
|
|
-
|
|
|
- parser.add_argument('--errdir', action='store',
|
|
|
- help='output directory for stderr files')
|
|
|
-
|
|
|
- self.args = parser.parse_args()
|
|
|
-
|
|
|
-
|
|
|
-if __name__ == '__main__':
|
|
|
- if len(sys.argv) == 1:
|
|
|
- print "\nError: No options given. Use --help to see the available options\n"
|
|
|
- sys.exit(0)
|
|
|
-
|
|
|
- try:
|
|
|
- opssh = Opssh()
|
|
|
- exitcode = opssh.run()
|
|
|
- sys.exit(exitcode)
|
|
|
- except ArgumentError as e:
|
|
|
- print "\nError: %s\n" % e.message
|
|
|
+function usage() {
|
|
|
+ cat << EOF
|
|
|
+Usage: opssh [OPTIONS] command [...]
|
|
|
+
|
|
|
+Options:
|
|
|
+ --version show program's version number and exit
|
|
|
+ --help show this help message and exit
|
|
|
+ -l USER, --user=USER username (OPTIONAL)
|
|
|
+ -p PAR, --par=PAR max number of parallel threads (OPTIONAL)
|
|
|
+ --outdir=OUTDIR output directory for stdout files (OPTIONAL)
|
|
|
+ --errdir=ERRDIR output directory for stderr files (OPTIONAL)
|
|
|
+ -e ENV, --env ENV which environment to use
|
|
|
+ -t HOST_TYPE, --host-type HOST_TYPE
|
|
|
+ which host type to use
|
|
|
+ --list-host-types list all of the host types
|
|
|
+ --timeout=TIMEOUT timeout (secs) (0 = no timeout) per host (OPTIONAL)
|
|
|
+ -O OPTION, --option=OPTION
|
|
|
+ SSH option (OPTIONAL)
|
|
|
+ -v, --verbose turn on warning and diagnostic messages (OPTIONAL)
|
|
|
+ -A, --askpass Ask for a password (OPTIONAL)
|
|
|
+ -x ARGS, --extra-args=ARGS
|
|
|
+ Extra command-line arguments, with processing for
|
|
|
+ spaces, quotes, and backslashes
|
|
|
+ -X ARG, --extra-arg=ARG
|
|
|
+ Extra command-line argument
|
|
|
+ -i, --inline inline aggregated output and error for each server
|
|
|
+ --inline-stdout inline standard output for each server
|
|
|
+ -I, --send-input read from standard input and send as input to ssh
|
|
|
+ -P, --print print output as we get it
|
|
|
+
|
|
|
+Example: opssh -t ex-srv -e stg -l irb2 --outdir /tmp/foo uptime
|
|
|
+
|
|
|
+EOF
|
|
|
+}
|
|
|
+
|
|
|
+if [ $# -eq 0 ] || [ "$1" == "--help" ]
|
|
|
+then
|
|
|
+ usage
|
|
|
+ exit 1
|
|
|
+fi
|
|
|
+
|
|
|
+# See if ohi is installed
|
|
|
+if ! which ohi &>/dev/null ; then
|
|
|
+ echo "ERROR: can't find ohi (OpenShift Host Inventory) on your system, please either install the openshift-ansible-bin package, or add openshift-ansible/bin to your path."
|
|
|
+
|
|
|
+ exit 10
|
|
|
+fi
|
|
|
+
|
|
|
+PAR=200
|
|
|
+USER=root
|
|
|
+TIMEOUT=0
|
|
|
+ARGS=()
|
|
|
+ENV=""
|
|
|
+HOST_TYPE=""
|
|
|
+while [ $# -gt 0 ] ; do
|
|
|
+ case $1 in
|
|
|
+ -t|--host-type)
|
|
|
+ shift # get past the option
|
|
|
+ HOST_TYPE=$1
|
|
|
+ shift # get past the value of the option
|
|
|
+ ;;
|
|
|
+
|
|
|
+ -e)
|
|
|
+ shift # get past the option
|
|
|
+ ENV=$1
|
|
|
+ shift # get past the value of the option
|
|
|
+ ;;
|
|
|
+
|
|
|
+ --timeout)
|
|
|
+ shift # get past the option
|
|
|
+ TIMEOUT=$1
|
|
|
+ shift # get past the value of the option
|
|
|
+ ;;
|
|
|
+
|
|
|
+ -p|--par)
|
|
|
+ shift # get past the option
|
|
|
+ PAR=$1
|
|
|
+ shift # get past the value of the option
|
|
|
+ ;;
|
|
|
+
|
|
|
+ -l|--user)
|
|
|
+ shift # get past the option
|
|
|
+ USER=$1
|
|
|
+ shift # get past the value of the option
|
|
|
+ ;;
|
|
|
+
|
|
|
+ --list-host-types)
|
|
|
+ ohi --list-host-types
|
|
|
+ exit 0
|
|
|
+ ;;
|
|
|
+
|
|
|
+ -h|--hosts|-H|--host|-o)
|
|
|
+ echo "ERROR: unknown option $1"
|
|
|
+ exit 20
|
|
|
+ ;;
|
|
|
+
|
|
|
+ *)
|
|
|
+ args+=("$1")
|
|
|
+ shift
|
|
|
+ ;;
|
|
|
+ esac
|
|
|
+done
|
|
|
+
|
|
|
+if [ -z "$ENV" ]
|
|
|
+then
|
|
|
+ echo
|
|
|
+ echo "-e is a required paramemeter"
|
|
|
+ echo
|
|
|
+ exit 10
|
|
|
+fi
|
|
|
+
|
|
|
+if [ -z "$HOST_TYPE" ]
|
|
|
+then
|
|
|
+ echo
|
|
|
+ echo "-t is a required paramemeter"
|
|
|
+ echo
|
|
|
+ exit 15
|
|
|
+fi
|
|
|
+
|
|
|
+# See if the ohi options are valid
|
|
|
+HOSTS="$(ohi -t "$HOST_TYPE" -e "$ENV" 2>/dev/null)"
|
|
|
+ECODE=$?
|
|
|
+
|
|
|
+if [ $ECODE -ne 0 ] ; then
|
|
|
+ echo
|
|
|
+ echo "ERROR: ohi failed with exit code $ECODE"
|
|
|
+ echo
|
|
|
+ echo "This is usually caused by a bad value passed for host-type or environment."
|
|
|
+ echo
|
|
|
+ exit 25
|
|
|
+fi
|
|
|
+
|
|
|
+exec pssh -t $TIMEOUT -p $PAR -l $USER -h <(echo "$HOSTS") "${args[@]}"
|