diff --git a/code/ddns-lambda.py b/code/ddns-lambda.py index 5e29838..5d954f6 100755 --- a/code/ddns-lambda.py +++ b/code/ddns-lambda.py @@ -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') @@ -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 != '' @@ -105,7 +107,7 @@ elif DEBUG_LOG_LEVEL == 'CRITICAL': LOGGER.setLevel(logging.CRITICAL) else: - LOGGER.setLevel(logging.INFO) + LOGGER.setLevel(logging.INFO) print('Loading function v{} tf_module_version {}: {}'.format( VERSION, TF_MODULE_VERSION, datetime.datetime.now().time().isoformat())) @@ -199,6 +201,7 @@ 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 @@ -206,10 +209,18 @@ def lambda_handler( 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 @@ -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 @@ -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) @@ -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 @@ -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: @@ -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' @@ -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' @@ -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):