App-FargateStack
view release on metacpan or search on metacpan
lib/App/FargateStack.pm view on Meta::CPAN
}
# more than 1, error or we found just 1
return $tasks[1] ? $EMPTY : $tasks[0];
}
########################################################################
sub cmd_run_task {
########################################################################
my ($self) = @_;
my ( $config, $tasks, $dryrun, $cluster, $security_groups )
= $self->common_args(qw(config tasks dryrun cluster security_groups));
my $task_name = $self->get_default_task_name('task');
die sprintf "usage: %s run-task task-name\n", $ENV{SCRIPT_NAME}
if !$task_name;
my $task = $tasks->{$task_name};
log_die( $self, "ERROR: no such task [%s] defined in config\n", $task_name )
if !$task;
log_die( $self, "ERROR: [%s] is not a task\n", $task_name )
if $task->{type} ne 'task';
my $subnet_id = $self->get_subnet_id;
my $is_public = $FALSE;
if ( !$subnet_id ) {
my @subnets = @{ $self->get_subnets->{private} // [] };
if ( !@subnets ) {
$self->log_warn('run-task: using public subnets is not recommended...');
@subnets = @{ $self->get_subnets->{public} // [] };
}
$subnet_id = $subnets[0];
}
elsif ( any { $subnet_id eq $_ } @{ $self->get_subnets->{public} // [] } ) {
$self->log_error( 'run-task: subnet-id: [%s] is in a public subnet...consider running your jobs in a private subnet',
$subnet_id );
$is_public = $TRUE;
}
elsif ( none { $subnet_id eq $_ } @{ $self->get_subnets->{private} // [] } ) {
log_die( $self, 'subnet: [%s] is not in a public or private subnet in this VPC.', $subnet_id );
}
my $network_configuration = {
awsvpcConfiguration => {
subnets => [$subnet_id],
securityGroups => [ $security_groups->{fargate}->{group_id} ],
assignPublicIp => $is_public ? 'ENABLED' : 'DISABLED',
}
};
# check for latest image...
$self->check_latest_image($task_name);
# this may be null if we are in dryrun mode and the config has not been updated
my $cluster_name
= $dryrun && !$cluster->{name}
? sprintf '%s-cluster', $config->{app}->{name}
: $cluster->{name};
$self->log_warn( 'run-task: cluster: [%s] launching task: [%s] in subnet: [%s]...%s',
$cluster_name, $task_name, $subnet_id, $dryrun );
$self->log_trace( sub { return Dumper( [ awsvpcConfiguration => $network_configuration ] ); } );
return $SUCCESS
if $dryrun;
log_die( $self, 'run-task: cluster has not been created yet...run "apply" first' )
if !$cluster_name;
my $ecs = $self->fetch_ecs;
my $result = $self->get_ecs->run_task(
cluster => $cluster->{name},
task_definition => $task_name,
network_configuration => $network_configuration,
);
log_die( $self, "ERROR: could not run task [%s]\n%s\n", $task_name, $self->get_ecs->get_error )
if !$result;
my @failures = @{ $result->{failures} };
log_die( $self, 'ERROR: task failed to launch: %s', Dumper( \@failures ) )
if @failures;
($tasks) = @{ $result->{tasks} };
my $task_arn = $tasks->{taskArn};
my $should_wait = $self->get_wait ? '(waiting)' : $EMPTY;
$self->log_warn( 'run-task: task [%s] launched. ARN: [%s]...%s', $task_name, $task_arn, $should_wait );
my $poll_limit = $self->get_task_timeout / $DEFAULT_ECS_POLL_TIME;
if ($should_wait) {
my $poll_count = 0;
while ( $poll_count++ < $poll_limit ) {
my ( $status, $stopped_reason, $exit_code ) = $self->get_task_status( $cluster_name, $task_arn );
$self->log_warn( 'run-task: task [%s] status: [%s], exit code:[%s], reason: [%s]',
$task_name, map { $_ // q{-} } ( $status, $exit_code, $stopped_reason ) );
last if $status eq 'STOPPED';
sleep $DEFAULT_ECS_POLL_TIME;
}
my $log_group = $config->{log_group}->{name};
# by convention our log groups are named after our app
lib/App/FargateStack.pm view on Meta::CPAN
########################################################################
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));
my $task_name = $self->get_default_task_name;
my $action = $self->get_skip_register ? 'update-target' : 'register';
log_die( $self, 'usage: %s %s task-name', $action, $ENV{SCRIPT_NAME} )
if !$task_name;
my $task_definition_file = sprintf 'taskdef-%s.json', $task_name;
$self->check_task($task_name);
log_die( $self, "ERROR: no task definition file found for %s\n", $task_name )
if !-s $task_definition_file;
my $task_definition_arn;
my $ecs = $self->fetch_ecs;
if ( !$self->get_skip_register ) {
$self->log_warn( 'register: registering task definition for: [%s]...%s', $task_name, $dryrun );
if ( !$dryrun ) {
my $task_definition = $ecs->register_task_definition($task_definition_file);
$ecs->check_result( message => 'ERROR: register: could not register [%s]\n%s', $task_definition_file );
$self->log_trace( sub { return Dumper( [ task_definition => $task_definition ] ) } );
$task_definition_arn = $task_definition->{taskDefinition}->{taskDefinitionArn};
log_die( $self, 'register: no taskDefinitionArn found? %s', Dumper( [ task_definition => $task_definition ] ) )
if !$task_definition_arn;
$self->log_warn( 'register: registered...[%s]', $task_definition_arn );
$tasks->{$task_name}->{arn} = $task_definition_arn;
my $latest_image = $self->get_latest_image($task_name);
$self->log_info( 'register: updating image digest: [%s]', $latest_image->{imageDigest} );
$tasks->{$task_name}->{image_digest} = $latest_image->{imageDigest};
$self->update_config; # record new task definition arn
}
}
## - events -
if ( $tasks->{$task_name}->{type} eq 'task' ) {
require App::Events;
my $event = $self->fetch_events;
lib/App/FargateStack.pm view on Meta::CPAN
END_OF_ERROR
print {*STDERR} colored( $msg, 'bright_red' );
}
return $self->delete_task_resources($task_name);
}
########################################################################
sub cmd_delete_http_service {
########################################################################
my ($self) = @_;
my $tasks = $self->get_config->{tasks};
my ( $task_name, $err ) = $self->get_default_service_name();
die "usage: $ENV{SCRIPT_NAME} delete-http task-name\n"
if !$task_name || $err;
die "ERROR: [$task_name] is not an http task"
if !$tasks->{$task_name}->{type} =~ /^https?/xsm;
if ( scalar keys %{$tasks} == 1 ) {
my $msg = <<'END_OF_WARNING';
WARNING: This is the only task in your configuration.
- You can stop the http service from running with the "stop-service" command.
- You can delete only the service with the "delete-service" command.
END_OF_WARNING
print {*STDERR} colored( $msg, 'bright_red' );
}
return $self->delete_task_resources($task_name);
}
########################################################################
sub cmd_redeploy {
########################################################################
my ( $self, @args ) = @_;
my $cluster = $self->common_args('cluster');
my $cluster_name = $cluster->{name};
my ( $service_name, $err ) = $self->get_default_service_name;
die sprintf "usage: %s redeploy service-name\n", $ENV{SCRIPT_NAME}
if !$service_name || $err;
my $ecs = $self->get_ecs;
my $result = $ecs->update_service(
cluster_name => $cluster_name,
service_name => $service_name,
force => $TRUE
);
log_die( $self, "ERROR: could not update service: [%s]\n%s", $service_name, $ecs->get_error )
if !$result;
$self->log_info( 'redeploy: successfully updated service: [%s]', $service_name );
return $SUCCESS;
}
########################################################################
sub cmd_reset_history {
########################################################################
my ( $self, @args ) = @_;
$self->fetch_option_defaults($TRUE);
return $SUCCESS;
}
########################################################################
sub fetch_option_defaults {
########################################################################
my ( $self, $reset ) = @_;
my $options = {};
my $defaults_file = '.fargatestack/defaults.json';
if ( -s $defaults_file ) {
$options = slurp_file( $defaults_file, $TRUE );
}
else {
mkdir '.fargatestack';
}
return $self->write_json_file( $defaults_file, {} )
if $reset;
$options->{profile} = $self->get_profile // $options->{profile};
$options->{config} = $self->get_config_name // $options->{config};
$options->{region} = $self->default_region( $options->{region} );
$options->{route53_profile} = $self->get_route53_profile // $options->{route53_profile};
$options->{max_events} = $self->get_max_events // $options->{max_events};
$self->set_profile( $options->{profile} );
$self->set_config_name( $options->{config} );
$self->set_route53_profile( $options->{route53_profile} );
$self->set_max_events( $options->{max_events} );
$self->write_json_file( $defaults_file, $options );
return $options;
}
########################################################################
sub build_section_paths {
########################################################################
my @items = @_; # list of strings like '1:Title'
my %paths;
my @stack;
foreach my $line (@items) {
next if $line !~ /^(\d+):(.*)$/xsm;
( run in 0.632 second using v1.01-cache-2.11-cpan-e1769b4cff6 )