Amazon-API/DescribeInstances.pl
#!/usr/bin/env perl
package Amazon::CLI::EC2;
use strict;
use warnings;
use Amazon::API::EC2;
use Carp::Always;
use Carp;
use Data::Dumper;
use English qw( -no_match_vars );
use Getopt::Long qw(:config no_ignore_case);
use JSON;
use List::Util qw(pairs);
use Term::ANSIColor;
use Text::ASCIITable;
use Readonly;
Readonly our $TRUE => 1;
Readonly our $FALSE => 0;
Readonly our $EMPTY => q{};
Readonly our $OCTOTHORP => q{#};
Readonly::Hash our %COLORS => (
running => 'green',
terminated => 'red',
stopped => 'magenta',
pending => 'yellow',
);
our $VERSION = '0.01';
caller or __PACKAGE__->main();
########################################################################
{
my $service;
sub _api_method {
my ( $method, @args ) = @_;
$service //= Amazon::API::EC2->new(log_level => 'info');
my $result = eval { return $service->$method(@args); };
if ( $EVAL_ERROR && ref($EVAL_ERROR) =~ /API::Error/xsm ) {
print Dumper( [ $EVAL_ERROR->get_response, $EVAL_ERROR->get_error ] );
}
elsif ($EVAL_ERROR) {
croak $EVAL_ERROR;
}
return $result;
}
}
########################################################################
########################################################################
sub describe_instances {
########################################################################
my (@args) = @_;
return _api_method( 'DescribeInstances', @args );
}
########################################################################
sub get_instances {
########################################################################
my ($result) = @_;
return map { @{ $_->{Instances} } } @{ $result->{Reservations} };
}
########################################################################
sub resolve_instance_name {
########################################################################
my (@instances) = @_;
foreach my $item (@instances) {
my $tags = $item->{Tags};
if ( $tags && @{$tags} ) {
foreach my $p ( pairs map { @{$_}{qw(Key Value)} } @{$tags} ) {
next if $p->[0] ne 'Name';
$item->{Name} = $p->[1];
last;
}
}
}
return @instances;
}
########################################################################
sub sort_instances {
########################################################################
my (@instances) = @_;
for (@instances) {
$_->{Name} //= q{};
}
return sort { $a->{State}->{Name} cmp $b->{State}->{Name} or $a->{Name} cmp $b->{Name} } @instances;
}
########################################################################
sub create_instances_table {
########################################################################
my (@instances) = @_;
my $t = Text::ASCIITable->new(
{ headingText => 'EC2 Instances',
allowANSI => $TRUE
}
);
my @columns = qw(InstanceId Name ImageId InstanceType PrivateIpAddress LaunchTime);
$t->setCols( $OCTOTHORP, @columns, 'State' );
my $row = 0;
foreach my $item (@instances) {
my $state = $item->{State}->{Name};
my $ansi_color = colored( $state, $COLORS{$state} // 'red' );
$t->addRow( ++$row, @{$item}{@columns}, $ansi_color );
}
return $t;
}
########################################################################
sub get_filters {
########################################################################
my ($options) = @_;
return
if !$options->{filters};
my @filter_list;
foreach my $filter ( @{ $options->{filters} } ) {
if ( $filter =~ /^Name=([^,]+),Values=(.*)?/xsm ) {
my ( $name, $values ) = ( $1, $2 );
my $value_list = [ split /,/xsm, $values ];
push @filter_list, { Name => $name, Values => $value_list };
}
else {
croak 'not a valid filter';
}
}
return { Filters => \@filter_list };
}
########################################################################
sub usage {
########################################################################
print {*STDOUT} <<"END_OF_HELP";
usage: $PROGRAM_NAME Options
Options Description
------- -----------
--help|h help
--filters|f filter list
Filters is a list of filter names and values.
Examples:
--filters Name=instance-type,Values=t2.micro
--filters Name=instance-id,Values=i-0628639cfba021f19
--filters Name=instance-type,Values=t2.micro Name=instance-state-name,Values=running
END_OF_HELP
return 0;
}
########################################################################
sub main {
########################################################################
my @option_specs = ( 'help|h', 'filters:s{1,}' );
my %options = ( filters => [] );
GetOptions( \%options, @option_specs )
or croak "$EVAL_ERROR";
if ( $options{help} ) {
return usage();
}
my $filters = get_filters( \%options );
my $result = describe_instances($filters);
my @instances = get_instances($result);
resolve_instance_name(@instances);
@instances = sort_instances(@instances);
print {*STDOUT} create_instances_table(@instances);
return 0;
}
1;