awstools / scripts / ec2ssh

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2012 Ludia Inc.
# This software is licensed as described in the file LICENSE, which
# you should have received as part of this distribution.
# Author: Pior Bastida <pbastida@socialludia.com>

import os
import subprocess
import argparse

import argh
from argh.exceptions import CommandError

from awstools import ec2helper

HELP_INSTANCE = "Instance or list of instances"
HELP_COMMAND = "Command to run on the instances"
HELP_LIST = "List instances by name"
HELP_CONFIRM = "Always confirm"
HELP_VERBOSE = "Verbose mode"
HELP_ONE = "Run on the first instance found only"
HELP_YES = "Always answer yes"

epilog = """The 'instance' argument can be one or multiple specifiers
separated by commas.

valid specifiers:
    Private IP:             12.34.567.89
    Instance ID:            i-1a2b3c4d5e
    Tag Name (or altName):  tt-api-stage
    Wildcard on tag Name:   tt-api-*"""


@argh.arg('instance', default=None, nargs='?', help=HELP_INSTANCE)
@argh.arg('command', default=None, nargs='*', help=HELP_COMMAND)
@argh.arg('-l', '--list', default=False, help=HELP_LIST)
@argh.arg('-c', '--confirm', default=False, help=HELP_CONFIRM)
@argh.arg('-v', '--verbose', default=False, help=HELP_VERBOSE)
@argh.arg('-y', '--yes', default=False, help=HELP_YES)
@argh.arg('-1', '--one', default=False, help=HELP_ONE)
def connect(args):
    """SSH to multiple EC2 instances by name, instance-id or private ip"""

    if args.list:
        instances = ec2helper.get_instances()
        names = sorted([ec2helper.get_name(i) for i in instances])
        yield '\n'.join(names)

    elif args.instance is None:
        raise CommandError("No instances specified.")

    else:
        if args.confirm and args.yes:
            raise CommandError("Option confirm and yes are not compatible")

        try:
            specifiers = args.instance.lower().strip().split(',')
            instances = ec2helper.filter_instances(
                specifiers,
                ec2helper.get_instances(),
                )
            if len(instances) == 0:
                raise CommandError("No instances found.")
        except KeyboardInterrupt:
            raise CommandError("Killed while accessing AWS api.")

        if args.one:
            instances = instances[0:1]

        if len(instances) > 1 or args.confirm:
            args.verbose = True
        if len(instances) > 1 and not args.yes:
            args.confirm = True

        if args.verbose and args.command:
            yield '----- Command: %s' % ' '.join(args.command)
        if args.verbose:
            names = sorted([ec2helper.get_name(i) for i in instances])
            yield '----- Instances(%s): %s' % (len(names), ",".join(names))

        if args.confirm:
            if not argh.confirm('Confirm', default=True):
                raise CommandError("Aborted")

        if len(instances) == 1:
            host = instances[0].public_dns_name
            try:
                os.execvp('ssh', ['ec2ssh', host] + args.command)
            except OSError as e:
                raise Exception("Failed to call the ssh command: %s" % e)
        else:
            for instance in instances:
                if args.verbose:
                    yield "----- %s: %s  %s" % (
                        instance.id,
                        instance.public_dns_name,
                        instance.private_ip_address,
                        )

                host = instance.public_dns_name
                subprocess.call(['ssh', host] + args.command)

        if args.verbose:
            yield '----- DONE'


def main():
    parser = argh.ArghParser(
        epilog=epilog,
        formatter_class=argparse.RawDescriptionHelpFormatter
        )
    parser.set_default_command(connect)
    parser.dispatch(completion=False)

if __name__ == '__main__':
    main()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.