]> Frank Brehm's Git Trees - pixelpark/create-vmware-tpl.git/commitdiff
Moving class CrTplConfiguration to BaseMultiConfig in module cr_vmware_tpl.config...
authorFrank Brehm <frank@brehm-online.com>
Tue, 21 Jun 2022 16:20:26 +0000 (18:20 +0200)
committerFrank Brehm <frank@brehm-online.com>
Tue, 21 Jun 2022 16:20:26 +0000 (18:20 +0200)
lib/cr_vmware_tpl/config.py

index a77757ab907f70254dc566c880c40c38564e431f..a979ac5395bd51c113ef7f5a495fefb7ab60553b 100644 (file)
@@ -18,14 +18,18 @@ import crypt
 from pathlib import Path
 
 # Own modules
-from fb_tools.config import ConfigError, BaseConfiguration
+from fb_tools.common import is_sequence
+from fb_tools.multi_config import MultiConfigError, BaseMultiConfig
+from fb_tools.multi_config import DEFAULT_ENCODING
 from fb_tools.xlate import format_list
 
 from fb_vmware.config import VSPhereConfigInfo
 
+from . import DEFAULT_CONFIG_DIR
+
 from .xlate import XLATOR
 
-__version__ = '1.7.2'
+__version__ = '1.8.1'
 LOG = logging.getLogger(__name__)
 
 _ = XLATOR.gettext
@@ -33,7 +37,7 @@ ngettext = XLATOR.ngettext
 
 
 # =============================================================================
-class CrTplConfigError(ConfigError):
+class CrTplConfigError(MultiConfigError):
     """Base error class for all exceptions happened during
     execution this configured application"""
 
@@ -41,13 +45,13 @@ class CrTplConfigError(ConfigError):
 
 
 # =============================================================================
-class CrTplConfiguration(BaseConfiguration):
+class CrTplConfiguration(BaseMultiConfig):
     """
     A class for providing a configuration for the CrTplApplication class
     and methods to read it from configuration files.
     """
 
-    default_os_id = 'centos8'
+    default_os_id = 'centos-stream-8'
 
     default_vsphere_host = 'vcs01.ppbrln.internal'
     default_vsphere_port = 443
@@ -124,7 +128,22 @@ class CrTplConfiguration(BaseConfiguration):
     # -------------------------------------------------------------------------
     def __init__(
         self, appname=None, verbose=0, version=__version__, base_dir=None,
-            encoding=None, config_dir=None, config_file=None, initialized=False):
+            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=False, use_chardet=True, initialized=False):
+
+        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 'mail' not in add_stems:
+            add_stems.append('mail')
+        if 'cobbler-repos' not in add_stems:
+            add_stems.append('cobbler-distros')
 
         self.os_id = self.default_os_id
 
@@ -173,13 +192,22 @@ class CrTplConfiguration(BaseConfiguration):
         self.cobbler_ws_base_url = self.default_cobbler_ws_base_url
         self.cobbler_ws_docroot = self.default_cobbler_ws_docroot
         self.cobbler_ws_rel_filesdir = self.default_cobbler_ws_rel_filesdir
+        self.cobbler_distros = {}
+
         self.system_status = self.default_system_status
 
         self.excluded_datastores = []
 
+        if config_dir is None:
+            config_dir = DEFAULT_CONFIG_DIR
+        LOG.debug("Config dir: {!r}.".format(config_dir))
+
         super(CrTplConfiguration, self).__init__(
             appname=appname, verbose=verbose, version=version, base_dir=base_dir,
-            encoding=encoding, config_dir=config_dir, config_file=config_file, initialized=False,
+            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,
         )
 
         self.vsphere_info = VSPhereConfigInfo(
@@ -236,7 +264,7 @@ class CrTplConfiguration(BaseConfiguration):
     @property
     def cobbler_profile_ks(self):
         """The absolute pathname of the profile kickstart file."""
-        return self.cobbler_ks_dir / (self.cobbler_profile + '.ks')
+        return self.cobbler_ks_dir / ('profile.' + self.cobbler_profile + '.ks')
 
     # -------------------------------------------------------------------------
     @property
@@ -316,10 +344,10 @@ class CrTplConfiguration(BaseConfiguration):
         return res
 
     # -------------------------------------------------------------------------
-    def eval_config(self, config):
-        """Evaluating of all found configuration options."""
+    def eval(self):
+        """Evaluating read configuration and storing them in object properties."""
 
-        super(CrTplConfiguration, self).eval_config(config)
+        super(CrTplConfiguration, self).eval()
 
         if self.verbose > 1:
             LOG.debug(_("Checking for unconfigured options ..."))
@@ -339,29 +367,76 @@ class CrTplConfiguration(BaseConfiguration):
         if not self.cobbler_profile_given:
             self.cobbler_profile = 'vmware-template-' + self.os_id
 
+        self.verify_cobbler_distros()
+
+    # -------------------------------------------------------------------------
+    def verify_cobbler_distros(self):
+
+        LOG.debug(_("Verifying cobbler distros ..."))
+
+        if not len(self.cobbler_distros):
+            msg = _("Did not found configured Cobbler distros.")
+            raise CrTplConfigError(msg)
+
+        for distro_id in self.cobbler_distros.keys():
+            distro_info = self.cobbler_distros[distro_id]
+
+            if 'distro' not in distro_info:
+                msg = _("Did not found distro of configured Cobbler distro {!r}.").format(
+                    distro_id)
+                raise CrTplConfigError(msg)
+
+            if not len(distro_info['repos']):
+                msg = _(
+                    "Did not found repo definitions for configured Cobbler "
+                    "distro {!r}.").format(distro_id)
+                LOG.warn(msg)
+
+            if 'description' not in distro_info:
+                distro_info['description'] = distro_id
+
+        if self.os_id not in self.cobbler_distros:
+            msg = _("Did not found distro {!r} in configured Cobbler distros.").format(self.os_id)
+            raise CrTplConfigError(msg)
+
+        self.cobbler_distro = self.cobbler_distros[self.os_id]['distro']
+
+        LOG.info(_("Using OS {os!r} with cobbler distro {di!r}.").format(
+            os=self.os_id, di=self.cobbler_distro))
+
     # -------------------------------------------------------------------------
-    def eval_config_section(self, config, section_name):
+    def eval_section(self, section_name):
+
+        re_cobbler_distros = re.compile(r'^\s*cobbler[_-]?distros\s*$', re.IGNORECASE)
+
+        LOG.debug(_("Evaluating section {!r} ...").format(section_name))
+
+        super(CrTplConfiguration, self).eval_section(section_name)
 
-        super(CrTplConfiguration, self).eval_config_section(config, section_name)
+        sn = section_name.lower()
+        section = self.cfg[section_name]
 
-        if section_name.lower() == 'vsphere':
-            self._eval_config_vsphere(config, section_name)
+        if sn == 'vsphere':
+            self._eval_config_vsphere(section_name, section)
             return
-        if section_name.lower() == 'template':
-            self._eval_config_template(config, section_name)
+        if sn == 'template':
+            self._eval_config_template(section_name, section)
             return
-        if section_name.lower() == 'timeouts':
-            self._eval_config_timeouts(config, section_name)
+        if sn == 'timeouts':
+            self._eval_config_timeouts(section_name, section)
             return
-        if section_name.lower() == 'cobbler':
-            self._eval_config_cobbler(config, section_name)
+        if sn == 'cobbler':
+            self._eval_config_cobbler(section_name, section)
+            return
+        if re_cobbler_distros.match(section_name):
+            self._eval_cobbler_distros(section_name, section)
             return
 
         if self.verbose > 1:
             LOG.debug(_("Unhandled configuration section {!r}.").format(section_name))
 
     # -------------------------------------------------------------------------
-    def _eval_config_vsphere(self, config, section_name):
+    def _eval_config_vsphere(self, section_name, section):
 
         if self.verbose > 1:
             LOG.debug(_("Checking config section {!r} ...").format(section_name))
@@ -370,7 +445,8 @@ class CrTplConfiguration(BaseConfiguration):
         re_split_ds = re.compile(r'[,;\s]+')
         re_storage_cluster = re.compile(r'^\s*storage[-_]?cluster\s*$', re.IGNORECASE)
 
-        for (key, value) in config.items(section_name):
+        for key in section.keys():
+            value = section[key]
 
             if key.lower() == 'host':
                 self.vsphere_info.host = value
@@ -421,7 +497,7 @@ class CrTplConfiguration(BaseConfiguration):
         return
 
     # -------------------------------------------------------------------------
-    def _eval_config_template(self, config, section_name):
+    def _eval_config_template(self, section_name, section):
 
         if self.verbose > 1:
             LOG.debug(_("Checking config section {!r} ...").format(section_name))
@@ -432,7 +508,9 @@ class CrTplConfiguration(BaseConfiguration):
         re_root_pwd = re.compile(r'^\s*root[-_]?password\s*$', re.IGNORECASE)
         re_swap_space = re.compile(r'^\s*swap[-_]?space(?:[-_]?mb)?\s*$', re.IGNORECASE)
 
-        for (key, value) in config.items(section_name):
+        for key in section.keys():
+            value = section[key]
+
             if re_os_id.match(key):
                 v = value.strip().lower()
                 v = re_os_id_subst.sub('', v)
@@ -518,12 +596,14 @@ class CrTplConfiguration(BaseConfiguration):
         setattr(self, prop_name, v)
 
     # -------------------------------------------------------------------------
-    def _eval_config_timeouts(self, config, section_name):
+    def _eval_config_timeouts(self, section_name, section):
 
         if self.verbose > 1:
             LOG.debug(_("Checking config section {!r} ...").format(section_name))
 
-        for (key, value) in config.items(section_name):
+        for key in section.keys():
+            value = section[key]
+
             if key.lower() == 'max_wait_for_general':
                 self._eval_timeout_value(
                     prop_name='max_wait_for_general', value=value,
@@ -532,7 +612,6 @@ class CrTplConfiguration(BaseConfiguration):
                     default_val=self.default_max_wait_for_general)
                 continue
 
-        for (key, value) in config.items(section_name):
             if key.lower() == 'max_wait_for_create_vm':
                 self._eval_timeout_value(
                     prop_name='max_wait_for_create_vm', value=value,
@@ -570,7 +649,7 @@ class CrTplConfiguration(BaseConfiguration):
                 continue
 
     # -------------------------------------------------------------------------
-    def _eval_config_cobbler(self, config, section_name):
+    def _eval_config_cobbler(self, section_name, section):
 
         if self.verbose > 1:
             LOG.debug(_("Checking config section {!r} ...").format(section_name))
@@ -592,7 +671,9 @@ class CrTplConfiguration(BaseConfiguration):
         re_system_status = re.compile(r'^\s*system[-_]?status\s*$', re.IGNORECASE)
         re_cobbler_bin_key = re.compile(r'^\s*(?:cobbler[_-]?)?bin\s*$', re.IGNORECASE)
 
-        for (key, value) in config.items(section_name):
+        for key in section.keys():
+            value = section[key]
+
             if key.lower() == 'distro' and value.strip() != '':
                 self.cobbler_distro = value.strip()
                 continue
@@ -661,6 +742,50 @@ class CrTplConfiguration(BaseConfiguration):
                     LOG.error(msg)
                 continue
 
+    # -------------------------------------------------------------------------
+    def _eval_cobbler_distros(self, section_name, section):
+
+        if self.verbose > 1:
+            LOG.debug(_("Checking config section {!r} ...").format(section_name))
+
+        for distro_id in section.keys():
+            distro_info = section[distro_id]
+            distro_id = distro_id.lower()
+            if distro_id not in self.cobbler_distros:
+                self.cobbler_distros[distro_id] = {}
+
+            self._eval_cobbler_distro(distro_id, distro_info)
+
+    # -------------------------------------------------------------------------
+    def _eval_cobbler_distro(self, distro_id, distro_info):
+
+        if self.verbose > 2:
+            LOG.debug(_("Evaluating Cobbler distro {!r} ...").format(distro_id))
+
+        distro = self.cobbler_distros[distro_id]
+
+        if 'repos' not in distro:
+            distro['repos'] = []
+
+        for key in distro_info.keys():
+            value = distro_info[key]
+
+            if key.lower() == 'distro' and value.strip() != '':
+                distro['distro'] = value.strip()
+                continue
+            if key.lower() == 'description' and value.strip() != '':
+                distro['description'] = value.strip()
+                continue
+            if key.lower() == 'repos':
+                if is_sequence(value):
+                    for repo in value:
+                        repo = repo.strip()
+                        if repo != '':
+                            distro['repos'].append(repo)
+                elif value.strip() != '':
+                    distro['repos'].append(value.strip())
+                continue
+
     # -------------------------------------------------------------------------
     def get_root_pwd_hash(self, method='sha256'):
         """Generates a password hash based on the root password."""