--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+@author: Frank Brehm
+@contact: frank.brehm@pixelpark.com
+@copyright: © 2022 by Frank Brehm, Berlin
+@summary: A module for providing a configuration for applications,
+ which are Working with PowerDNS.
+ It's based on class MailConfigError.
+"""
+from __future__ import absolute_import
+
+# Standard module
+import logging
+import pwd
+import re
+import copy
+
+from numbers import Number
+
+# Third party modules
+
+# Own modules
+
+from fb_tools.common import is_sequence
+
+# from .config import ConfigError, BaseConfiguration
+from fb_tools.multi_config import MultiConfigError
+from fb_tools.multi_config import DEFAULT_ENCODING
+
+from .mail_config import MailConfigError, MailConfiguration
+from .mail_config import DEFAULT_CONFIG_DIR, MAX_PORT_NUMBER
+
+from .xlate import XLATOR
+
+MAX_PDNS_API_TIMEOUT = 3600
+
+__version__ = '0.1.0'
+LOG = logging.getLogger(__name__)
+
+_ = XLATOR.gettext
+
+
+# =============================================================================
+class PdnsConfigError(MailConfigError):
+ """Base error class for all exceptions happened during
+ execution this configured application"""
+
+ pass
+
+
+# =============================================================================
+class PdnsConfiguration(MailConfiguration):
+ """
+ A class for providing a configuration for an arbitrary PowerDNS Application
+ and methods to read it from configuration files.
+ """
+
+ default_pdns_api_instances = {
+ 'global': {
+ 'host': "dnsmaster.pp-dns.com",
+ },
+ 'public': {
+ 'host': "dnsmaster-public.pixelpark.com",
+ },
+ 'local': {
+ 'host': "dnsmaster-local.pixelpark.com",
+ },
+ }
+
+ default_pdns_api_port = 8081
+ default_pdns_api_servername = "localhost"
+ default_pdns_timeout = 20
+
+ default_pdns_instance = 'global'
+
+ # -------------------------------------------------------------------------
+ def __init__(
+ self, appname=None, verbose=0, version=__version__, base_dir=None,
+ append_appname_to_stems=True, additional_stems=None, config_dir=DEFAULT_CONFIG_DIR,
+ additional_config_file=None, additional_cfgdirs=None, encoding=DEFAULT_ENCODING,
+ ensure_privacy=True, use_chardet=True, initialized=False):
+
+ self.pdns_api_instances = {}
+ for inst_name in self.default_pdns_api_instances.keys():
+
+ def_inst = self.default_pdns_api_instances[inst_name]
+
+ inst = {}
+ inst['host'] = def_inst['host']
+ inst['port'] = self.default_pdns_api_port
+ inst['key'] = None
+ inst['servername'] = self.default_pdns_api_servername
+
+ self.pdns_api_instances[inst_name] = inst
+
+ self.pdns_timeout = self.default_pdns_timeout
+
+ add_stems = []
+ if additional_stems:
+ if is_sequence(additional_stems):
+ for stem in additional_stems:
+ add_stems.append(stem)
+ else:
+ add_stems.append(additional_stems)
+
+ if 'pdns' not in add_stems:
+ add_stems.append('pdns')
+
+ if 'powerdns' not in add_stems:
+ add_stems.append('powerdns')
+
+ super(PdnsConfiguration, self).__init__(
+ appname=appname, verbose=verbose, version=version, base_dir=base_dir,
+ append_appname_to_stems=append_appname_to_stems, config_dir=config_dir,
+ additional_stems=add_stems, additional_config_file=additional_config_file,
+ additional_cfgdirs=additional_cfgdirs, encoding=encoding, use_chardet=use_chardet,
+ ensure_privacy=ensure_privacy, initialized=False,
+ )
+
+ if initialized:
+ self.initialized = True
+
+ # -------------------------------------------------------------------------
+ def as_dict(self, short=True):
+ """
+ Transforms the elements of the object into a dict
+
+ @param short: don't include local properties in resulting dict.
+ @type short: bool
+
+ @return: structure as dict
+ @rtype: dict
+ """
+
+ res = super(PdnsConfiguration, self).as_dict(short=short)
+
+ res['default_pdns_api_instances'] = self.default_pdns_api_instances
+ res['default_pdns_api_port'] = self.default_pdns_api_port
+ res['default_pdns_api_servername'] = self.default_pdns_api_servername
+ res['default_pdns_timeout'] = self.default_pdns_timeout
+ res['default_pdns_instance'] = self.default_pdns_instance
+
+ return res
+
+ # -------------------------------------------------------------------------
+ def eval_section(self, section_name):
+
+ super(PdnsConfiguration, self).eval_section(section_name)
+ sn = section_name.lower()
+
+ if sn == 'pdns' or sn == 'powerdns':
+ section = self.cfg[section_name]
+ return self._eval_pdns(section_name, section)
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns(self, section_name, section):
+
+ if self.verbose > 2:
+ msg = _("Evaluating config section {!r}:").format(section_name)
+ LOG.debug(msg + '\n' + pp(section))
+
+ self._eval_pdns_timeout(section_name, section)
+ self._eval_pdns_instances(section_name, section)
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns_timeout(self, section_name, section):
+
+ re_timeout = re.compile(r'^\s*timeout\s*$', re.IGNORECASE)
+
+ for key in section.keys():
+ if not re_timeout.search(key):
+ continue
+
+ val = section[key]
+ try:
+ timeout = int(val)
+ except (ValueError, TypeError) as e:
+ msg = _("Value {!r} for PowerDNS API timeout is invalid:").format(val)
+ LOG.error(msg)
+ continue
+ if timeout <= 0 or port > MAX_PDNS_API_TIMEOUT:
+ msg = _("Value {!r} for PowerDNS API timeout is invalid:").format(timeout)
+ LOG.error(msg)
+ continue
+
+ self.pdns_timeout = timeout
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns_instances(self, section_name, section):
+
+ re_inst = re.compile(r'^\s*instances?\s*$', re.IGNORECASE)
+
+ for key in section.keys():
+ if not re_inst.search(key):
+ continue
+
+ for instance_name in section[key].keys():
+ self._eval_pdns_instance(self, instance_name, section[key][instance_name])
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns_instance(self, instance_name, section):
+
+ iname = instance_name.lower()
+
+ if self.verbose > 2:
+ msg = _("Evaluating PowerDNS instance {!r}:").format(iname)
+ LOG.debug(msg + '\n' + pp(section))
+
+ self._eval_pdns_inst_host(iname, section)
+ self._eval_pdns_inst_port(iname, section)
+ self._eval_pdns_inst_servername(iname, section)
+ self._eval_pdns_inst_key(iname, section)
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns_inst_host(self, iname, section):
+
+ pass
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns_inst_port(self, iname, section):
+
+ pass
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns_inst_servername(self, iname, section):
+
+ pass
+
+ # -------------------------------------------------------------------------
+ def _eval_pdns_inst_key(self, iname, section):
+
+ pass
+
+# re_cc = re.compile(r'^\s*(mail[_-]?)?cc\s*$', re.IGNORECASE)
+#
+# for key in section.keys():
+#
+# self._mail_cc_configured = True
+# if not re_cc.search(key):
+# continue
+#
+# val = section[key]
+# if not val:
+# continue
+# if is_sequence(val):
+# for v in val:
+# result = self._split_mailaddress_tokens(v, _("cc mail address"))
+# if result:
+# self.mail_cc.expand(result)
+# else:
+# result = self._split_mailaddress_tokens(val, _("cc mail address"))
+# if result:
+# self.mail_cc.expand(result)
+#
+# # -------------------------------------------------------------------------
+# def _eval_mail_reply_to(self, section_name, section):
+#
+# re_reply = re.compile(r'^\s*(mail[_-]?)?reply([-_]?to)?\s*$', re.IGNORECASE)
+#
+# for key in section.keys():
+# if not re_reply.search(key):
+# continue
+#
+# val = section[key]
+#
+# if is_sequence(val):
+# if not len(val):
+# continue
+# val = val[0]
+#
+# if MailAddress.valid_address(val):
+# self.reply_to = val
+# else:
+# msg = _("Found invalid {what} {addr!r} in configuration.")
+# LOG.error(msg.format(what=_("reply to address"), addr=val))
+#
+# # -------------------------------------------------------------------------
+# def _eval_mail_method(self, section_name, section):
+#
+# re_method = re.compile(r'^\s*(mail[_-]?)?method\s*$', re.IGNORECASE)
+#
+# for key in section.keys():
+# if not re_reply.search(key):
+# continue
+#
+# val = section[key].strip().lower()
+# if not val:
+# continue
+#
+# if val not in self.valid_mail_methods:
+# msg = _("Found invalid mail method {!r} in configuration.")
+# LOG.error(msg.format(section[key]))
+# continue
+#
+# self.mail_method = val
+#
+# # -------------------------------------------------------------------------
+# def _eval_mail_server(self, section_name, section):
+#
+# re_server = re.compile(r'^\s*(mail[_-]?)?server\s*$', re.IGNORECASE)
+#
+# for key in section.keys():
+# if not re_server.search(key):
+# continue
+#
+# val = section[key].strip().lower()
+# if not val:
+# continue
+#
+# self.mail_server = val
+#
+# # -------------------------------------------------------------------------
+# def _eval_smtp_port(self, section_name, section):
+#
+# re_server = re.compile(r'^\s*(smtp[_-]?)?port\s*$', re.IGNORECASE)
+#
+# for key in section.keys():
+# if not re_server.search(key):
+# continue
+#
+# val = section[key]
+# try:
+# port = int(val)
+# except (ValueError, TypeError) as e:
+# msg = _("Value {!r} for SMTP port is invalid:").format(val)
+# LOG.error(msg)
+# continue
+# if port <= 0 or port > MAX_PORT_NUMBER:
+# msg = _("Found invalid SMTP port number {} in configuration.").format(port)
+# LOG.error(msg)
+# continue
+#
+# self.smtp_port = port
+
+# =============================================================================
+if __name__ == "__main__":
+
+ pass
+
+# =============================================================================
+
+# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list