#!/usr/bin/env python3
# -*- encoding: UTF8 -*-
# author: Pascal Gollor (https://gitbucket.pgollor.de)
from INWX.Domrobot import ApiClient
from configuration import get_account_data
import argparse
from getIPaddress import getPublicIP
import sys, os
def errorCheck(ret):
if (ret['code'] != 1000):
raise RuntimeError('[ERROR] Code: ' + str(ret['code']) + ' Message: ' + ret['msg'])
# end if
return ret
# end errorCheck
def updateRecord(mode, username, password, domain, sub, record_type, ttl, content=None, config_section="live", update_only_changes=True, verbose=False):
debug_mode = False
api_url = ApiClient.API_LIVE_URL
if (config_section == "ote"):
debug_mode = True
api_url = ApiClient.API_OTE_URL
api_client = ApiClient(api_url=api_url, debug_mode=debug_mode)
ret = errorCheck(api_client.login(username, password))
if (verbose):
print("login:", ret)
# check domain
ret = errorCheck(api_client.call_api(api_method='nameserver.list', method_params={'domain': domain}))
if (verbose):
print('list:', ret)
if (ret['resData']['count'] == 0):
raise RuntimeError("You are not user of this domain.")
# looking if subdomain exists
ret = errorCheck(api_client.call_api(api_method='nameserver.info', method_params={'domain': domain}))
records = ret['resData']['record']
if (verbose):
print(records)
fqdn = sub + '.' + domain
if (mode == "delete" or mode == "update"):
recordFound = False
for r in records:
if (r['name'] == fqdn and r['type'] == record_type):
recordFound = True
if (verbose):
print('entry:', r)
# delete entry
if (mode == "delete"):
# if content is not none: delete only entry with given content.
if (content != None and r['content'] != content):
continue
ret = errorCheck(api_client.call_api(api_method='nameserver.deleteRecord', method_params={'id': r['id']}))
if (verbose):
print('delete:', ret)
# update entry
elif (mode == "update"):
if (update_only_changes and content == r['content']):
continue
ret = errorCheck(api_client.call_api(api_method='nameserver.updateRecord', method_params={'id': r['id'], 'type': record_type, 'content': content, 'ttl': ttl}))
if (verbose):
print('update:', ret)
# end if
# end if
# end for
if (mode == "delete" and not recordFound):
raise RuntimeError('can not delete entry.')
# end if
if (mode == "create" or (mode == "update" and not recordFound)):
ret = errorCheck(api_client.call_api(api_method='nameserver.createRecord', method_params={'domain': domain, 'name': sub, 'type': record_type, 'content': content, 'ttl': ttl}))
if (verbose):
print('create:', ret)
# end if
api_client.logout()
# end updateRecord
def main(args):
# do some checks
if (args.mode != 'delete' and not args.public_ip and not args.content):
raise ValueError("Missing content for domain entry.")
# end if
# split domain
domain = args.domain
h = domain.split('.')
if (len(h) < 3):
raise ValueError("invalid subdomain")
sub = h[0]
for i in range(1, len(h)-2):
sub += '.' + h[i]
domain = h[-2] + '.' + h[-1]
if (args.debug):
print(args)
# get config and login
username, password, shared_secret = get_account_data(True, config_file=args.config_file, config_section=args.config_section)
# use puplic ip as content
content= args.content
if (args.public_ip and (args.mode == 'create' or args.mode == 'update')):
if (args.record_type != 'A' and args.record_type != 'AAAA'):
raise RuntimeError('Record type have to be A or AAAA')
content = getPublicIP(ipv4=(args.record_type=='A'))
# end if
updateRecord(
mode=args.mode,
username=username,
password=password,
domain=domain,
sub=sub,
content=content,
record_type=args.record_type,
ttl=args.ttl,
config_section=args.config_section,
update_only_changes=args.update_only_changes,
verbose=args.verbose
)
# end main
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='inwx subdomain update')
parser.add_argument('domain', metavar='domain', help='full domain like subdomain.example.com')
parser.add_argument('content', metavar='content', nargs='?', default=None, help='ip or string to fill/update into subdomain domain entry')
parser.add_argument('-r', '--record-type', metavar='type', required=True, choices=['A', 'AAAA', 'TXT', 'CNAME', 'TLSA'], help='record type (A, AAAA, TXT, CNAME, TLSA)')
parser.add_argument('-m', '--mode', metavar='mode', required=True, choices=['create', 'update', 'delete'], help='operation mode (create, update, delete)\nupdate:update all existing records if one exists, or create if not existing\ndelete: delete existing record with given content, or delete all records if no content is given')
parser.add_argument('--update-only-changes', action='store_false', required=False, help='Do not update entry if content has changed. Default is aktive')
parser.add_argument('-p', '--public-ip', action='store_true', required=False, help='insert public ip. Use -r A for ip4 an -r AAAA for ipv6')
parser.add_argument('-c', '--config_file', metavar='path', default='./conf.cfg', help='path to configuration file')
parser.add_argument('-t', '--ttl', default=3600, type=int, help='TTL (time to live) of the nameserver record in seconds (default 3600)')
parser.add_argument('-s', '--config_section', metavar='section', default='live', choices=['live', 'ote'], help='configuration section (live, ote) default: live')
parser.add_argument('-v', '--verbose', action='store_true', help='verbose')
parser.add_argument('-d', '--debug', action='store_true', help='debug')
args = parser.parse_args()
if (args.debug):
main(args)
else:
try:
main(args)
except RuntimeError as e:
print(e.args[0])
sys.exit(os.EX_SOFTWARE)
except (NameError, ValueError) as e:
print(e.args[0])
sys.exit(os.EX_DATAERR)
except TimeoutError as e:
print('Timeout:', e)
sys.exit(os.EX_SOFTWARE)
# end try
# end if
sys.exit(os.EX_OK)
# end if