App-FargateStack

 view release on metacpan or  search on metacpan

lib/App/EC2.pm  view on Meta::CPAN

  )
);

########################################################################
sub new {
########################################################################
  my ( $class, @args ) = @_;

  my $self = $class->SUPER::new(@args);

  if ( !$self->get_vpc_id ) {
    my @eligible_vpcs = $self->find_eligible_vpcs;
    $self->get_logger->info( sprintf 'eligible VPCS: [%s]', join q{,}, @eligible_vpcs );

    croak 'ERROR: could not find a Fargate-compatible VPC'
      if !@eligible_vpcs;

    croak sprintf "ERROR: found more than one Fargate-compatible VPC:\n%s", join "\n  - ", q{}, @eligible_vpcs
      if @eligible_vpcs > 1;

    $self->get_logger->warn( sprintf 'WARNING: no vpc_id set in config, using compatible VPC: [%s]', $eligible_vpcs[0] );

    $self->set_vpc_id( $eligible_vpcs[0] );
  }

  my $subnets = $self->get_subnets;
  my $vpc_id  = $self->get_vpc_id;

  # if the caller did not send any subnets, find all usable public and
  # private subnets
  if ( !$subnets ) {
    my $result = $self->describe_subnets( $vpc_id, 'Subnets' );

    croak sprintf "ERROR: there are no subnets in %s\n", $vpc_id
      if !@{$result};

    $subnets = $self->categorize_subnets;  # find private, public subnets
    $self->set_subnets($subnets);
  }
  else {
    my $usable_subnets = $self->categorize_subnets;

    my @all_subnets = map { @{ $usable_subnets->{$_} || [] } } qw(public private);

    $self->get_logger->debug(
      sub {
        return Dumper(
          [ all_subnets    => \@all_subnets,
            usable_subnets => $usable_subnets,
            subnets        => $subnets,
          ]
        );
      }
    );

    my $warning = <<'END_OF_WARNING';
WARNING: %s is not in the list of subnets with a route to the internet.

Tasks in private subnets require either:
- A NAT gateway (for general internet access), or
- Properly configured VPC endpoints for ECR, S3, STS, Logs, etc.

Without one of these, your task may fail to start or access required services.
END_OF_WARNING

    foreach my $type (qw(public private)) {
      foreach my $id ( @{ $subnets->{$type} || [] } ) {
        next if any { $_ eq $id } @all_subnets;
        $self->get_logger->warn( sprintf $warning, $id );
      }
    }
  }

  return $self;
}

########################################################################
sub find_eligible_vpcs {
########################################################################
  my ($self) = @_;

  my $result = $self->describe_internet_gateways('InternetGateways[].Attachments[]');

  my @vpcs_with_igw = map { $_->{VpcId} } @{ $result || [] };
  my @vpcs_with_natgw;

  my $query = 'NatGateways[?State==`available`][{VpcId: VpcId}][].VpcId';

  foreach my $vpc_id (@vpcs_with_igw) {
    my $gateways = $self->describe_nat_gateways( vpc_id => $vpc_id, query => $query );
    push @vpcs_with_natgw, @{$gateways};
  }

  return uniq @vpcs_with_natgw, @vpcs_with_igw;
}

########################################################################
sub describe_internet_gateways {
########################################################################
  my ( $self, $query ) = @_;

  return $self->command( 'describe-internet-gateways' => [ $query ? ( '--query' => $query ) : () ] );
}

########################################################################
sub find_security_group_name {
########################################################################
  my ( $self, $group_id ) = @_;

  my $query = 'SecurityGroups[].GroupName';

  return $self->command(
    'describe-security-groups' => [
      '--group-ids' => $group_id,
      '--output'    => 'text',
      '--query'     => $query,
    ]
  );
}

########################################################################



( run in 0.816 second using v1.01-cache-2.11-cpan-524268b4103 )