Merge pull request #801 from cyso/pr/sync-accounts

Implement account update method
This commit is contained in:
Khanh Ngo 2020-10-12 12:48:22 +02:00 committed by GitHub
commit 70b1accaa0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 107 additions and 9 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")
@ -88,7 +98,7 @@ class Account(db.Model):
db.session.commit() db.session.commit()
return {'status': True, 'msg': 'Account updated successfully'} return {'status': True, 'msg': 'Account updated successfully'}
def delete_account(self): def delete_account(self, commit=True):
""" """
Delete an account Delete an account
""" """
@ -97,13 +107,14 @@ class Account(db.Model):
try: try:
Account.query.filter(Account.name == self.name).delete() Account.query.filter(Account.name == self.name).delete()
db.session.commit() if commit:
db.session.commit()
return True return True
except Exception as e: except Exception as e:
db.session.rollback() db.session.rollback()
current_app.logger.error( current_app.logger.error(
'Cannot delete account {0} from DB. DETAIL: {1}'.format( 'Cannot delete account {0} from DB. DETAIL: {1}'.format(
self.username, e)) self.name, e))
return False return False
def get_user(self): def get_user(self):
@ -200,3 +211,59 @@ 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'])
current_app.logger.info("Found {} accounts in PowerDNS".format(
len(list_jaccount)))
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)
account.delete_account(commit=False)
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

31
update_accounts.py Normal file
View file

@ -0,0 +1,31 @@
#!/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.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()

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()