PowerDNS-Admin/powerdnsadmin/models/domain.py

947 lines
37 KiB
Python

import json
import re
import traceback
from flask import current_app
from flask_login import current_user
from urllib.parse import urljoin
from distutils.util import strtobool
from ..lib import utils
from .base import db, domain_apikey
from .setting import Setting
from .user import User
from .account import Account
from .account import AccountUser
from .domain_user import DomainUser
from .domain_setting import DomainSetting
from .history import History
class Domain(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), index=True, unique=True)
master = db.Column(db.String(128))
type = db.Column(db.String(8), nullable=False)
serial = db.Column(db.BigInteger)
notified_serial = db.Column(db.BigInteger)
last_check = db.Column(db.Integer)
dnssec = db.Column(db.Integer)
account_id = db.Column(db.Integer, db.ForeignKey('account.id'))
account = db.relationship("Account", back_populates="domains")
settings = db.relationship('DomainSetting', back_populates='domain')
apikeys = db.relationship("ApiKey",
secondary=domain_apikey,
back_populates="domains")
def __init__(self,
id=None,
name=None,
master=None,
type='NATIVE',
serial=None,
notified_serial=None,
last_check=None,
dnssec=None,
account_id=None):
self.id = id
self.name = name
self.master = master
self.type = type
self.serial = serial
self.notified_serial = notified_serial
self.last_check = last_check
self.dnssec = dnssec
self.account_id = account_id
# PDNS configs
self.PDNS_STATS_URL = Setting().get('pdns_api_url')
self.PDNS_API_KEY = Setting().get('pdns_api_key')
self.PDNS_VERSION = Setting().get('pdns_version')
self.API_EXTENDED_URL = utils.pdns_api_extended_uri(self.PDNS_VERSION)
def __repr__(self):
return '<Domain {0}>'.format(self.name)
def add_setting(self, setting, value):
try:
self.settings.append(DomainSetting(setting=setting, value=value))
db.session.commit()
return True
except Exception as e:
current_app.logger.error(
'Can not create setting {0} for zone {1}. {2}'.format(
setting, self.name, e))
return False
def get_domain_info(self, domain_name):
"""
Get all zones which has in PowerDNS
"""
headers = {'X-API-Key': self.PDNS_API_KEY}
jdata = utils.fetch_json(urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(domain_name)),
headers=headers,
timeout=int(
Setting().get('pdns_api_timeout')),
verify=Setting().get('verify_ssl_connections'))
return jdata
def get_domains(self):
"""
Get all zones which has in PowerDNS
"""
headers = {'X-API-Key': self.PDNS_API_KEY}
jdata = utils.fetch_json(
urljoin(self.PDNS_STATS_URL,
self.API_EXTENDED_URL + '/servers/localhost/zones'),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
verify=Setting().get('verify_ssl_connections'))
return jdata
def get_id_by_name(self, name):
"""
Return domain id
"""
try:
domain = Domain.query.filter(Domain.name == name).first()
return domain.id
except Exception as e:
current_app.logger.error(
'Zone does not exist. ERROR: {0}'.format(e))
return None
def search_idn_domains(self, search_string):
"""
Search for IDN zones using the provided search string.
"""
# Compile the regular expression pattern for matching IDN zone names
idn_pattern = re.compile(r'^xn--')
# Search for zone names that match the IDN pattern
idn_domains = [
domain for domain in self.get_domains() if idn_pattern.match(domain)
]
# Filter the search results based on the provided search string
return [domain for domain in idn_domains if search_string in domain]
def update(self):
"""
Fetch zones (zones) from PowerDNS and update into DB
"""
db_domain = Domain.query.all()
list_db_domain = [d.name for d in db_domain]
dict_db_domain = dict((x.name, x) for x in db_domain)
current_app.logger.info("Found {} zones in PowerDNS-Admin".format(
len(list_db_domain)))
headers = {'X-API-Key': self.PDNS_API_KEY}
try:
jdata = utils.fetch_json(
urljoin(self.PDNS_STATS_URL,
self.API_EXTENDED_URL + '/servers/localhost/zones'),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
verify=Setting().get('verify_ssl_connections'))
list_jdomain = [d['name'].rstrip('.') for d in jdata]
current_app.logger.info(
"Found {} zones in PowerDNS server".format(len(list_jdomain)))
try:
# zones should remove from db since it doesn't exist in powerdns anymore
should_removed_db_domain = list(
set(list_db_domain).difference(list_jdomain))
for domain_name in should_removed_db_domain:
self.delete_domain_from_pdnsadmin(domain_name, do_commit=False)
except Exception as e:
current_app.logger.error(
'Can not delete zone from DB. DETAIL: {0}'.format(e))
current_app.logger.debug(traceback.format_exc())
# update/add new zone
account_cache = {}
for data in jdata:
if 'account' in data:
# if no account is set don't try to query db
if data['account'] == '':
find_account_id = None
else:
find_account_id = account_cache.get(data['account'])
# if account was not queried in the past and hence not in cache
if find_account_id is None:
find_account_id = Account().get_id_by_name(data['account'])
# add to cache
account_cache[data['account']] = find_account_id
account_id = find_account_id
else:
current_app.logger.debug(
"No 'account' data found in API result - Unsupported PowerDNS version?"
)
account_id = None
domain = dict_db_domain.get(data['name'].rstrip('.'), None)
if domain:
self.update_pdns_admin_domain(domain, account_id, data, do_commit=False)
else:
# add new domain
self.add_domain_to_powerdns_admin(domain=data, do_commit=False)
db.session.commit()
current_app.logger.info('Update zone finished')
return {
'status': 'ok',
'msg': 'Zone table has been updated successfully'
}
except Exception as e:
db.session.rollback()
current_app.logger.error(
'Cannot update zone table. Error: {0}'.format(e))
return {'status': 'error', 'msg': 'Cannot update zone table'}
def update_pdns_admin_domain(self, domain, account_id, data, do_commit=True):
# existing domain, only update if something actually has changed
if (domain.master != str(data['masters'])
or domain.type != data['kind']
or domain.serial != data['serial']
or domain.notified_serial != data['notified_serial']
or domain.last_check != (1 if data['last_check'] else 0)
or domain.dnssec != data['dnssec']
or domain.account_id != account_id):
domain.master = str(data['masters'])
domain.type = data['kind']
domain.serial = data['serial']
domain.notified_serial = data['notified_serial']
domain.last_check = 1 if data['last_check'] else 0
domain.dnssec = 1 if data['dnssec'] else 0
domain.account_id = account_id
try:
if do_commit:
db.session.commit()
current_app.logger.info("Updated PDNS-Admin zone {0}".format(
domain.name))
except Exception as e:
db.session.rollback()
current_app.logger.info("Rolled back zone {0} {1}".format(
domain.name, e))
raise
def add(self,
domain_name,
domain_type,
soa_edit_api,
domain_ns=[],
domain_master_ips=[],
account_name=None):
"""
Add a zone to power dns
"""
headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'}
domain_name = domain_name + '.'
domain_ns = [ns + '.' for ns in domain_ns]
if soa_edit_api not in ["DEFAULT", "INCREASE", "EPOCH", "OFF"]:
soa_edit_api = 'DEFAULT'
elif soa_edit_api == 'OFF':
soa_edit_api = ''
post_data = {
"name": domain_name,
"kind": domain_type,
"masters": domain_master_ips,
"nameservers": domain_ns,
"soa_edit_api": soa_edit_api,
"account": account_name
}
try:
jdata = utils.fetch_json(
urljoin(self.PDNS_STATS_URL,
self.API_EXTENDED_URL + '/servers/localhost/zones'),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
method='POST',
verify=Setting().get('verify_ssl_connections'),
data=post_data)
if 'error' in jdata.keys():
current_app.logger.error(jdata['error'])
if jdata.get('http_code') == 409:
return {'status': 'error', 'msg': 'Zone already exists'}
return {'status': 'error', 'msg': jdata['error']}
else:
current_app.logger.info(
'Added zone successfully to PowerDNS: {0}'.format(
domain_name))
self.add_domain_to_powerdns_admin(domain_dict=post_data)
return {'status': 'ok', 'msg': 'Added zone successfully'}
except Exception as e:
current_app.logger.error('Cannot add zone {0} {1}'.format(
domain_name, e))
current_app.logger.debug(traceback.format_exc())
return {'status': 'error', 'msg': 'Cannot add this zone.'}
def add_domain_to_powerdns_admin(self, domain=None, domain_dict=None, do_commit=True):
"""
Read zone from PowerDNS and add into PDNS-Admin
"""
headers = {'X-API-Key': self.PDNS_API_KEY}
if not domain:
try:
domain = utils.fetch_json(
urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(
domain_dict['name'])),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
verify=Setting().get('verify_ssl_connections'))
except Exception as e:
current_app.logger.error('Can not read zone from PDNS')
current_app.logger.error(e)
current_app.logger.debug(traceback.format_exc())
if 'account' in domain:
account_id = Account().get_id_by_name(domain['account'])
else:
current_app.logger.debug(
"No 'account' data found in API result - Unsupported PowerDNS version?"
)
account_id = None
# add new domain
d = Domain()
d.name = domain['name'].rstrip('.') # lgtm [py/modification-of-default-value]
d.master = str(domain['masters'])
d.type = domain['kind']
d.serial = domain['serial']
d.notified_serial = domain['notified_serial']
d.last_check = domain['last_check']
d.dnssec = 1 if domain['dnssec'] else 0
d.account_id = account_id
db.session.add(d)
try:
if do_commit:
db.session.commit()
current_app.logger.info(
"Synced PowerDNS zone to PDNS-Admin: {0}".format(d.name))
return {
'status': 'ok',
'msg': 'Added zone successfully to PowerDNS-Admin'
}
except Exception as e:
db.session.rollback()
current_app.logger.info("Rolled back zone {0}".format(d.name))
raise
def update_soa_setting(self, domain_name, soa_edit_api):
domain = Domain.query.filter(Domain.name == domain_name).first()
if not domain:
return {'status': 'error', 'msg': 'Zone does not exist.'}
headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'}
if soa_edit_api not in ["DEFAULT", "INCREASE", "EPOCH", "OFF"]:
soa_edit_api = 'DEFAULT'
elif soa_edit_api == 'OFF':
soa_edit_api = ''
post_data = {"soa_edit_api": soa_edit_api, "kind": domain.type}
try:
jdata = utils.fetch_json(urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(domain.name)),
headers=headers,
timeout=int(
Setting().get('pdns_api_timeout')),
method='PUT',
verify=Setting().get('verify_ssl_connections'),
data=post_data)
if 'error' in jdata.keys():
current_app.logger.error(jdata['error'])
return {'status': 'error', 'msg': jdata['error']}
else:
current_app.logger.info(
'soa-edit-api changed for zone {0} successfully'.format(
domain_name))
return {
'status': 'ok',
'msg': 'soa-edit-api changed successfully'
}
except Exception as e:
current_app.logger.debug(e)
current_app.logger.debug(traceback.format_exc())
current_app.logger.error(
'Cannot change soa-edit-api for zone {0}'.format(
domain_name))
return {
'status': 'error',
'msg': 'Cannot change soa-edit-api for this zone.'
}
def update_kind(self, domain_name, kind, masters=[]):
"""
Update zone kind: Native / Master / Slave
"""
domain = Domain.query.filter(Domain.name == domain_name).first()
if not domain:
return {'status': 'error', 'msg': 'Znoe does not exist.'}
headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'}
post_data = {"kind": kind, "masters": masters}
try:
jdata = utils.fetch_json(urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(domain.name)),
headers=headers,
timeout=int(
Setting().get('pdns_api_timeout')),
method='PUT',
verify=Setting().get('verify_ssl_connections'),
data=post_data)
if 'error' in jdata.keys():
current_app.logger.error(jdata['error'])
return {'status': 'error', 'msg': jdata['error']}
else:
current_app.logger.info(
'Update zone kind for {0} successfully'.format(
domain_name))
return {
'status': 'ok',
'msg': 'Zone kind changed successfully'
}
except Exception as e:
current_app.logger.error(
'Cannot update kind for zone {0}. Error: {1}'.format(
domain_name, e))
current_app.logger.debug(traceback.format_exc())
return {
'status': 'error',
'msg': 'Cannot update kind for this zone.'
}
def create_reverse_domain(self, domain_name, domain_reverse_name):
"""
Check the existing reverse lookup zone,
if not exists create a new one automatically
"""
domain_obj = Domain.query.filter(Domain.name == domain_name).first()
domain_auto_ptr = DomainSetting.query.filter(
DomainSetting.domain == domain_obj).filter(
DomainSetting.setting == 'auto_ptr').first()
domain_auto_ptr = strtobool(
domain_auto_ptr.value) if domain_auto_ptr else False
system_auto_ptr = Setting().get('auto_ptr')
self.name = domain_name
domain_id = self.get_id_by_name(domain_reverse_name)
if domain_id is None and \
(
system_auto_ptr or
domain_auto_ptr
):
result = self.add(domain_reverse_name, 'Master', 'DEFAULT', [], [])
self.update()
if result['status'] == 'ok':
history = History(msg='Add reverse lookup zone {0}'.format(
domain_reverse_name),
detail=json.dumps({
'domain_type': 'Master',
'domain_master_ips': ''
}),
created_by='System')
history.add()
else:
return {
'status': 'error',
'msg': 'Adding reverse lookup zone failed'
}
domain_user_ids = self.get_user()
if len(domain_user_ids) > 0:
self.name = domain_reverse_name
self.grant_privileges(domain_user_ids)
return {
'status':
'ok',
'msg':
'New reverse lookup zone created with granted privileges'
}
return {
'status': 'ok',
'msg': 'New reverse lookup zone created without users'
}
return {'status': 'ok', 'msg': 'Reverse lookup zone already exists'}
def get_reverse_domain_name(self, reverse_host_address):
c = 1
if re.search('ip6.arpa', reverse_host_address):
for i in range(1, 32, 1):
address = re.search(
'((([a-f0-9]\.){' + str(i) + '})(?P<ipname>.+6.arpa)\.?)',
reverse_host_address)
if None != self.get_id_by_name(address.group('ipname')):
c = i
break
return re.search(
'((([a-f0-9]\.){' + str(c) + '})(?P<ipname>.+6.arpa)\.?)',
reverse_host_address).group('ipname')
else:
for i in range(1, 4, 1):
address = re.search(
'((([0-9]+\.){' + str(i) + '})(?P<ipname>.+r.arpa)\.?)',
reverse_host_address)
if None != self.get_id_by_name(address.group('ipname')):
c = i
break
return re.search(
'((([0-9]+\.){' + str(c) + '})(?P<ipname>.+r.arpa)\.?)',
reverse_host_address).group('ipname')
def delete(self, domain_name):
"""
Delete a single zone name from powerdns
"""
try:
self.delete_domain_from_powerdns(domain_name)
self.delete_domain_from_pdnsadmin(domain_name)
return {'status': 'ok', 'msg': 'Delete zone successfully'}
except Exception as e:
current_app.logger.error(
'Cannot delete zone {0}'.format(domain_name))
current_app.logger.error(e)
current_app.logger.debug(traceback.format_exc())
return {'status': 'error', 'msg': 'Cannot delete zone'}
def delete_domain_from_powerdns(self, domain_name):
"""
Delete a single zone name from powerdns
"""
headers = {'X-API-Key': self.PDNS_API_KEY}
utils.fetch_json(urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(domain_name)),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
method='DELETE',
verify=Setting().get('verify_ssl_connections'))
current_app.logger.info(
'Deleted zone successfully from PowerDNS: {0}'.format(
domain_name))
return {'status': 'ok', 'msg': 'Delete zone successfully'}
def delete_domain_from_pdnsadmin(self, domain_name, do_commit=True):
# Revoke permission before deleting zone
domain = Domain.query.filter(Domain.name == domain_name).first()
domain_user = DomainUser.query.filter(
DomainUser.domain_id == domain.id)
if domain_user:
domain_user.delete()
domain_setting = DomainSetting.query.filter(
DomainSetting.domain_id == domain.id)
if domain_setting:
domain_setting.delete()
domain.apikeys[:] = []
# Remove history for zone
if not Setting().get('preserve_history'):
domain_history = History.query.filter(
History.domain_id == domain.id
)
if domain_history:
domain_history.delete()
# then remove zone
Domain.query.filter(Domain.name == domain_name).delete()
if do_commit:
db.session.commit()
current_app.logger.info(
"Deleted zone successfully from pdnsADMIN: {}".format(
domain_name))
def get_user(self):
"""
Get users (id) who have access to this zone name
"""
user_ids = []
query = db.session.query(
DomainUser, Domain).filter(User.id == DomainUser.user_id).filter(
Domain.id == DomainUser.domain_id).filter(
Domain.name == self.name).all()
for q in query:
user_ids.append(q[0].user_id)
return user_ids
def grant_privileges(self, new_user_ids):
"""
Reconfigure domain_user table
"""
domain_id = self.get_id_by_name(self.name)
domain_user_ids = self.get_user()
removed_ids = list(set(domain_user_ids).difference(new_user_ids))
added_ids = list(set(new_user_ids).difference(domain_user_ids))
try:
for uid in removed_ids:
DomainUser.query.filter(DomainUser.user_id == uid).filter(
DomainUser.domain_id == domain_id).delete()
db.session.commit()
except Exception as e:
db.session.rollback()
current_app.logger.error(
'Cannot revoke user privileges on zone {0}. DETAIL: {1}'.
format(self.name, e))
current_app.logger.debug(print(traceback.format_exc()))
try:
for uid in added_ids:
du = DomainUser(domain_id, uid)
db.session.add(du)
db.session.commit()
except Exception as e:
db.session.rollback()
current_app.logger.error(
'Cannot grant user privileges to zone {0}. DETAIL: {1}'.
format(self.name, e))
current_app.logger.debug(print(traceback.format_exc()))
def revoke_privileges_by_id(self, user_id):
"""
Remove a single user from privilege list based on user_id
"""
new_uids = [u for u in self.get_user() if u != user_id]
users = []
for uid in new_uids:
users.append(User(id=uid).get_user_info_by_id().username)
self.grant_privileges(users)
def add_user(self, user):
"""
Add a single user to zone by User
"""
try:
du = DomainUser(self.id, user.id)
db.session.add(du)
db.session.commit()
return True
except Exception as e:
db.session.rollback()
current_app.logger.error(
'Cannot add user privileges on zone {0}. DETAIL: {1}'.
format(self.name, e))
return False
def update_from_master(self, domain_name):
"""
Update records from Master DNS server
"""
import urllib.parse
domain = Domain.query.filter(Domain.name == domain_name).first()
if domain:
headers = {'X-API-Key': self.PDNS_API_KEY}
try:
r = utils.fetch_json(urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}/axfr-retrieve'.format(
urllib.parse.quote_plus(domain.name))),
headers=headers,
timeout=int(
Setting().get('pdns_api_timeout')),
method='PUT',
verify=Setting().get('verify_ssl_connections'))
return {'status': 'ok', 'msg': r.get('result')}
except Exception as e:
current_app.logger.error(
'Cannot update from master. DETAIL: {0}'.format(e))
return {
'status':
'error',
'msg':
'There was something wrong, please contact administrator'
}
else:
return {'status': 'error', 'msg': 'This zone does not exist'}
def get_domain_dnssec(self, domain_name):
"""
Get zone DNSSEC information
"""
import urllib.parse
domain = Domain.query.filter(Domain.name == domain_name).first()
if domain:
headers = {'X-API-Key': self.PDNS_API_KEY}
try:
jdata = utils.fetch_json(
urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}/cryptokeys'.format(
urllib.parse.quote_plus(domain.name))),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
method='GET',
verify=Setting().get('verify_ssl_connections'))
if 'error' in jdata:
return {
'status': 'error',
'msg': 'DNSSEC is not enabled for this zone'
}
else:
return {'status': 'ok', 'dnssec': jdata}
except Exception as e:
current_app.logger.error(
'Cannot get zone dnssec. DETAIL: {0}'.format(e))
return {
'status':
'error',
'msg':
'There was something wrong, please contact administrator'
}
else:
return {'status': 'error', 'msg': 'This zone does not exist'}
def enable_domain_dnssec(self, domain_name):
"""
Enable zone DNSSEC
"""
import urllib.parse
domain = Domain.query.filter(Domain.name == domain_name).first()
if domain:
headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'}
try:
# Enable API-RECTIFY for domain, BEFORE activating DNSSEC
post_data = {"api_rectify": True}
jdata = utils.fetch_json(
urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(
urllib.parse.quote_plus(domain.name)
)),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
method='PUT',
verify=Setting().get('verify_ssl_connections'),
data=post_data)
if 'error' in jdata:
return {
'status': 'error',
'msg':
'API-RECTIFY could not be enabled for this zone',
'jdata': jdata
}
# Activate DNSSEC
post_data = {"keytype": "ksk", "active": True}
jdata = utils.fetch_json(
urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}/cryptokeys'.format(
urllib.parse.quote_plus(domain.name)
)),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
method='POST',
verify=Setting().get('verify_ssl_connections'),
data=post_data)
if 'error' in jdata:
return {
'status':
'error',
'msg':
'Cannot enable DNSSEC for this zone. Error: {0}'.
format(jdata['error']),
'jdata':
jdata
}
return {'status': 'ok'}
except Exception as e:
current_app.logger.error(
'Cannot enable dns sec. DETAIL: {}'.format(e))
current_app.logger.debug(traceback.format_exc())
return {
'status':
'error',
'msg':
'There was something wrong, please contact administrator'
}
else:
return {'status': 'error', 'msg': 'This zone does not exist'}
def delete_dnssec_key(self, domain_name, key_id):
"""
Remove keys DNSSEC
"""
import urllib.parse
domain = Domain.query.filter(Domain.name == domain_name).first()
if domain:
headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'}
try:
# Deactivate DNSSEC
jdata = utils.fetch_json(
urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}/cryptokeys/{1}'.format(
urllib.parse.quote_plus(domain.name), key_id)),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
method='DELETE',
verify=Setting().get('verify_ssl_connections'))
if jdata != True:
return {
'status':
'error',
'msg':
'Cannot disable DNSSEC for this zone. Error: {0}'.
format(jdata['error']),
'jdata':
jdata
}
# Disable API-RECTIFY for zone, AFTER deactivating DNSSEC
post_data = {"api_rectify": False}
jdata = utils.fetch_json(
urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(domain.name)),
headers=headers,
timeout=int(Setting().get('pdns_api_timeout')),
method='PUT',
verify=Setting().get('verify_ssl_connections'),
data=post_data)
if 'error' in jdata:
return {
'status': 'error',
'msg':
'API-RECTIFY could not be disabled for this zone',
'jdata': jdata
}
return {'status': 'ok'}
except Exception as e:
current_app.logger.error(
'Cannot delete dnssec key. DETAIL: {0}'.format(e))
current_app.logger.debug(traceback.format_exc())
return {
'status': 'error',
'msg':
'There was something wrong, please contact administrator',
'domain': domain.name,
'id': key_id
}
else:
return {'status': 'error', 'msg': 'This zone does not exist'}
def assoc_account(self, account_id, update=True):
"""
Associate account with a zone, specified by account id
"""
domain_name = self.name
# Sanity check - domain name
if domain_name == "":
return {'status': False, 'msg': 'No zone name specified'}
# read domain and check that it exists
domain = Domain.query.filter(Domain.name == domain_name).first()
if not domain:
return {'status': False, 'msg': 'Zone does not exist'}
headers = {'X-API-Key': self.PDNS_API_KEY, 'Content-Type': 'application/json'}
account_name_old = Account().get_name_by_id(domain.account_id)
account_name = Account().get_name_by_id(account_id)
post_data = {"account": account_name}
try:
jdata = utils.fetch_json(urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL +
'/servers/localhost/zones/{0}'.format(domain_name)),
headers=headers,
timeout=int(
Setting().get('pdns_api_timeout')),
method='PUT',
verify=Setting().get('verify_ssl_connections'),
data=post_data)
if 'error' in jdata.keys():
current_app.logger.error(jdata['error'])
return {'status': 'error', 'msg': jdata['error']}
else:
if update:
self.update()
msg_str = 'Account changed for zone {0} successfully'
current_app.logger.info(msg_str.format(domain_name))
history = History(msg='Update zone {0} associate account {1}'.format(domain.name, 'none' if account_name == '' else account_name),
detail = json.dumps({
'assoc_account': 'None' if account_name == '' else account_name,
'dissoc_account': 'None' if account_name_old == '' else account_name_old
}),
created_by=current_user.username)
history.add()
return {'status': 'ok', 'msg': 'account changed successfully'}
except Exception as e:
current_app.logger.debug(e)
current_app.logger.debug(traceback.format_exc())
msg_str = 'Cannot change account for zone {0}'
current_app.logger.error(msg_str.format(domain_name))
return {
'status': 'error',
'msg': 'Cannot change account for this zone.'
}
def get_account(self):
"""
Get current account associated with this zone
"""
domain = Domain.query.filter(Domain.name == self.name).first()
return domain.account
def is_valid_access(self, user_id):
"""
Check if the user is allowed to access this
zone name
"""
return db.session.query(Domain) \
.outerjoin(DomainUser, Domain.id == DomainUser.domain_id) \
.outerjoin(Account, Domain.account_id == Account.id) \
.outerjoin(AccountUser, Account.id == AccountUser.account_id) \
.filter(
db.or_(
DomainUser.user_id == user_id,
AccountUser.user_id == user_id
)).filter(Domain.id == self.id).first()
# Return None if this zone does not exist as record,
# Return the parent zone that hold the record if exist
def is_overriding(self, domain_name):
upper_domain_name = '.'.join(domain_name.split('.')[1:])
while upper_domain_name != '':
if self.get_id_by_name(upper_domain_name.rstrip('.')) != None:
upper_domain = self.get_domain_info(upper_domain_name)
if 'rrsets' in upper_domain:
for r in upper_domain['rrsets']:
if domain_name.rstrip('.') in r['name'].rstrip('.'):
current_app.logger.error('Zone already exists as a record: {} under zone: {}'.format(r['name'].rstrip('.'), upper_domain_name))
return upper_domain_name
upper_domain_name = '.'.join(upper_domain_name.split('.')[1:])
return None