Implement account update method

Allow syncing of all known accounts from PowerDNS, in the same
way that Domain().update() does for domains.
This commit is contained in:
Nick Douma 2020-08-06 15:16:18 +02:00
parent 4e63f8380b
commit 0ef57b2f9f
4 changed files with 103 additions and 6 deletions

View file

@ -1,6 +1,10 @@
import traceback
from flask import current_app from flask import current_app
from urllib.parse import urljoin
from ..lib import utils
from .base import db from .base import db
from .setting import Setting
from .user import User from .user import User
from .account_user import AccountUser from .account_user import AccountUser
@ -20,6 +24,12 @@ class Account(db.Model):
self.contact = contact self.contact = contact
self.mail = mail self.mail = mail
# 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)
if self.name is not None: if self.name is not None:
self.name = ''.join(c for c in self.name.lower() self.name = ''.join(c for c in self.name.lower()
if c in "abcdefghijklmnopqrstuvwxyz0123456789") if c in "abcdefghijklmnopqrstuvwxyz0123456789")
@ -200,3 +210,57 @@ class Account(db.Model):
'Cannot revoke user privileges on account {0}. DETAIL: {1}'. 'Cannot revoke user privileges on account {0}. DETAIL: {1}'.
format(self.name, e)) format(self.name, e))
return False return False
def update(self):
"""
Fetch accounts from PowerDNS and syncs them into DB
"""
db_accounts = Account.query.all()
list_db_accounts = [d.name for d in db_accounts]
current_app.logger.info("Found {} accounts in PowerDNS-Admin".format(
len(list_db_accounts)))
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_jaccount = set(d['account'] for d in jdata if d['account'])
try:
# Remove accounts that don't exist any more
should_removed_db_account = list(
set(list_db_accounts).difference(list_jaccount))
for account_name in should_removed_db_account:
account_id = self.get_id_by_name(account_name)
if not account_id:
continue
current_app.logger.info("Deleting account for {0}".format(account_name))
account = Account.query.get(account_id)
db.session.delete(account)
except Exception as e:
current_app.logger.error(
'Can not delete account from DB. DETAIL: {0}'.format(e))
current_app.logger.debug(traceback.format_exc())
for account_name in list_jaccount:
account_id = self.get_id_by_name(account_name)
if account_id:
continue
current_app.logger.info("Creating account for {0}".format(account_name))
account = Account(name=account_name)
db.session.add(account)
db.session.commit()
current_app.logger.info('Update accounts finished')
return {
'status': 'ok',
'msg': 'Account table has been updated successfully'
}
except Exception as e:
db.session.rollback()
current_app.logger.error(
'Cannot update account table. Error: {0}'.format(e))
return {'status': 'error', 'msg': 'Cannot update account table'}

View file

@ -116,7 +116,7 @@ class Domain(db.Model):
db_domain = Domain.query.all() db_domain = Domain.query.all()
list_db_domain = [d.name for d in db_domain] list_db_domain = [d.name for d in db_domain]
dict_db_domain = dict((x.name, x) for x in db_domain) dict_db_domain = dict((x.name, x) for x in db_domain)
current_app.logger.info("Found {} entries in PowerDNS-Admin".format( current_app.logger.info("Found {} domains in PowerDNS-Admin".format(
len(list_db_domain))) len(list_db_domain)))
headers = {'X-API-Key': self.PDNS_API_KEY} headers = {'X-API-Key': self.PDNS_API_KEY}
try: try:
@ -128,7 +128,7 @@ class Domain(db.Model):
verify=Setting().get('verify_ssl_connections')) verify=Setting().get('verify_ssl_connections'))
list_jdomain = [d['name'].rstrip('.') for d in jdata] list_jdomain = [d['name'].rstrip('.') for d in jdata]
current_app.logger.info( current_app.logger.info(
"Found {} entries in PowerDNS server".format(len(list_jdomain))) "Found {} zones in PowerDNS server".format(len(list_jdomain)))
try: try:
# domains should remove from db since it doesn't exist in powerdns anymore # domains should remove from db since it doesn't exist in powerdns anymore
@ -166,8 +166,8 @@ class Domain(db.Model):
except Exception as e: except Exception as e:
db.session.rollback() db.session.rollback()
current_app.logger.error( current_app.logger.error(
'Can not update domain table. Error: {0}'.format(e)) 'Cannot update domain table. Error: {0}'.format(e))
return {'status': 'error', 'msg': 'Can not update domain table'} return {'status': 'error', 'msg': 'Cannot update domain table'}
def update_pdns_admin_domain(self, domain, account_id, data, do_commit=True): def update_pdns_admin_domain(self, domain, account_id, data, do_commit=True):
# existing domain, only update if something actually has changed # existing domain, only update if something actually has changed

33
update_accounts.py Normal file
View file

@ -0,0 +1,33 @@
#!/usr/bin/env python3
####################################################################################################################################
# A CLI Script to update list of accounts. Can be useful for people who want to execute updates from a cronjob
#
# Tip:
# When running from a cron, use flock (you might need to install it) to be sure only one process is running a time. eg:
# */5 * * * * flock -xn "/tmp/pdns-update-zones.lock" python /var/www/html/apps/poweradmin/update_accounts.py >/dev/null 2>&1
#
##############################################################
### Imports
import sys
import logging
from powerdnsadmin import create_app
from powerdnsadmin.models.account import Account
from powerdnsadmin.models.domain import Domain
from powerdnsadmin.models.setting import Setting
app = create_app()
app.logger.setLevel(logging.INFO)
with app.app_context():
status = Setting().get('bg_domain_updates')
### Check if bg_domain_updates is set to true
if not status:
app.logger.error('Please turn on "bg_domain_updates" setting to run this job.')
sys.exit(1)
Account().update()
Domain().update()

View file

@ -29,6 +29,6 @@ with app.app_context():
sys.exit(1) sys.exit(1)
### Start the update process ### Start the update process
app.logger.info('Update zones from nameserver API') app.logger.info('Update domains from nameserver API')
d = Domain().update() Domain().update()