#!/usr/bin/env python #----------------------------------------------------------------------------- # Copyright (C) 2016, by Phil D. Howard - all other rights reserved # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # # The author may be contacted using the short first name, middle initial, # and last name, separated by periods, with gmail dot com as the host part # of an email address. #----------------------------------------------------------------------------- # audience linux and unix users # script list-instances.py # purpose show instances # syntax python list-instances.py [ region ... ] # alternate python list-running-instances.py [ region ... ] # note copy or symlink so the command for list-running-instances.py runs list-instances.py to list only running (and pending) instances #----------------------------------------------------------------------------- from __future__ import division, print_function """ show instances """ import botocore.session from aws_regions import aws_regions_list_long, aws_regions_any_to_long from imports import * from multiprocessing import Pipe, Process from os import getpid, remove from pickle import dump, load from pyutils import eprint, plural pipe = None region = None run = None #----------------------------------------------------------------------------- # function print_instance # purpose print one line describing one instance #----------------------------------------------------------------------------- def print_instance( region, instance ): if instance == None: return None s = region + ' ' + instance['InstanceId'] n = region + '_' if 'State' in instance: s += ' ' s += instance['State']['Name'] if 'ImageId' in instance: s += ' ' s += instance['ImageId'] n += instance['ImageId'] if 'Placement' in instance: if 'AvailabilityZone' in instance['Placement']: s += ' ' s += instance['Placement']['AvailabilityZone'][-1] if 'InstanceType' in instance: s += ' ' s += instance['InstanceType'] if 'VpcId' in instance: s += ' ' s += instance['VpcId'] if 'PublicIpAddress' in instance: s += ' ' s += instance['PublicIpAddress'] if 'PrivateIpAddress' in instance: s += ' ( ' s += instance['PrivateIpAddress'] s += ' )' if 'Tags' in instance: tags = sorted([(tag['Key'], tag['Value']) for tag in instance['Tags']],cmptag) for tag in tags: s += ' ' s += tag[0] s += '=' s += repr(tag[1]) try: print( s ) except IOError: pass return s #----------------------------------------------------------------------------- # function cmptag # purpose compare logic for sort() so 'Name' collates lowest #----------------------------------------------------------------------------- def cmptag(a,b): if a == 'Name': return -1 if b == 'Name': return 1 if a < b: return -1 if a > b: return 1 return 0 #----------------------------------------------------------------------------- # function lookup # purpose run as a child process per region to get instance info # pickle the info from the describe_instances method # pipe this info to the parent using pickle format # note the pipe is inherited from the parent #----------------------------------------------------------------------------- def lookup(): session = botocore.session.get_session() client = session.create_client( 'ec2', region_name=region ) paginator = client.get_paginator( 'describe_instances' ) page_iterator = paginator.paginate() pipe[0].close() for page in page_iterator: for resv in page[ 'Reservations' ]: for instance in resv[ 'Instances' ]: if run and 'State' in instance: if instance['State']['Name'][1:] != 'unning': continue pipe[1].send( instance ) pipe[1].send( None ) pipe[1].close() # send EOF return #----------------------------------------------------------------------------- # function main #----------------------------------------------------------------------------- def main( args ): global pipe, region, run # passing as globals instead of args errors = 0 # arguments are regions region_list = [] if 'run' in args[0]: run = True else: run = False #----------------------------------------------------------------------------- for arg in args[1:]: if arg in ('-r','+r','--run','++run'): run = True continue if arg.lower() in aws_regions_any_to_long: region = aws_regions_any_to_long[ arg.lower() ] if region in region_list: print( 'region', region, 'already specified', file=stderr ) errors += 1 else: region_list += [ region ] else: print( 'argument', repr(arg), 'is not a valid region', file=stderr ) errors += 1 if errors > 0: return 'aborting due to '+repr( errors )+'error'+plural( errors ) if len( region_list ) == 0: region_list = list( aws_regions_list_long ) region_list.sort() region_count = len( region_list ) #----------------------------------------------------------------------------- # setup, record, and start all the processes #----------------------------------------------------------------------------- plist = [] for region in region_list: pipe = Pipe( False ) process = Process( target = lookup ) # child inherits pipe and region, so no args needed. plist += [ ( region, process, pipe ) ] process.start() #----------------------------------------------------------------------------- # read all the results of each process. # so what if we delay on the first ones, we have to wait on all the data. #----------------------------------------------------------------------------- for this_region, this_process, this_pipe in plist: pipe[1].close() # close the parent copy of the send side of the pipe. while True: try: if print_instance( this_region, this_pipe[0].recv() ) == None: break except EOFError: break #----------------------------------------------------------------------------- # wait up to 6 minutes for all of them to finish #----------------------------------------------------------------------------- for this_region, this_process, this_pipe in plist: this_process.join( 360 ) #----------------------------------------------------------------------------- # all done #----------------------------------------------------------------------------- return 0 #----------------------------------------------------------------------------- if __name__ == '__main__': from sys import argv, stderr, stdout result = main( argv ) stdout.flush() try: exit( int( result ) ) except ValueError: print( str( result ), file=stderr ) exit( 1 ) except TypeError: if result == None: exit( 0 ) exit( 254 ) except: exit( 255 ) #----------------------------------------------------------------------------- # EOF