Created
December 2, 2014 07:05
-
-
Save robheittman/675860dfe122e9a089bc to your computer and use it in GitHub Desktop.
Fixed Python zone migration script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import dns.zone | |
from dns.zone import NoSOA | |
from dns.exception import DNSException | |
from dns.rdataclass import * | |
from dns.rdatatype import * | |
from dns import rdatatype | |
import httplib2 | |
import json | |
import sys | |
from apiclient.discovery import build | |
from oauth2client.client import SignedJwtAssertionCredentials | |
# Update SERVICE_ACCOUNT_EMAIL with the email address of the service account for | |
# the client id created in the developer console. | |
SERVICE_ACCOUNT_EMAIL = '[email protected]' | |
# Update SERVICE_ACCOUNT_PKCS12_FILE_PATH with the file path to the private key | |
# file downloaded from the developer console. | |
SERVICE_ACCOUNT_PKCS12_FILE_PATH = 'set-me.p12' | |
# Scopes for access to data. | |
SCOPES = ['https://www.googleapis.com/auth/ndev.clouddns.readwrite'] | |
# See https://developers.google.com/dns/what-is-cloud-dns#supported_record_types | |
SUPPORTED_RECORD_TYPES = [A, AAAA, CNAME, MX, PTR, SPF, SRV, TXT, DS] | |
def parseZone(): | |
jsonOutput = {} | |
additions = [] | |
zone_file = '%s.zone' % domain | |
try: | |
zone = dns.zone.from_file(zone_file, domain) | |
for name, node in zone.nodes.items(): | |
rdatasets = node.rdatasets | |
for rdataset in rdatasets: | |
api_name = qualifyName(name) | |
if rdataset.rdtype in SUPPORTED_RECORD_TYPES: | |
addition = { | |
'name' : api_name, | |
'ttl' : str(rdataset.ttl), | |
'type' : rdatatype.to_text(rdataset.rdtype), | |
'kind' : 'dns#resourceRecordSet' | |
} | |
elif rdataset.rdtype in [SOA,NS]: | |
# Skip the SOA and NS records in this example. The | |
# SOA record is generated as part of the managed zone | |
# the NS records here aren't applicable because this | |
# zone is using Google Cloud DNS rather than providing | |
# its own name servers | |
# In your situation, you might want to keep the NS | |
# records, if so add them to the SUPPORTED_RECORD_TYPES | |
continue | |
# Array of records for this name/type combination | |
rrdatas = [] | |
for rdata in rdataset: | |
if rdataset.rdtype == MX: | |
rrdatas.append('%s %s' % (rdata.preference, qualifyName(rdata.exchange))) | |
if rdataset.rdtype == CNAME: | |
rrdatas.append(qualifyName(rdata.target)) | |
if rdataset.rdtype == A: | |
rrdatas.append(rdata.address) | |
if rdataset.rdtype == TXT: | |
rrdatas.append(rdata.strings[0]) | |
if rdataset.rdtype == SRV: | |
rrdatas.append(str(rdata.priority) + " " + str(rdata.weight) + " " + str(rdata.port) + " " + qualifyName(rdata.target)) | |
addition.update({'rrdatas' : rrdatas}) | |
additions.append(addition) | |
jsonOutput.update({'additions' : additions }) | |
return jsonOutput | |
except DNSException, e: | |
if e.__class__ is NoSOA: | |
print ('Check that your SOA line starts with a qualified domain and is in the form of: \n') | |
print (' example.com. IN SOA ns1.example.com. hostmaster.example.com. (') | |
print e.__class__, e | |
def qualifyName(dnsName): | |
dnsName = str(dnsName) | |
if dnsName.endswith("."): | |
return dnsName | |
if domain not in dnsName and dnsName != '@': | |
return dnsName + '.' + domain + '.' | |
else: | |
# Catches the @ symbol case too. | |
return domain + '.' | |
def authenticate(): | |
"""Build and return a DNS service object authorized with the | |
service accounts that act on behalf of the given user. | |
Returns: | |
DNS service object. | |
""" | |
f = open(SERVICE_ACCOUNT_PKCS12_FILE_PATH, 'rb') | |
key = f.read() | |
f.close() | |
# Setting the sub field with USER_EMAIL allows you to make API calls using the | |
# special keyword 'me' in place of a user id for that user. | |
credentials = SignedJwtAssertionCredentials( | |
SERVICE_ACCOUNT_EMAIL, | |
key, | |
scope=SCOPES) | |
http = httplib2.Http() | |
http = credentials.authorize(http) | |
# Create and return the DNS service object | |
return build('dns', 'v1beta1', http=http) | |
def createZone(service): | |
body = { | |
'name' : domain.replace('.', '-'), | |
'dnsName' : domain + '.', | |
'description' : 'A generated zone for ' + domain | |
} | |
args = { 'project' : project, 'body' : body } | |
try: | |
response = service.managedZones().create(**args).execute() | |
return response['name'] | |
except: | |
if 'already exists' in str(sys.exc_info()): | |
print('Zone already exists, moving on.') | |
return domain.replace('.','-') | |
else: | |
print str(sys.exc_info()) | |
exit() | |
def createRecords(service, zone_name, records): | |
args = { | |
'project' : project, | |
'managedZone' : zone_name, | |
'body' : records | |
} | |
try: | |
print json.dumps(args, | |
sort_keys=True, | |
indent=4, | |
separators=(',', ': ')) | |
response = service.changes().create(**args).execute() | |
print 'Record set created, result object: ' | |
print json.dumps(response, | |
sort_keys=True, | |
indent=4, | |
separators=(',', ': ')) | |
except: | |
print str(sys.exc_info()) | |
exit() | |
if __name__ == '__main__': | |
if len(sys.argv) > 2: | |
project = sys.argv[1] | |
domain = sys.argv[2] | |
service = authenticate() | |
records = parseZone() | |
zone_name = createZone(service) | |
createRecords(service, zone_name, records) | |
else: | |
print ('Missing arguments. Provide both the Developer Console project ID' | |
'and domain name. ') | |
print ('Usage: migrateZone.py console-project-name example.com') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment