App-FargateStack
view release on metacpan or search on metacpan
lib/App/FargateStack.pm view on Meta::CPAN
$path = realpath($path);
my $fqp = sprintf '%s/%s%s', $path, $name, $ext || 'yml';
die sprintf "ERROR: file not found: [%s]\n", $fqp
if !-s $fqp;
$options->{config} = $fqp;
$self->write_json_file( $defaults_file, $options );
$config_name = $name;
}
my $data = [
{ Profile => $options->{profile},
'DNS Profile' => $options->{route53_profile},
'Max Events', => $options->{max_events},
'Config' => $options->{config},
'Region' => $options->{region},
}
];
my @columns = ( 'Profile', 'DNS Profile', 'Region', 'Config', 'Max Events' );
print {*STDOUT} easy_table(
table_options => { headingText => sprintf 'Current Defaults: %s', $config_name },
columns => \@columns,
data => $data,
);
return $SUCCESS;
}
########################################################################
sub cmd_show {
########################################################################
my ( $self, @args ) = @_;
my ($command) = $self->get_args;
my %sub_commands = ( 'cloudtrail-events' => \&cmd_cloudtrail_events, );
die sprintf "ERROR: not a valid command. Must be one of: \n\t%s\n", join "\n\t", keys %sub_commands
if !$sub_commands{$command};
return $sub_commands{$command}->($self);
}
########################################################################
sub cmd_service_status {
########################################################################
my ( $self, @args ) = @_;
my $service_name = $self->check_service_name( @args, $self->get_args );
my ( $cluster, $tasks ) = $self->common_args(qw(cluster tasks));
my $cluster_name = $cluster->{name};
$self->verify_service($service_name);
require Text::Wrap;
Text::Wrap->import('wrap');
{
## no critic
no warnings 'once';
$Text::Wrap::columns = 100;
}
my @elems = qw(running_count desired_count status pending_count events task_definition);
my $query = jmespath_mapping 'services[0]' => \@elems;
my $ecs = $self->fetch_ecs;
my $result = $ecs->describe_services(
cluster_name => $cluster_name,
service_name => $service_name,
query => $query,
);
log_die( $self, "ERROR: could not describe service [%s]\n%s", $service_name, $self->get_ecs->get_error )
if !$result;
my ( $running_count, $desired_count, $status, $pending_count, $events, $task_definition_arn )
= @{$result}{@elems};
$pending_count //= q{-};
$status = $self->maybe_color( $status eq 'ACTIVE' ? 'bright_green' : 'bright_yellow' => $status );
my $title = sprintf "Service:[%s]\n", $self->maybe_color( bright_white => $service_name );
$title .= sprintf "Status:[%s] Running:[%s] Pending:[%s] Desired:[%s]\n",
$status,
$self->maybe_color( green => $running_count ),
$self->maybe_color( yellow => $pending_count ),
$self->maybe_color( bright_white => $desired_count );
$title .= sprintf 'Task Definition: [%s]', $self->maybe_color( 'bright_white' => $task_definition_arn );
my @events = grep {defined} @{ $result->{events} }[ 0 .. ( $self->get_max_events - 1 ) ];
my @data = map { { 'Time' => $_->{createdAt}, Event => wrap( q{}, q{}, $_->{message} ) } } @events;
print {*STDOUT} easy_table(
table_options => { headingText => $title, allowANSI => $TRUE },
data => \@data,
columns => [qw(Time Event)],
);
$self->display_task_status($service_name);
return $SUCCESS;
}
########################################################################
sub display_task_status {
########################################################################
my ( $self, $service_name ) = @_;
lib/App/FargateStack.pm view on Meta::CPAN
( $task_name, my $err ) = $self->get_default_service_name($TRUE); # skip arg
if ( $err || !$task_name ) {
if ($err) {
$self->log_error('ERROR: multiple services in configuration.');
}
elsif ( !$task_name ) {
$self->log_error( 'ERROR: %s',
$task_name ? "service: [$task_name] not found in configuration" : 'no service types in configuration' );
}
die sprintf "usage: %s deploy-service service-name\n", $ENV{SCRIPT_NAME};
}
}
if ( !$desired_count || !looks_like_number $desired_count ) {
$desired_count = $tasks->{$task_name}->{desired_count} // 1;
}
$self->log_info('service: checking to see if task and latest image are aligned...');
$self->check_latest_image($task_name);
return $self->build_service( $task_name, $desired_count );
}
########################################################################
sub check_task {
########################################################################
my ( $self, $task_name, $warn ) = @_;
my $level = $warn ? 'warn' : 'die';
my $config = $self->get_config;
return $TRUE
if $task_name && $config->{tasks}->{$task_name};
log_die( $self, 'ERROR: no such task [%s] defined in config', $task_name )
if $level eq 'die';
$self->get_logger->warn( 'WARNING: no such task [%s] defined in config...trying anyway ¯\_(ã)_/¯', $task_name );
return;
}
########################################################################
sub cmd_remove_service {
########################################################################
my ($self) = @_;
my ( $task_name, $err ) = $self->get_default_service_name();
die "usage: %s remove-service task-name\n", $ENV{SCRIPT_NAME}
if !$task_name || $err;
my ( $config, $cluster, $dryrun ) = $self->common_args(qw(config cluster dryrun));
my $cluster_name = $cluster->{name};
$self->verify_service($task_name);
$self->check_task( $task_name, 'warn' );
$self->log_warn( 'remove-service: task [%s] will be deleted...%s', $task_name, $dryrun );
return $SUCCESS
if $dryrun;
my $ecs = $self->fetch_ecs;
my $result = $ecs->delete_service( $cluster->{name}, $task_name );
$ecs->check_result( message => 'ERROR: could not stop service %s', $task_name );
return $SUCCESS;
}
########################################################################
sub verify_service {
########################################################################
my ( $self, $service_name ) = @_;
my ( $cluster, $config ) = $self->common_args(qw(cluster config));
my $cluster_name //= $cluster->{name};
my $ecs = $self->fetch_ecs;
my $services = $ecs->list_services( $cluster_name, 'serviceArns' );
die sprintf "ERROR: could not list services for cluster: [%s]\n%s", $cluster_name, $ecs->get_error
if !$services;
die sprintf "ERROR: no services running in cluster: [%s]\n", $cluster_name
if !@{$services};
die sprintf "ERROR: service [%s] is not running in cluster: [%s]\n", $service_name, $cluster_name
if none { $_ =~ /$service_name/xsm } @{$services};
return;
}
########################################################################
sub get_task_image_digests {
########################################################################
my ( $self, $task_name ) = @_;
my $ecs = $self->fetch_ecs;
my $cluster_name = $self->get_config->{cluster}->{name};
my $task_arns = $ecs->list_tasks( $cluster_name, 'taskArns' );
$ecs->check_result( message => 'ERROR: Could not list tasks for cluster: [%s]', $cluster_name );
my $group = sprintf 'service:%s', $task_name;
my $query = sprintf 'tasks[?group == `%s`].containers[].{imageDigest:imageDigest}[].imageDigest', $task_name;
my $image_digests = $ecs->describe_tasks( $cluster_name, $task_arns, $query );
$ecs->check_result( message => 'ERROR: could not describe tasks for task arns: [%s]', join q{,}, @{$task_arns} );
return $image_digests;
}
########################################################################
sub get_latest_task_definition {
########################################################################
my ( $self, $task_name ) = @_;
my $tasks = $self->get_config->{tasks};
my $task_definition_arn = $tasks->{$task_name};
my $ecs = $self->fetch_ecs;
my $task_definitions = $ecs->list_task_definitions( $task_name, 'taskDefinitionArns' );
$ecs->check_result( message => 'ERROR: could list task definitions for [%s]', $task_name );
my ($latest_task_definition) = sort {
my ($num_a) = $a =~ /:(\d+)$/xsm;
my ($num_b) = $b =~ /:(\d+)$/xsm;
$num_b <=> $num_a
} @{$task_definitions};
my ($latest_task_definition_version) = $latest_task_definition =~ /(:\d+)$/xsm;
my ($task_definition_version) = $task_definition_arn =~ /(:\d+)$/xsm;
return $latest_task_definition,;
}
########################################################################
sub cmd_update_service {
########################################################################
my ( $self, @args ) = @_;
my $service_name = $self->check_service_name( @args, $self->get_args );
my ($cluster) = $self->common_args(qw(cluster));
my $cluster_name = $cluster->{name};
$self->verify_service($service_name);
my $ecs = $self->fetch_ecs;
my $task_definition_arn = $self->get_latest_task_definition($service_name);
my @elems = qw(status running_count desired_count pending_count task_definition);
my $result = $ecs->update_service(
cluster_name => $cluster_name,
service_name => $service_name,
task_definition => basename($task_definition_arn),
query => jmespath_mapping( service => \@elems ),
);
$ecs->check_result( message => 'ERROR: could not update service: [%s]', $service_name );
$self->log_debug( sub { return Dumper( [ result => $result ] ) } );
my @data = {
'Status' => $self->maybe_color( bright_white => $result->{status} ),
'Running Count' => $self->maybe_color( green => $result->{running_count} ),
'Desired Count' => $self->maybe_color( bright_white => $result->{desired_count} ),
'Pending Count' => $self->maybe_color( yellow => $result->{pending_count} ),
};
print {*STDOUT} easy_table(
table_options => {
allowANSI => $TRUE,
headingText => sprintf "Service Status\nTask Definition: %s",
$result->{task_definition}
},
data => \@data,
columns => [ 'Status', 'Running Count', 'Pending Count', 'Desired Count' ]
);
print {*STDOUT} <<'END_OF_NOTE';
* Note that this command will not force redeployment of your services! To force redeployment of your servicce:
app-FargateStack redeploy [service-name]
END_OF_NOTE
return;
}
########################################################################
sub update_task_count {
########################################################################
my ( $self, $task_name, $desired_count ) = @_;
my ( $config, $cluster ) = $self->common_args(qw(config cluster));
my $cluster_name = $cluster->{name};
$self->verify_service($task_name);
my $ecs = $self->get_ecs;
my $result = $ecs->update_service(
cluster_name => $cluster_name,
desired_count => $desired_count,
service_name => $task_name,
);
log_die( $self, "ERROR: could not update service: [%s]\n%s", $task_name, $ecs->get_error )
if !$result;
return $result;
}
########################################################################
sub cmd_start_stop_service {
########################################################################
my ($self) = @_;
my ( $task_name, $count ) = $self->get_args;
if ( looks_like_number $task_name ) {
$count = $task_name;
$task_name = $EMPTY;
}
$task_name = $self->check_service_name($task_name);
my $command = $self->command;
if ( $command eq 'start-service' ) {
$count ||= 1;
}
elsif ( $command eq 'update-service' ) {
}
else {
$count = 0;
}
if ( !$task_name ) {
if ( $count == 0 ) {
die sprintf "usage: %s -c config-name stop-service task-name\n", $ENV{SCRIPT_NAME};
}
die sprintf "usage: %s -c config-name start-service task-name [count]\n", $ENV{SCRIPT_NAME};
}
my $result = $self->update_task_count( $task_name, $count );
sleep 2; # wait a few seconds for status to be updated
return $self->cmd_service_status($task_name);
}
########################################################################
sub cmd_register_task_definition {
########################################################################
my ($self) = @_;
my ( $config, $tasks, $dryrun ) = $self->common_args(qw(config tasks dryrun));
( run in 0.983 second using v1.01-cache-2.11-cpan-13bb782fe5a )