updated force command, texts, error handling of requests and http code,

updated readme.
This commit is contained in:
cave beat 2017-08-15 17:54:18 +02:00
parent a2adf9ecab
commit e0866f3f86
5 changed files with 102 additions and 30 deletions

View file

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding//src/gandi_live_dns.py=utf-8

View file

@ -6,12 +6,12 @@ This is a simple dynamic DNS updater for the
the zone file for a subdomain of a domain to point at the external IPv4 the zone file for a subdomain of a domain to point at the external IPv4
address of the computer it has been run from. address of the computer it has been run from.
It has been developed and tested on Debian 8 Jessie GNU/Linux using Python 2.7. It has been developed on Debian 8 Jessie and tested on Debian 9 Sretch GNU/Linux using Python 2.7.
With the new v5 Website, Gandi has also launched a With the new v5 Website, Gandi has also launched a
new REST API which makes it easier to communicate via bash/curl or python/requests. new REST API which makes it easier to communicate via bash/curl or python/requests.
### Walkthrough ### Goal
You want your homeserver to be always available at `dynamic.mydomain.tld`. You want your homeserver to be always available at `dynamic.mydomain.tld`.
@ -20,32 +20,84 @@ First, you must apply for an API key with Gandi. Visit
https://account.gandi.net/en/ and apply for (at least) the production API https://account.gandi.net/en/ and apply for (at least) the production API
key by following their directions. key by following their directions.
#### A Record Setup #### A DNS Record
Create the DNS A Records in the GANDI Webinterface which you want to update if your IP changes. Create the DNS A Records in the GANDI Webinterface which you want to update if your IP changes.
### Debian Package Requirements
`apt-get update && apt-get upgrade && apt-get install unzip python-requests python-args python-simplejson`
#### Git Clone or Download the Script #### Git Clone or Download the Script
Download the Script from [GitHub](https://github.com/cavebeat/gandi_live_dns/archive/master.zip) Download the Script from [GitHub](https://github.com/cavebeat/gandi_live_dns/archive/master.zip) and unzip it.
or or
`git clone https://github.com/cavebeat/gandi_live_dns.git` `git clone https://github.com/cavebeat/gandi_live_dns.git`
#### Script Configuration #### Script Configuration
Then you'd need to configure the script in the src directory. Then you'd need to configure the script in the src directory.
Copy `example.config.py` to `config.py`, and put it in the same directory as the script.
Copy `example.config.py` to `config.py`, and put it in the same directory Edit the config file to fit your needs.
as the script.
##### api_secret
Start by retrieving your API Key from the "Security" section in new [Gandi Account admin panel](https://account.gandi.net/) to be able to make authenticated requests to the API.
api_secret = '---my_secret_API_KEY----'
##### api_endpoint
Gandiv5 LiveDNS API Location
http://doc.livedns.gandi.net/#api-endpoint
'''
api_endpoint = 'https://dns.beta.gandi.net/api/v5'
##### domain
Your domain with the subdomains to be updated
domain = 'mydomain.tld'
##### subdomains
All subdomains which should be updated. They get created if they do not yet exist.
subdomains = ["subdomain1", "subdomain2", "subdomain3"]
The first domain is used to find out the actual IP in the Zone Records.
#### Run the script #### Run the script
And run the script:
`
root@dyndns:~/gandi_live_dns-master/src# ./gandi_live_dns.py
Checking dynamic IP: 127.0.0.1
Checking IP from DNS Record subdomain1: 127.0.0.1
IP Address Match - no further action
`
If your IP has changed, it will be detected and the update will be triggered.
Make the script executeable.
` `
$ cd gandi_live_dns/src root@dyndns:~/gandi_live_dns-master/src# ./gandi_live_dns.py
$ chmod +x gandi_live_dns.py Checking dynamic IP: 127.0.0.2
Checking IP from DNS Record subdomain1: 127.0.0.1
IP Address Mismatch - going to update the DNS Records for the subdomains with new IP 127.0.0.2
Status Code: 201 , DNS Record Created , IP updated for subdomain1
Status Code: 201 , DNS Record Created , IP updated for subdomain2
Status Code: 201 , DNS Record Created , IP updated for subdomain3
` `
And run the script
#### Command Line Arguments
` `
$ ./gandi_live_dns.py root@dyndns:~/gandi_live_dns-master/src# ./gandi_live_dns.py -h
usage: gandi_live_dns.py [-h] [-f]
optional arguments:
-h, --help show this help message and exit
-f, --force force an update/create
` `
The force option runs the script, even when no IP change has been detected.
It will update all subdomains and even create them if they are missing in the
Zone File/Zone UUID. This can be used if additional/new subdomains get appended to the conig file.
This DynDNS updater is inspired by https://github.com/jasontbradshaw/gandi-dyndns which worked very well This DynDNS updater is inspired by https://github.com/jasontbradshaw/gandi-dyndns which worked very well
with the classic DNS from Gandiv4 Website and their XML-RPC API. with the classic DNS from Gandiv4 Website and their XML-RPC API.

Binary file not shown.

View file

@ -18,7 +18,7 @@ Gandiv5 LiveDNS API Location
http://doc.livedns.gandi.net/#api-endpoint http://doc.livedns.gandi.net/#api-endpoint
https://dns.beta.gandi.net/api/v5/ https://dns.beta.gandi.net/api/v5/
''' '''
api = 'https://dns.beta.gandi.net/api/v5' api_endpoint = 'https://dns.beta.gandi.net/api/v5'
#your domain with the subdomains in the zone file/UUID #your domain with the subdomains in the zone file/UUID
domain = 'mydomain.tld' domain = 'mydomain.tld'

View file

@ -32,23 +32,36 @@ def get_uuid():
GET /domains/<DOMAIN>: GET /domains/<DOMAIN>:
''' '''
url = config.api + '/domains/' + config.domain url = config.api_endpoint + '/domains/' + config.domain
u = requests.get(url, headers={"X-Api-Key":config.api_secret}) u = requests.get(url, headers={"X-Api-Key":config.api_secret})
json_object = json.loads(u._content) json_object = json.loads(u._content)
if u.status_code == 200:
return json_object['zone_uuid'] return json_object['zone_uuid']
else:
print 'Error: HTTP Status Code ', u.status_code, 'when trying to get Zone UUID'
print json_object['message']
exit()
def get_dnsip(uuid): def get_dnsip(uuid):
''' find out IP from first Subdomain DNS-Record ''' find out IP from first Subdomain DNS-Record
List all records with name "NAME" and type "TYPE" in the zone UUID List all records with name "NAME" and type "TYPE" in the zone UUID
GET /zones/<UUID>/records/<NAME>/<TYPE>: GET /zones/<UUID>/records/<NAME>/<TYPE>:
The first subdomain from config.subdomain will be used to get
the actual DNS Record IP
''' '''
url = config.api + '/zones/' + uuid + '/records/' + config.subdomains[0] + '/A' url = config.api_endpoint+ '/zones/' + uuid + '/records/' + config.subdomains[0] + '/A'
headers = {"X-Api-Key":config.api_secret} headers = {"X-Api-Key":config.api_secret}
u = requests.get(url, headers=headers) u = requests.get(url, headers=headers)
if u.status_code == 200:
json_object = json.loads(u._content) json_object = json.loads(u._content)
print 'Checking IP from DNS Record' , config.subdomains[0], ' : ', json_object['rrset_values'][0].encode('ascii','ignore').strip('\n') print 'Checking IP from DNS Record' , config.subdomains[0], ':', json_object['rrset_values'][0].encode('ascii','ignore').strip('\n')
return json_object['rrset_values'][0].encode('ascii','ignore').strip('\n') return json_object['rrset_values'][0].encode('ascii','ignore').strip('\n')
else:
print 'Error: HTTP Status Code ', u.status_code, 'when trying to get IP from subdomain', config.subdomains[0]
print json_object['message']
exit()
def update_records(uuid, dynIP, subdomain): def update_records(uuid, dynIP, subdomain):
''' update DNS Records for Subdomains ''' update DNS Records for Subdomains
@ -60,21 +73,26 @@ def update_records(uuid, dynIP, subdomain):
"rrset_values": ["<VALUE>"]}' \ "rrset_values": ["<VALUE>"]}' \
https://dns.beta.gandi.net/api/v5/zones/<UUID>/records/<NAME>/<TYPE> https://dns.beta.gandi.net/api/v5/zones/<UUID>/records/<NAME>/<TYPE>
''' '''
url = config.api + '/zones/' + uuid + '/records/' + subdomain + '/A' url = config.api_endpoint+ '/zones/' + uuid + '/records/' + subdomain + '/A'
payload = {"rrset_ttl": config.ttl, "rrset_values": [dynIP]} payload = {"rrset_ttl": config.ttl, "rrset_values": [dynIP]}
headers = {"Content-Type": "application/json", "X-Api-Key":config.api_secret} headers = {"Content-Type": "application/json", "X-Api-Key":config.api_secret}
record_update = requests.put(url, data=json.dumps(payload), headers=headers) u = requests.put(url, data=json.dumps(payload), headers=headers)
json_object = json.loads(record_update._content) json_object = json.loads(u._content)
print 'Status Code: ', record_update.status_code, ', ', json_object['message'], ', IP updated for', subdomain
if u.status_code == 201:
print 'Status Code:', u.status_code, ',', json_object['message'], ', IP updated for', subdomain
return True return True
else:
print 'Error: HTTP Status Code ', u.status_code, 'when trying to update IP from subdomain', subdomain
print json_object['message']
exit()
def main(force_update, verbosity): def main(force_update, verbosity):
if force_update:
print "force update turned on"
if verbosity: if verbosity:
print "verbosity turned on" print "verbosity turned on - not implemented by now"
#get zone ID from Account #get zone ID from Account
@ -85,21 +103,21 @@ def main(force_update, verbosity):
dnsIP = get_dnsip(uuid) dnsIP = get_dnsip(uuid)
if force_update: if force_update:
print "Going to update the DNS Records for the subdomains" print "Going to update/create the DNS Records for the subdomains"
for sub in config.subdomains: for sub in config.subdomains:
update_records(uuid, dynIP, sub) update_records(uuid, dynIP, sub)
else: else:
if dynIP == dnsIP: if dynIP == dnsIP:
print "IP Address Match - no further action" print "IP Address Match - no further action"
else: else:
print "IP Address Mismatch - going to update the DNS Records for the subdomains" print "IP Address Mismatch - going to update the DNS Records for the subdomains with new IP", dynIP
for sub in config.subdomains: for sub in config.subdomains:
update_records(uuid, dynIP, sub) update_records(uuid, dynIP, sub)
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', help="increase output verbosity", action="store_true") parser.add_argument('-v', '--verbose', help="increase output verbosity", action="store_true")
parser.add_argument('-f', '--force', help="force an update", action="store_true") parser.add_argument('-f', '--force', help="force an update/create", action="store_true")
args = parser.parse_args() args = parser.parse_args()