From 0a4da5504640600e81094dbb374c28fab2e2accb Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Thu, 11 Jan 2018 16:42:12 +0100 Subject: [PATCH] Adding DB connection stuff --- bin/check-dnsui-users | 2 +- etc/check-dnsui-users.ini.default | 19 ++++ pp_lib/dnsui_users.py | 159 +++++++++++++++++++++++++++++- 3 files changed, 178 insertions(+), 2 deletions(-) diff --git a/bin/check-dnsui-users b/bin/check-dnsui-users index fa4ef4e..0d8c667 100755 --- a/bin/check-dnsui-users +++ b/bin/check-dnsui-users @@ -34,7 +34,7 @@ app.initialized = True if app.verbose > 2: print("{c}-Object:\n{a}".format(c=app.__class__.__name__, a=app)) -#app() +app() sys.exit(0) diff --git a/etc/check-dnsui-users.ini.default b/etc/check-dnsui-users.ini.default index 3f42897..c8f965d 100644 --- a/etc/check-dnsui-users.ini.default +++ b/etc/check-dnsui-users.ini.default @@ -34,4 +34,23 @@ bind_dn = uid=Solaris_NSS,ou=Unix NSS,ou=Applications,o=pixelpark,o=isp # Timeout in seconds for all LDAP operations timeout = 5 + +[database] +; Connection details to the Postgres database + +# Zhe hostname or address of the PostgreSQL instance +#host = master.pp-dns.com + +# The TCP port number of the PostgreSQL instance +#port = 5432 + +# The database in the PostgreSQL instance +#db = dnsui + +# The name of the database user +#user = pdnsadm + +# The password of the database user +#password = + # vim: filetype=dosini diff --git a/pp_lib/dnsui_users.py b/pp_lib/dnsui_users.py index 2d81536..c1e8bb2 100644 --- a/pp_lib/dnsui_users.py +++ b/pp_lib/dnsui_users.py @@ -12,6 +12,7 @@ from __future__ import absolute_import import logging import logging.config import textwrap +import socket # Third party modules # from ldap3 import ObjectDef, AttrDef, Reader, Writer @@ -23,7 +24,7 @@ from .common import pp from .ldap_app import PpLdapAppError, PpLdapApplication -__version__ = '0.1.1' +__version__ = '0.2.1' LOG = logging.getLogger(__name__) @@ -41,12 +42,26 @@ class DnsuiUsersApp(PpLdapApplication): default_admin_group = "cn=Administratoren Pixelpark Berlin,ou=Groups,o=Pixelpark,o=isp" + # DB data + default_db_host = 'master.pp-dns.com' + default_db_port = 5432 + default_db_db = 'dnsui' + default_db_user = 'pdnsadm' + # ------------------------------------------------------------------------- def __init__(self, appname=None, version=__version__): self.admin_users = [] self.admin_group = self.default_admin_group + self.db_host = self.default_db_host + self.db_port = self.default_db_port + self.db_db = self.default_db_db + self.db_user = self.default_db_user + self.db_pass = None + + self.db_connection = None + self._show_simulate_opt = True description = textwrap.dedent('''\ @@ -60,7 +75,149 @@ class DnsuiUsersApp(PpLdapApplication): self.initialized = True + # ------------------------------------------------------------------------- + def perform_config(self): + """ + Execute some actions after reading the configuration. + + This method should be explicitely called by all perform_config() + methods in descendant classes. + """ + + super(DnsuiUsersApp, self).perform_config() + + for section_name in self.cfg.keys(): + + if self.verbose > 2: + LOG.debug("Checking config section {!r} ...".format(section_name)) + section = self.cfg[section_name] + + if section_name.lower() in ('db', 'database'): + self.do_db_cfg(section_name, section) + + # ------------------------------------------------------------------------- + def do_db_cfg(self, section_name, section): + + if self.verbose > 2: + LOG.debug("Evaluating config section {n!r}:\n{s}".format( + n=section_name, s=pp(section))) + + if 'host' in section: + host = section['host'].lower().strip() + if not host: + LOG.error('Invalid hostname {!r} in configuration section {!r} found.'.format( + section['host'], section_name)) + else: + try: + _ = socket.getaddrinfo(host, 5432, proto=socket.IPPROTO_TCP) + except socket.gaierror as e: + msg = 'Invalid hostname {!r} in configuration section {!r}: {}'.format( + section['host'], section_name, e) + LOG.error(msg) + self.config_has_errors = True + else: + self.db_host = host + + if 'port' in section: + try: + port = int(section['port']) + if port <= 0: + raise ValueError("port number may not be negative.") + elif port >= (2 ** 16): + raise ValueError("port number must be less than {}".format((2 ** 16))) + except (ValueError, TypeError) as e: + msg = 'Invalid port number {!r} in configuration section {!r}: {}'.format( + section['port'],section_name, e) + LOG.error(msg) + self.config_has_errors = True + else: + self.db_port = port + + if 'db' in section: + db = section['db'].lower().strip() + if not db: + LOG.error('Invalid database name {!r} in configuration section {!r} found.'.format( + section['db'], section_name)) + else: + self.db_db = db + + if 'user' in section: + user = section['user'].lower().strip() + if not user: + LOG.error('Invalid database user {!r} in configuration section {!r} found.'.format( + section['user'], section_name)) + self.config_has_errors = True + else: + self.db_user = user + + if 'password' in section: + self.db_pass = section['password'] + + # ------------------------------------------------------------------------- + def pre_run(self): + + self.connect_db() + + # ------------------------------------------------------------------------- + def connect_db(self): + + result = None + + LOG.debug("Connecting to PostgreSQL database on {}@{}:{}/{} ...".format( + self.db_user, self.db_host, self.db_port, self.db_db)) + try: + self.db_connection = psycopg2.connect( + host=self.db_host, + port=self.db_port, + dbname=self.db_db, + user=self.db_user, + password=self.db_pass, + ) + + sql = 'SHOW server_version' + if self.verbose > 1: + LOG.debug("SQL: {}".format(sql)) + with self.db_connection.cursor() as cursor: + cursor.execute(sql) + result = cursor.fetchone() + if self.verbose > 2: + LOG.debug("Got version info:\n{}".format(pp(result))) + LOG.info("Database is PostgreSQL version {!r}.".format(result[0])) + + except psycopg2.OperationalError as e: + LOG.error("Could not connect to database ({}): {}".format( + e.__class__.__name__, e)) + self.exit(7) + + # ------------------------------------------------------------------------- + def _run(self): + + try: + + LOG.info("Starting user checks ...") + + finally: + self._close_db() + + # ------------------------------------------------------------------------- + def _close_db(self): + + if self.db_connection: + LOG.debug("Closing database connection.") + try: + self.db_connection.close() + except Exception as e: + LOG.error("Could not close database connection ({}): {}".format( + e.__class__.__name__, e)) + traceback.print_exc() + self.db_connection = None + + # ------------------------------------------------------------------------- + def post_run(self): + if self.verbose > 1: + LOG.info("executing post_run() ...") + self._close_db() # ============================================================================= -- 2.39.5