def run(self, event, context):

        gh_hook = json.loads(event['body'])
        repo = gh_hook['repository']['full_name']
        sha = gh_hook['pull_request']['head']['sha']

        try:
            hooks_yml = get_github().get_repo(repo, lazy=True).get_file_contents('.hooks.yml', ref=sha)
            logger.info("Fetched .hooks.yml from repo {}".format(repo))
        except github.GithubException:
            logger.error("Missig .hooks.yml on repo {}".format(repo))
            send_status(event, context, gh_hook, self.configname, 'success', ".hooks.yml not present in branch")
            return

        try:
            hook_config = yaml.safe_load(hooks_yml.decoded_content)
            logger.info("Basic yml validation passed")
        except Exception as e:
            logger.error("Failed to decode hook yaml: " + e.message)
            send_status(event, context, gh_hook, self.configname, 'failure', "Could not decode branch .hooks.yml")
            return

        logger.info("Advanced schema validation")
        c = Core(source_data=hook_config,
                 schema_files=[os.path.join(os.path.dirname(__file__), "..", "hooks.schema.yml")])
        c.validate(raise_exception=False)
        vc = len(c.validation_errors)
        if vc > 0:
            for err in c.validation_errors:
                logger.error(" - {}".format(err))
            send_status(event, context, gh_hook, self.configname, 'failure', ".hooks.yml has {} validation errors; see log".format(vc))
            return

        send_status(event, context, gh_hook, self.configname, 'success', ".hooks.yml present and valid")
Beispiel #2
0
    def test_files_with_unicode_content_success(self):
        """
        These tests should pass with no exception raised
        """
        _pass_tests = [
            # Test mapping with unicode key and value
            u"1s.yaml",
            # Test unicode filename
            u"2så.yaml",
            # Test sequence with unicode keys
            u"3s.yaml",
        ]

        for passing_test_files in _pass_tests:
            f = unicode(self.f(passing_test_files))

            with open(f, "r") as stream:
                yaml_data = yaml.load(stream)
                data = yaml_data["data"]
                schema = yaml_data["schema"]

            try:
                print(u"Running test files: {}".format(f))
                c = Core(source_data=data, schema_data=schema)
                c.validate()
                compare(c.validation_errors, [], prefix="No validation errors should exist...")
            except Exception as e:
                print(u"ERROR RUNNING FILES: {}".format(f))
                raise e

            # This serve as an extra schema validation that tests more complex structures then testrule.py do
            compare(c.root_rule._schema_str, schema, prefix=u"Parsed rules is not correct, something have changed... files : {}".format(f))
Beispiel #3
0
def load_config(path):

    """validates, loads and configures the yaml document at the specified path

    :param path: the path to the file
    :return: the parsed yaml document
    :raises SchemaError: if the yaml document does not validate
    """

    validator = Core(source_file=path, schema_data=config_schema)
    validator.validate(raise_exception=True)

    pattern = re.compile(r'^(.*)<%= ENV\[\'(.*)\'\] %>(.*)$')
    yaml.add_implicit_resolver('!env_regex', pattern)

    def env_regex(loader, node):
        value = loader.construct_scalar(node)
        front, variable_name, back = pattern.match(value).groups()
        return str(front) + os.environ[variable_name] + str(back)

    yaml.add_constructor('!env_regex', env_regex)

    with open(path, 'r') as stream:
        doc = yaml.load(stream)
        return doc
Beispiel #4
0
    def _validate_cfg(self):
        """
        Open and parse the YAML configuration file and ensure it matches
        our Schema for a Dogen configuration.
        """
        # Fail early if descriptor file is not found
        if not os.path.exists(self.descriptor):
            raise Error("Descriptor file '%s' could not be found. Please make sure you specified correct path." % self.descriptor)

        schema_path = os.path.join(self.pwd, "schema", "kwalify_schema.yaml")
        schema = {}
        with open(schema_path, 'r') as fh:
            schema = yaml.safe_load(fh)

        if schema is None:
            raise Error("couldn't read a valid schema at %s" % schema_path)

        for plugin in self.plugins:
            plugin.extend_schema(schema)

        with open(self.descriptor, 'r') as stream:
            self.cfg = yaml.safe_load(stream)

        c = Core(source_data=self.cfg, schema_data=schema)
        try:
            c.validate(raise_exception=True)
        except SchemaError as e:
            raise Error(e)
def incoming(event, context):
    """
    Validate the incoming event from the API gateway
    """

    print json.dumps(event)  # not logger.info() so it doesn't show up in logview itself :)

    # validate the secret
    if not validate_secret(event['headers'].get('X-Hub-Signature'), event['body']):
        return {"body": json.dumps({"error": "invalid signature"}), "statusCode": 403}

    # Get the hook info
    try:
        hookdata = json.loads(event['body'])
    except Exception:
        logger.error("Failed to decode json")
        return {"body": json.dumps({"error": "json decode failure"}), "statusCode": 500}

    # this will only work, for now, with hooks that include repo information
    if 'repository' not in hookdata:
        logger.error("No repository in the hook, no processing")
        return {"body": json.dumps({"error": "unsupported hook type; missing repository information"}), "statusCode": 501}

    repo = hookdata['repository']['full_name']

    # Now, we fetch the config from the repo to see what hooks we should trigger
    try:
        hooks_yml = get_github().get_repo(repo, lazy=True).get_file_contents('.hooks.yml')
        logger.info("Fetched .hooks.yml from repo {}".format(repo))
    except github.GithubException:
        logger.error("Missig .hooks.yml on repo {}".format(repo))
        return {"body": json.dumps({"error": "no .hooks.yml present"}), "statusCode": 501}

    try:
        hook_config = yaml.safe_load(hooks_yml.decoded_content)
    except Exception:
        logger.error("Failed to decode hook yaml")
        return {"body": json.dumps({"error": "hook yaml failure"}), "statusCode": 500}

    # Schema based validation
    c = Core(source_data=hook_config, schema_files=[os.path.join(os.path.dirname(__file__), "..", "hooks.schema.yml")])
    c.validate(raise_exception=False)
    if len(c.validation_errors) > 0:
        logger.error(c.validation_errors)
        return {"body": json.dumps({"error": "invalid hooks configuration"}), "statusCode": 501}

    ghevent = event['headers'].get('X-GitHub-Event', '')

    # Check hooks!
    logger.info("Qualifying checks:")
    for name, check in all_checks.get_all_checks().iteritems():
        check_config = check.qualify(ghevent, hookdata, hook_config)
        if check_config != False: # use boolean in case of "empty" configs
            logger.info("- {} passed qualify, invoking secondary call".format(name))
            invoke_secondary(name, check_config, event)
        else:
            logger.info("- {} did not qualify, skipping".format(name))

    # all done!
    return {"body": json.dumps({"message": "Thanks"}), "statusCode": 200}
Beispiel #6
0
    def __init__(self, config_path, schema_path, config_changes):
        with open(config_path, 'rt') as src:
            config = read_config(src)
        make_config_changes(config, config_changes)

        self.multi_stage = 'stages' in config
        if self.multi_stage:
            ordered_changes = OrderedDict(
                sorted(config['stages'].items(),
                       key=lambda (k, v): v['number'],))
            self.ordered_stages = OrderedDict()
            for name, changes in ordered_changes.items():
                current_config = copy.deepcopy(config)
                del current_config['stages']
                del changes['number']
                merge_recursively(current_config, changes)
                self.ordered_stages[name] = current_config

        # Validate the configuration and the training stages
        with open(os.path.expandvars(schema_path)) as schema_file:
            schema = yaml.safe_load(schema_file)
            core = Core(source_data=config, schema_data=schema)
            core.validate(raise_exception=True)
            if self.multi_stage:
                for stage in self.ordered_stages.values():
                    core = Core(source_data=config, schema_data=schema)
                    core.validate(raise_exception=True)
        super(Configuration, self).__init__(config)
Beispiel #7
0
    def test_files_with_unicode_content_failing(self):
        """
        These tests should fail with the specified exception
        """
        _fail_tests = [
            # Test mapping with unicode key and value but wrong type
            (u"1f.yaml", SchemaError),
            # Test unicode filename with validation errors
            (u"2få.yaml", SchemaError),
            # Test unicode data inside seq but wrong type
            (u"3f.yaml", SchemaError),
        ]

        for failing_test, exception_type in _fail_tests:
            # f = self.f(os.path.join("fail", failing_test))
            f = unicode(self.f(failing_test))

            with open(f, "r") as stream:
                yaml_data = yaml.load(stream)
                data = yaml_data["data"]
                schema = yaml_data["schema"]
                errors = yaml_data["errors"]

            try:
                print(u"Running test files: {}".format(f))
                c = Core(source_data=data, schema_data=schema)
                c.validate()
            except exception_type:
                pass  # OK
            else:
                raise AssertionError(u"Exception {} not raised as expected... FILES: {} : {}".format(exception_type, exception_type))

            compare(sorted(c.validation_errors), sorted(errors), prefix=u"Wrong validation errors when parsing files : {}".format(f))
Beispiel #8
0
def check_schema_test(opts, file):
    logging.info("check schema...: %s" % file)
    try:
        c = Core(source_file=file, schema_files=[opts.yaml_schema])
        c.validate(raise_exception=True)
    except SchemaError, e:
        print "check schema: %-80s  %s" % (file, RET_ERROR)
        raise
Beispiel #9
0
def validate_result(data):
    try:
        validator = Core(source_data=data, schema_data=result_schema)
        validator.validate(raise_exception=True)
    except SchemaError as se:
        raise PresenceError(se)

    return data
Beispiel #10
0
def validate_with_schema(source_data, schema_file):
    core = Core(source_data=source_data, schema_files=[schema_file])
    try:
        core.validate(raise_exception=True)
    except Exception as error:
        if len(core.errors) > 0:
            show_validation_errors(source_data, core.errors)
        else:
            raise error
Beispiel #11
0
 def load(self, validate=True):
     schema_file = os.path.join(sys._MEIPASS, 'schema.yml') \
         if hasattr(sys, '_MEIPASS') else self._default_schema_path
     try:
         self._yaml = anyconfig.load(self.path, ignore_missing=False)
     except FileNotFoundError:
         panic('ERROR - %s configuration file does not exist' % self.path)
     if validate:
         validator = Core(source_file=self.path, schema_files=[schema_file])
         validator.validate(raise_exception=True)
def validate_config_yaml(package_name):
  """Check that an integration's config.yaml file has a valid schema

  Raises:
    Exception if the config.yaml file has an improper schema
  """
  resource_path = os.path.join('schema_files', 'config_schema.yaml')
  file_path = pkg_resources.resource_filename(resource_package, resource_path)
  schema_validator = Core(source_file=os.path.join(package_name, 'config.yaml'), schema_files=[file_path])
  schema_validator.validate(raise_exception=True)
Beispiel #13
0
def check_schema_test(opts, file):
    logging.info("check schema...: %s" % file)
    try:
        c = Core(source_file=file, schema_files=[opts.yaml_schema])
        c.validate(raise_exception=True)
    except SchemaError as e:
        six.print_("check schema: %-80s  ERROR" % file)
        raise
    else:
        six.print_("check schema: %-80s  OK" % file)
Beispiel #14
0
    def test_validation_error_but_not_raise_exception(self):
        """
        Test that if 'raise_exception=False' when validating that no exception is raised.

        Currently file 2a.yaml & 2b.yaml is designed to cause exception.
        """
        c = Core(source_file=self.f("cli", "2a.yaml"), schema_files=[self.f("cli", "2b.yaml")])
        c.validate(raise_exception=False)

        assert c.validation_errors == ["Value: 1 is not of type 'str' : /0", "Value: 2 is not of type 'str' : /1", "Value: 3 is not of type 'str' : /2"]
Beispiel #15
0
    def test_files_with_unicode_content_failing(self, tmpdir):
        """
        These tests should fail with the specified exception
        """
        # To trigger schema exception we must pass in a source file
        fail_data_2f_yaml = {
            'schema': {
                'type': 'map',
                'mapping': {
                    'msg': {
                        'type': 'int',
                    },
                }
            },
            'data': {
                'msg': 'Foobar',
            },
            'errors': ["Value 'Foobar' is not of type 'int'. Path: '/msg'"]
        }

        source_f = tmpdir.join(u"2få.json")
        source_f.write(yaml.safe_dump(fail_data_2f_yaml, allow_unicode=True))

        _fail_tests = [
            # Test mapping with unicode key and value but wrong type
            (u"1f.yaml", SchemaError),
            # Test unicode filename with validation errors.
            # It is not possible to package a file with unicode characters
            # like åäö in the filename in some python versions.
            # Mock a file with åäö during testing to properly simulate this again.
            (unicode(source_f), SchemaError),
            # Test unicode data inside seq but wrong type
            (u"3f.yaml", SchemaError),
        ]

        for failing_test, exception_type in _fail_tests:
            f = self.f(failing_test)

            with open(f, "r") as stream:
                yaml_data = yaml.safe_load(stream)
                data = yaml_data["data"]
                schema = yaml_data["schema"]
                errors = yaml_data["errors"]

            try:
                print(u"Running test files: {0}".format(f))
                c = Core(source_data=data, schema_data=schema)
                c.validate()
            except exception_type:
                pass  # OK
            else:
                raise AssertionError(u"Exception {0} not raised as expected... FILES: {1} : {2}".format(exception_type, exception_type))

            compare(sorted(c.validation_errors), sorted(errors), prefix=u"Wrong validation errors when parsing files : {0}".format(f))
def test_component_data_valid():
    """ Check that the content of data fits with masonry schema v2 """
    validator = Core(source_data={}, schema_data=get_schema())
    for component_file in iglob('*/component.yaml'):
        print(component_file)
        source_data = yaml.load(open(component_file))
        validator.source = source_data
        try:
            validator.validate(raise_exception=True)
        except:
            assert False, "Error found in: {0}".format(component_file)
Beispiel #17
0
    def test_files_with_unicode_content_success(self, tmpdir):
        """
        These tests should pass with no exception raised
        """
        fail_data_2s_yaml = {
            'schema': {
                'type': 'map',
                'mapping': {
                    'msg': {
                        'type': 'int',
                    },
                }
            },
            'data': {
                'msg': 123,
            },
            'errors': []
        }

        source_f = tmpdir.join(u"2så.json")
        source_f.write(yaml.safe_dump(fail_data_2s_yaml, allow_unicode=True))

        _pass_tests = [
            # Test mapping with unicode key and value
            u"1s.yaml",
            # # Test unicode filename.
            # It is not possible to package a file with unicode characters
            # like åäö in the filename in some python versions.
            # Mock a file with åäö during testing to properly simulate this again.
            unicode(source_f),
            # Test sequence with unicode keys
            u"3s.yaml",
        ]

        for passing_test_files in _pass_tests:
            f = self.f(passing_test_files)

            with open(f, "r") as stream:
                yaml_data = yaml.safe_load(stream)
                data = yaml_data["data"]
                schema = yaml_data["schema"]

            try:
                print(u"Running test files: {0}".format(f))
                c = Core(source_data=data, schema_data=schema)
                c.validate()
                compare(c.validation_errors, [], prefix="No validation errors should exist...")
            except Exception as e:
                print(u"ERROR RUNNING FILES: {0}".format(f))
                raise e

            # This serve as an extra schema validation that tests more complex structures then testrule.py do
            compare(c.root_rule.schema_str, schema, prefix=u"Parsed rules is not correct, something have changed... files : {0}".format(f))
def validate_fittings(file_path):
    with open(file_path, 'r') as document_stream:
        document = document_stream.read()
        for settings in yaml.load_all(document):
            logging.debug("Validating source data %s",
                         settings)

            c = Core(source_data=settings, schema_files=["schema.yaml"])
            try:
                c.validate(raise_exception=True)
            except pykwalify.errors.SchemaError as schema_error:
                logging.error("Validation of %s failed.", file_path)
                logging.error(schema_error)
Beispiel #19
0
    def load(self, config_file):
        """Load configuration from config_file."""
        with resource_stream(__name__, 'config-schema.yaml') as schema_stream:
            schema = yaml.load(schema_stream)

        core = Core(source_file=config_file, schema_data=schema)
        self.config = core.validate(raise_exception=True)
Beispiel #20
0
 def validate_config(self):
     try:
         c = Core(source_file="/Users/JohnS5/dev/replication_manager/src/webapp/bdr_app.yml",
             schema_files=['/Users/JohnS5/dev/replication_manager/src/webapp/schema.yml'])
         return c.validate(raise_exception=True)
     except Exception as e:
         print "LOG: ERROR: config file is not valid"
         print e
         return None
Beispiel #21
0
def validate_parameters(parameters, kliko):
    """
    validate a set of parameters given a kliko definition

    args:
        parameters (dict): A structure that should follow the given kliko structure
        kliko (dict): A nested dict which defines the valid parameters in Kliko format

    returns:
        str: the parsed parameters

    raises:
        an exception if the string can't be parsed or is not in the defining valid parameters
    """
    schema = convert_to_parameters_schema(kliko)
    c = Core(source_data=parameters, schema_data=schema)
    c.validate(raise_exception=True)
    return True
Beispiel #22
0
def validate_kliko(kliko, version=SCHEMA_VERSION):
    """
    validate a kliko yaml string

    args:
        kliko: a parsed kliko object

    returns:
        dict: a (nested) kliko structure

    raises:
        an exception if the string can't be parsed or is not in the following the Kliko schema
    """
    # first try to parse it, to make sure it is parsable

    schema_file = os.path.join(here, "schemas/%s.yml" % version)
    c = Core(source_data=kliko, schema_files=[schema_file])
    c.validate(raise_exception=True)
    return kliko
Beispiel #23
0
    def validate_domain_yaml(cls, yaml):
        """Validate domain yaml."""
        from pykwalify.core import Core

        log = logging.getLogger('pykwalify')
        log.setLevel(logging.WARN)

        schema_file = pkg_resources.resource_filename(__name__,
                                                      "schemas/domain.yml")
        source_data = utils.read_yaml_string(yaml)
        c = Core(source_data=source_data,
                 schema_files=[schema_file])
        try:
            c.validate(raise_exception=True)
        except SchemaError:
            raise ValueError("Failed to validate your domain yaml. "
                             "Make sure the file is correct, to do so"
                             "take a look at the errors logged during "
                             "validation previous to this exception. ")
Beispiel #24
0
def parse_data(site):
    base = op.join(op.dirname(__file__), 'games')
    data = []
    for fn in sorted(os.listdir(base)):
        if fn.endswith('.yaml'):
            data.extend(yaml.load(open(op.join(base, fn))))

    try:
        core = Core(source_data=data, schema_files=['schema.yaml'])
        core.validate(raise_exception=True)
    except Exception as error:
        if len(core.errors) > 0:
            show_validation_errors(data, core.errors)
        else:
            raise error

    for item in data:
        parse_global_tags(site, item.get('meta', {}), 'genre')
        parse_items(site, item, 'remakes')
        parse_items(site, item, 'clones')
Beispiel #25
0
def import_from_yaml(statechart: Iterable[str], ignore_schema: bool=False, ignore_validation: bool=False) -> Statechart:
    """
    Import a statechart from a YAML representation.
    YAML is first validated against *sismic.io.yaml.SCHEMA_PATH*, and resulting statechart is validated
    using its *validate* method.

    :param statechart: string or any equivalent object
    :param ignore_schema: set to *True* to disable yaml validation.
    :param ignore_validation: set to *True* to disable statechart validation.
    :return: a *Statechart* instance
    """
    data = yaml.load(statechart)  # type: dict
    if not ignore_schema:
        checker = Core(source_data=data, schema_files=[SCHEMA_PATH])
        checker.validate(raise_exception=True)

    sc = import_from_dict(data)
    if not ignore_validation:
        sc.validate()
    return sc
Beispiel #26
0
def import_from_yaml(statechart: str, validate_yaml=True, validate_statechart=True) -> StateChart:
    """
    Import a statechart from a YAML representation.
    YAML is first validated against ``io.SCHEMA``.

    :param statechart: string or any equivalent object
    :param validate_yaml: set to ``False`` to disable yaml validation.
    :param validate_statechart: set to ``False`` to disable statechart validation
      (see ``model.StateChart.validate``).
    :return: a ``StateChart`` instance
    """
    statechart_data = yaml.load(statechart)
    if validate_yaml:
        checker = Core(source_data=statechart_data, schema_files=[SCHEMA_PATH])
        checker.validate(raise_exception=True)

    sc = _import_from_dict(statechart_data['statechart'])
    if validate_statechart:
        sc.validate()

    return sc
Beispiel #27
0
    def test_multi_file_support(self):
        """
        This should test that multiple files is supported correctly
        """
        pass_tests = [
            # Test that include directive can be used at top level of the schema
            ([self.f("partial_schemas", "1s-schema.yaml"), self.f("partial_schemas", "1s-partials.yaml")], self.f("partial_schemas", "1s-data.yaml"), {'sequence': [{'include': 'fooone'}], 'type': 'seq'}),
            # # This test that include directive works inside sequence
            # ([self.f("33a.yaml"), self.f("33b.yaml")], self.f("33c.yaml"), {'sequence': [{'include': 'fooone'}], 'type': 'seq'}),
            # This test recursive schemas
            ([self.f("partial_schemas", "2s-schema.yaml"), self.f("partial_schemas", "2s-partials.yaml")], self.f("partial_schemas", "2s-data.yaml"), {'sequence': [{'include': 'fooone'}], 'type': 'seq'})
        ]

        failing_tests = [
            # Test include inside partial schema
            ([self.f("partial_schemas", "1f-schema.yaml"), self.f("partial_schemas", "1f-partials.yaml")], self.f("partial_schemas", "1f-data.yaml"), SchemaError, ['No partial schema found for name : fooonez : Existing partial schemas: fooone, foothree, footwo'])
        ]

        for passing_test in pass_tests:
            try:
                c = Core(source_file=passing_test[1], schema_files=passing_test[0])
                c.validate()
                compare(c.validation_errors, [], prefix="No validation errors should exist...")
            except Exception as e:
                print("ERROR RUNNING FILE: {} : {}".format(passing_test[0], passing_test[1]))
                raise e

            # This serve as an extra schema validation that tests more complex structures then testrule.py do
            compare(c.root_rule._schema_str, passing_test[2], prefix="Parsed rules is not correct, something have changed...")

        for failing_test in failing_tests:
            with pytest.raises(failing_test[2], msg="Test files: {} : {}".format(", ".join(failing_test[0]), failing_test[1])):
                c = Core(schema_files=failing_test[0], source_file=failing_test[1])
                c.validate()

            if not c.validation_errors:
                raise AssertionError("No validation_errors was raised...")

            compare(sorted(c.validation_errors), sorted(failing_test[3]), prefix="Wrong validation errors when parsing files : {} : {}".format(failing_test[0], failing_test[1]))
Beispiel #28
0
def _validate(args, app_desc):
    path = _find_config(args, app_desc)
    # Allow empty mapping (not allowed by pykawlify)
    raw_config = _order_load_path(path)
    if raw_config.get(app_desc.app_name, None) is None:
        raw_config[app_desc.app_name] = {}
        config_p = tempfile.NamedTemporaryFile(delete=False, suffix=".yml")
        _ordered_dump(raw_config, config_p)
        config_p.flush()
        path = config_p.name

    fp = tempfile.NamedTemporaryFile(delete=False, suffix=".yml")
    _ordered_dump(app_desc.schema.raw_schema, fp)
    fp.flush()
    name = fp.name
    if Core is None:
        raise Exception("Cannot validate file, pykwalify is not installed.")
    c = Core(
        source_file=path,
        schema_files=[name],
    )
    c.validate()
Beispiel #29
0
def load_config(file_name):
    """
    Load the file, verify that it conforms to the schema,
    and return the configuration.
    """
    import yaml
    from pykwalify.core import Core
    from pykwalify.errors import SchemaError

    # Disable most logging for pykwalify
    import logging
    logging.getLogger('pykwalify').setLevel(logging.CRITICAL)
    logging.getLogger('pykwalify').addHandler(logging.NullHandler())

    try:
        with open(file_name, 'r') as conf_file:
            data = yaml.safe_load(conf_file)
            validator = Core(
                source_data=data,
                schema_files=[dirname(__file__) + "/rebench-schema.yml"])
            try:
                validator.validate(raise_exception=True)
            except SchemaError as err:
                errors = [escape_braces(val_err) for val_err in validator.validation_errors]
                raise UIError(
                    "Validation of " + file_name + " failed.\n{ind}" +
                    "\n{ind}".join(errors) + "\n", err)
            return data
    except IOError as err:
        if err.errno == 2:
            assert err.strerror == "No such file or directory"
            raise UIError("The requested config file (%s) could not be opened. %s.\n"
                          % (file_name, err.strerror), err)
        raise UIError(str(err) + "\n", err)
    except yaml.YAMLError as err:
        raise UIError("Parsing of the config file "
                      + file_name + " failed.\nError " + str(err) + "\n", err)
Beispiel #30
0
    def validate_deploy(self):
        """
        Validates the deployment yaml file with the schema
        :raises pykwalify.errors.SchemaError: if validation fails
        :raises pykwalify.errors.CoreError: for other type of errors
        """
        logging.debug(self.__class__.__name__ + ': ' + sys._getframe().f_code.co_name)
        if not self.deploy_file:
            raise AssertionError

        try:
            c = Core(source_file=self.deploy_file,
                     schema_files=[self.schema_file],
                     extensions=[self.schema_functions_file])
            c.validate()
        except CoreError as e:
            # Most probably there is something wrong with the source files
            logging.debug(self.__class__.__name__ + ': ' + sys._getframe().f_code.co_name + ': ' + e.msg)
            raise
        except SchemaError as e:
            # The deploy file is not valid
            logging.debug(self.__class__.__name__ + ': ' + sys._getframe().f_code.co_name + ': ' + e.msg)
            print("The deployment file at '%s' is not valid." % (self.deploy_file_host,))
            raise
Beispiel #31
0
    def __init__(self,
                 config_file,
                 options=None,
                 layer_name=None,
                 base_config=None):
        self._close_actions = []
        self._layers_geoms = {}
        self.error_files_ = {}

        if options is not None:
            if not hasattr(options, 'bbox'):
                options.bbox = None
            if not hasattr(options, 'zoom'):
                options.zoom = None
            if not hasattr(options, 'test'):
                options.test = None
            if not hasattr(options, 'near'):
                options.near = None
            if not hasattr(options, 'time'):
                options.time = None
            if not hasattr(options, 'geom'):
                options.geom = True

        self._configure_logging(
            options, '%(levelname)s:%(name)s:%(funcName)s:%(message)s')

        with open(config_file) as f:
            self.config = {}
            self.config.update({} if base_config is None else base_config)
            self.config.update(yaml.safe_load(f))
        self.options = options
        if 'defaults' in self.config:
            del self.config['defaults']
        # generate base structure
        if 'cost' in self.config:
            if 's3' not in self.config['cost']:
                self.config['cost']['s3'] = {}
            if 'cloudfront' not in self.config['cost']:
                self.config['cost']['cloudfront'] = {}
            if 'sqs' not in self.config['cost']:
                self.config['cost']['sqs'] = {}
        if 'generation' not in self.config:
            self.config['generation'] = {}
        for gname, grid in sorted(self.config.get('grids', {}).items()):
            if grid is not None:
                grid["name"] = gname
        for cname, cache in sorted(self.config.get('caches', {}).items()):
            if cache is not None:
                cache["name"] = cname
        for lname, layer in sorted(self.config.get('layers', {}).items()):
            if layer is not None:
                layer["name"] = lname

        c = Core(
            source_data=self.config,
            schema_data=yaml.safe_load(
                pkgutil.get_data("tilecloud_chain", "schema.yaml")),
        )
        path_ = ''
        try:
            self.config = c.validate()

            for name, cache in self.config['caches'].items():
                if cache['type'] == 's3':
                    c = Core(
                        source_data=cache,
                        schema_data=yaml.safe_load(
                            pkgutil.get_data("tilecloud_chain",
                                             "schema-cache-s3.yaml")),
                    )
                    path_ = 'caches/{}'.format(name)
                    self.config['caches'][name] = c.validate()
            for name, layer in self.config['layers'].items():
                c = Core(
                    source_data=layer,
                    schema_data=yaml.safe_load(
                        pkgutil.get_data(
                            "tilecloud_chain",
                            "schema-layer-{}.yaml".format(layer['type']))),
                )
                path_ = 'layers/{}'.format(name)
                self.config['layers'][name] = c.validate()

        except SchemaError:
            logger.error("The config file '{}' is invalid.\n{}".format(
                config_file, "\n".join(
                    sorted([
                        " - {}: {}".format(
                            os.path.join('/', path_,
                                         re.sub('^/', '', error.path)),
                            re.sub(" Path: '{path}'", '',
                                   error.msg).format(**error.__dict__))
                        for error in c.errors
                    ]))))
            exit(1)
        except NotSequenceError as e:  # pragma: no cover
            logger.error("The config file '{}' is invalid.\n - {}".format(
                config_file, e.msg))
            exit(1)
        except NotMappingError as e:  # pragma: no cover
            logger.error("The config file '{}' is invalid.\n - {}".format(
                config_file, e.msg))
            exit(1)

        error = False
        self.grids = self.config['grids']
        for gname, grid in sorted(self.grids.items()):
            if 'resolution_scale' in grid:
                scale = grid['resolution_scale']
                for r in grid['resolutions']:
                    if r * scale % 1 != 0.0:
                        logger.error(
                            "The resolution {} * resolution_scale {} is not an integer."
                            .format(r, scale))
                        error = True
            else:
                grid['resolution_scale'] = self._resolution_scale(
                    grid['resolutions'])

            srs = int(grid["srs"].split(":")[1])
            if 'proj4_literal' not in grid:
                if srs == 3857:  # pragma: no cover
                    grid['proj4_literal'] = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 ' \
                        '+x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'
                elif srs == 21781:
                    grid['proj4_literal'] = \
                        '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 ' \
                        '+x_0=600000 +y_0=200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 ' \
                        '+units=m +no_defs'
                elif srs == 2056:  # pragma: no cover
                    grid['proj4_literal'] = \
                        '+proj=somerc +lat_0=46.95240555555556 +lon_0=7.439583333333333 +k_0=1 ' \
                        '+x_0=2600000 +y_0=1200000 +ellps=bessel +towgs84=674.374,15.056,405.346,0,0,0,0 ' \
                        '+units=m +no_defs'
                else:  # pragma: no cover
                    grid['proj4_literal'] = '+init={}'.format(grid['srs'])

            scale = grid['resolution_scale']
            grid['obj'] = FreeTileGrid(
                resolutions=[int(r * scale) for r in grid['resolutions']],
                scale=scale,
                max_extent=grid['bbox'],
                tile_size=grid['tile_size']) if not error else None

        self.layers = self.config['layers']
        for lname, layer in sorted(self.layers.items()):
            layer['grid_ref'] = self.grids[
                layer['grid']] if not error else None
            self.layers[lname] = layer
            if 'geoms' not in layer:
                layer['geoms'] = []
            if 'params' not in layer and layer['type'] == 'wms':
                layer['params'] = {}
            if 'headers' not in layer and layer['type'] == 'wms':
                layer['headers'] = {
                    'Cache-Control': 'no-cache, no-store',
                    'Pragma': 'no-cache',
                }
            if 'dimensions' not in layer:
                layer['dimensions'] = []
            if layer['type'] == 'mapnik' and \
                    layer['output_format'] == 'grid' and \
                    layer.get('meta', False):  # pragma: no cover
                logger.error(
                    "The layer '{}' is of type Mapnik/Grid, that can't support matatiles."
                    .format(lname))
                error = True

        self.caches = self.config['caches']
        self.metadata = self.config.get('metadata')
        self.provider = self.config.get('provider')

        if error:
            exit(1)

        if 'log_format' in self.config.get('generation', {}):
            self._configure_logging(options,
                                    self.config['generation']['log_format'])

        if options is not None and options.zoom is not None:
            error_message = (
                "The zoom argument '%s' has incorrect format, "
                "it can be a single value, a range (3-9), a list of values (2,5,7)."
            ) % options.zoom
            if options.zoom.find('-') >= 0:
                r = options.zoom.split('-')
                if len(r) != 2:  # pragma: no cover
                    logger.error(error_message)
                    error = True
                try:
                    options.zoom = range(int(r[0]), int(r[1]) + 1)
                except ValueError:  # pragma: no cover
                    logger.error(error_message, exc_info=True)
                    error = True
            elif options.zoom.find(',') >= 0:
                try:
                    options.zoom = [int(z) for z in options.zoom.split(',')]
                except ValueError:  # pragma: no cover
                    logger.error(error_message, exc_info=True)
                    error = True
            else:
                try:
                    options.zoom = [int(options.zoom)]
                except ValueError:  # pragma: no cover
                    logger.error(error_message, exc_info=True)
                    error = True

        if error:  # pragma: no cover
            exit(1)

        if layer_name and not error:
            self.init_layer(self.layers[layer_name], options)
Beispiel #32
0
    def load_conf(self, schema_file="schema_config.yaml"):
        """Load the configuration from a config file.

        Keyword arguments:
        schema_file -- relative/absolute path and filename for yaml schema
        """
        log.debug("Loading configuration")

        # cleaning targets list
        self.list_groups = []
        self.list_targets = []
        self.list_special_targets = []
        self.list_target_name = []
        self.global_vars = {}
        self.first_iter = True

        # instantiate a new generator
        self.instantiate_generator()

        # validate yaml config with the schema
        schema = pkg_resources.resource_filename(__name__, schema_file)
        yaml_validator = Core(source_file=self.config_file,
                              schema_files=[schema])
        yaml_validator.validate(raise_exception=True)

        # we load the configuration from the file
        with open(self.config_file, "r") as conf_file:
            # load as a yaml
            conf = yaml.safe_load(conf_file)

        # get global variables
        self.global_vars = conf["global"]

        # setting logging level
        log.setLevel(self.global_vars["logging_level"])

        # setting default percentile values if needed
        if self.global_vars.get("percentile") is None:
            self.global_vars["percentile"] = [95, 50]

        # get groups
        for group_name in conf["groups"]:
            group = conf["groups"][group_name]
            self.list_groups.append(
                Group(
                    name=group_name,
                    src_ipv4=group.get("src_ipv4", group.get("src_ip")),
                    src_ipv6=group.get("src_ipv6"),
                    src_subnet_ipv4=group.get("src_subnet_ipv4"),
                    src_subnet_ipv6=group.get("src_subnet_ipv6"),
                    src_port_a=group.get("src_port_a", 65000),
                    src_port_z=group.get("src_port_z", 65001),
                    ip_payload_size=group.get("ip_payload_size"),
                    dscp=group.get("dscp", 0),
                    permit_target_auto_register=group.get(
                        "permit_target_auto_register", True),
                ))

        # check targets are set
        if not conf.get("targets"):
            return

        # get target list
        for target_name in conf["targets"]:
            target = conf["targets"][target_name]

            if not target.get("address_family"):
                try:
                    ip = ip_address(target.get("destination"))
                    target["address_family"] = "ipv{}".format(ip.version)
                except ValueError:
                    log.debug(
                        "was not able to detect address-family from destination"
                        ", setting to default (%s)",
                        DEFAULT_ADDRESS_FAMILY,
                    )
                    target["address_family"] = DEFAULT_ADDRESS_FAMILY

            if target_name in self.list_target_name:
                log.warning("Duplicate target name %s", target_name)
                APP_TARGET_NAME_DUP.labels(target_name=target_name).inc(1)
            else:
                self.list_target_name.append(target_name)

            # manage group association
            target_groups = set()

            # we register to all group if allowed
            if target.get("auto_register_to_groups", True):
                for grp in self.list_groups:
                    if grp.permit_target_auto_register:
                        target_groups.add(grp.name)

            # we explicitly register to a group
            for grp in target.get("explicit_groups",
                                  {}).get("register_to", []):
                if grp in conf["groups"]:
                    target_groups.add(grp)
                else:
                    log.warning(
                        "Trying to associate '%s' to an inexistant group: %s",
                        target_name, grp)

            # we remove the target from a group
            for grp in target.get("explicit_groups",
                                  {}).get("exclude_from", []):
                try:
                    target_groups.remove(grp)
                except Exception:
                    log.info("Failed to remove target %s from %s", target_name,
                             grp)

            # create target objects
            self.load_target_conf(target, target_name, target_groups)

            log.debug("Target %s created", target_name)

            if len(target_groups) == 0 and target["type"] != "iperf":
                log.warning("Target %s disabled: not associated to any group",
                            target_name)
Beispiel #33
0
 def validate_config_format(config_file, config_schema):
     schema = os.path.abspath(config_schema)
     c = PyKwalify(source_file=config_file, schema_files=[schema])
     c.validate(raise_exception=True)
def validate(f):
    logger.info('Validating {}'.format(f.name))
    c = Core(source_file=f.name, schema_files=[resolve_from_site_packages('schema.yaml')])
    c.validate(raise_exception=True)
    click.echo("Finished validating: {}".format(f.name))
    click.echo("Finished validating: OK")
Beispiel #35
0
 def test_scenario_02(self):
     c = Core(source_file="wetest/tests/scenario_example02.yaml",
             schema_files=["wetest/resources/scenario_schema.yaml"])
     c.validate()
Beispiel #36
0
def validate_metadata_contents(metadata, filepath, cache):
    # Initialize output
    is_metadata_error = False
    metadata_error_output = []

    core = Core(source_file=filepath, schema_files=["schema.yml"])
    core.validate(raise_exception=False, silent=True)

    if len(core.validation_errors) > 0:
        metadata_error_output.extend(
            ['METADATA_ERROR: %s' % err for err in core.validation_errors])
        is_metadata_error = True

    pat_model = re.compile(r"metadata-(.+)\.txt")
    model_name_file = re.findall(pat_model, os.path.basename(filepath))[0]
    # print(f"model_name_file: {model_name_file} \t\t filepath: {filepath}")

    # This is a critical error and hence do not run further checks.
    if 'model_abbr' not in metadata:
        metadata_error_output.extend([
            'METADATA_ERROR: model_abbr key not present in the metadata file'
        ])
        is_metadata_error = True
        return is_metadata_error, metadata_error_output

    if model_name_file != metadata['model_abbr']:
        metadata_error_output.append(
            f"METADATA_ERROR: Model abreviation in metadata inconsistent with folder name for model_abbr={metadata['model_abbr']} as specified in metadata. NOTE: model name on file is: {model_name_file}"
        )
        is_metadata_error = True
    metadata['team_abbr'] = metadata['model_abbr'].split('-')[0]
    # Check if every team has only one `team_model_designation` as `primary`
    if 'team_abbr' in metadata.keys():
        # add designated primary model acche entry to the cache if not present
        if DESIGNATED_MODEL_CACHE_KEY not in cache:
            cache[DESIGNATED_MODEL_CACHE_KEY] = []

        # if the current models designation is primary AND the team_name is already present in the cache, then report error
        if metadata['team_abbr'] in cache[
                DESIGNATED_MODEL_CACHE_KEY] and metadata[
                    'team_model_designation'] == 'primary':
            is_metadata_error = True
            metadata_error_output.append(
                'METADATA ERROR: %s has more than 1 model designated as \"primary\"'
                % (metadata['team_abbr']))
        # else if the current model designation is "primary", then add it to the cache
        elif metadata['team_model_designation'] == 'primary':
            cache[DESIGNATED_MODEL_CACHE_KEY].append(metadata['team_abbr'])

    # if `this_model_is_an_emnsemble` is rpesent, show a warning.

    # Check for Required Fields
    required_fields = [
        'team_name', 'team_abbr', 'model_name', 'model_contributors',
        'model_abbr', 'website_url', 'license', 'team_model_designation',
        'methods'
    ]
    # required_fields = ['team_name', 'team_abbr', 'model_name', 'model_abbr',\
    #                        'methods', 'team_url', 'license', 'include_in_ensemble_and_visualization']

    # for field in required_fields:
    #     if field not in metadata.keys():
    #         is_metadata_error = True
    #         metadata_error_output += ["METADATA ERROR: %s missing '%s'" % (filepath, field)]

    # Check methods character length (warning not error)
    # if 'methods' in metadata.keys():
    #     methods_char_lenth = len(metadata['methods'])
    #     if methods_char_lenth > 200:
    #         metadata_error_output += [
    #             "METADATA WARNING: %s methods is too many characters (%i should be less than 200)" %
    #             (filepath, methods_char_lenth)]

    # Check if forecast_startdate is date
    if 'forecast_startdate' in metadata.keys():
        forecast_startdate = str(metadata['forecast_startdate'])
        try:
            dateutil.parser.parse(forecast_startdate)
            is_date = True
        except ValueError:
            is_date = False
        if not is_date:
            is_metadata_error = True
            metadata_error_output += [
                "METADATA ERROR: %s forecast_startdate %s must be a date and should be in YYYY-MM-DD format"
                % (filepath, forecast_startdate)
            ]

    # Check if this_model_is_an_ensemble and this_model_is_unconditional are boolean
    boolean_fields = [
        'this_model_is_an_ensemble', 'this_model_is_unconditional',
        'include_in_ensemble_and_visualization'
    ]
    possible_booleans = ['true', 'false']
    for field in boolean_fields:
        if field in metadata.keys():
            if metadata[field] not in possible_booleans:
                is_metadata_error = True
                metadata_error_output += [
                    "METADATA ERROR: %s '%s' field must be lowercase boolean (true, false) not '%s'"
                    % (filepath, field, metadata[field])
                ]

    # Validate team URLS
    regex = re.compile(
        r'^(?:http|ftp)s?://'  # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
        r'localhost|'  # localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
        r'(?::\d+)?'  # optional port
        r'(?:/?|[/?]\S+)$',
        re.IGNORECASE)

    # if 'team_url' in metadata.keys():
    #     if re.match(regex, str(metadata['team_url'])) is None:
    #         is_metadata_error = True
    #         metadata_error_output += [
    #             "METADATA ERROR: %s 'team_url' field must be a full URL (https://www.example.com) '%s'" %
    #             (filepath, metadata[field])]

    # Validate licenses
    license_df = pd.read_csv('accepted-licenses.csv')
    accepted_licenses = list(license_df['license'])
    if 'license' in metadata.keys():
        if metadata['license'] not in accepted_licenses:
            is_metadata_error = True
            metadata_error_output += [
                "METADATA ERROR: %s 'license' field must be in `./code/accepted-licenses.csv` 'license' column '%s'"
                % (filepath, metadata['license'])
            ]
    return is_metadata_error, metadata_error_output
Beispiel #37
0
    def validate_with(schema, target, raise_exception=True):
        validator = Core(source_data=target,
                         schema_files=[f"{schema_path}/{schema}.yml"])

        return validator.validate(raise_exception=raise_exception)
Beispiel #38
0
#!/usr/bin/env python

import glob
from pykwalify.core import Core
import pykwalify

exitCode = 0

pykwalify.init_logging(0)

for file in glob.glob("radar/**/*.yaml"):
    c = Core(source_file=file, schema_files=["src/radar_entry.schema.yaml"])
    try:
        c.validate(raise_exception=True)
    except Exception as e:
        print("ERROR - " + file + "\n" + e.msg)
        exitCode += 1

for file in glob.glob("radar/**/*.yml"):
    print("ERROR - " + file + "\nIncorrect extension, rename to '.yaml'")
    exitCode += 1

if exitCode > 0:
    print(str(exitCode) + " validation error(s).")

exit(exitCode)
Beispiel #39
0
    def parse(
        file=None,
        wf_data=None,
        step=None,
        skipped_steps=[],
        substitutions=[],
        allow_loose=False,
        immutable=True,
    ):
        """Returns an immutable workflow structure (a frozen Box) with 'steps' and
        'options' properties. See WorkflowParser._wf_schema above for their structure.
        If immutable=False is given, the returned object representing the workflow
        can be modified (an "unfrozen" ``box.Box``).
        """

        if not file and not wf_data:
            log.fail("Expecting 'file' or 'wf_data'")

        if file:
            if wf_data:
                log.fail("Expecting only one of 'file' and 'wf_data'")

            if not os.path.exists(file):
                log.fail(f"File {file} was not found.")

            if not file.endswith(".yml") and not file.endswith(".yaml"):
                log.fail("Unrecognized workflow file format.")

            with open(file, "r") as f:
                _wf_data = yaml.safe_load(f)

                if not _wf_data:
                    log.fail(f"File {file} is empty")
        else:
            _wf_data = dict(wf_data)

        # disable logging in order to silence warnings about "error() to fail()" change
        logging.disable(logging.CRITICAL)

        v = YMLValidator(source_data=_wf_data,
                         schema_data=WorkflowParser._wf_schema)

        try:
            v.validate()
        except SchemaError as e:
            # reenable logging
            logging.disable(logging.NOTSET)
            log.fail(f"{e.msg}")

        logging.disable(logging.NOTSET)

        WorkflowParser.__add_missing_ids(_wf_data)
        WorkflowParser.__propagate_options_to_steps(_wf_data)
        WorkflowParser.__apply_substitutions(_wf_data,
                                             substitutions=substitutions,
                                             allow_loose=allow_loose)
        WorkflowParser.__skip_steps(_wf_data, skipped_steps)
        WorkflowParser.__filter_step(_wf_data, step)

        # create and frozen a box
        wf_box = Box(_wf_data,
                     frozen_box=(immutable is True),
                     default_box=True)

        log.debug(f"Parsed workflow:\n{wf_box}")

        return wf_box
Beispiel #40
0
    def test_core_files(self):
        # These tests should pass with no exception raised
        pass_tests = [
            # All tests for keyword assert
            "test_assert.yaml",
            # All tests for keyword default
            "test_default.yaml",
            # All tests for keyword desc
            "test_desc.yaml",
            # All tests for keyword enum
            "test_enum.yaml",
            # All tests for keyword example
            "test_example.yaml",
            # All tests for keyword extensions
            "test_extensions.yaml",
            # All tests for keyword func
            "test_func.yaml",
            # All tests for keyword ident
            "test_ident.yaml",
            # All tests for keyword include
            "test_include.yaml",
            # All tests for keyword length
            "test_length.yaml",
            # All tests for keyword mapping
            "test_mapping.yaml",
            # All tests for keyword matching
            "test_matching.yaml",
            # All tests for keyword name
            "test_name.yaml",
            # All tests for keyword pattern
            "test_pattern.yaml",
            # All tests for keyword range
            "test_range.yaml",
            # All tests for keyword required
            "test_required.yaml",
            # All tests for keyword schema
            "test_schema.yaml",
            # All tests for keyword sequence
            "test_sequence.yaml",
            # All tests for keyword unique
            "test_unique.yaml",
            # All tests for keyword version
            "test_version.yaml",

            # All test cases for Multiple sequence checks
            "test_sequence_multi.yaml",
            # All test cases for merging
            "test_merge.yaml",
            # All test cases for yaml anchors
            "test_anchor.yaml",

            # All tests for TYPE: any
            "test_type_any.yaml",
            # All tests for TYPE: bool
            "test_type_bool.yaml",
            # All tests for TYPE: date
            "test_type_date.yaml",
            # All tests for TYPE: enum
            "test_type_enum.yaml",
            # All tests for TYPE: float
            "test_type_float.yaml",
            # All tests for TYPE: int
            "test_type_int.yaml",
            # All tests for TYPE: map
            "test_type_map.yaml",
            # All tests for TYPE: none
            "test_type_none.yaml",
            # All tests for TYPE: number
            "test_type_number.yaml",
            # All tests for TYPE: scalar
            "test_type_scalar.yaml",
            # All tests for TYPE: seq
            "test_type_seq.yaml",
            # All tests for TYPE: str
            "test_type_str.yaml",
            # All tests for TYPE: symbol
            "test_type_symbol.yaml",
            # All tests for TYPE: text
            "test_type_text.yaml",
            # All tests for TYPE: timestamp
            "test_type_timestamp.yaml",
        ]

        _fail_tests = [
            # All tests for keyword assert
            ("test_assert.yaml", SchemaError),
            # All tests for keyword default
            ("test_default.yaml", SchemaError),
            # All tests for keyword desc
            ("test_desc.yaml", SchemaError),
            # All tests for keyword enum
            ("test_enum.yaml", SchemaError),
            # All tests for keyword example
            ("test_example.yaml", SchemaError),
            # All tests for keyword extensions
            ("test_extensions.yaml", SchemaError),
            # All tests for keyword func
            ("test_func.yaml", SchemaError),
            # All tests for keyword ident
            ("test_ident.yaml", SchemaError),
            # All tests for keyword include
            ("test_include.yaml", SchemaError),
            # All tests for keyword length
            ("test_length.yaml", SchemaError),
            # All tests for keyword mapping
            ("test_mapping.yaml", SchemaError),
            # All tests for keyword matching
            ("test_matching.yaml", SchemaError),
            # All tests for keyword name
            ("test_name.yaml", SchemaError),
            # All tests for keyword pattern
            ("test_pattern.yaml", SchemaError),
            # All tests for keyword range
            ("test_range.yaml", SchemaError),
            # All tests for keyword required
            ("test_required.yaml", SchemaError),
            # All tests for keyword schema
            ("test_schema.yaml", SchemaError),
            # All tests for keyword sequence
            ("test_sequence.yaml", SchemaError),
            # All tests for keyword unique
            ("test_unique.yaml", SchemaError),
            # All tests for keyword version
            ("test_version.yaml", SchemaError),

            # All test cases for Multiple sequence checks
            ("test_sequence_multi.yaml", SchemaError),
            # All test cases for merging
            ("test_merge.yaml", SchemaError),
            # All test cases for yaml anchors
            ("test_anchor.yaml", SchemaError),

            # All tests for TYPE: any
            ("test_type_any.yaml", SchemaError),
            # All tests for TYPE: bool
            ("test_type_bool.yaml", SchemaError),
            # All tests for TYPE: date
            ("test_type_date.yaml", SchemaError),
            # All tests for TYPE: float
            ("test_type_float.yaml", SchemaError),
            # All tests for TYPE: int
            ("test_type_int.yaml", SchemaError),
            # All tests for TYPE: map
            ("test_type_map.yaml", SchemaError),
            # All tests for TYPE: none
            ("test_type_none.yaml", SchemaError),
            # All tests for TYPE: number
            ("test_type_number.yaml", SchemaError),
            # All tests for TYPE: scalar
            ("test_type_scalar.yaml", SchemaError),
            # All tests for TYPE: seq
            ("test_type_seq.yaml", SchemaError),
            # All tests for TYPE: str
            ("test_type_str.yaml", SchemaError),
            # All tests for TYPE: symbol
            ("test_type_symbol.yaml", SchemaError),
            # All tests for TYPE: text
            ("test_type_text.yaml", SchemaError),
            # All tests for TYPE: timestamp
            ("test_type_timestamp.yaml", SchemaError),
        ]

        # Add override magic to make it easier to test a specific file
        if "S" in os.environ:
            pass_tests = [os.environ["S"]]
            _fail_tests = []
        elif "F" in os.environ:
            pass_tests = []
            _fail_tests = [(os.environ["F"], SchemaError)]

        for passing_test_file in pass_tests:
            f = self.f(os.path.join("success", passing_test_file))
            with open(f, "r") as stream:
                yaml_data = yaml.load_all(stream)

                for document_index, document in enumerate(yaml_data):
                    data = document["data"]
                    schema = document["schema"]

                    try:
                        print("Running test files: {0}".format(f))
                        c = Core(source_data=data,
                                 schema_data=schema,
                                 strict_rule_validation=True,
                                 allow_assertions=True)
                        c.validate()
                        compare(c.validation_errors, [],
                                prefix="No validation errors should exist...")
                    except Exception as e:
                        print("ERROR RUNNING FILES: {0} : {1}:{2}".format(
                            f, document_index, document.get('name',
                                                            'UNKNOWN')))
                        raise e

            # This serve as an extra schema validation that tests more complex structures then testrule.py do
            compare(
                c.root_rule.schema_str,
                schema,
                prefix=
                "Parsed rules is not correct, something have changed... files : {0} : {1}"
                .format(f, document_index))

        for failing_test, exception_type in _fail_tests:
            f = self.f(os.path.join("fail", failing_test))
            with open(f, "r") as stream:
                yaml_data = yaml.load_all(stream)

                for document_index, document in enumerate(yaml_data):
                    data = document["data"]
                    schema = document["schema"]
                    errors = document.get("errors", [])

                    try:
                        print("Running test files: {0}".format(f))
                        c = Core(source_data=data,
                                 schema_data=schema,
                                 strict_rule_validation=True,
                                 allow_assertions=True)
                        c.validate()
                    except exception_type as e:
                        pass
                    else:
                        print("ERROR RUNNING FILES: {0} : {1}:{2}".format(
                            f, document_index, document.get('name',
                                                            'UNKNOWN')))
                        raise AssertionError(
                            "Exception {0} not raised as expected... FILES: {1} : {2} : {3}:{4}"
                            .format(exception_type, exception_type,
                                    failing_test, document_index,
                                    document.get('name', 'UNKNOWN')))

                    compare(
                        sorted(c.validation_errors),
                        sorted(errors),
                        prefix=
                        "Wrong validation errors when parsing files : {0} : {1} : {2}"
                        .format(f, document_index,
                                document.get('name', 'UNKNOWN')))
Beispiel #41
0
    def test_multi_file_support(self):
        """
        This should test that multiple files is supported correctly
        """
        pass_tests = [
            # Test that include directive can be used at top level of the schema
            ([
                self.f("partial_schemas", "1s-schema.yaml"),
                self.f("partial_schemas", "1s-partials.yaml"),
            ], self.f("partial_schemas", "1s-data.yaml"), {
                'sequence': [{
                    'include': 'fooone'
                }],
                'type': 'seq',
            }),
            # # This test that include directive works inside sequence
            # ([self.f("33a.yaml"), self.f("33b.yaml")], self.f("33c.yaml"), {'sequence': [{'include': 'fooone'}], 'type': 'seq'}),
            # This test recursive schemas
            ([
                self.f("partial_schemas", "2s-schema.yaml"),
                self.f("partial_schemas", "2s-partials.yaml"),
            ], self.f("partial_schemas", "2s-data.yaml"), {
                'sequence': [{
                    'include': 'fooone'
                }],
                'type': 'seq',
            })
        ]

        failing_tests = [
            # Test include inside partial schema
            ([
                self.f("partial_schemas", "1f-schema.yaml"),
                self.f("partial_schemas", "1f-partials.yaml")
            ], self.f("partial_schemas", "1f-data.yaml"), SchemaError, [
                "Cannot find partial schema with name 'fooonez'. Existing partial schemas: 'fooone, foothree, footwo'. Path: '/0'"
            ]),
            ([self.f('partial_schemas', '2f-schema.yaml')],
             self.f('partial_schemas', '2f-data.yaml'), SchemaError,
             ["Value 'True' is not of type 'str'. Path: '/0'"]),
            ([self.f('partial_schemas', '3f-schema.yaml')],
             self.f('partial_schemas', '3f-data.yaml'), SchemaError,
             ["Value 'True' is not of type 'str'. Path: ''"]),
            ([self.f('partial_schemas', '4f-schema.yaml')],
             self.f('partial_schemas', '4f-data.yaml'), SchemaError,
             ["Value 'True' is not of type 'str'. Path: '/0/foo/0/bar'"]),
            ([self.f('partial_schemas', '5f-schema.yaml')],
             self.f('partial_schemas', '5f-data.yaml'), SchemaError,
             ["Value 'True' is not of type 'str'. Path: '/0/0/0/0'"]),
            ([self.f('partial_schemas', '6f-schema.yaml')],
             self.f('partial_schemas', '6f-data.yaml'), SchemaError,
             ["Value 'True' is not of type 'str'. Path: '/foo/bar/qwe/ewq'"])
        ]

        for passing_test in pass_tests:
            try:
                c = Core(source_file=passing_test[1],
                         schema_files=passing_test[0])
                c.validate()
                compare(c.validation_errors, [],
                        prefix="No validation errors should exist...")
            except Exception as e:
                print("ERROR RUNNING FILE: {0} : {1}".format(
                    passing_test[0], passing_test[1]))
                raise e

            # This serve as an extra schema validation that tests more complex structures then testrule.py do
            compare(
                c.root_rule.schema_str,
                passing_test[2],
                prefix="Parsed rules is not correct, something have changed..."
            )

        for failing_test in failing_tests:
            with pytest.raises(failing_test[2],
                               msg="Test files: {0} : {1}".format(
                                   ", ".join(failing_test[0]),
                                   failing_test[1])):
                c = Core(schema_files=failing_test[0],
                         source_file=failing_test[1])
                c.validate()

            if not c.validation_errors:
                raise AssertionError("No validation_errors was raised...")

            compare(
                sorted(c.validation_errors),
                sorted(failing_test[3]),
                prefix="Wrong validation errors when parsing files : {0} : {1}"
                .format(
                    failing_test[0],
                    failing_test[1],
                ),
            )
Beispiel #42
0
def validate_yaml_schema(yaml_file_content: Text, schema_path: Text) -> None:
    """
    Validate yaml content.

    Args:
        yaml_file_content: the content of the yaml file to be validated
        schema_path: the schema of the yaml file
    """
    from pykwalify.core import Core
    from pykwalify.errors import SchemaError
    from ruamel.yaml import YAMLError
    import pkg_resources
    import logging

    log = logging.getLogger("pykwalify")
    log.setLevel(logging.CRITICAL)

    try:
        # we need "rt" since
        # it will add meta information to the parsed output. this meta information
        # will include e.g. at which line an object was parsed. this is very
        # helpful when we validate files later on and want to point the user to the
        # right line
        source_data = rasa.shared.utils.io.read_yaml(
            yaml_file_content, reader_type=["safe", "rt"]
        )
    except YAMLError:
        raise YamlValidationException(
            "The provided yaml file is invalid. You can use "
            "http://www.yamllint.com/ to validate the yaml syntax "
            "of your file."
        )
    except DuplicateKeyError as e:
        raise YamlValidationException(
            "The provided yaml file contains a duplicated key: '{}'. You can use "
            "http://www.yamllint.com/ to validate the yaml syntax "
            "of your file.".format(str(e))
        )

    schema_file = pkg_resources.resource_filename(PACKAGE_NAME, schema_path)
    schema_utils_file = pkg_resources.resource_filename(
        PACKAGE_NAME, RESPONSES_SCHEMA_FILE
    )
    schema_extensions = pkg_resources.resource_filename(
        PACKAGE_NAME, SCHEMA_EXTENSIONS_FILE
    )

    c = Core(
        source_data=source_data,
        schema_files=[schema_file, schema_utils_file],
        extensions=[schema_extensions],
    )

    try:
        c.validate(raise_exception=True)
    except SchemaError:
        raise YamlValidationException(
            "Please make sure the file is correct and all "
            "mandatory parameters are specified. Here are the errors "
            "found during validation",
            c.errors,
            content=source_data,
        )
Beispiel #43
0
def validate_metadata_contents(metadata, filepath, cache):
    # Initialize output
    is_metadata_error = False
    metadata_error_output = []

    core = Core(source_file=filepath, schema_files=["schema.yml"])
    core.validate(raise_exception=False, silent=True)

    if len(core.validation_errors) > 0:
        metadata_error_output.extend(
            ['METADATA_ERROR: %s' % err for err in core.validation_errors])
        is_metadata_error = True

    folder_name = filepath.split('/')[-2]
    if folder_name != metadata['model_abbr']:
        metadata_error_output.append(
            f"METADATA_ERROR: Model abreviation in metadata inconsistent with folder name for model_abbr={metadata['model_abbr']} as specified in metadata. NOTE: Folder name is: {folder_name}"
        )
        is_metadata_error = True
    metadata['team_abbr'] = metadata['model_abbr'].split('-')[0]
    # Check if every team has only one `team_model_designation` as `primary`

    # Check if forecast_startdate is date
    if 'forecast_startdate' in metadata.keys():
        forecast_startdate = str(metadata['forecast_startdate'])
        try:
            dateutil.parser.parse(forecast_startdate)
            is_date = True
        except ValueError:
            is_date = False
        if not is_date:
            is_metadata_error = True
            metadata_error_output += [
                "METADATA ERROR: %s forecast_startdate %s must be a date and should be in YYYY-MM-DD format"
                % (filepath, forecast_startdate)
            ]

    # Check if this_model_is_an_ensemble and this_model_is_unconditional are boolean
    boolean_fields = [
        'this_model_is_an_ensemble', 'this_model_is_unconditional',
        'include_in_ensemble_and_visualization'
    ]
    possible_booleans = ['true', 'false']
    for field in boolean_fields:
        if field in metadata.keys():
            if metadata[field] not in possible_booleans:
                is_metadata_error = True
                metadata_error_output += [
                    "METADATA ERROR: %s '%s' field must be lowercase boolean (true, false) not '%s'"
                    % (filepath, field, metadata[field])
                ]

    # Validate team URLS
    regex = re.compile(
        r'^(?:http|ftp)s?://'  # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
        r'localhost|'  # localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
        r'(?::\d+)?'  # optional port
        r'(?:/?|[/?]\S+)$',
        re.IGNORECASE)

    # if 'team_url' in metadata.keys():
    #     if re.match(regex, str(metadata['team_url'])) is None:
    #         is_metadata_error = True
    #         metadata_error_output += [
    #             "METADATA ERROR: %s 'team_url' field must be a full URL (https://www.example.com) '%s'" %
    #             (filepath, metadata[field])]

    # Validate licenses
    license_df = pd.read_csv('./code/validation/accepted-licenses.csv')
    accepted_licenses = list(license_df['license'])
    if 'license' in metadata.keys():
        if metadata['license'] not in accepted_licenses:
            is_metadata_error = True
            metadata_error_output += [
                "METADATA ERROR: %s 'license' field must be in `./code/validations/accepted-licenses.csv` 'license' column '%s'"
                % (filepath, metadata['license'])
            ]
    return is_metadata_error, metadata_error_output
Beispiel #44
0
def parse_data(site):
    base = op.dirname(__file__)

    originals = []
    for fn in os.listdir(op.join(base, 'originals')):
        if fn.endswith('.yaml'):
            originals.extend(yaml.load(open(op.join(base, 'originals', fn))))

    def sort_key(game):
        name = game_name(game)
        # Always sort SCUMM first
        if name == 'SCUMM':
            return '0'
        if name.startswith('The '):
            return name[4:]
        return name

    originals = natsorted(originals, key=sort_key, alg=ns.IGNORECASE)
    print(str(len(originals)) + ' games in total')

    try:
        core = Core(source_data=originals,
                    schema_files=['schema/originals.yaml'])
        core.validate(raise_exception=True)
    except Exception as error:
        if len(core.errors) > 0:
            show_validation_errors(originals, core.errors)
        else:
            raise error

    clones = []
    for fn in sorted(os.listdir(op.join(base, 'games'))):
        if fn.endswith('.yaml'):
            clones.extend(yaml.load(open(op.join(base, 'games', fn))))
    print(str(len(clones)) + ' clones in total')

    try:
        core = Core(source_data=clones, schema_files=['schema/games.yaml'])
        core.validate(raise_exception=True)
    except Exception as error:
        if len(core.errors) > 0:
            show_validation_errors(clones, core.errors)
        else:
            raise error

    errors = []
    originals_map = {}

    for item in originals:
        name = game_name(item)

        if name in originals_map:
            errors.append({
                "name": name,
                "error": "Duplicate original game '%s'" % name
            })

        originals_map[name] = item

    if len(errors) > 0:
        show_errors(errors)

    for clone in clones:
        if 'originals' not in clone:
            show_errors([{
                "name":
                clone["name"],
                "error":
                "Unable to find 'remakes' or 'clones' in game"
            }])

        for original in clone['originals']:
            if original not in originals_map:
                errors.append({
                    "name":
                    clone["name"],
                    "error":
                    "Original game '%s' not found" % original
                })

    if len(errors) > 0:
        show_errors(errors)

    for item in originals:
        parse_global_tags(site, item.get('meta', {}), 'genre')
        # Recombine originals and clones
        combined = copy.deepcopy(item)
        name = game_name(combined)

        combined['games'] = [
            clone for clone in clones if name in clone['originals']
        ]
        parse_items(site, combined, 'games')
Beispiel #45
0
    def testCore(self):
        # These tests should pass with no exception raised
        pass_tests = [
            # Test sequence with only string values
            ("1a.yaml", "1b.yaml", {
                'sequence': [{
                    'type': 'str'
                }],
                'type': 'seq'
            }),
            # Test sequence where the only valid items is integers
            ("3a.yaml", "3b.yaml", {
                'sequence': [{
                    'type': 'int'
                }],
                'type': 'seq'
            }),
            # Test sequence with only booleans
            ("4a.yaml", "4b.yaml", {
                'sequence': [{
                    'type': 'bool'
                }],
                'type': 'seq'
            }),
            # Test mapping with different types of data and some extra conditions
            ("8a.yaml", "8b.yaml", {
                'mapping': {
                    'age': {
                        'type': 'int'
                    },
                    'birth': {
                        'type': 'str'
                    },
                    'email': {
                        'pattern': '.+@.+',
                        'type': 'str'
                    },
                    'name': {
                        'required': True,
                        'type': 'str'
                    }
                },
                'type': 'map'
            }),
            # Test sequence with mapping with valid mapping
            ("10a.yaml", "10b.yaml", {
                'sequence': [{
                    'mapping': {
                        'email': {
                            'type': 'str'
                        },
                        'name': {
                            'required': True,
                            'type': 'str'
                        }
                    },
                    'type': 'map'
                }],
                'type':
                'seq'
            }),
            # Test mapping with sequence with mapping and valid data
            ("12a.yaml", "12b.yaml", {
                'mapping': {
                    'company': {
                        'required': True,
                        'type': 'str'
                    },
                    'email': {
                        'type': 'str'
                    },
                    'employees': {
                        'sequence': [{
                            'mapping': {
                                'code': {
                                    'required': True,
                                    'type': 'int'
                                },
                                'email': {
                                    'type': 'str'
                                },
                                'name': {
                                    'required': True,
                                    'type': 'str'
                                }
                            },
                            'type': 'map'
                        }],
                        'type':
                        'seq'
                    }
                },
                'type': 'map'
            }),
            # Test most of the implemented functions
            ("14a.yaml", "14b.yaml", {
                'sequence': [{
                    'mapping': {
                        'age': {
                            'range': {
                                'max': 30,
                                'min': 18
                            },
                            'type': 'int'
                        },
                        'birth': {
                            'type': 'str'
                        },
                        'blood': {
                            'enum': ['A', 'B', 'O', 'AB'],
                            'type': 'str'
                        },
                        'deleted': {
                            'type': 'bool'
                        },
                        'email': {
                            'pattern': '.+@.+',
                            'required': True,
                            'type': 'str'
                        },
                        'memo': {
                            'type': 'any'
                        },
                        'name': {
                            'required': True,
                            'type': 'str'
                        },
                        'password': {
                            'length': {
                                'max': 16,
                                'min': 8
                            },
                            'type': 'str'
                        }
                    },
                    'type': 'map'
                }],
                'type':
                'seq'
            }),
            # This will test the unique constraint
            ("16a.yaml", "16b.yaml", {
                'sequence': [{
                    'mapping': {
                        'email': {
                            'type': 'str'
                        },
                        'groups': {
                            'sequence': [{
                                'type': 'str',
                                'unique': True
                            }],
                            'type': 'seq'
                        },
                        'name': {
                            'required': True,
                            'type': 'str',
                            'unique': True
                        }
                    },
                    'required': True,
                    'type': 'map'
                }],
                'type':
                'seq'
            }),
            #
            ("18a.yaml", "18b.yaml", {
                'mapping': {
                    'datasources': {
                        'allowempty': True,
                        'type': 'map'
                    }
                },
                'type': 'map'
            }),
            #
            ("19a.yaml", "19b.yaml", {
                'mapping': {
                    'datasources': {
                        'allowempty': True,
                        'mapping': {
                            'test1': {
                                'type': 'str'
                            }
                        },
                        'type': 'map'
                    }
                },
                'type': 'map'
            }),
            #
            ("20a.yaml", "20b.yaml", {
                'type': 'float'
            }),
            # This tests number validation rule
            ("21a.yaml", "21b.yaml", {
                'sequence': [{
                    'type': 'number'
                }],
                'type': 'seq'
            }),
            # This test the text validation rule
            ("23a.yaml", "23b.yaml", {
                'sequence': [{
                    'type': 'text'
                }],
                'type': 'seq'
            }),
            # This test the text validation rule
            ("24a.yaml", "25b.yaml", {
                'sequence': [{
                    'type': 'any'
                }],
                'type': 'seq'
            }),
            #
            ("26a.yaml", "26b.yaml", {
                'type': 'any'
            }),
            #
            ("28a.yaml", "28b.yaml", {
                'allowempty': True,
                'mapping': {
                    'name': {
                        'type': 'str'
                    }
                },
                'pattern': '^[a-z0-9]+$',
                'type': 'map'
            }),
            #
            ("29a.yaml", "29b.yaml", {
                'sequence': [{
                    'mapping': {
                        'bits': {
                            'type': 'str'
                        },
                        'name': {
                            'type': 'str'
                        }
                    },
                    'pattern': '.+',
                    'type': 'map'
                }],
                'type':
                'seq'
            }),
            #
            ("30a.yaml", "30b.yaml", {
                'sequence': [{
                    'mapping': {
                        'foobar': {
                            'mapping': {
                                'opa': {
                                    'type': 'bool'
                                }
                            },
                            'type': 'map'
                        },
                        'media': {
                            'type': 'int'
                        },
                        'regex;[mi.+]': {
                            'sequence': [{
                                'type': 'str'
                            }],
                            'type': 'seq'
                        },
                        'regex;[mo.+]': {
                            'sequence': [{
                                'type': 'bool'
                            }],
                            'type': 'seq'
                        }
                    },
                    'matching-rule': 'any',
                    'type': 'map'
                }],
                'type':
                'seq'
            }),
            # This test that a regex that will compile
            ("31a.yaml", "31b.yaml", {
                'mapping': {
                    'regex;mi.+': {
                        'sequence': [{
                            'type': 'str'
                        }],
                        'type': 'seq'
                    }
                },
                'matching-rule': 'any',
                'type': 'map'
            }),
        ]

        # These tests are designed to fail with some exception raised
        fail_tests = [
            # Test sequence with defined string content type but data only has integers
            ("2a.yaml", "2b.yaml", SchemaError, [
                "Value: 1 is not of type 'str' : /0",
                "Value: 2 is not of type 'str' : /1",
                "Value: 3 is not of type 'str' : /2"
            ]),
            # Test sequence with defined string content type but data only has booleans
            ("5a.yaml", "5b.yaml", SchemaError, [
                "Value: True is not of type 'str' : /0",
                "Value: False is not of type 'str' : /1"
            ]),
            # Test sequence with defined booleans but with one integer
            ("6a.yaml", "6b.yaml", SchemaError,
             ["Value: 1 is not of type 'bool' : /2"]),
            # Test sequence with strings and and lenght on each string
            ("7a.yaml", "7b.yaml", SchemaError,
             ['length.toolong : 5 < 6 : /2']),
            # Test mapping that do not work
            ("9a.yaml", "8b.yaml", SchemaError, [
                "Value: twnty is not of type 'int' : /age",
                'pattern.unmatch : .+@.+ --> foo(at)mail.com : /email'
            ]),
            # Test sequence with mapping with missing required key
            ("11a.yaml", "10b.yaml", SchemaError, [
                'required.nokey : name : /1', 'key.undefined : naem : /1',
                'key.undefined : mail : /2'
            ]),
            # Test mapping with sequence with mapping and invalid data
            ("13a.yaml", "12b.yaml", SchemaError, [
                "Value: A101 is not of type 'int' : /employees/0/code",
                'key.undefined : mail : /employees/1'
            ]),
            # TODO: write
            ("15a.yaml", "14b.yaml", SchemaError, [
                "Value: twenty is not of type 'int' : /0/age",
                'length.tooshort : 8 > 6 : /0/password',
                'pattern.unmatch : .+@.+ --> foo(at)mail.com : /0/email',
                'enum.notexists : a : /0/blood', 'required.nokey : name : /1',
                'key.undefined : given-name : /1',
                'key.undefined : family-name : /1',
                'range.toosmall : 18 > 15 : /1/age'
            ]),
            # TODO: The reverse unique do not currently work proper # This will test the unique constraint but should fail
            ("17a.yaml", "16b.yaml", SchemaError,
             ['value.notunique :: value: foo : /0/groups/3 : /0/groups/0']),
            # This tests number validation rule with wrong data
            ("22a.yaml", "22b.yaml", SchemaError,
             ["Value: abc is not of type 'number' : /2"]),
            # This test the text validation rule with wrong data
            ("24a.yaml", "24b.yaml", SchemaError,
             ["Value: True is not of type 'text' : /3"]),
            # This tests pattern matching on keys in a map
            ("27a.yaml", "27b.yaml", SchemaError,
             ['pattern.unmatch : ^[a-z]+$ --> na1me : ']),
        ]

        for passing_test in pass_tests:
            c = Core(source_file=self.f(passing_test[0]),
                     schema_file=self.f(passing_test[1]))
            c.validate()
            compare(c.validation_errors, [],
                    prefix="No validation errors should exist...")

            # This serve as an extra schema validation that tests more complex structures then testrule.py do
            compare(
                c.root_rule._schema_str,
                passing_test[2],
                prefix="Parsed rules is not correct, something have changed..."
            )

        for failing_test in fail_tests:
            with self.assertRaises(failing_test[2],
                                   msg="Test file: {} : {}".format(
                                       failing_test[0], failing_test[1])):
                c = Core(source_file=self.f(failing_test[0]),
                         schema_file=self.f(failing_test[1]))
                c.validate()

            compare(
                sorted(c.validation_errors),
                sorted(failing_test[3]),
                prefix="Wrong validation errors when parsing files : {} : {}".
                format(failing_test[0], failing_test[1]))
from pykwalify.core import Core
import yaml

inventory = yaml.load(open("manoci.yaml"), Loader=yaml.FullLoader)
#
print(inventory)
for i in inventory['localhost_fake'].keys():
    print(i)

inven_validation = Core(source_file="manoci.yaml",
                        schema_files=["schema2.yaml"])
inven_validation.validate(raise_exception=True)
Beispiel #47
0
def validate_metadata_contents(metadata, filepath, cache):
    # Initialize output
    is_metadata_error = False
    metadata_error_output = []

    core = Core(source_file=filepath, schema_files=[SCHEMA_FILE])
    core.validate(raise_exception=False, silent=True)

    if len(core.validation_errors) > 0:
        metadata_error_output.extend(
            ['METADATA_ERROR: %s' % err for err in core.validation_errors])
        is_metadata_error = True

    path = os.path.normpath(filepath)
    folder_name = path.split(os.sep)[-2]

    # This is a critical error and hence do not run further checks.
    if 'model_abbr' not in metadata:
        metadata_error_output.extend([
            'METADATA_ERROR: model_abbr key not present in the metadata file'
        ])
        is_metadata_error = True
        return is_metadata_error, metadata_error_output

    if folder_name != metadata['model_abbr']:
        metadata_error_output.append(
            f"METADATA_ERROR: Model abreviation in metadata inconsistent with folder name for model_abbr={metadata['model_abbr']} as specified in metadata. NOTE: Folder name is: {folder_name}"
        )
        is_metadata_error = True
    metadata['team_abbr'] = metadata['model_abbr'].split('-')[0]
    # Check if every team has only one `team_model_designation` as `primary`
    if 'team_abbr' in metadata.keys():
        # add designated primary model acche entry to the cache if not present
        if DESIGNATED_MODEL_CACHE_KEY not in cache:
            cache[DESIGNATED_MODEL_CACHE_KEY] = []

        # if the current models designation is primary AND the team_name is already present in the cache, then report error
        if metadata['team_abbr'] in cache[
                DESIGNATED_MODEL_CACHE_KEY] and metadata[
                    'team_model_designation'] == 'primary':
            is_metadata_error = True
            metadata_error_output.append(
                'METADATA ERROR: %s has more than 1 model designated as \"primary\"'
                % (metadata['team_abbr']))
        # else if the current model designation is "primary", then add it to the cache
        elif metadata['team_model_designation'] == 'primary':
            cache[DESIGNATED_MODEL_CACHE_KEY].append(metadata['team_abbr'])

    # Check if forecast_startdate is date
    if 'forecast_startdate' in metadata.keys():
        forecast_startdate = str(metadata['forecast_startdate'])
        try:
            dateutil.parser.parse(forecast_startdate)
            is_date = True
        except ValueError:
            is_date = False
        if not is_date:
            is_metadata_error = True
            metadata_error_output += [
                "METADATA ERROR: %s forecast_startdate %s must be a date and should be in YYYY-MM-DD format"
                % (filepath, forecast_startdate)
            ]

    # Check if this_model_is_an_ensemble and this_model_is_unconditional are boolean
    boolean_fields = [
        'this_model_is_an_ensemble', 'this_model_is_unconditional',
        'include_in_ensemble_and_visualization'
    ]
    possible_booleans = ['true', 'false']
    for field in boolean_fields:
        if field in metadata.keys():
            if metadata[field] not in possible_booleans:
                is_metadata_error = True
                metadata_error_output += [
                    "METADATA ERROR: %s '%s' field must be lowercase boolean (true, false) not '%s'"
                    % (filepath, field, metadata[field])
                ]

    # Validate team URLS
    regex = re.compile(
        r'^(?:http|ftp)s?://'  # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
        r'localhost|'  # localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
        r'(?::\d+)?'  # optional port
        r'(?:/?|[/?]\S+)$',
        re.IGNORECASE)

    # Validate licenses
    license_df = pd.read_csv('./code/validation/accepted-licenses.csv')
    accepted_licenses = list(license_df['license'])
    if 'license' in metadata.keys():
        if metadata['license'] not in accepted_licenses:
            is_metadata_error = True
            metadata_error_output += [
                "\nMETADATA ERROR: %s 'license' field must be in `./code/validations/accepted-licenses.csv` 'license' column '%s'"
                % (filepath, metadata['license'])
            ]
    return is_metadata_error, metadata_error_output
Beispiel #48
0
def validate_yaml_schema(
    yaml_file_content: Text, schema_path: Text, show_validation_errors: bool = True
) -> None:
    """
    Validate yaml content.

    Args:
        yaml_file_content: the content of the yaml file to be validated
        schema_path: the schema of the yaml file
        show_validation_errors: if true, validation errors are shown
    """
    from pykwalify.core import Core
    from pykwalify.errors import SchemaError
    from ruamel.yaml import YAMLError
    import pkg_resources
    import rasa.utils.io
    import logging

    log = logging.getLogger("pykwalify")
    if show_validation_errors:
        log.setLevel(logging.WARN)
    else:
        log.setLevel(logging.CRITICAL)

    try:
        source_data = rasa.utils.io.read_yaml(yaml_file_content)
    except YAMLError:
        raise InvalidYamlFileError(
            "The provided yaml file is invalid. You can use "
            "http://www.yamllint.com/ to validate the yaml syntax "
            "of your file."
        )
    except DuplicateKeyError as e:
        raise InvalidYamlFileError(
            "The provided yaml file contains a duplicated key: '{}'. You can use "
            "http://www.yamllint.com/ to validate the yaml syntax "
            "of your file.".format(str(e))
        )

    try:
        schema_file = pkg_resources.resource_filename(PACKAGE_NAME, schema_path)
        schema_utils_file = pkg_resources.resource_filename(
            PACKAGE_NAME, SCHEMA_UTILS_FILE
        )
        schema_extensions = pkg_resources.resource_filename(
            PACKAGE_NAME, SCHEMA_EXTENSIONS_FILE
        )

        c = Core(
            source_data=source_data,
            schema_files=[schema_file, schema_utils_file],
            extensions=[schema_extensions],
        )
        c.validate(raise_exception=True)
    except SchemaError:
        raise InvalidYamlFileError(
            "Failed to validate yaml file. "
            "Please make sure the file is correct and all "
            "mandatory parameters are specified; to do so, "
            "take a look at the errors logged during "
            "validation previous to this exception."
        )
Beispiel #49
0
def parse_data(site):
    base = op.join(op.dirname(__file__), 'games')

    originals = []
    for fn in os.listdir(op.join(base, 'originals')):
        if fn.endswith('.yaml'):
            originals.extend(yaml.load(open(op.join(base, 'originals', fn))))

    def sort_key(game):
        name = game_name(game)
        # Always sort SCUMM first
        if name == 'SCUMM':
            return '0'
        if name.startswith('The '):
            return name[4:]
        return name

    originals = natsorted(originals, key=sort_key, alg=ns.IGNORECASE)
    print(str(len(originals)) + ' games in total')

    try:
        core = Core(source_data=originals,
                    schema_files=['schema_originals.yaml'])
        core.validate(raise_exception=True)
    except Exception as error:
        if len(core.errors) > 0:
            show_validation_errors(originals, core.errors)
        else:
            raise error

    clones = []
    for fn in sorted(os.listdir(op.join(base, 'clones'))):
        if fn.endswith('.yaml'):
            clones.extend(yaml.load(open(op.join(base, 'clones', fn))))
    print(str(len(clones)) + ' clones in total')

    try:
        core = Core(source_data=clones, schema_files=['schema_clones.yaml'])
        core.validate(raise_exception=True)
    except Exception as error:
        if len(core.errors) > 0:
            show_validation_errors(clones, core.errors)
        else:
            raise error

    for item in originals:
        parse_global_tags(site, item.get('meta', {}), 'genre')
        # Recombine originals and clones
        combined = copy.deepcopy(item)
        name = game_name(combined)
        combined_remakes = [
            clone for clone in clones
            if 'remakes' in clone and name in clone['remakes']
        ]
        if len(combined_remakes) > 0:
            combined['remakes'] = combined_remakes
        combined_clones = [
            clone for clone in clones
            if 'clones' in clone and name in clone['clones']
        ]
        if len(combined_clones) > 0:
            combined['clones'] = combined_clones
        parse_items(site, combined, 'remakes')
        parse_items(site, combined, 'clones')
Beispiel #50
0
 def test_suite(self):
     c = Core(source_file="wetest/tests/suite_example01.yaml",
             schema_files=["wetest/resources/suite_schema.yaml"])
     c.validate()
Beispiel #51
0
 def validate_topology(scheme_file, data_file):
     c = Core(source_file=data_file, schema_files=[scheme_file])
     c.validate(raise_exception=True)
     print 'Topology validated'
Beispiel #52
0
    def validate_config(self, config_file):
        """Validates configuration file.
        Returns tuple of content, version, where content is validated config dict.
        Else raises ConfigErrors.
        """
        with open(config_file, 'r') as file:
            try:
                config_content = ruamel.yaml.load(file, ruamel.yaml.RoundTripLoader, version=(1, 1))
            except BaseException as exc:
                raise ConfigErrors(config_file, {'at top level': [str(exc)]})


        version = None
        # Validate each worker section against the schema and
        # parse schema to extract types and set up cmd argument parser

        #self._parser = parser = cls.__primary_parser(add_help=True)
        validated_content = OrderedDict()

        errors = OrderedDict()

        for worker, variables in config_content.items():
            # schema_version specifies config version
            if worker == "schema_version":
                version = variables
                continue
            _worker = worker.split("__")[0]

            if worker in self._schemas:
                schema_fn, _ = self._schemas[worker]
            elif _worker in self._schemas:
                schema_fn, _ = self._schemas[worker] = self._schemas[_worker]
            else:
                schema_fn = os.path.join(caracal.pckgdir,"schema", "{0:s}_schema.yml".format(_worker))

                if _worker == "worker" or not os.path.exists(schema_fn):
                    errors[worker] = ["this is not a recognized worker name, or its schema file is missing"]
                    continue

                with open(schema_fn, 'r') as file:
                    full_schema = ruamel.yaml.load(file, ruamel.yaml.RoundTripLoader, version=(1, 1))

                schema = full_schema["mapping"][_worker]
                self._schemas[worker] = self._schemas[_worker] = schema_fn, schema

            # validate worker config
            core = Core(source_data={_worker: variables}, schema_files=[schema_fn])

            validated_content[worker] = core.validate(raise_exception=False)[_worker]

            # check for errors
            if core.validation_errors:
                errs = errors[worker] = []
                for message in core.validation_errors:
                    # crude hack: we're already fooling the schema by using "flag" for the worker name
                    # when the name is e.g. "flag__2", so the message is misleading. Substitute the hack back.
                    message = message.replace("'/{}'".format(_worker), "'/{}'".format(worker))
                    errs.append(message)

        if errors:
            raise ConfigErrors(config_file, errors)

        return validated_content, version
Beispiel #53
0
def validate(config,schema):
    c = Core(source_file=config, schema_files=[schema])
    c.validate(raise_exception=True)
Beispiel #54
0
def start(
    targets, module_name, logging_level, config_file="api.yaml", schema_file="api.schema.yaml"
):
    """Start the API.

    Keyword arguments:
    targets -- shared target list
    module_name -- module name set by the main code to separate targets
    logging_level -- level logging set in the global config file
    config_file -- name of the config file for the API
    schema_file -- schema of the config file for the API
    """
    global shared_targets_list
    global global_module_name
    global token
    global max_targets
    global target_lifetime
    global max_target_lifetime

    # initiate list in dict from Manager (shared variable with main code)
    targets[module_name] = []

    # transform config file to absolute path
    entry_path = os.path.dirname(os.path.abspath(sys.argv[0]))
    config_file_abs = os.path.join(entry_path, config_file)

    # load inventory configuration
    if not os.path.exists(config_file_abs):
        log_api.info("No configuration file for api module")
        return

    # getting a reference of this list and module name
    shared_targets_list = targets
    global_module_name = module_name

    # validate yaml config with the schema
    schema = pkg_resources.resource_filename(__name__, schema_file)
    yaml_validator = Core(source_file=config_file_abs, schema_files=[schema])
    yaml_validator.validate(raise_exception=True)

    # if config file exists, we load it and parse it
    with open(config_file_abs, "r") as conf_file:
        try:
            conf = yaml.safe_load(conf_file)
            log_api.debug("network_devices configuration loaded")
        except Exception as error:
            log_api.error("Unable to load config file: {0}".format(error))

    listen_address = conf.get("listen_address", "0.0.0.0")
    listen_port = conf.get("listen_port", 8009)
    groups.extend(conf.get("groups", []))
    token = conf.get("token")
    max_targets = conf.get("max_targets", 10)
    target_lifetime = common.explode_datetime(conf.get("target_lifetime", "1d"))
    max_target_lifetime = common.explode_datetime(conf.get("max_target_lifetime", "30d"))

    # starting the API
    log_api.logging_level = "WARNING"
    app = connexion.FlaskApp(__name__, server="tornado", debug=False)
    app.add_api("api.swagger.yml")
    app.run(host=listen_address, port=listen_port, debug=False)
Beispiel #55
0
    def test_core_files(self):
        # These tests should pass with no exception raised
        pass_tests = [
            # Test sequence with only string values
            "1s.yaml",
            # Test sequence where the only valid items is integers
            "2s.yaml",
            # Test sequence with only booleans
            "3s.yaml",
            # Test mapping with different types of data and some extra conditions
            "4s.yaml",
            # Test sequence with mapping with valid mapping
            "5s.yaml",
            # Test mapping with sequence with mapping and valid data
            "6s.yaml",
            # Test most of the implemented functions
            "7s.yaml",
            # This will test the unique constraint
            "8s.yaml",
            #
            "9s.yaml",
            #
            "10s.yaml",
            #
            "11s.yaml",
            # This tests number validation rule
            "12s.yaml",
            # This test the text validation rule
            "13s.yaml",
            # This test the any validation rule
            "14s.yaml",
            #
            "15s.yaml",
            #
            # TODO: Currently slightly broken
            # # "16s.yaml",
            # This test that a regex that will compile
            "17s.yaml",
            # Test that type can be set to 'None' and it will validate ok
            "18s.yaml",
            # Test that range validates with map
            "19s.yaml",
            # Test that range validates with seq
            "20s.yaml",
            # Test that 'seq' can use seq instead of 'sequence'
            "21s.yaml",
            # Test that 'map' can be used instead of 'mapping'
            "22s.yaml",
            # Test that 're' can be used instead of 'regex'
            "23s.yaml",
            # Test that 'req' can be used instead of 'required'
            "24s.yaml",
            # Test that there is no need to specify 'type: seq' or 'type: map'
            "25s.yaml",
            # Test that the different types of timestamps can be validated
            "26s.yaml",
            # Test that multiple sequence values is supported
            "27s.yaml",
            # Test that multiple sequence values with matching 'all' is supported
            "28s.yaml",
            # Test that multiple sequence values with matching '*' is supported
            "29s.yaml",
            # Test that multiple sequence values with nested data structures work
            "30s.yaml",
            # Test that multiple sequence vlaues with nested lists works
            "31s.yaml",
            # Test Complex tree with many different structures
            "32s.yaml",
        ]

        _fail_tests = [
            # Test sequence with defined string content type but data only has integers
            ("1f.yaml", SchemaError),
            # Test sequence with defined string content type but data only has booleans
            ("2f.yaml", SchemaError),
            # Test sequence with defined booleans but with one integer
            ("3f.yaml", SchemaError),
            # Test sequence with strings and and lenght on each string
            ("4f.yaml", SchemaError),
            # Test mapping that do not work
            ("5f.yaml", SchemaError),
            # Test sequence with mapping with missing required key
            ("6f.yaml", SchemaError),
            # Test mapping with sequence with mapping and invalid data
            ("7f.yaml", SchemaError),
            #
            ("8f.yaml", SchemaError),
            # TODO: The reverse unique do not currently work proper # This will test the unique constraint but should fail
            ("9f.yaml", SchemaError),
            # This tests number validation rule with wrong data
            ("10f.yaml", SchemaError),
            # This test the text validation rule with wrong data
            ("11f.yaml", SchemaError),
            # This test that typechecking works when value in map is None
            ("12f.yaml", SchemaError),
            # Test that range validates on 'map' raise correct error
            ("13f.yaml", SchemaError),
            # Test that range validates on 'seq' raise correct error
            ("14f.yaml", SchemaError),
            # Test timestamps that should throw errors
            ("15f.yaml", SchemaError),
            # Test multiple sequence values with wrong sub type and 'any' matching rule
            ("16f.yaml", SchemaError),
            # Test multiple sequence values with wrong sub type and 'all' matching rule
            ("17f.yaml", SchemaError),
            # Test multiple nested sequence values with error in level 2 with 'any' matching rule
            ("18f.yaml", SchemaError),
        ]

        # Add override magic to make it easier to test a specific file
        if "S" in os.environ:
            pass_tests = [os.environ["S"]]
            _fail_tests = []
        elif "F" in os.environ:
            pass_tests = []
            _fail_tests = [(os.environ["F"], SchemaError)]

        for passing_test_file in pass_tests:
            f = self.f(os.path.join("success", passing_test_file))
            with open(f, "r") as stream:
                yaml_data = yaml.load(stream)
                data = yaml_data["data"]
                schema = yaml_data["schema"]

            try:
                print("Running test files: {}".format(f))
                c = Core(source_data=data, schema_data=schema)
                c.validate()
                compare(c.validation_errors, [],
                        prefix="No validation errors should exist...")
            except Exception as e:
                print("ERROR RUNNING FILES: {}".format(f))
                raise e

            # This serve as an extra schema validation that tests more complex structures then testrule.py do
            compare(
                c.root_rule._schema_str,
                schema,
                prefix=
                "Parsed rules is not correct, something have changed... files : {}"
                .format(f))

        for failing_test, exception_type in _fail_tests:
            f = self.f(os.path.join("fail", failing_test))
            with open(f, "r") as stream:
                yaml_data = yaml.load(stream)
                data = yaml_data["data"]
                schema = yaml_data["schema"]
                errors = yaml_data["errors"]

            try:
                print("Running test files: {}".format(f))
                c = Core(source_data=data, schema_data=schema)
                c.validate()
            except exception_type:
                pass  # OK
            else:
                raise AssertionError(
                    "Exception {} not raised as expected... FILES: {} : {}".
                    format(exception_type, exception_type))

            compare(sorted(c.validation_errors),
                    sorted(errors),
                    prefix="Wrong validation errors when parsing files : {}".
                    format(f))