"""Lambda trigger ECS tasks module.""" import boto3 from lambdacommon.common_config import logger import sentry_sdk from sentry_sdk.integrations.aws_lambda import AwsLambdaIntegration import config sentry_sdk.init( dsn=config.SENTRY_DSN, integrations=[AwsLambdaIntegration()], traces_sample_rate=1.0, ) ec2_client = boto3.client('ec2', region_name='us-east-1') ecs_client = boto3.client('ecs', region_name='us-east-1') def get_vpc_id(): """ Get VPC corresponding to environment. Raises: SystemExit: If VPC cannot be found Returns: str: ID of VPC """ response = ec2_client.describe_vpcs( Filters=[ { 'Name': 'tag:Name', 'Values': [ 'backup-terraform-aws-vpc', ] }, ], ) if response['Vpcs']: vpc_id = response['Vpcs'][0]['VpcId'] return vpc_id else: logger.info('VPC named {} not found'.format( 'backup-terraform-aws-vpc')) def get_security_group(vpc_id): """ Returns security group corresponding to service. Args: vpc_id (string): ID of VPC for use in lookup filter Raises: SystemExit: If security group cannot be found Returns: str: ID of security group for service """ response = ec2_client.describe_security_groups( Filters=[ { 'Name': 'group-name', 'Values': [ config.SECURITY_GROUP_NAME, ] }, { 'Name': 'vpc-id', 'Values': [ vpc_id, ] }, ], ) if response['SecurityGroups']: security_group_id = response['SecurityGroups'][0]['GroupId'] return security_group_id else: logger.info('Security group named {} not found'.format( config.SECURITY_GROUP_NAME)) def get_subnets(vpc_id): """ Returns subnet IDs with most available IP addresses. Args: vpc_id (string): ID of VPC for use in lookup filter Raises: SystemExit: If subnets cannot be found Returns: list: IDs of subnets """ response = ec2_client.describe_subnets( Filters=[ { 'Name': 'tag:Name', 'Values': [ '*private*', ] }, { 'Name': 'tag:tier', 'Values': [ 'private', ] }, { 'Name': 'vpc-id', 'Values': [ vpc_id, ] }, ], ) if response['Subnets']: sorted_subnets = sorted( response['Subnets'], key=lambda k: k['AvailableIpAddressCount'], reverse=True ) subnet_ids = [subnet['SubnetId'] for subnet in sorted_subnets] return subnet_ids[0:2] else: logger.info('No subnets found in VPC ID {}'.format(vpc_id)) def handler(event, context): """Lambda entry point.""" account_ids = config.ACCOUNT_IDS_TO_BACKUP for account_id in account_ids: try: logger.info(f'ECS task for account {account_id} will run') ecs_client.run_task( cluster='backup-orcd-secrets-manager-secrets', count=1, launchType='FARGATE', networkConfiguration={ 'awsvpcConfiguration': { 'subnets': get_subnets(get_vpc_id()), 'securityGroups': [ get_security_group(get_vpc_id()) ], 'assignPublicIp': 'DISABLED' } }, overrides={ 'containerOverrides': [ { 'name': config.SERVICE_NAME, 'environment': [ { 'name': 'ACCOUNT_ID_TO_BACKUP', 'value': f'{account_id}' }, ] }] }, tags=[ { 'key': 'environment', 'value': config.ENVIRONMENT }, { 'key': 'service_name', 'value': 'backup-orcd-secrets-manager-secrets' }, ], # Always run the latest task definition taskDefinition='backup-orcd-secrets-manager-secrets' ) logger.info(f'ECS task for account {account_id} started') except Exception as error: logger.exception(str(error)) sentry_sdk.capture_exception(error)