Ejemplo n.º 1
0
def parse_configuration(config_filename, schema_filename):
    '''
    Given the path to a config filename in YAML format and the path to a schema filename in
    pykwalify YAML schema format, return the parsed configuration as a data structure of nested
    dicts and lists corresponding to the schema. Example return value:

       {'location': {'source_directories': ['/home', '/etc'], 'repository': 'hostname.borg'},
       'retention': {'keep_daily': 7}, 'consistency': {'checks': ['repository', 'archives']}}

    Raise FileNotFoundError if the file does not exist, PermissionError if the user does not
    have permissions to read the file, or Validation_error if the config does not match the schema.
    '''
    logging.getLogger('pykwalify').setLevel(logging.ERROR)

    try:
        config = load.load_configuration(config_filename)
        schema = load.load_configuration(schema_filename)
    except (ruamel.yaml.error.YAMLError, RecursionError) as error:
        raise Validation_error(config_filename, (str(error),))

    # pykwalify gets angry if the example field is not a string. So rather than bend to its will,
    # remove all examples before passing the schema to pykwalify.
    for section_name, section_schema in schema['map'].items():
        for field_name, field_schema in section_schema['map'].items():
            field_schema.pop('example', None)

    validator = pykwalify.core.Core(source_data=config, schema_data=schema)
    parsed_result = validator.validate(raise_exception=False)

    if validator.validation_errors:
        raise Validation_error(config_filename, validator.validation_errors)

    apply_logical_validation(config_filename, parsed_result)

    return parsed_result
Ejemplo n.º 2
0
def parse_configuration(config_filename, schema_filename, overrides=None):
    '''
    Given the path to a config filename in YAML format, the path to a schema filename in pykwalify
    YAML schema format, a sequence of configuration file override strings in the form of
    "section.option=value", return the parsed configuration as a data structure of nested dicts and
    lists corresponding to the schema. Example return value:

       {'location': {'source_directories': ['/home', '/etc'], 'repository': 'hostname.borg'},
       'retention': {'keep_daily': 7}, 'consistency': {'checks': ['repository', 'archives']}}

    Raise FileNotFoundError if the file does not exist, PermissionError if the user does not
    have permissions to read the file, or Validation_error if the config does not match the schema.
    '''
    logging.getLogger('pykwalify').setLevel(logging.ERROR)

    try:
        config = load.load_configuration(config_filename)
        schema = load.load_configuration(schema_filename)
    except (ruamel.yaml.error.YAMLError, RecursionError) as error:
        raise Validation_error(config_filename, (str(error), ))

    override.apply_overrides(config, overrides)
    normalize.normalize(config)

    validator = pykwalify.core.Core(source_data=config,
                                    schema_data=remove_examples(schema))
    parsed_result = validator.validate(raise_exception=False)

    if validator.validation_errors:
        raise Validation_error(config_filename, validator.validation_errors)

    apply_logical_validation(config_filename, parsed_result)

    return parsed_result
Ejemplo n.º 3
0
def parse_configuration(config_filename, schema_filename):
    '''
    Given the path to a config filename in YAML format and the path to a schema filename in
    pykwalify YAML schema format, return the parsed configuration as a data structure of nested
    dicts and lists corresponding to the schema. Example return value:

       {'location': {'source_directories': ['/home', '/etc'], 'repository': 'hostname.borg'},
       'retention': {'keep_daily': 7}, 'consistency': {'checks': ['repository', 'archives']}}

    Raise FileNotFoundError if the file does not exist, PermissionError if the user does not
    have permissions to read the file, or Validation_error if the config does not match the schema.
    '''
    logging.getLogger('pykwalify').setLevel(logging.ERROR)

    try:
        config = load.load_configuration(config_filename)
        schema = load.load_configuration(schema_filename)
    except (ruamel.yaml.error.YAMLError, RecursionError) as error:
        raise Validation_error(config_filename, (str(error),))

    # pykwalify gets angry if the example field is not a string. So rather than bend to its will,
    # remove all examples before passing the schema to pykwalify.
    for section_name, section_schema in schema['map'].items():
        for field_name, field_schema in section_schema['map'].items():
            field_schema.pop('example', None)

    validator = pykwalify.core.Core(source_data=config, schema_data=schema)
    parsed_result = validator.validate(raise_exception=False)

    if validator.validation_errors:
        raise Validation_error(config_filename, validator.validation_errors)

    apply_logical_validation(config_filename, parsed_result)

    return parsed_result
Ejemplo n.º 4
0
def test_load_configuration_inlines_include():
    builtins = flexmock(sys.modules['builtins'])
    builtins.should_receive('open').with_args('include.yaml').and_return('value')
    builtins.should_receive('open').with_args('config.yaml').and_return(
        'key: !include include.yaml'
    )

    assert module.load_configuration('config.yaml') == {'key': 'value'}
Ejemplo n.º 5
0
def test_load_configuration_does_not_merge_include_list():
    builtins = flexmock(sys.modules['builtins'])
    builtins.should_receive('open').with_args('include.yaml').and_return('''
          - one
          - two
        ''')
    builtins.should_receive('open').with_args('config.yaml').and_return('''
        foo: bar
        repositories:
          <<: !include include.yaml
        ''')

    with pytest.raises(ruamel.yaml.error.YAMLError):
        assert module.load_configuration('config.yaml')
Ejemplo n.º 6
0
def test_load_configuration_merges_include():
    builtins = flexmock(sys.modules['builtins'])
    builtins.should_receive('open').with_args('include.yaml').and_return('''
        foo: bar
        baz: quux
        ''')
    builtins.should_receive('open').with_args('config.yaml').and_return('''
        foo: override
        <<: !include include.yaml
        ''')

    assert module.load_configuration('config.yaml') == {
        'foo': 'override',
        'baz': 'quux'
    }
Ejemplo n.º 7
0
def test_load_configuration_merges_include():
    builtins = flexmock(sys.modules['builtins'])
    builtins.should_receive('open').with_args('include.yaml').and_return(
        '''
        foo: bar
        baz: quux
        '''
    )
    builtins.should_receive('open').with_args('config.yaml').and_return(
        '''
        foo: override
        <<: !include include.yaml
        '''
    )

    assert module.load_configuration('config.yaml') == {'foo': 'override', 'baz': 'quux'}
Ejemplo n.º 8
0
def generate_sample_configuration(source_filename, destination_filename, schema_filename):
    '''
    Given an optional source configuration filename, and a required destination configuration
    filename, and the path to a schema filename in pykwalify YAML schema format, write out a
    sample configuration file based on that schema. If a source filename is provided, merge the
    parsed contents of that configuration into the generated configuration.
    '''
    schema = yaml.round_trip_load(open(schema_filename))
    source_config = None

    if source_filename:
        source_config = load.load_configuration(source_filename)

    destination_config = merge_source_configuration_into_destination(
        _schema_to_sample_configuration(schema), source_config
    )

    write_configuration(
        destination_filename,
        _comment_out_optional_configuration(render_configuration(destination_config)),
    )
Ejemplo n.º 9
0
def test_load_configuration_parses_contents():
    builtins = flexmock(sys.modules['builtins'])
    builtins.should_receive('open').with_args('config.yaml').and_return('key: value')

    assert module.load_configuration('config.yaml') == {'key': 'value'}