Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS Route 53 Listing CNAME Records using boto3

I want to list all the CNAME records in a certain hosted zone. Let's say I have over 400 records in my hosted zone. I'm using boto3:

response_per_zone = client.list_resource_record_sets(HostedZoneId=Id, MaxItems='100')

This command list 100 records of all types. There is a lot of CNAME records missing.
How do I iterate through all the records so that I can list all the CNAME records?

like image 458
Amit740 Avatar asked Jan 18 '17 10:01

Amit740


4 Answers

You should just use the official paginator method provided by AWS: https://boto3.readthedocs.io/en/latest/reference/services/route53.html#Route53.Paginator.ListResourceRecordSets

Example code for listing CNAME records regardless of the number of records:

#!/usr/bin/env python3

paginator = client.get_paginator('list_resource_record_sets')

try:
    source_zone_records = paginator.paginate(HostedZoneId='HostedZoneId')
    for record_set in source_zone_records:
        for record in record_set['ResourceRecordSets']:
            if record['Type'] == 'CNAME':
                print(record['Name'])

except Exception as error:
    print('An error occurred getting source zone records:')
    print(str(error))
    raise
like image 152
Serban Cezar Avatar answered Sep 22 '22 18:09

Serban Cezar


Okay I found the answer to this after clearly reading the documentation. Each 100 records will have a trailing NextRecordType and NextRecordName field if the maxitems returned will be more than 100. We need to use these to get the next 100 items and so on. This code is working for me, let me know if my approach is wrong.

NextRecordName = 'a'
NextRecordType = 'CNAME'
while(NextRecordName is not None and NextRecordType is not None):
    response_per_zone = client.list_resource_record_sets(HostedZoneId=Id,StartRecordName=NextRecordName, StartRecordType=NextRecordType ,MaxItems='400')

    try:
        NextRecordName = response_per_zone['NextRecordName']
        NextRecordType = response_per_zone['NextRecordType']
    except Exception as e:
        NextRecordName = None
        NextRecordType = None



    print NextRecordType
    print NextRecordName
    #Since I need to find CNAME records, this is a function to check whether the record is CNAME, checking it is done using response_record = client.list_resource_record_sets(HostedZoneId=hostedzone, StartRecordName=cname_record, MaxItems='1')

    private_zone = resp['Config']['PrivateZone']
    if private_zone == False:
        find_record(response_per_zone, Id, record_stack)
like image 43
Amit740 Avatar answered Sep 24 '22 18:09

Amit740


As per the AWS documentation: A flag will be set in the response to indicate if the result has been truncated (IsTruncated will be set to True) - you can then look at the result of NextRecordName in the response as the argument to StartRecordName

Let me know if you need me to code up an example and I'd be happy to :)

like image 26
Michael Avatar answered Sep 22 '22 18:09

Michael


Most listing methods will return NextToken if there are more records. list_resource_record_sets uses NextRecordName instead and you can use it the same way like NexToken. Here's sample code that will iterate all records,

import boto3

aws_profile = '...'
zone_id = 'Z2A...'
max_records = 1000
session = boto3.Session(profile_name=aws_profile)
route53 = session.client('route53')
dns_records = []

dns_in_iteration = route53.list_resource_record_sets(HostedZoneId=zone_id)
dns_records.extend(dns_in_iteration['ResourceRecordSets'])

while len(dns_records) < max_records and 'NextRecordName' in dns_in_iteration.keys():
    next_record_name = dns_in_iteration['NextRecordName']
    print('listing next set: ' + next_record_name)
    dns_in_iteration = route53.list_resource_record_sets(HostedZoneId=zone_id, StartRecordName=next_record_name)
    dns_records.extend(dns_in_iteration['ResourceRecordSets'])

print('records found: ' + str(len(dns_records)))    
for record in dns_records:
    if record['Type'] == 'CNAME':
        print(record['Name'])

I added max_records to test my 20k+ records, so it can stop with smaller set or records.

like image 27
barryku Avatar answered Sep 21 '22 18:09

barryku