diff --git a/code/ddns-lambda.py b/code/ddns-lambda.py index 54986a9..c2b132a 100755 --- a/code/ddns-lambda.py +++ b/code/ddns-lambda.py @@ -73,7 +73,7 @@ LOGGER = logging.getLogger() account_id = None region = None -VERSION = '1.2.0b82' +VERSION = '1.2.0b83' # Read Env variables DEBUG_LOG_LEVEL = os.environ.get('DebugLogLevel', 'INFO') @@ -82,6 +82,7 @@ TAGKEY_CNAME = os.environ.get('TagKeyCname', 'boc:dns:cname') TAGKEY_ZONE = os.environ.get('TagKeyZone', 'boc:dns:zone') TAGKEY_HOSTNAME = os.environ.get('TagKeyHostName', 'boc:dns:name') +TAGKEY_PTRNAME = os.environ.get('TagKeyPtrName', 'boc:dns:ptrname') TAGKEY_FLAGS = os.environ.get('TagKeyFlags', 'boc:dns:flags') DNS_RR_TTL = int(os.environ.get('DNS_RR_TimeToLive', '60')) DNS_RR_TTL = 60 if DNS_RR_TTL == 0 else DNS_RR_TTL @@ -653,14 +654,16 @@ def lambda_handler( LOGGER.info("Options flags: " + ' '.join([f"{x}={flags[x]}" for x in flags])) tag_data = {} - tag_data_fields = ['valid', 'hostname', 'zonename'] + tag_data_fields = ['defined', 'valid', 'hostname', 'zonename'] tag_data_tuple = namedtuple('TagData', tag_data_fields) tag_data['option_cname'] = tag_data_tuple(*process_tags_option_cname(tags)) tag_data['option_zone'] = tag_data_tuple(*process_tags_option_zone(tags)) tag_data['option_name'] = tag_data_tuple(*process_tags_option_name(tags)) - tag_data['dhcp_options'] = tag_data_tuple( - has_dhcp_dns_zone_associated_vpc, None, private_hosted_zone_name) - tag_data['ptr_entry'] = tag_data_tuple(True, reversed_entry, reversed_lookup_zone) + tag_data['option_ptrname'] = tag_data_tuple(*process_tags_option_ptrname(tags)) + tag_data['dhcp_options'] = tag_data_tuple(True, + has_dhcp_dns_zone_associated_vpc, None, private_hosted_zone_name) + tag_data['ptr_entry'] = tag_data_tuple( + True, True, reversed_entry, reversed_lookup_zone) tag_data['name'] = tag_data_tuple(*process_tags_name(tags)) LOGGER.debug("New tag_data structure: %s", str(pformat(tag_data)) + lineno()) @@ -688,11 +691,11 @@ def lambda_handler( f"2.1 instance: {instance_id}, using tag_option.name hostname {tag_data['option_name'].hostname} and and tag_option.name zone {tag_data['option_name'].zonename}") f_hostname = tag_data['option_name'].hostname f_zonename = tag_data['option_name'].zonename - elif not tag_data['option_name'].valid and tag_data['option_name'].hostname and tag_data['option_name'].zonename and all(flags['noforward'], flags['forcename']): - LOGGER.info( - f"2.2 instance: {instance_id}, using tag_option.name hostname {tag_data['option_name'].hostname} and and tag_option.name zone {tag_data['option_name'].zonename} [noforward,forcename]") - f_hostname = tag_data['option_name'].hostname - f_zonename = tag_data['option_name'].zonename +# elif not tag_data['option_name'].valid and tag_data['option_name'].hostname and tag_data['option_name'].zonename and all(flags['noforward'], flags['forcename']): +# LOGGER.info( +# f"2.2 instance: {instance_id}, using tag_option.name hostname {tag_data['option_name'].hostname} and and tag_option.name zone {tag_data['option_name'].zonename} [noforward,forcename]") +# f_hostname = tag_data['option_name'].hostname +# f_zonename = tag_data['option_name'].zonename elif not tag_data['option_name'].valid and tag_data['option_name'].hostname and tag_data['dhcp_options'].valid: LOGGER.info( f"2.3 instance: {instance_id}, using tag_option.name hostname {tag_data['option_name'].hostname} and and tag_option.name zone {tag_data['dhcp_options'].zonename}") @@ -738,11 +741,30 @@ def lambda_handler( else: cf_fqdn = '' + if tag_data['option_ptrname'].valid: + LOGGER.info( + f"5.1 instance: {instance_id}, PTR using tag_option.ptrname hostname {tag_data['option_ptrname'].hostname} and tag_option.ptrname zone {tag_data['option_ptrname'].zonename}") + p_hostname = tag_data['option_ptrname'].hostname + p_zonename = tag_data['option_ptrname'].zonename + elif tag_data['option_ptrname'].exists: + LOGGER.info( + f"5.2 instance: {instance_id}, PTR using name not-valid, forcing tag_option.ptrname hostname {tag_data['option_ptrname'].hostname} and tag_option.ptrname zone {tag_data['option_ptrname'].zonename}") + p_hostname = tag_data['option_ptrname'].hostname + p_zonename = tag_data['option_ptrname'].zonename + else: + LOGGER.info( + f"5.3 instance: {instance_id}, PTR default using current hostname {f_hostname} and current zone {f_zonename}") + p_hostname = f_hostname + p_zonename = f_zonename + p_fqdn = create_fqdn(final_private_hostname, final_hosted_zone_name) + + # note this will not continue and set a cname final_private_hostname = f_hostname if len(f_hostname) > 0 else default_hostname final_hosted_zone_name = f_zonename - final_private_dns_name = '.'.join([f_hostname, f_zonename]) +# final_private_dns_name = '.'.join([f_hostname, f_zonename]) + final_private_dns_name = p_fqdn zone_data_fields = ['name', 'zone_id', 'owner_account', 'is_amazon', 'enabled'] zone_data_tuple = namedtuple('ZoneData', zone_data_fields) @@ -3100,11 +3122,11 @@ def process_tags_value(name): """ if name != '': - return parse_hostname_to_components(name) + return (True,) + parse_hostname_to_components(name) # components = parse_hostname_to_components(name) # if components: # return (True, components[0], components[1]) - return (False, name, None) + return (name != '', False, name, None) def process_tags_option_cname(tags): @@ -3149,6 +3171,25 @@ def process_tags_option_name(tags): return process_tags_value(value) +def process_tags_option_ptrname(tags): + """ + Process the Name option tag 'boc:dns:ptrname', determine if name if and zone are valid. This name is used to provide and + alternate target name for the PTR address. A warning is issued if the zone/domain does not exist, but it will still create the + name anyway. This is expected to be used in the case of a Windows host, where the hostname cannot be set in route53, but the PTR + can, and it has to point back to the real AD hostname. Using this involves two tags: + + boc:dns:flags = noforward + boc:dns:ptrname = winhostname.ead.census.gov + + : param list(dict(string)) tags: tags from instance, list of dict of string + : return: + """ + + tag_dict = {tag['Key'].lstrip().lower(): tag['Value'] for tag in tags} + value = tag_dict.get(TAGKEY_PTRNAME.lower(), '') + return process_tags_value(value) + + def process_tags_name(tags): """ Process the Hostname from the Name tag to determine if name if and zone are valid diff --git a/code/ddns-lambda.zip b/code/ddns-lambda.zip index 19a5fe0..01b0c2a 100644 Binary files a/code/ddns-lambda.zip and b/code/ddns-lambda.zip differ