]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Refactoring lib/pp_admintools/pdns_app.py
authorFrank Brehm <frank@brehm-online.com>
Tue, 29 Mar 2022 16:47:44 +0000 (18:47 +0200)
committerFrank Brehm <frank@brehm-online.com>
Tue, 29 Mar 2022 16:47:44 +0000 (18:47 +0200)
lib/pp_admintools/pdns_app.py

index 61f01438a2841d43e3592c597b84ddc76c9e03dc..236df5b20f4d95e4b50aa11af04a692c5c471b3b 100644 (file)
@@ -27,99 +27,64 @@ from fb_pdnstools.zone import PowerDNSZone
 from fb_pdnstools.server import PowerDNSServer
 from fb_pdnstools.errors import PDNSApiNotFoundError
 from fb_pdnstools.errors import PDNSApiValidationError
+from fb_tools.xlate import format_list
 
-from fb_tools.errors import FbCfgAppError
+from . import __version__ as GLOBAL_VERSION
 
-from fb_tools.cfg_app import FbConfigApplication
+from .argparse_actions import PortOptionAction, TimeoutOptionAction
+
+from .mail_app import MailAppError, BaseMailApplication
+
+from .pdns_config import PdnsConfigError, PdnsConfiguration, LIBRARY_NAME
 
 from .xlate import XLATOR
 
-__version__ = '0.8.0'
+__version__ = '0.9.0'
 LOG = logging.getLogger(__name__)
-_LIBRARY_NAME = "pp-pdns-api-client"
 
 _ = XLATOR.gettext
 
 
 # =============================================================================
-class PpPDNSAppError(FbCfgAppError):
+class PpPDNSAppError(MailAppError):
     """Base error class for all exceptions happened during
     execution this configured application"""
     pass
 
 
 # =============================================================================
-class PpPDNSApplication(FbConfigApplication):
+class PpPDNSApplication(BaseMailApplication):
     """
     Class for configured application objects related to PowerDNS.
     """
 
-    api_keys = {
-        'global': "6d1b08e2-59c6-49e7-9e48-039ade102016",
-        'public': "cf0fb928-2a73-49ec-86c2-36e85c9672ff",
-        'local': "d94b183a-c50d-47f7-b338-496090af1577"
-    }
-
-    api_hosts = {
-        'global': "dnsmaster.pp-dns.com",
-        'public': "dnsmaster-public.pixelpark.com",
-        'local': "dnsmaster-local.pixelpark.com"
-    }
-
-    default_api_port = 8081
-    default_api_servername = "localhost"
-    default_timeout = 20
-
     # -------------------------------------------------------------------------
     def __init__(
-        self, appname=None, verbose=0, version=__version__, base_dir=None,
-            initialized=None, usage=None, description=None,
+        self, appname=None, verbose=0, version=GLOBAL_VERSION, base_dir=None,
+            cfg_class=PdnsConfiguration, initialized=False, usage=None, description=None,
             argparse_epilog=None, argparse_prefix_chars='-', env_prefix=None,
-            cfg_dir=None, cfg_stems=None, cfg_encoding='utf-8', need_config_file=False,
-            environment='global'):
+            instance=None):
+
+        if instance:
+            self._instance = instance
+        else:
+            self._instance = PdnsConfiguration.default_pdns_instance
 
-        self._api_key = self.api_keys['global']
-        self._api_host = self.api_hosts['global']
-        self._api_port = self.default_api_port
-        self._api_servername = self.default_api_servername
+        self._api_key = None
+        self._api_host = None
+        self._api_port = None
+        self._api_servername = None
         self._api_server_version = 'unknown'
-        self._user_agent = '{}/{}'.format(_LIBRARY_NAME, self.version)
-        self._timeout = self.default_timeout
 
         self.local_addresses = []
 
         self.pdns = None
 
-        self._environment = 'global'
-        if environment != 'global':
-            self.environment = environment
-
-        stems = []
-        if cfg_stems:
-            if isinstance(cfg_stems, list):
-                for stem in cfg_stems:
-                    s = str(stem).strip()
-                    if not s:
-                        msg = _("Invalid configuration stem {!r} given.").format(stem)
-                        raise PpPDNSAppError(msg)
-                    stems.append(s)
-            else:
-                s = str(cfg_stems).strip()
-                if not s:
-                    msg = _("Invalid configuration stem {!r} given.").format(cfg_stems)
-                    raise PpPDNSAppError(msg)
-                stems.append(s)
-        else:
-            stems = [self.appname]
-        if 'pdns-api' not in stems:
-            stems.insert(0, 'pdns-api')
-
         super(PpPDNSApplication, self).__init__(
             appname=appname, verbose=verbose, version=version, base_dir=base_dir,
-            initialized=False, usage=usage, description=description,
+            description=description, cfg_class=cfg_class, initialized=False,
             argparse_epilog=argparse_epilog, argparse_prefix_chars=argparse_prefix_chars,
-            env_prefix=env_prefix, cfg_dir=cfg_dir, cfg_stems=stems,
-            cfg_encoding=cfg_encoding, need_config_file=need_config_file,
+            env_prefix=env_prefix,
         )
 
         for interface, snics in psutil.net_if_addrs().items():
@@ -129,7 +94,11 @@ class PpPDNSApplication(FbConfigApplication):
                     if addr not in self.local_addresses:
                         self.local_addresses.append(addr)
 
-        self._user_agent = '{}/{}'.format(_LIBRARY_NAME, self.version)
+        if not self.cfg:
+            msg=_("Configuration not available.")
+            raise PpPDNSAppError(msg)
+
+        self.eval_instance(instance)
 
     # -----------------------------------------------------------
     @property
@@ -188,45 +157,38 @@ class PpPDNSApplication(FbConfigApplication):
 
     # -----------------------------------------------------------
     @property
-    def user_agent(self):
-        "The name of the user agent used in API calls."
-        return self._user_agent
+    def instance(self):
+        "The name of the PowerDNS instance."
+        return self._instance
 
-    @user_agent.setter
-    def user_agent(self, value):
-        if value is None or str(value).strip() == '':
-            raise PpPDNSAppError(_("Invalid user agent {!r} given.").format(value))
-        self._user_agent = str(value).strip()
+    @instance.setter
+    def instance(self, value):
+        if value is None:
+            raise PpPDNSAppError(_("Invalid instance {!r} given.").format(None))
+        v = str(value).strip().lower()
+        if v not in self.api_keys.keys():
+            raise PpPDNSAppError(_("Invalid instance {!r} given.").format(value))
 
-    # -----------------------------------------------------------
-    @property
-    def timeout(self):
-        "The timeout in seconds on requesting the PowerDNS API."
-        return self._timeout
+        self.eval_instance(v)
 
-    @timeout.setter
-    def timeout(self, value):
-        v = int(value)
-        if v < 1:
-            raise PpPDNSAppError(_("Invalid timeout {!r} given.").format(value))
-        self._timeout = v
+    # -------------------------------------------------------------------------
+    def eval_instance(self, inst_name):
 
-    # -----------------------------------------------------------
-    @property
-    def environment(self):
-        "The name of the PowerDNS environment."
-        return self._environment
+        if not self.cfg:
+            msg = _("Configuration not available.")
+            raise PpPDNSAppError(msg)
 
-    @environment.setter
-    def environment(self, value):
-        if value is None:
-            raise PpPDNSAppError(_("Invalid environment {!r} given.").format(None))
-        v = str(value).strip().lower()
-        if v not in self.api_keys.keys():
-            raise PpPDNSAppError(_("Invalid environment {!r} given.").format(value))
-        self._environment = v
-        self._api_host = self.api_hosts[v]
-        self._api_key = self.api_keys[v]
+        if inst_name not in self.cfg.pdns_api_instances:
+            msg = _("PDNS instance {!r} is not configured.").format(inst_name)
+            raise PpPDNSAppError(msg)
+
+        inst = self.cfg.pdns_api_instances[inst_name]
+
+        self._instance = inst_name
+        self.api_host = inst['host']
+        self.api_port = inst['port']
+        self.api_key = inst['key']
+        self.api_servername = inst['servername']
 
     # -------------------------------------------------------------------------
     def as_dict(self, short=True):
@@ -242,17 +204,10 @@ class PpPDNSApplication(FbConfigApplication):
 
         res = super(PpPDNSApplication, self).as_dict(short=short)
         res['api_host'] = self.api_host
-        res['api_hosts'] = copy.copy(self.api_hosts)
         res['api_key'] = self.api_key
-        res['api_keys'] = copy.copy(self.api_keys)
         res['api_port'] = self.api_port
         res['api_servername'] = self.api_servername
-        res['default_api_port'] = self.default_api_port
-        res['default_api_servername'] = self.default_api_servername
-        res['default_timeout'] = self.default_timeout
-        res['environment'] = self.environment
-        res['timeout'] = self.timeout
-        res['user_agent'] = self.user_agent
+        res['instance'] = self.instance
         res['api_server_version'] = self.api_server_version
 
         return res
@@ -269,52 +224,53 @@ class PpPDNSApplication(FbConfigApplication):
         super(PpPDNSApplication, self).init_arg_parser()
 
         pdns_group = self.arg_parser.add_argument_group(_('PowerDNS API options'))
-        env_group = pdns_group.add_mutually_exclusive_group()
+        inst_group = pdns_group.add_mutually_exclusive_group()
 
-        envs = []
-        for env in self.api_keys.keys():
-            envs.append(str(env))
-        envs.sort()
+        insts = PdnsConfiguration.valid_pdns_api_instances
+        inst_list = format_list(insts, do_repr=True)
+        default_timeout = PdnsConfiguration.default_pdns_timeout
 
-        env_group.add_argument(
-            '-E', '--env', '--environment',
-            metavar=_("ENVIRONMENT"), choices=envs, dest="env",
+        inst_group.add_argument(
+            '-I', '--inst', '--instance',
+            metavar=_("INSTANCE"), choices=envs, dest="inst",
             help=_(
-                "Select, which PowerDNS environment to use. "
-                "Valid values: {v}, default: {d!r}.").format(
-                    v=', '.join(map(lambda x: repr(x), envs)), d='global')
+                "Select, which PowerDNS instance to use. Valid values: {v}, "
+                "default: {d!r}.").format(v=inst_list, d=self.instance),
         )
 
-        env_group.add_argument(
+        inst_group.add_argument(
             '-G', '--global',
-            action='store_true', dest="env_global",
-            help=_("Using the {!r} PowerDNS environment.").format('global'),
+            action='store_true', dest="inst_global",
+            help=_("Using the {!r} PowerDNS instance.").format('global'),
         )
 
-        env_group.add_argument(
+        inst_group.add_argument(
             '-L', '--local',
-            action='store_true', dest="env_local",
-            help=_("Using the {!r} PowerDNS environment.").format('local'),
+            action='store_true', dest="inst_local",
+            help=_("Using the {!r} PowerDNS instance.").format('local'),
         )
 
-        env_group.add_argument(
+        inst_group.add_argument(
             '-P', '--public',
-            action='store_true', dest="env_public",
-            help=_("Using the {!r} PowerDNS environment.").format('public'),
+            action='store_true', dest="inst_public",
+            help=_("Using the {!r} PowerDNS instance.").format('public'),
         )
 
         pdns_group.add_argument(
             '-p', '--port',
-            metavar=_("PORT"), type=int, dest='api_port', default=self.default_api_port,
+            metavar=_("PORT"), type=int, dest='api_port',
+            default=PdnsConfiguration.default_pdns_api_port,
+            what="PowerDNS API", action=PortOptionAction,
             help=_("Which port to connect to PowerDNS API, default: {}.").format(
-                self.default_api_port),
+                PdnsConfiguration.default_pdns_api_port),
         )
 
         pdns_group.add_argument(
             '-t', '--timeout',
-            metavar=_("SECS"), type=int, dest='timeout', default=self.default_timeout,
+            metavar=_("SECS"), type=int, dest='timeout', default=default_timeout,
+            what=_("PowerDNS API access"), action=TimeoutOptionAction,
             help=_("The timeout in seconds to request the PowerDNS API, default: {}.").format(
-                self.default_timeout),
+                default_timeout),
         )
 
     # -------------------------------------------------------------------------
@@ -324,80 +280,6 @@ class PpPDNSApplication(FbConfigApplication):
         the command line parameters.
         """
 
-        if self.args.env:
-            self.environment = self.args.env
-        elif self.args.env_global:
-            self.environment = 'global'
-        elif self.args.env_local:
-            self.environment = 'local'
-        elif self.args.env_public:
-            self.environment = 'public'
-
-        if self.args.api_port:
-            self.api_port = self.args.api_port
-
-        if self.args.timeout:
-            self.timeout = self.args.timeout
-
-    # -------------------------------------------------------------------------
-    def perform_config(self):
-
-        super(PpPDNSApplication, self).perform_config()
-
-        for section_name in self.cfg.keys():
-
-            if self.verbose > 3:
-                LOG.debug(_("Checking config section {!r} ...").format(section_name))
-
-            section = self.cfg[section_name]
-
-            if section_name.lower() in (
-                    'powerdns-api', 'powerdns_api', 'powerdnsapi',
-                    'pdns-api', 'pdns_api', 'pdnsapi'):
-                self.set_cfg_api_options(section, section_name)
-
-    # -------------------------------------------------------------------------
-    def set_cfg_api_options(self, section, section_name):
-
-        if self.verbose > 2:
-            LOG.debug(
-                _("Evaluating config section {!r}:").format(section_name) + '\n' + pp(section))
-
-        if 'environment' in section:
-            v = section['environment'].strip().lower()
-            if v not in self.api_hosts:
-                LOG.error(_("Wrong environment {!r} found in configuration.").format(
-                    section['environment']))
-                self.config_has_errors = True
-            else:
-                self.environment = v
-
-        if 'host' in section:
-            v = section['host']
-            host = v.lower().strip()
-            if host:
-                self.api_host = host
-
-        if 'port' in section:
-            try:
-                port = int(section['port'])
-                if port <= 0 or port > 2**16:
-                    raise ValueError(
-                        _("A port must be greater than 0 and less than {}.").format(2**16))
-            except (TypeError, ValueError) as e:
-                LOG.error(_("Wrong port number {p!r} in configuration section {s!r}: {e}").format(
-                    p=section['port'], s=section_name, e=e))
-                self.config_has_errors = True
-            else:
-                self.api_port = port
-
-        if 'server_id' in section and section['server_id'].strip():
-            self.api_servername = section['server_id'].strip().lower()
-
-        if 'key' in section:
-            key = section['key'].strip()
-            self.api_key = key
-
     # -------------------------------------------------------------------------
     def _check_path_config(self, section, section_name, key, class_prop, absolute=True, desc=None):
 
@@ -442,6 +324,23 @@ class PpPDNSApplication(FbConfigApplication):
         if self.verbose > 1:
             LOG.debug(_("Executing {} ...").format('post_init()'))
 
+        super(PpPDNSApplication, self).post_init()
+
+        if self.args.inst:
+            self.instance = self.args.inst
+        elif self.args.inst_global:
+            self.instance = 'global'
+        elif self.args.inst_local:
+            self.instance = 'local'
+        elif self.args.inst_public:
+            self.instance = 'public'
+
+        if self.args.api_port:
+            self.api_port = self.args.api_port
+
+        if self.args.timeout:
+            self.cfg.pdns_timeout = self.args.timeout
+
         self.pdns = PowerDNSServer(
             appname=self.appname, verbose=self.verbose, base_dir=self.base_dir,
             master_server=self.api_host, port=self.api_port,
@@ -450,8 +349,6 @@ class PpPDNSApplication(FbConfigApplication):
         )
         self.pdns.initialized = True
 
-        self.initialized = True
-
     # -------------------------------------------------------------------------
     def pre_run(self):
         """
@@ -490,6 +387,9 @@ class PpPDNSApplication(FbConfigApplication):
         if self.verbose > 1:
             LOG.debug(_("Executing {} ...").format('post_run()'))
 
+        if self.pdns:
+            self.pdns = None
+
     # -------------------------------------------------------------------------
     def get_api_server_version(self):