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
# =============================================================================
-class CrTplConfigError(ConfigError):
+class CrTplConfigError(MultiConfigError):
"""Base error class for all exceptions happened during
execution this configured application"""
# =============================================================================
-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
# -------------------------------------------------------------------------
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
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(
@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
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 ..."))
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))
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
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))
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)
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,
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,
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))
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
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."""