Esempio n. 1
0
def test_load_default():
    """
    Test load of default config
    """
    config.load()

    assert config.SETTINGS.main_directory == "schema"
Esempio n. 2
0
def test_load_custom():
    """
    Test load from configuration file
    """
    # Load config file using fixture of config file
    config_file_name = FIXTURES_DIR + "/pyproject.toml"
    config.load(config_file_name=config_file_name)

    assert config.SETTINGS.main_directory == "schema1"
Esempio n. 3
0
def test_load_data():
    """
    Test load from python data structure
    """
    data = {
        "main_directory": "schema2",
    }
    config.load(config_data=data)

    assert config.SETTINGS.main_directory == "schema2"
Esempio n. 4
0
def validate(show_pass, show_checks, strict):  # noqa D205
    """Validates instance files against defined schema.

    \f

    Args:
        show_pass (bool): show successful schema validations
        show_checks (bool): show schemas which will be validated against each instance file
        strict (bool): Forces a stricter schema check that warns about unexpected additional properties
    """
    config.load()

    # ---------------------------------------------------------------------
    # Load Schema(s) from disk
    # ---------------------------------------------------------------------
    smgr = SchemaManager(config=config.SETTINGS)

    if not smgr.schemas:
        error("No schemas were loaded")
        sys.exit(1)

    # ---------------------------------------------------------------------
    # Load Instances
    # ---------------------------------------------------------------------
    ifm = InstanceFileManager(config=config.SETTINGS)

    if not ifm.instances:
        error("No instance files were found to validate")
        sys.exit(1)

    if show_checks:
        ifm.print_schema_mapping()
        sys.exit(0)

    error_exists = False
    for instance in ifm.instances:
        for result in instance.validate(smgr, strict):

            result.instance_type = "FILE"
            result.instance_name = instance.filename
            result.instance_location = instance.path

            if not result.passed():
                error_exists = True
                result.print()

            elif result.passed() and show_pass:
                result.print()

    if not error_exists:
        print(colored("ALL SCHEMA VALIDATION CHECKS PASSED", "green"))
    else:
        sys.exit(1)
Esempio n. 5
0
def test_load_mixed():
    """
    Test config load when config_file_name, data, and defaults are all used
    """
    config_file_name = FIXTURES_DIR + "/pyproject2.toml"
    data = {"main_directory": "fake_dir"}

    config.load(config_file_name=config_file_name, config_data=data)

    # Assert main_directory inhered from data passed in
    assert config.SETTINGS.main_directory == "fake_dir"

    # Assert definitions_directory inhered from default, and not from file
    assert config.SETTINGS.definition_directory == "definitions"
Esempio n. 6
0
def schema(check, generate_invalid, list_schemas, schema_id,
           dump_schemas):  # noqa: D417,D301,D205
    """Manage your schemas.

    \f

    Args:
        check (bool): Validates that all schemas are valid (spec and unit tests)
        generate_invalid (bool): Generates expected invalid data from a given schema
        list_schemas (bool): List all available schemas
        schema_id (str): Name of schema to evaluate
        dump_schemas (bool): Dump all schema data or a single schema if schema_id is provided
    """
    if not check and not generate_invalid and not list_schemas and not schema_id and not dump_schemas:
        error(
            "The 'schema' command requires one or more arguments. You can run the command 'schema-enforcer schema --help' to see the arguments available."
        )
        sys.exit(1)

    config.load()

    # ---------------------------------------------------------------------
    # Load Schema(s) from disk
    # ---------------------------------------------------------------------
    smgr = SchemaManager(config=config.SETTINGS)

    if not smgr.schemas:
        error("No schemas were loaded")
        sys.exit(1)

    if list_schemas:
        smgr.print_schemas_list()
        sys.exit(0)

    if dump_schemas:
        smgr.dump_schema(schema_id)
        sys.exit(0)

    if generate_invalid:
        if not schema_id:
            sys.exit(
                "Please indicate the schema you'd like to generate invalid data for using the --schema-id flag"
            )
        smgr.generate_invalid_tests_expected(schema_id=schema_id)
        sys.exit(0)

    if check:
        smgr.test_schemas()
        sys.exit(0)
Esempio n. 7
0
def ansible(inventory, limit, show_pass, show_checks):  # pylint: disable=too-many-branches,too-many-locals,too-many-locals  # noqa: D417,D301
    """Validate the hostvars for all hosts within an Ansible inventory.

    The hostvars are dynamically rendered based on groups to which each host belongs.
    For each host, if a variable `schema_enforcer_schema_ids` is defined, it will be used
    to determine which schemas should be use to validate each key. If this variable is
    not defined, the hostvars top level keys will be automatically mapped to a schema
    definition's top level properties to automatically infer which schema should be used
    to validate which hostvar.
    \f

    Args:
        inventory (string): The name of the file used to construct an ansible inventory.
        limit (string, None): Name of a host to limit the execution to.
        show_pass (bool): Shows validation checks that pass. Defaults to False.
        show_checks (bool): Shows the schema ids each host will be evaluated against.

    Example:
        $ cd examples/ansible
        $ ls -ls
        total 8
        drwxr-xr-x  5 damien  staff   160B Jul 25 16:37 group_vars
        drwxr-xr-x  4 damien  staff   128B Jul 25 16:37 host_vars
        -rw-r--r--  1 damien  staff    69B Jul 25 16:37 inventory.ini
        drwxr-xr-x  4 damien  staff   128B Jul 25 16:37 schema
        $ schema-enforcer ansible -i inventory.ini
        Found 4 hosts in the inventory
        FAIL | [ERROR] False is not of type 'string' [HOST] spine1 [PROPERTY] dns_servers:0:address
        FAIL | [ERROR] False is not of type 'string' [HOST] spine2 [PROPERTY] dns_servers:0:address
        $ schema-enforcer ansible -i inventory.ini -h leaf1
        Found 4 hosts in the inventory
        ALL SCHEMA VALIDATION CHECKS PASSED
        $ schema-enforcer ansible -i inventory.ini -h spine1 --show-pass
        Found 4 hosts in the inventory
        FAIL | [ERROR] False is not of type 'string' [HOST] spine1 [PROPERTY] dns_servers:0:address
        PASS | [HOST] spine1 [SCHEMA ID] schemas/interfaces
    """
    # Ansible is currently always installed by schema-enforcer. This was added in the interest of making ansible an
    # optional dependency. We decided to make two separate packages installable via PyPi, one with ansible, one without.
    # This has been left in the code until such a time as we implement the change to two packages so code will not need
    # to be re-written/
    try:
        from schema_enforcer.ansible_inventory import AnsibleInventory  # pylint: disable=import-outside-toplevel
    except ModuleNotFoundError:
        error(
            "ansible package not found, you can run the command 'pip install schema-enforcer[ansible]' to install the latest schema-enforcer sanctioned version."
        )
        sys.exit(1)

    if inventory:
        config.load(config_data={"ansible_inventory": inventory})
    else:
        config.load()

    # ---------------------------------------------------------------------
    # Load Schema(s) from disk
    # ---------------------------------------------------------------------
    smgr = SchemaManager(config=config.SETTINGS)

    if not smgr.schemas:
        error("No schemas were loaded")
        sys.exit(1)

    # ---------------------------------------------------------------------
    # Load Ansible Inventory file
    #  - generate hostvar for all devices in the inventory
    #  - Validate Each key in the hostvar individually against the schemas defined in the var jsonschema_mapping
    # ---------------------------------------------------------------------
    inv = AnsibleInventory(inventory=config.SETTINGS.ansible_inventory)
    hosts = inv.get_hosts_containing()
    print(f"Found {len(hosts)} hosts in the inventory")

    if show_checks:
        inv.print_schema_mapping(hosts, limit, smgr)
        sys.exit(0)

    error_exists = False

    for host in hosts:
        if limit and host.name != limit:
            continue

        # Acquire Host Variables
        hostvars = inv.get_clean_host_vars(host)

        # Acquire validation settings for the given host
        schema_validation_settings = inv.get_schema_validation_settings(host)
        declared_schema_ids = schema_validation_settings["declared_schema_ids"]
        strict = schema_validation_settings["strict"]
        automap = schema_validation_settings["automap"]

        # Validate declared schemas exist
        smgr.validate_schemas_exist(declared_schema_ids)

        # Acquire schemas applicable to the given host
        applicable_schemas = inv.get_applicable_schemas(
            hostvars, smgr, declared_schema_ids, automap)
        # import pdb; pdb.set_trace()
        for schema_obj in applicable_schemas.values():
            # Combine host attributes into a single data structure matching to properties defined at the top level of the schema definition
            if not strict:
                data = dict()
                for var in schema_obj.top_level_properties:
                    data.update({var: hostvars.get(var)})

            # If the schema_enforcer_strict bool is set, hostvars should match a single schema exactly.
            # Thus, we want to pass the entirety of the cleaned host vars into the validate method rather
            # than creating a data structure with only the top level vars defined by the schema.
            else:
                data = hostvars

            # Validate host vars against schema
            for result in schema_obj.validate(data=data, strict=strict):

                result.instance_type = "HOST"
                result.instance_hostname = host.name

                if not result.passed():
                    error_exists = True
                    result.print()

                elif result.passed() and show_pass:
                    result.print()

    if not error_exists:
        print(colored("ALL SCHEMA VALIDATION CHECKS PASSED", "green"))
    else:
        sys.exit(1)