def _load_file(conf_file): '''Parse a configuration file and return it as a dictionary. The option values are checked for type correctness against a default Config object. :param conf_file: file path (string) or file handler to the configuration file in YAML syntax :return: dictionary parsed from the configuration file :raise CheckbConfigError: if any problem occurs during the parsing or some values have incorrect variable type ''' # convert file path to file handle if needed if isinstance(conf_file, basestring): try: conf_file = open(conf_file) except IOError as e: log.exception('Could not open config file: %s', conf_file) raise exc.CheckbConfigError(e) filename = (conf_file.name if hasattr(conf_file, 'name') else '<unnamed file>') try: conf_obj = yaml.safe_load(conf_file) except yaml.YAMLError as e: log.exception('Could not parse config file: %s', filename) raise exc.CheckbConfigError(e) # config file might be empty (all commented out), returning None. For # further processing, let's replace it with empty dict if conf_obj is None: conf_obj = {} # check correct types # we should receive a single dictionary with keyvals if not isinstance(conf_obj, abc.Mapping): raise exc.CheckbConfigError( 'The config file %s does not have ' 'a valid structure. Instead of a mapping, it is recognized as: %s' % (filename, type(conf_obj))) default_conf = Config() for option, value in conf_obj.items(): # check for unknown options try: default_value = getattr(default_conf, option) except AttributeError: log.warning('Unknown option "%s" in the config file %s', option, filename) continue # check for correct type assert default_value is not None, \ "Default values must not be None: %s" % option if type(default_value) is not type(value): raise exc.CheckbConfigError( 'Option "%s" in config file %s ' 'has an invalid type. Expected: %s, Found: %s' % (option, filename, type(default_value), type(value))) return conf_obj
def top_parent(self, reponame): '''Go through the repo hiearchy and find the top parent for a repo :param str reponame: repository name :return: the top parent reponame. If ``reponame`` doesn't have any parent, its name is returned (it's its own top parent) :rtype: str :raise CheckbConfigError: if infinite parent loop detected ''' parents = [] repo = reponame while True: parent = self.get(repo, 'parent') if not parent: # we've found the top parent return repo # detect infinite parent loops if parent in parents: raise exc.CheckbConfigError('Infinite parent loop detected ' 'in yumrepoinfo: %s' % parents) parents.append(parent) repo = parent
def __init__(self, arch=None, filelist=None, resolve_baseurl=True, resolve_retry=3): ''' :param str arch: architecture for which to adjust repo URLs. By default it refers to the architecture of the current machine. It's always converted to basearch. :param filelist: list of config files to read information from. The first available config file is used. If ``None``, then the default list of locations is used. :type filelist: iterable of str :param bool resolve_baseurl: if baseurl is a known redirect, resolve it for each section during initialization. If this is ``False``, you must call :meth:`_switch_to_mirror` manually. :param int resolve_retry: how many tries to retry resolving the URL for each section in case the network request fails :raise CheckbConfigError: if no YUM repositories data is found (empty or non-existent config file). It's not raised if you specifically request no data to load (``filelist=[]``). :raise CheckbRemoteError: if url resolving fails ''' if config.get_config().profile == config.ProfileName.TESTING: resolve_baseurl = False self.arch = arch_utils.basearch(arch) self.filelist = (filelist if filelist is not None else [ os.path.join(confdir, 'yumrepoinfo.conf') for confdir in config.CONF_DIRS ]) self.resolve_retry = resolve_retry self.parser = PARSER_CLASS(defaults={'arch': self.arch}) if not self.filelist: # no data should be loaded return self._read() if not self.repos(): msg = ("No YUM repo definitions found in the following locations: " "%s" % self.filelist) log.critical(msg) raise exc.CheckbConfigError(msg) self._adjust_baseurl() # download.fp.o is a known redirect if resolve_baseurl and ('download.fedoraproject.org' in self.parser.get('DEFAULT', 'baseurl')): self._switch_to_mirror()
def parse_yaml_from_file(filename): ''' Parse given file in YAML format into a dictionary. :param str filename: a filename that yaml data are loaded from :return: dictionary constructed from the yaml document :raise CheckbConfigError: when YAML parsing fails ''' with open(filename, 'r') as datafile: try: return yaml.safe_load(datafile.read()) except yaml.YAMLError as e: raise exc.CheckbConfigError(e)
def _check_sanity(config): '''Check important config keys for sane/allowed values. Raise exception if config file is not correct. :param config: :class:`.Config` instance :raise CheckbConfigError: when important config key has invalid value ''' # runtask_mode value must be from its enum if config.runtask_mode not in [ RuntaskModeName.LOCAL, RuntaskModeName.LIBVIRT ]: raise exc.CheckbConfigError('Invalid runtask mode name: %s' % config.runtask_mode)
def get(self, reponame, key): '''Get a specific key value from a repo :param str reponame: repository name :param str key: name of the key you want to retrieve from a repository (section) :raise CheckbConfigError: if the key can't be retrieved (e.g. wrong key or repo name) ''' try: return self.parser.get(reponame, key) except configparser.Error as e: raise exc.CheckbConfigError("Can't retrieve key '%s' from repo " "'%s': %s" % (key, reponame, e))
def _load_defaults(profile): '''Load and return Config (or its subclass) based on chosen profile. :param str profile: profile name as defined in :class:`.ProfileName` :return: :class:`.Config` instance or its subclass :raise CheckbConfigError: if unknown profile name is requested ''' if profile == ProfileName.PRODUCTION: return ProductionConfig() elif profile == ProfileName.TESTING: return TestingConfig() elif profile == ProfileName.DEVELOPMENT or not profile: # the default is the development profile return Config() else: raise exc.CheckbConfigError('Invalid profile name: %s' % profile)