예제 #1
0
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
예제 #2
0
    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
예제 #3
0
    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()
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
    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))
예제 #7
0
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)