#!/usr/bin/env python
# -*- coding: utf-8 -*-
# src: https://stackoverflow.com/a/47166985/65706
# courtesy of: Naftuli Kay
#
from __future__ import absolute_import, print_function
from time import sleep
import argparse
import boto
import pprint
import sys
def set_vars():
usage_examples = '''
clear ; poetry run python process_dns.py --action upsert --dns-zone cgfinics.com --dns-name dev.cgfinics.com --dns-value 168.10.172.10 --record-type A
clear ; poetry run python process_dns.py --action upsert --dns-zone cgfinics.com --dns-name www.dev.cgfinics.com --dns-value www.dev.cgfinics.com --record-type CNAME
clear ; poetry run python process_dns.py --action delete --dns-zone cgfinics.com --dns-name dev.cgfinics.com
'''
parser = argparse.ArgumentParser('A quick and dirty DNS upsert to aws with boto \n\n' + usage_examples)
parser.add_argument('--action', required=True, nargs='?',
help="The action to perform - upsert or delete ")
parser.add_argument('--dns-zone', required=True, nargs='?',
help="The DNS zone to process ")
parser.add_argument('--dns-name', required=True, nargs='?',
help="The DNS name to process ")
parser.add_argument('--dns-value', required=False, nargs='?',
help="The DNS value to process ")
parser.add_argument('--record-type', required=True, nargs='?',
help="The DNS record type - could be A, CNAME ")
args = parser.parse_args()
return args
def main():
"""Entrypoint."""
args = set_vars()
action = args.action
r53 = boto.connect_route53()
zones = r53.get_all_hosted_zones()['ListHostedZonesResponse']['HostedZones']
dns_zone = args.dns_zone + '.' if not args.dns_zone.endswith('.') else args.dns_zone
public_zone = find_public_zone(dns_zone , zones)
dns_name = args.dns_name + '.' if not args.dns_name.endswith('.') else args.dns_name
dns_value = args.dns_value
record_type = args.record_type
if action == "upsert":
upsert_record(r53, public_zone, dns_name, dns_value, record_type, wait=True)
sys.exit(0)
if action == "delete":
delete_record(r53, public_zone, dns_name, dns_value, record_type, wait=True)
sys.exit(0)
print("only the upser and delete actions are supported !!!")
sys.exit(1)
def find_public_zone(name, zones):
for zone in zones:
if zone.get('Name') == name and zone.get('Config', {}).get('PrivateZone') in [True, 'false']:
return zone
return None
def find_record(r53, zone_id, name, record_type):
records = r53.get_all_rrsets(zone_id)
for record in records:
if record.name == name and record.type == record_type:
return record
return None
def upsert_record(r53, zone, name, record, record_type, ttl=60, wait=False):
print("Inserting record {}[{}] -> {}; TTL={}".format(name, record_type, record, ttl))
recordset = boto.route53.record.ResourceRecordSets(connection=r53, hosted_zone_id=zone.get('Id').split('/')[-1])
recordset.add_change_record('UPSERT', boto.route53.record.Record(
name=name,
type=record_type,
resource_records=[record],
ttl=ttl
))
changeset = recordset.commit()
change_id = changeset['ChangeResourceRecordSetsResponse']['ChangeInfo']['Id'].split('/')[-1]
while wait:
status = r53.get_change(change_id)['GetChangeResponse']['ChangeInfo']['Status']
if status == 'INSYNC':
break
sleep(6)
def delete_record(r53, zone, name, record, record_type, wait=False):
print("Deleting record {}[{}] -> {}".format(name, record_type, record))
zone_id = zone.get('Id').split('/')[-1]
record = find_record(r53, zone_id, name, record_type)
if not record:
print("No record exists.")
return
recordset = boto.route53.record.ResourceRecordSets(connection=r53, hosted_zone_id=zone.get('Id').split('/')[-1])
recordset.add_change_record('DELETE', record)
changeset = recordset.commit()
change_id = changeset['ChangeResourceRecordSetsResponse']['ChangeInfo']['Id'].split('/')[-1]
while wait:
status = r53.get_change(change_id)['GetChangeResponse']['ChangeInfo']['Status']
if status == 'INSYNC':
break
sleep(10)
if __name__ == "__main__":
main()