App-FargateStack
view release on metacpan or search on metacpan
lib/App/FargateStack/Builder/Utils.pm view on Meta::CPAN
package App::FargateStack::Builder::Utils;
use strict;
use warnings;
BEGIN {
use Log::Log4perl;
# this register ths package as a wrapper class helps resolve
# callstack issue when covering Log4perl methods.
Log::Log4perl->wrapper_register(__PACKAGE__);
}
use Carp;
use Data::Dumper;
use Date::Parse qw(str2time);
use English qw(no_match_vars);
use JSON;
use List::Util qw(any none);
use Scalar::Util qw(blessed reftype refaddr looks_like_number);
use Term::ANSIColor;
use Time::Piece;
use Time::HiRes qw(time);
use Text::Diff;
use JSON;
use Role::Tiny;
use parent qw(Exporter Class::Accessor::Fast);
__PACKAGE__->follow_best_practice;
__PACKAGE__->mk_accessors(qw(_var_pool));
our @EXPORT = qw(
ToCamelCase
choose
common_args
confirm
display_diffs
dmp
elapsed_time
jmespath_mapping
log_die
normalize_name
normalize_time_range
normalize_timestamp
toCamelCase
slurp_file
write_json_file
fetch_acm
fetch_cloudtrail
fetch_application_autoscaling
fetch_ecr
fetch_ec2
fetch_ecs
fetch_ecr
fetch_elbv2
fetch_events
fetch_efs
fetch_iam
fetch_logs
fetch_secrets
fetch_sts
fetch_route53
fetch_cli_api
fetch_wafv2
);
########################################################################
sub fetch_application_autoscaling { return shift->fetch_cli_api( 'Application-Autoscaling', @_ ); }
sub fetch_acm { return shift->fetch_cli_api( 'ACM', @_ ); }
sub fetch_cloudtrail { return shift->fetch_cli_api( 'CloudTrail', @_ ); }
sub fetch_iam { return shift->fetch_cli_api( 'IAM', @_ ); }
sub fetch_logs { return shift->fetch_cli_api( 'Logs', @_ ); }
sub fetch_efs { return shift->fetch_cli_api( 'EFS', @_ ); }
sub fetch_ecs { return shift->fetch_cli_api( 'ECS', @_ ); }
sub fetch_ec2 { return shift->fetch_cli_api( 'EC2', @_ ); }
sub fetch_ecr { return shift->fetch_cli_api( 'ECR', @_ ); }
sub fetch_events { return shift->fetch_cli_api( 'Events', @_ ); }
sub fetch_sts { return shift->fetch_cli_api( 'STS', @_ ); }
lib/App/FargateStack/Builder/Utils.pm view on Meta::CPAN
return $json ? decode_json($content) : $content;
}
########################################################################
sub section_break { return shift->get_logger->info( q{-} x 80 ) }
########################################################################
########################################################################
sub normalize_name {
########################################################################
my ( $self, $name ) = @_;
return join q{}, map {ucfirst} split /[_-]+/xsm, $name;
}
########################################################################
sub abbrev {
########################################################################
my ( $text, $len, $offset ) = @_;
$offset //= 0;
$text //= q{};
return sprintf '%s...', substr $text, $offset, $len;
}
########################################################################
sub is_service_running {
########################################################################
my ( $self, $task_name ) = @_;
my ( $config, $cluster ) = $self->common_args(qw(config cluster));
my $cluster_name = $cluster->{name};
my $ecs = $self->fetch_ecs;
my $services = $ecs->list_services( $cluster_name, 'serviceArns' );
croak sprintf "ERROR: could not list services for: [%s]\n%s", $cluster_name, $ecs->get_error
if !$services;
return
if none {/\/$task_name/xsm} @{$services};
my $status = $ecs->describe_services(
cluster_name => $cluster_name,
service_name => $task_name,
query => 'services[0].runningCount'
);
croak sprintf "ERROR: could not describe services for: [%s/%s]\n%s", $cluster_name, $task_name, $ecs->get_error
if !defined $status;
return $status;
}
########################################################################
sub _log {
########################################################################
my ( $logger, $level, @args ) = @_;
# If first arg looks like a sprintf format string AND we have more args, call sprintf
if ( @args > 1 && $args[0] =~ /%/xsm ) {
return $logger->$level( sprintf shift(@args), @args );
}
else {
return $logger->$level(@args);
}
}
sub log_info { return _log( shift->get_logger, 'info', @_ ) }
sub log_debug { return _log( shift->get_logger, 'debug', @_ ) }
sub log_warn { return _log( shift->get_logger, 'warn', @_ ) }
sub log_error { return _log( shift->get_logger, 'error', @_ ) }
sub log_die { _log( shift->get_logger, 'error', @_ ); die q{}; }
sub log_trace { return _log( shift->get_logger, 'trace', @_ ) }
sub log_fatal { return _log( shift->get_logger, 'fatal', @_ ) }
########################################################################
sub normalize_timestamp {
########################################################################
my ($ts) = @_;
return
if !$ts;
# Already epoch?
return int $ts if $ts =~ /^\d{10}$/xsm; # seconds
return int $ts / 1000 if $ts =~ /^\d{13}$/xsm; # millis
my $s = "$ts";
# Common cleanups:
$s =~ s/,//xsmg; # "Aug 12, 2025, 4:55:04 PM" -> "Aug 12 2025 4:55:04 PM"
$s =~ s/Z$/+0000/xsm; # ISO8601Z -> explicit offset
$s =~ s/([+\-]\d\d):(\d\d)$/$1$2/xsm; # "+05:30" -> "+0530"
$s =~ s/[.]\d+(?=(?:Z|[+\-]\d\d:?\d\d)$)//xsm; # strip fractional seconds if present
# Some services append " UTC" or similarâstrip trailing timezone words
$s =~ s/\s+UTC$//xsmi;
my $epoch = str2time($s);
die "unrecognized timestamp: [$ts]"
if !defined $epoch;
return int $epoch;
}
use Readonly;
Readonly::Scalar our $SEC_PER_MIN => 60;
Readonly::Scalar our $SEC_PER_HOUR => 60 * $SEC_PER_MIN;
Readonly::Scalar our $SEC_PER_DAY => 24 * $SEC_PER_HOUR;
########################################################################
sub normalize_time_range {
########################################################################
my ( $start, $end ) = @_;
return
if !$start;
( run in 0.797 second using v1.01-cache-2.11-cpan-39bf76dae61 )