return None # In this block we use the account credentials we got above, to create and cache a client # connection to an AWS service. try: client = boto3.client( service, region_name=region, aws_access_key_id=credentials['AccessKeyId'], aws_secret_access_key=credentials['SecretAccessKey'], aws_session_token=credentials['SessionToken'], config=Config(retries=dict(max_attempts=10))) LOGGER.debug('Obtained fresh client connection.') return client except BaseException: LOGGER.error(f'Unexpected error: {sys.exc_info()[1]}', exc_info=True) def tag_resource(client: Any, resource: str, tags: Mapping, dryrun: bool = False) -> None: """ Tags an AWS resource with the provided tags. Example Usage: ``` ec2_client = aws_client(account_id, 'ec2', region) tags = {'peerd_support': '*****@*****.**', 'peerd_datetime': str(datetime.now())} tag_resource(ec2_client, peerding_id, tags) ``` :param client: An AWS boto3 client connection to an AWS resource :type client: boto3 client
} for key, value in local_tags.items(): tags[key] = value for key, value in remote_tags.items(): tags[key] = value tag_resource(ec2_client, peering_id, tags, dryrun=dryrun) # Add the peering to the list of peerings that we will need to accept peering_descriptor_copy = deepcopy(peering_descriptor) peering_descriptor_copy[1]['peering_id'] = peering_id peering_descriptor_copy[1]['tags'] = tags pending_acceptance_peerings.append(peering_descriptor_copy) except BaseException: LOGGER.error("Unexpected error: %s", sys.exc_info()[1], exc_info=True) continue LOGGER.info( f"Successfully created peering request {peering_id} between {account_id} {vpc_id} " f"{region} and {remote_account_id} {remote_vpc_id} {remote_region}" ) # Return the list of peerings that need to be accepted. return pending_acceptance_peerings def accept_vpc_peerings(target_peerings: list, metadata: dict, dryrun: bool): """ Loops through a list of peerings, with existing peering id, to accept them.
def accept_vpc_peerings(target_peerings: list, metadata: dict, dryrun: bool): """ Loops through a list of peerings, with existing peering id, to accept them. Requests, accepts and tags them. Repairs any half open peerings. Example target_peerings: ``` [ [ { "account_id": "415432961280", "peering_id": "pcx-41u5h345h2", "vpc_id": "vpc-e08fb484", "region": "ap-southeast-2", "cidr_overrides": [ "10.53.101.0/27" ], "peering_tags": [ { "peerd_az_affinity": "0" } ] }, { "account_id": 415432961280, "peering_id": "pcx-41u5h345h2", "vpc_id": "vpc-7a83b81e", "region": "ap-southeast-2" } ] ] ``` :param target_peerings: A list of lists representing the requester and accepter for each peering. :type target_peerings: list :param metadata: A dictionary with the environment, owner, etc for tagging :type metadata: list """ for peering_descriptor in target_peerings: # Unpack some common variables account_id = peering_descriptor[0]['account_id'] vpc_id = peering_descriptor[0]['vpc_id'] region = peering_descriptor[0]['region'] local_tags = peering_descriptor[0].get('peering_tags', {}) remote_account_id = peering_descriptor[1]['account_id'] remote_vpc_id = peering_descriptor[1]['vpc_id'] remote_region = peering_descriptor[1]['region'] remote_tags = peering_descriptor[1].get('peering_tags', {}) peering_id = peering_descriptor[1]['peering_id'] tags = peering_descriptor[1]['tags'] try: # Accept the VPC Peering LOGGER.info( f"Accepting peering request {peering_id} between {account_id} {vpc_id} {region} and " f"{remote_account_id} {remote_vpc_id} {remote_region}") ec2_client = aws_client(remote_account_id, 'ec2', remote_region) # Wait until the peering exists # The AWS API is eventually consistent and we need to wait. LOGGER.info(f'Waiting for peering to exist...') ec2_client.get_waiter('vpc_peering_connection_exists').wait( VpcPeeringConnectionIds=[peering_id], WaiterConfig={'Delay': 5}) # Tag the VPC Peering tags['Name'] = f'peerd peering to {account_id} {vpc_id} {region}' tags['peerd_role'] = 'accepter' tag_resource(ec2_client, peering_id, tags, dryrun=dryrun) # Accept the peering try: ec2_client.accept_vpc_peering_connection( VpcPeeringConnectionId=peering_id, DryRun=dryrun) except ClientError as err: if err.response['Error']['Code'] == 'DryRunOperation': continue raise except BaseException: LOGGER.error("Unexpected error: %s", sys.exc_info()[1], exc_info=True) continue LOGGER.info( f"Successfully accepted peering {peering_id} between {account_id} {vpc_id} " f"{region} and {remote_account_id} {remote_vpc_id} {remote_region}" )
# We must wait for active state to install routes, otherwise the peering will be ignored. # Note, usually this step takes a few seconds, but can sometimes take up to a minute or two in rare cases. while not ec2_client.describe_vpc_peering_connections( Filters=[{ 'Name': 'status-code', 'Values': ['active'] }, { 'Name': 'vpc-peering-connection-id', 'Values': [peerding_id] }])['VpcPeeringConnections']: LOGGER.info( f'Waiting for peering {peerding_id} to become active...') sleep(5) except BaseException: LOGGER.error("Unexpected error: %s", sys.exc_info()[1], exc_info=True) continue LOGGER.info( f"Successfully created peering {peerding_id} between {account_id} {vpc_id} " f"{region} and {remote_account_id} {remote_vpc_id} {remote_region}" ) def update_route_tables(target_peerings: list, metadata: dict, dryrun: bool): """ Loops through a list of peerings and updates the route tables on each side. Example target_peerings: ```