def wait_for_change(self, change_id, host): _, change_id = change_id client = self._find_client_for_domain(host) while True: response = client.get_change(Id=change_id) if response["ChangeInfo"]["Status"] == "INSYNC": return time.sleep(5)
def update_txt_record_route53(self, domain, challenge, key, access_key_id, secret_access_key): session = boto3.Session(aws_access_key_id=access_key_id, aws_secret_access_key=secret_access_key) client = session.client('route53') # Finding zone id for the given domain paginator = client.get_paginator('list_hosted_zones') target_labels = domain.rstrip('.').split('.') zones = [] try: for page in paginator.paginate(): for zone in page['HostedZones']: if zone['Config']['PrivateZone']: continue candidate_labels = zone['Name'].rstrip('.').split('.') if candidate_labels == target_labels[-len(candidate_labels ):]: zones.append((zone['Name'], zone['Id'])) if not zones: raise CallError( f'Unable to find a Route53 hosted zone for {domain}') except boto_exceptions.ClientError as e: raise CallError( f'Failed to get Hosted zones with provided credentials :{e}') # Order the zones that are suffixes for our desired to domain by # length, this puts them in an order like: # ["foo.bar.baz.com", "bar.baz.com", "baz.com", "com"] # And then we choose the first one, which will be the most specific. zones.sort(key=lambda z: len(z[0]), reverse=True) zone_id = zones[0][1] try: resp = client.change_resource_record_sets( HostedZoneId=zone_id, ChangeBatch={ 'Changes': [{ 'Action': 'UPSERT', 'ResourceRecordSet': { 'Name': challenge.validation_domain_name(domain), 'ResourceRecords': [{ 'Value': f'"{challenge.validation(key)}"' }], 'TTL': 3600, 'Type': 'TXT' } }], 'Comment': f'{"Free" if self.middleware.call_sync("system.is_freenas") else "True"}' 'NAS-dns-route53 certificate validation' }) except boto_BaseClientException as e: raise CallError(f'Failed to update record sets : {e}') """ Wait for a change to be propagated to all Route53 DNS servers. https://docs.aws.amazon.com/Route53/latest/APIReference/API_GetChange.html """ for unused_n in range(0, 120): r = client.get_change(Id=resp['ChangeInfo']['Id']) if r['ChangeInfo']['Status'] == 'INSYNC': return resp['ChangeInfo']['Id'] time.sleep(5) raise CallError( f'Timed out waiting for Route53 change. Current status: {resp["ChangeInfo"]["Status"]}' )
def update_txt_record_route53(self, domain, challenge, key, access_key_id, secret_access_key): session = boto3.Session( aws_access_key_id=access_key_id, aws_secret_access_key=secret_access_key ) client = session.client('route53') # Finding zone id for the given domain paginator = client.get_paginator('list_hosted_zones') target_labels = domain.rstrip('.').split('.') zones = [] try: for page in paginator.paginate(): for zone in page['HostedZones']: if zone['Config']['PrivateZone']: continue candidate_labels = zone['Name'].rstrip('.').split('.') if candidate_labels == target_labels[-len(candidate_labels):]: zones.append((zone['Name'], zone['Id'])) if not zones: raise CallError( f'Unable to find a Route53 hosted zone for {domain}' ) except boto_exceptions.ClientError as e: raise CallError( f'Failed to get Hosted zones with provided credentials :{e}' ) # Order the zones that are suffixes for our desired to domain by # length, this puts them in an order like: # ["foo.bar.baz.com", "bar.baz.com", "baz.com", "com"] # And then we choose the first one, which will be the most specific. zones.sort(key=lambda z: len(z[0]), reverse=True) zone_id = zones[0][1] try: resp = client.change_resource_record_sets( HostedZoneId=zone_id, ChangeBatch={ 'Changes': [ { 'Action': 'UPSERT', 'ResourceRecordSet': { 'Name': challenge.validation_domain_name(domain), 'ResourceRecords': [{'Value': f'"{challenge.validation(key)}"'}], 'TTL': 3600, 'Type': 'TXT' } } ], 'Comment': f'{"Free" if self.middleware.call_sync("system.is_freenas") else "True"}' 'NAS-dns-route53 certificate validation' } ) except boto_BaseClientException as e: raise CallError( f'Failed to update record sets : {e}' ) """ Wait for a change to be propagated to all Route53 DNS servers. https://docs.aws.amazon.com/Route53/latest/APIReference/API_GetChange.html """ for unused_n in range(0, 120): r = client.get_change(Id=resp['ChangeInfo']['Id']) if r['ChangeInfo']['Status'] == 'INSYNC': return resp['ChangeInfo']['Id'] time.sleep(5) raise CallError( f'Timed out waiting for Route53 change. Current status: {resp["ChangeInfo"]["Status"]}' )