Skip to content

Version 0.2.1 - Added SNS logic and additional SNS publish statement #17

Merged
merged 2 commits into from
Mar 10, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 63 additions & 15 deletions code/ddns-lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
LOGGER = logging.getLogger()
ACCOUNT = None
REGION = None
VERSION = '0.2.0'
VERSION = '0.2.1'

# Read Env variables
DEBUG_LOG_LEVEL = os.environ.get('DebugLogLevel', 'INFO')
Expand All @@ -85,6 +85,8 @@
DNS_RR_TTL = 60 if DNS_RR_TTL == 0 else DNS_RR_TTL
TF_MODULE_VERSION = os.environ.get('tf_module_version', '(unknown)')
MAX_API_RETRY = int(os.environ.get('MaxApiRetry', '10'))

# for SNS topic
SNS_TOPIC_ARN = os.environ.get('SnsTopicArn', '')
SNS_ENABLE = (os.environ.get('SnsEnable', 'False').lower() in [
'yes', 'y', 'true', '1']) and SNS_TOPIC_ARN != ''
Expand Down Expand Up @@ -199,17 +201,26 @@ def lambda_handler(
"""
LOGGER.info("event: %s", str(event) + lineno())
LOGGER.info("context: %s", str(context) + lineno())
LOGGER.info("Sns Topic Mode: %s, sending to %s", str(SNS_ENABLE), SNS_TOPIC_ARN)

caller_response = []
# Checking to make sure there is a dynamodb table named in the Env Variable
tables = list_tables(dynamodb_client)

LOGGER.info("tables: %s", str(tables))
if DDBNAME in tables['TableNames']:
LOGGER.info('DynamoDB table already exists')
LOGGER.info('DynamoDB table already exists: %s', DDBNAME)
else:
LOGGER.info('DynamoDB table does not exist, exiting function: %s', DDBNAME)
return None
LOGGER.error('DynamoDB table does not exist, exiting function: %s', DDBNAME)
caller_response.append('DynamoDB table does not exist, exiting function: ' + DDBNAME)
if SNS_ENABLE:
sns_msg = {}
sns_msg['instance_id'] = event['detail']['instance-id']
sns_msg['account_id'] = get_caller_account_id()
sns_msg['region'] = event['region']
sns_msg['message'] = 'DynamoDB table does not exist: ' + DDBNAME
publish_to_sns(sns_client, json.dumps(sns_msg))
return caller_response

# Set variables
# Get the state from the Event stream
Expand Down Expand Up @@ -325,8 +336,19 @@ def lambda_handler(
LOGGER.debug("subnet_mask: %s", str(subnet_mask) + lineno())
reversed_ip_address = reverse_list(private_ip)

if reversed_ip_address == None:
LOGGER.error("Error in getting reverse IP address for: %s", str(private_ip) + lineno())
caller_response.append("Error in getting reverse IP address for: " + str(private_ip))
return caller_response

reversed_domain_prefix = get_reversed_domain_prefix(subnet_mask, private_ip)
reversed_domain_prefix = reverse_list(reversed_domain_prefix)

if reversed_domain_prefix == None:
LOGGER.error("Error in getting reverse domain prefix for: %s", str(private_ip) + lineno())
caller_response.append("Error in getting reverse domain prefix for: " + str(private_ip))
return caller_response

LOGGER.debug("reversed_domain_prefix is: %s",
str(reversed_domain_prefix) + lineno())
# Set the reverse lookup zone
Expand All @@ -341,14 +363,34 @@ def lambda_handler(
if is_dns_hostnames_enabled(compute, vpc_id):
LOGGER.debug("DNS hostnames enabled for %s", str(vpc_id) + lineno())
else:
LOGGER.debug(
"DNS hostnames disabled for %s. You have to enable DNS hostnames to use Route 53 private hosted zones. %s", vpc_id, lineno())
LOGGER.error("DNS hostnames disabled for %s. You have to enable DNS hostnames to use Route 53 private hosted zones. %s", vpc_id, lineno())
caller_response.append("You have to enable DNS hostnames to use Route 53 private hosted zones. DNS hostnames disabled for " + vpc_id)
if SNS_ENABLE:
sns_msg = {}
sns_msg['instance_id'] = instance_id
sns_msg['account_id'] = account_id
sns_msg['region'] = region
sns_msg['client'] = 'ec2'
sns_msg['boto3_method'] = 'describe_vpc_attribute'
sns_msg['message'] = "You have to enable DNS hostnames to use Route 53 private hosted zones. DNS hostnames disabled for " + vpc_id
publish_to_sns(sns_client, json.dumps(sns_msg))
return caller_response

if is_dns_support_enabled(compute, vpc_id):
LOGGER.debug("DNS support enabled for %s", str(vpc_id) + lineno())
else:
LOGGER.debug("DNS support disabled for %s. You have to enabled DNS support to use Route 53 private hosted zones. %s", str(
vpc_id), lineno())
exit()
LOGGER.error("DNS support disabled for %s. You have to enabled DNS support to use Route 53 private hosted zones. %s", vpc_id, lineno())
caller_response.append("You have to enabled DNS support to use Route 53 private hosted zones. DNS support disabled for " + vpc_id)
if SNS_ENABLE:
sns_msg = {}
sns_msg['instance_id'] = instance_id
sns_msg['account_id'] = account_id
sns_msg['region'] = region
sns_msg['client'] = 'ec2'
sns_msg['boto3_method'] = 'describe_vpc_attribute'
sns_msg['message'] = "You have to enabled DNS support to use Route 53 private hosted zones. DNS support disabled for " + vpc_id
publish_to_sns(sns_client, json.dumps(sns_msg))
return caller_response

# These are collections of zones in Route 53.
hosted_zones = new_list_hosted_zones(route53, instance_id)
Expand Down Expand Up @@ -431,14 +473,17 @@ def lambda_handler(
except BaseException as err:
LOGGER.error("instance: %s, No DHCP option set assigned to this VPC %s\n",
instance_id, str(err) + lineno())
caller_response.append('No DHCP option set assigned to this VPC %s' + vpc_id)
if SNS_ENABLE:
sns_msg = {}
sns_msg['instance_id'] = instance_id
sns_msg['account_id'] = account_id
sns_msg['region'] = region
sns_msg['client'] = 'ec2'
sns_msg['boto3_method'] = 'describe_vpcs'
sns_msg['message'] = 'No DHCP option set assigned to this VPC: ' + vpc_id
publish_to_sns(get_sns_client(), json.dumps(sns_msg))
exit()
publish_to_sns(sns_client, json.dumps(sns_msg))
return caller_response

# Look to see whether there's a DHCP option set assigned to
# the VPC. Obtain the zone name, and check if there is a Private Hosted Zone
Expand Down Expand Up @@ -824,7 +869,6 @@ def lambda_handler(
LOGGER.error("instance: %s, unexpected error. %s\n",
instance_id, str(err) + lineno())

# elif state == 'terminated':
else: # not running so delete the records
# delete A record
try:
Expand Down Expand Up @@ -1590,6 +1634,7 @@ def new_change_resource_recordset(client, instance_id, zone_id, host_name, hoste
try:
sns_msg = {}
sns_msg['instance_id'] = instance_id
sns_msg['account_id'] = get_caller_account_id()
sns_msg['client'] = 'route53'
sns_msg['boto3_method'] = 'change_resource_record_sets'
sns_msg['message'] = 'change_resource_record_sets could not UPSERT record'
Expand Down Expand Up @@ -1901,6 +1946,7 @@ def new_delete_resource_record(client, instance_id, zone_id, host_name, hosted_z
try:
sns_msg = {}
sns_msg['instance_id'] = instance_id
sns_msg['account_id'] = get_caller_account_id()
sns_msg['client'] = 'route53'
sns_msg['boto3_method'] = 'change_resource_record_sets'
sns_msg['message'] = 'change_resource_record_sets could not DELETE record'
Expand Down Expand Up @@ -2117,10 +2163,12 @@ def reverse_list(ip_list):
LOGGER.debug("returning: %s", str(reversed_list) + lineno())
return reversed_list

LOGGER.info('Not a valid ip')
exit()
LOGGER.error('Not a valid ip. %s', lineno())
return None

except:
LOGGER.info("unexpected error. %s\n", str(sys.exc_info()[0]) + lineno())
LOGGER.error("unexpected error. %s\n", str(sys.exc_info()[0]) + lineno())
return None


def get_reversed_domain_prefix(subnet_mask, private_ip):
Expand Down