Last active
November 19, 2020 13:27
-
-
Save reidca/c181d2e959ea070bb902073a690a7c22 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import os | |
import os.path | |
import sys | |
import logging | |
from botocore.exceptions import ClientError | |
from str2bool import str2bool | |
from crhelper import CfnResource | |
helper = CfnResource(json_logging=False, log_level='DEBUG', | |
boto_level='CRITICAL') | |
logger = logging.getLogger(__name__) | |
try: | |
# Init code goes here | |
# The code below is used for loading the bundled version of boto rather than the one in the lambda runtime environment | |
envLambdaTaskRoot = os.environ["LAMBDA_TASK_ROOT"] | |
print("LAMBDA_TASK_ROOT env var:" + os.environ["LAMBDA_TASK_ROOT"]) | |
print("sys.path:" + str(sys.path)) | |
sys.path.insert(0, envLambdaTaskRoot+"/NewBotoVersion") | |
print("sys.path:"+str(sys.path)) | |
import botocore | |
import boto3 | |
print("boto3 version:"+boto3.__version__) | |
print("botocore version:"+botocore.__version__) | |
ec2_client = boto3.client('ec2') | |
pass | |
except Exception as e: | |
helper.init_failure(e) | |
def cast_tunnel_options(tunnel_options): | |
# Go through the dictionary and convert any strings that can be numbers to ints and if the item is a list then go through the items in the list doing the same | |
for key in tunnel_options: | |
if isinstance(tunnel_options[key], list): | |
for d in tunnel_options[key]: | |
if isinstance(d, dict): | |
if d["Value"].isnumeric(): | |
d["Value"] = int(d["Value"]) | |
else: | |
if tunnel_options[key].isnumeric(): | |
tunnel_options[key] = int(tunnel_options[key]) | |
return tunnel_options | |
@helper.create | |
@helper.update | |
def update_create(event, context): | |
props = event['ResourceProperties'] | |
kwargs = {} | |
# Mandatory properties | |
if "CustomerGatewayId" in props: | |
kwargs["CustomerGatewayId"] = props["CustomerGatewayId"] | |
if "VpnGatewayId" in props: | |
kwargs["VpnGatewayId"] = props["VpnGatewayId"] | |
if "TransitGatewayId" in props: | |
kwargs["TransitGatewayId"] = props["TransitGatewayId"] | |
# Does resource already exist? If so update instead of create new | |
if event["RequestType"] == "Update": | |
vpn_connection_id = event['PhysicalResourceId'] | |
kwargs["VpnConnectionId"] = vpn_connection_id | |
#Check to see if any of the details are different or whether there is nothing | |
response = ec2_client.describe_vpn_connections( | |
VpnConnectionIds=[vpn_connection_id] | |
) | |
#Assume no work to do | |
update_flag = False | |
current_vpn_connection = response["VpnConnections"][0] | |
if "CustomerGatewayId" in kwargs: | |
if not("CustomerGatewayId" in current_vpn_connection) or (current_vpn_connection["CustomerGatewayId"] != kwargs["CustomerGatewayId"]): | |
update_flag = True | |
else: | |
del kwargs["CustomerGatewayId"] | |
if "VpnGatewayId" in kwargs: | |
if not("VpnGatewayId" in current_vpn_connection) or (current_vpn_connection["VpnGatewayId"] != kwargs["VpnGatewayId"]): | |
update_flag = True | |
else: | |
del kwargs["VpnGatewayId"] | |
if "TransitGatewayId" in kwargs: | |
if not("TransitGatewayId" in current_vpn_connection) or (current_vpn_connection["TransitGatewayId"] != kwargs["TransitGatewayId"]): | |
update_flag = True | |
else: | |
del kwargs["TransitGatewayId"] | |
if update_flag: | |
logger.info( | |
f"Updating VPN connection '{vpn_connection_id}' using parameters {kwargs}") | |
response = ec2_client.modify_vpn_connection(**kwargs) | |
logger.info(f"VPN connection modified successfully'") | |
else: | |
logger.info(f"VPN connection '{vpn_connection_id}' does not require updating") | |
else: | |
# Some properties can only be specified on the create | |
kwargs["Type"] = props["Type"] | |
options = {} | |
if 'StaticRoutesOnly' in props: | |
options["StaticRoutesOnly"] = str2bool(props["StaticRoutesOnly"]) | |
if 'EnableAcceleration' in props: | |
options["EnableAcceleration "] = str2bool( | |
props["EnableAcceleration"]) | |
#Tunnel options can be passed a list (separate options for each tunnel, so we need to call the cast method on each list item) | |
if 'TunnelOptions' in props: | |
options["TunnelOptions"] = list(map(cast_tunnel_options,props["TunnelOptions"])) | |
# If any options have been specified then set the key on the main arguments | |
if options: | |
kwargs["Options"] = options | |
if 'Tags' in props: | |
kwargs["TagSpecifications"] = [ | |
{'ResourceType': 'vpn-connection', 'Tags': props["Tags"]}] | |
logger.info(f"Creating VPN connection with properties {kwargs}") | |
response = ec2_client.create_vpn_connection(**kwargs) | |
vpn_connection_id = response["VpnConnection"]["VpnConnectionId"] | |
logger.info( | |
f"A Vpn connection with id '{vpn_connection_id}' has been created") | |
physical_resource_id = vpn_connection_id | |
response_data = {} | |
response_data["VpnConnectionId"] = vpn_connection_id | |
helper.Data.update(response_data) | |
return physical_resource_id | |
@helper.delete | |
def delete(event, context): | |
""" | |
Place your code to handle Delete events here | |
To return a failure to CloudFormation simply raise an exception, the exception message will be sent to CloudFormation Events. | |
""" | |
vpn_connection_id = event["PhysicalResourceId"] | |
logger.info(f"Deleting Vpn Connection with id '{vpn_connection_id}'") | |
try: | |
response = ec2_client.delete_vpn_connection( | |
VpnConnectionId=vpn_connection_id) | |
except botocore.exceptions.ClientError as error: | |
if error.response['Error']['Code'] == 'InvalidVpnConnectionID.NotFound': | |
logger.warning( | |
f"A Vpn connection with id '{vpn_connection_id}' does not exist") | |
else: | |
raise error | |
def handler(event, context): | |
""" | |
Main handler function, passes off it's work to crhelper's cfn_handler | |
""" | |
helper(event, context) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment