From 751af04ac2b8dfa2b8235310d815efd8e71854b6 Mon Sep 17 00:00:00 2001 From: Andy Date: Sat, 29 Jul 2017 23:02:37 -0700 Subject: [PATCH] Add support for multiple HUB's (one HUB per region) by allowing the tag value of the VGW to specify the HUB region that the VPN connection should be established too. Fixes race condition where whichever regions lambda function is triggered first will pick up the tagged VGW and claim it. --- transit-vpc-poller.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/transit-vpc-poller.py b/transit-vpc-poller.py index 5767704..2188fc8 100644 --- a/transit-vpc-poller.py +++ b/transit-vpc-poller.py @@ -16,13 +16,21 @@ from xml.dom import minidom import ast import logging -import datetime, sys, json, urllib2, urllib, re +import datetime, sys, json, urllib2, urllib, re, os log = logging.getLogger() log.setLevel(logging.INFO) bucket_name='%BUCKET_NAME%' bucket_prefix='%PREFIX%' +# Function checks input region is actually a valid one. Used to determine if HUB_TAG contains a valid region +def isValidRegion(region): + ec2=boto3.client('ec2',region_name='us-east-1') + for validRegion in ec2.describe_regions()['Regions']: + if validRegion['RegionName'] == region: + return True + return False + #VGW tags come in the format of [{"Key": "Tag1", "Value":"Tag1value"},{"Key":"Tag2","Value":"Tag2value"}] #This function converts the array of Key/Value dicts to a single tag dictionary def getTags(vgwTags): @@ -48,7 +56,7 @@ def updateConfigXML(xml, config, vgwTags, account_id, csr_number): #Create status xml block (create = tagged to create spoke, delete = tagged as spoke, but not with the correct spoke tag value) newXml = xmldoc.createElement("status") - if vgwTags[config['HUB_TAG']] == config['HUB_TAG_VALUE']: + if vgwTags[config['HUB_TAG']] == config['HUB_TAG_VALUE'] or isValidRegion(vgwTags[config['HUB_TAG']]): newXml.appendChild(xmldoc.createTextNode("create")) else: newXml.appendChild(xmldoc.createTextNode("delete")) @@ -142,7 +150,10 @@ def lambda_handler(event, context): #Determine if VGW is tagged as a spoke spoke_vgw = False - if vgwTags[config['HUB_TAG']] == config['HUB_TAG_VALUE']: + # Will grab spoke VGW in either of the two conditions (i.e. set spoke_vgw to True) + # 1. Value of HUB_TAG matches HUB_TAG_VALUE (original behaviour) + # 2. Value of HUB_TAG_VALUE matches code for the current execution region. Added to allow for mulit HUBs to exist in different regions + if vgwTags[config['HUB_TAG']] == config['HUB_TAG_VALUE'] or vgwTags[config['HUB_TAG']] == os.environ.get('AWS_DEFAULT_REGION'): spoke_vgw = True #Check to see if the VGW already has Transit VPC VPN Connections @@ -212,8 +223,8 @@ def lambda_handler(event, context): processed_vgw = True sendAnonymousData(config, vgwTags, region_id, 2) - #Need to delete VPN connections if this is no longer a spoke VPC (tagged for spoke, but tag != spoke tag value) but Transit VPC connections exist - if not spoke_vgw and vpn_existing: + # Need to delete VPN connections if this is no longer a spoke VPC (tagged for spoke, but tag != spoke tag value OR tag != a valid region code) but Transit VPC connections exist + if vpn_existing and not spoke_vgw and not isValidRegion(vgwTags[config['HUB_TAG']]): log.info('Found old VGW (%s) with VPN connections to remove.', vgw['VpnGatewayId']) #We need to go through the region's VPN connections to find the ones to delete for vpn in vpns['VpnConnections']: @@ -226,6 +237,12 @@ def lambda_handler(event, context): csrNum = '2' #Need to get VPN configuration to remove from CSR vpn_config=vpn['CustomerGatewayConfiguration'] + ### only delete if the configuration key actually exists in bucket + try: + s3.head_object(Bucket=bucket_name, Key=bucket_prefix+'CSR'+csrNum+'/'+region_id+'-'+vpn['VpnConnectionId']+'.conf') + except: + log.info('Skipping (%s), configuration does not exist (likely belongs to different hub) (', vgw['VpnGatewayId']) + continue #Update VPN configuration XML with transit VPC specific configuration info for this connection vpn_config=updateConfigXML(vpn_config, config, vgwTags, account_id, vpnTags['transitvpc:endpoint']) s3.put_object(