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 urllib.parse import urljoin
from ..lib import utils
from .base import db
from .setting import Setting
from .user import User
from .account_user import AccountUser
@ -20,6 +24,12 @@ class Account(db.Model):
self.contact = contact
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:
self.name = ''.join(c for c in self.name.lower()
if c in "abcdefghijklmnopqrstuvwxyz0123456789")
@ -88,7 +98,7 @@ class Account(db.Model):
db.session.commit()
return {'status': True, 'msg': 'Account updated successfully'}
def delete_account(self):
def delete_account(self, commit=True):
"""
Delete an account
"""
@ -97,13 +107,14 @@ class Account(db.Model):
try:
Account.query.filter(Account.name == self.name).delete()
db.session.commit()
if commit:
db.session.commit()
return True
except Exception as e:
db.session.rollback()
current_app.logger.error(
'Cannot delete account {0} from DB. DETAIL: {1}'.format(
self.username, e))
self.name, e))
return False
def get_user(self):
@ -200,3 +211,59 @@ class Account(db.Model):
'Cannot revoke user privileges on account {0}. DETAIL: {1}'.
format(self.name, e))
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()
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 {} entries in PowerDNS-Admin".format(
current_app.logger.info("Found {} domains in PowerDNS-Admin".format(
len(list_db_domain)))
headers = {'X-API-Key': self.PDNS_API_KEY}
try:
@ -128,7 +128,7 @@ class Domain(db.Model):
verify=Setting().get('verify_ssl_connections'))
list_jdomain = [d['name'].rstrip('.') for d in jdata]
current_app.logger.info(
"Found {} entries in PowerDNS server".format(len(list_jdomain)))
"Found {} zones in PowerDNS server".format(len(list_jdomain)))
try:
# 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:
db.session.rollback()
current_app.logger.error(
'Can not update domain table. Error: {0}'.format(e))
return {'status': 'error', 'msg': 'Can not update domain table'}
'Cannot update domain table. Error: {0}'.format(e))
return {'status': 'error', 'msg': 'Cannot update domain table'}
def update_pdns_admin_domain(self, domain, account_id, data, do_commit=True):
# 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)
### 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()