diff --git a/code/ddns-lambda.py b/code/ddns-lambda.py index 9e8bd49..e8ba0f5 100755 --- a/code/ddns-lambda.py +++ b/code/ddns-lambda.py @@ -62,7 +62,7 @@ LOGGER = logging.getLogger() ACCOUNT = None REGION = None -VERSION = '0.0.7' +VERSION = '0.0.8' # Adjust the logging level [logging.INFO, logging.DEBUG, logging.WARNING, etc] LOGGER.setLevel(logging.DEBUG) @@ -76,7 +76,7 @@ DNS_RR_TTL = int(os.environ.get('DNS_RR_TimeToLive', '60')) DNS_RR_TTL = 60 if DNS_RR_TTL == 0 else DNS_RR_TTL -print('Loading function v%s: %s'.format( +print('Loading function v{}: {}'.format( VERSION, datetime.datetime.now().time().isoformat())) @@ -87,6 +87,7 @@ def lineno(): # pragma: no cover """ return str(' - line number: ' + str(inspect.currentframe().f_back.f_lineno)) + def get_route53_client(): """ Get route53 client @@ -272,7 +273,7 @@ def lambda_handler( # Check to see whether a reverse lookup zone for the instance # already exists. If it does, check to see whether - # the reverse lookup zone is associated with the instance's VPC. + # the reverse lookup zone is associated with the instance's VPC. LOGGER.info("reversed_lookup_zone: %s", str(reversed_lookup_zone) + lineno()) reverse_zone = None for record in hosted_zones['HostedZones']: @@ -328,7 +329,7 @@ def lambda_handler( # the VPC. Obtain the zone name, and check if there is a Private Hosted Zone # associated with the VPC. If so, it will set the zone name to be used later. has_dhcp_dns_zone_associated_vpc = False - + for configuration in dhcp_configurations: LOGGER.debug("configuration: %s", str(configuration) + lineno()) LOGGER.debug("private hosted zones: %s", str( @@ -343,13 +344,13 @@ def lambda_handler( LOGGER.debug("Private_hosted_zone_id: %s", str( private_hosted_zone_id) + lineno()) private_hosted_zone_properties = get_hosted_zone_properties( - route53, - private_hosted_zone_id - ) + route53, + private_hosted_zone_id + ) LOGGER.debug("private_hosted_zone_properties:" " %s", str(private_hosted_zone_properties) + lineno()) - + has_dhcp_dns_zone_associated_vpc = True LOGGER.debug("iterating through tags %s", lineno()) @@ -365,16 +366,17 @@ def lambda_handler( LOGGER.debug("#### tag: %s", str(tag) + lineno()) if tag.get('Key').lstrip().lower() == TAGKEY_ZONE.lower(): - LOGGER.debug("Zone Tag key: %s", tag.get('Key') + lineno()) + LOGGER.debug("Zone Tag key: %s", tag.get('Key') + lineno()) custom_zone_name = tag.get('Value').lstrip().lower() - if custom_zone_name[-1] != '.': # add a trailing period if it does not have it. + # add a trailing period if it does not have it. + if custom_zone_name[-1] != '.': custom_zone_name = custom_zone_name + '.' # check if the zone is PHZ VPC associated if custom_zone_name in private_hosted_zone_collection: LOGGER.debug("Private zone found: %s", - str(custom_zone_name) + lineno()) + str(custom_zone_name) + lineno()) zone_tag_hosted_zone_name = custom_zone_name LOGGER.debug("zone_tag_hosted_zone_name: %s", str( @@ -383,20 +385,20 @@ def lambda_handler( has_valid_zone_tag = True else: LOGGER.debug("Private zone NOT found: %s", - str(custom_zone_name) + lineno()) + str(custom_zone_name) + lineno()) elif tag.get('Key').lstrip().lower() == TAGKEY_CNAME.lower(): LOGGER.debug("CNAME Tag key: %s", tag.get('Key') + lineno()) if is_valid_hostname(tag.get('Value')): - + LOGGER.debug("CNAME hostname of %s is valid %s", str(tag.get('Value')), lineno()) - + # convert the cname value to lower case and strip whitespace and newline characters icname = tag.get('Value').lstrip().lower() - if icname[-1] != '.': # add a trailing period if it does not have it. + if icname[-1] != '.': # add a trailing period if it does not have it. icname = icname + '.' LOGGER.debug("icname: %s", str(icname) + lineno()) @@ -417,12 +419,12 @@ def lambda_handler( # check if the zone is PHZ VPC associated if cname_domain_suffix.lower() in private_hosted_zone_collection: LOGGER.debug("Private zone found: %s", - str(tag.get('Value')) + lineno()) + str(tag.get('Value')) + lineno()) has_valid_cname_tag = True else: LOGGER.debug("cname domain is not associated with vpc: %s", - cname_domain_suffix + lineno()) + cname_domain_suffix + lineno()) elif tag.get('Key').lstrip().lower() == TAGKEY_HOSTNAME.lower(): LOGGER.debug("Custom Hostname Tag key: %s", tag.get('Key') + lineno()) @@ -452,66 +454,70 @@ def lambda_handler( # convert the hostname value to lower case and strip whitespace and newline characters name_value = tag.get('Value').lstrip().lower() - if name_value[-1] != '.': # add a trailing period if it does not have it. + # add a trailing period if it does not have it. + if name_value[-1] != '.': name_value = name_value + '.' LOGGER.debug("Name: %s", str(name_value) + lineno()) - + # Gets the host and the zone name (split up based) name_host = name_value.split('.')[0] LOGGER.debug("name_host: %s", str( - name_host) + lineno()) + name_host) + lineno()) name_domain_suffix = name_value[name_value.find('.') + 1:] LOGGER.debug("name_domain_suffix: %s", str( - name_domain_suffix) + lineno()) - + name_domain_suffix) + lineno()) + # check if the zone name == dhcp zone if name_domain_suffix == private_hosted_zone_name: - LOGGER.debug("name_domain_suffix is the same as DHCP dns: %s", str(name_domain_suffix) + lineno()) + LOGGER.debug("name_domain_suffix is the same as DHCP dns: %s", str( + name_domain_suffix) + lineno()) has_valid_Name_tag = True else: - LOGGER.debug("name_domain_suffix is NOT the same as DHCP dns: %s", str(name_domain_suffix) + lineno()) + LOGGER.debug("name_domain_suffix is NOT the same as DHCP dns: %s", str( + name_domain_suffix) + lineno()) else: LOGGER.debug("Name of %s is invalid %s", str(tag.get('Value')), lineno()) - else: - LOGGER.debug("Skipping Tag key: %s", tag.get('Key') + lineno()) + else: + LOGGER.debug("Skipping Tag key: %s", tag.get('Key') + lineno()) # determine correct A/PTR record to be created based upon the boolean values from the tags above - if has_valid_hostname_tag and has_valid_zone_tag: - LOGGER.info("custom hostname tag and custom zone tag valid.") - final_private_hostname = custom_host_name + if has_valid_hostname_tag and has_valid_zone_tag: + LOGGER.info("custom hostname tag and custom zone tag valid.") + final_private_hostname = custom_host_name final_hosted_zone_name = zone_tag_hosted_zone_name - elif has_valid_hostname_tag and not (has_valid_zone_tag) and has_dhcp_dns_zone_associated_vpc: #3 - LOGGER.info("custom hostname valid only.") - final_private_hostname = custom_host_name + elif has_valid_hostname_tag and not (has_valid_zone_tag) and has_dhcp_dns_zone_associated_vpc: # 3 + LOGGER.info("custom hostname valid only.") + final_private_hostname = custom_host_name final_hosted_zone_name = private_hosted_zone_name elif has_valid_Name_tag and has_dhcp_dns_zone_associated_vpc: - LOGGER.info("Name tag valid.") - final_private_hostname = name_host + LOGGER.info("Name tag valid.") + final_private_hostname = name_host final_hosted_zone_name = private_hosted_zone_name elif has_valid_zone_tag and not (has_valid_hostname_tag): - LOGGER.info("custom zone tag valid.") - final_private_hostname = private_host_name + LOGGER.info("custom zone tag valid.") + final_private_hostname = private_host_name final_hosted_zone_name = zone_tag_hosted_zone_name - elif has_dhcp_dns_zone_associated_vpc: - LOGGER.info("no custom tags - use default.") - final_private_hostname = private_host_name + elif has_dhcp_dns_zone_associated_vpc: + LOGGER.info("no custom tags - use default.") + final_private_hostname = private_host_name final_hosted_zone_name = private_hosted_zone_name - else: # none of the use-casem and no suitable zone to create the A record - LOGGER.info("No DHCP Associated for VPC and no custom tags. Exiting Script") + else: # none of the use-casem and no suitable zone to create the A record + LOGGER.info("No DHCP Associated for VPC and no custom tags. Exiting Script") # nothing to do, exit out script exit(-1) # put together the FQDN of the dns name... final_private_dns_name = final_private_hostname + '.' + final_hosted_zone_name - LOGGER.info("final hostname for A and PTR record: %s", str(final_private_dns_name) + lineno()) + LOGGER.info("final hostname for A and PTR record: %s", + str(final_private_dns_name) + lineno()) # Get the PHZ ID for the Zone final_hosted_zone_id = get_zone_id( route53, final_hosted_zone_name) LOGGER.debug("private_hosted_zone_id:" - " %s", str(final_hosted_zone_id) + lineno()) + " %s", str(final_hosted_zone_id) + lineno()) # Create OR Delete the A / PTR Record if state == 'running': @@ -528,12 +534,12 @@ def lambda_handler( ) caller_response.append('Created A record in zone id: ' + - str(final_hosted_zone_id) + - ' for hosted zone ' + - str(final_private_hostname) + '.' + - str(final_hosted_zone_name) + - ' with value: ' + - str(private_ip)) + str(final_hosted_zone_id) + + ' for hosted zone ' + + str(final_private_hostname) + '.' + + str(final_hosted_zone_name) + + ' with value: ' + + str(private_ip)) if reverse_zone_associated: create_resource_record( @@ -546,16 +552,16 @@ def lambda_handler( ) caller_response.append('Created PTR record in zone id: ' + - str(reverse_lookup_zone_id) + - ' for hosted zone ' + - str(reversed_ip_address) + - 'in-addr.arpa with value: ' + - str(final_private_dns_name)) + str(reverse_lookup_zone_id) + + ' for hosted zone ' + + str(reversed_ip_address) + + 'in-addr.arpa with value: ' + + str(final_private_dns_name)) except BaseException as err: LOGGER.info("unexpected error. %s\n", str(err) + lineno()) - else: # not running so delete the records + else: # not running so delete the records try: delete_resource_record( route53, @@ -567,12 +573,12 @@ def lambda_handler( ) caller_response.append('Deleted A record in zone id: ' + - str(final_hosted_zone_id) + - ' for hosted zone ' + - str(final_private_hostname) + '.' + - str(final_hosted_zone_name) + - ' with value: ' + - str(private_ip)) + str(final_hosted_zone_id) + + ' for hosted zone ' + + str(final_private_hostname) + '.' + + str(final_hosted_zone_name) + + ' with value: ' + + str(private_ip)) delete_resource_record( route53, @@ -584,12 +590,12 @@ def lambda_handler( ) caller_response.append('Deleted PTR record in zone id: ' + - str(reverse_lookup_zone_id) + - ' for hosted zone ' + - str(reversed_ip_address) + - str(private_dns_name) + - ' with value: ' + - str(final_private_dns_name)) + str(reverse_lookup_zone_id) + + ' for hosted zone ' + + str(reversed_ip_address) + + str(private_dns_name) + + ' with value: ' + + str(final_private_dns_name)) except BaseException as err: LOGGER.debug("%s", str(err) + lineno()) @@ -597,17 +603,17 @@ def lambda_handler( # Create the CNAME record only if it has passed the check if has_valid_cname_tag: LOGGER.debug("cname record is valid - creating CNAME record:" - " %s", str(cname_host_name) + "." + str(cname_domain_suffix) + lineno()) + " %s", str(cname_host_name) + "." + str(cname_domain_suffix) + lineno()) # create CNAME record in private zone if state == 'running': try: LOGGER.debug("cname_host_name:" - " %s", str(cname_host_name) + lineno()) + " %s", str(cname_host_name) + lineno()) LOGGER.debug("cname_domain_suffix:" - " %s", str(cname_domain_suffix) + lineno()) + " %s", str(cname_domain_suffix) + lineno()) LOGGER.debug("cname_domain_suffix_id:" - " %s", str(cname_domain_suffix_id) + lineno()) + " %s", str(cname_domain_suffix_id) + lineno()) create_resource_record( route53, @@ -619,12 +625,12 @@ def lambda_handler( ) caller_response.append('Created CNAME record in zone id: ' + - str(cname_domain_suffix_id) + - ' for hosted zone ' + - str(cname_host_name) + '.' + - str(cname_domain_suffix) + - ' with value: ' + - str(final_private_dns_name)) + str(cname_domain_suffix_id) + + ' for hosted zone ' + + str(cname_host_name) + '.' + + str(cname_domain_suffix) + + ' with value: ' + + str(final_private_dns_name)) except BaseException as err: LOGGER.debug("%s", str(err) + lineno()) @@ -642,12 +648,12 @@ def lambda_handler( ) caller_response.append('Deleted CNAME record in zone id: ' + - str(cname_domain_suffix_id) + - ' for hosted zone ' + - str(cname_host_name) + '.' + - str(cname_domain_suffix) + - ' with value: ' + - str(final_private_dns_name)) + str(cname_domain_suffix_id) + + ' for hosted zone ' + + str(cname_host_name) + '.' + + str(cname_domain_suffix) + + ' with value: ' + + str(final_private_dns_name)) except BaseException as err: LOGGER.debug("%s", str(err) + lineno()) @@ -873,6 +879,7 @@ def get_dynamodb_table(client, table_name): except ClientError as err: LOGGER.info("unexpected error. %s\n", str(err) + lineno()) + def change_resource_recordset(client, zone_id, host_name, hosted_zone_name, record_type, value): """ Change resource recordset @@ -1093,7 +1100,7 @@ def get_dhcp_configurations(client, dhcp_options_id): dhcp_configurations = response['DhcpOptions'][0]['DhcpConfigurations'] LOGGER.debug("dhcp_configurations: %s", str(dhcp_configurations) + lineno()) for configuration in dhcp_configurations: - if configuration['Key']=='domain-name': # only if the key is domain-name + if configuration['Key'] == 'domain-name': # only if the key is domain-name for item in configuration['Values']: LOGGER.debug("item: %s", str(item) + lineno()) zone_names.append(str(item['Value']) + '.') diff --git a/code/ddns-lambda.zip b/code/ddns-lambda.zip index 7609ad3..1c86ecd 100644 Binary files a/code/ddns-lambda.zip and b/code/ddns-lambda.zip differ