updated force command, texts, error handling of requests and http code,
updated readme.
This commit is contained in:
parent
a2adf9ecab
commit
e0866f3f86
2
.settings/org.eclipse.core.resources.prefs
Normal file
2
.settings/org.eclipse.core.resources.prefs
Normal file
|
@ -0,0 +1,2 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding//src/gandi_live_dns.py=utf-8
|
76
README.md
76
README.md
|
@ -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
|
||||
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
|
||||
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`.
|
||||
|
||||
|
@ -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
|
||||
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.
|
||||
|
||||
### 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
|
||||
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
|
||||
|
||||
`git clone https://github.com/cavebeat/gandi_live_dns.git`
|
||||
|
||||
#### Script Configuration
|
||||
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
|
||||
as the script.
|
||||
Edit the config file to fit your needs.
|
||||
|
||||
##### 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
|
||||
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
|
||||
$ chmod +x gandi_live_dns.py
|
||||
root@dyndns:~/gandi_live_dns-master/src# ./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
|
||||
with the classic DNS from Gandiv4 Website and their XML-RPC API.
|
||||
with the classic DNS from Gandiv4 Website and their XML-RPC API.
|
||||
|
|
BIN
src/config.pyc
BIN
src/config.pyc
Binary file not shown.
|
@ -18,7 +18,7 @@ Gandiv5 LiveDNS API Location
|
|||
http://doc.livedns.gandi.net/#api-endpoint
|
||||
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
|
||||
domain = 'mydomain.tld'
|
||||
|
|
|
@ -32,23 +32,36 @@ def get_uuid():
|
|||
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})
|
||||
json_object = json.loads(u._content)
|
||||
return json_object['zone_uuid']
|
||||
if u.status_code == 200:
|
||||
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):
|
||||
''' find out IP from first Subdomain DNS-Record
|
||||
List all records with name "NAME" and type "TYPE" in the zone UUID
|
||||
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}
|
||||
u = requests.get(url, headers=headers)
|
||||
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')
|
||||
return json_object['rrset_values'][0].encode('ascii','ignore').strip('\n')
|
||||
if u.status_code == 200:
|
||||
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')
|
||||
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):
|
||||
''' update DNS Records for Subdomains
|
||||
|
@ -60,21 +73,26 @@ def update_records(uuid, dynIP, subdomain):
|
|||
"rrset_values": ["<VALUE>"]}' \
|
||||
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]}
|
||||
headers = {"Content-Type": "application/json", "X-Api-Key":config.api_secret}
|
||||
record_update = requests.put(url, data=json.dumps(payload), headers=headers)
|
||||
json_object = json.loads(record_update._content)
|
||||
print 'Status Code: ', record_update.status_code, ', ', json_object['message'], ', IP updated for', subdomain
|
||||
return True
|
||||
u = requests.put(url, data=json.dumps(payload), headers=headers)
|
||||
json_object = json.loads(u._content)
|
||||
|
||||
if u.status_code == 201:
|
||||
print 'Status Code:', u.status_code, ',', json_object['message'], ', IP updated for', subdomain
|
||||
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):
|
||||
|
||||
if force_update:
|
||||
print "force update turned on"
|
||||
if verbosity:
|
||||
print "verbosity turned on"
|
||||
print "verbosity turned on - not implemented by now"
|
||||
|
||||
|
||||
#get zone ID from Account
|
||||
|
@ -85,21 +103,21 @@ def main(force_update, verbosity):
|
|||
dnsIP = get_dnsip(uuid)
|
||||
|
||||
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:
|
||||
update_records(uuid, dynIP, sub)
|
||||
else:
|
||||
if dynIP == dnsIP:
|
||||
print "IP Address Match - no further action"
|
||||
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:
|
||||
update_records(uuid, dynIP, sub)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
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()
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue