Beispiel #1
0
def pyang_plugin_init():
    """Called by pyang plugin framework at to initialize the plugin."""

    # Register the plugin
    plugin.register_plugin(SMIPlugin())

    # Add our special argument syntax checkers
    syntax.add_arg_type("smi-oid", _chk_smi_oid)
    syntax.add_arg_type("smi-max-access", _chk_smi_max_access)

    # Register that we handle extensions from the YANG module 'ietf-yang-smiv2'
    grammar.register_extension_module(smi_module_name)

    # Register the special grammar
    for (stmt, occurance, (arg, rules), add_to_stmts) in smi_stmts:
        grammar.add_stmt((smi_module_name, stmt), (arg, rules))
        grammar.add_to_stmts_rules(add_to_stmts, [((smi_module_name, stmt), occurance)])

    # Add validation step
    statements.add_validation_phase("smi_set_oid", after="inherit_properties")
    statements.add_validation_fun("smi_set_oid", [(smi_module_name, "oid")], v_set_oid)
    statements.add_validation_fun("smi_set_oid", [(smi_module_name, "subid")], v_set_subid)

    # Register special error codes
    error.add_error_code("SMIv2_BAD_SUBID", 1, "subid needs an oid or subid statement in an ancestor")
    error.add_error_code("SMIv2_SUBID_AND_OID", 1, "subid and oid cannot be given at the same time")
Beispiel #2
0
def pyang_plugin_init():
    """Called by pyang plugin framework at to initialize the plugin."""

    # Register the plugin
    plugin.register_plugin(RESTCONFPlugin())

    # Register that we handle extensions from the YANG module 'ietf-restconf'
    grammar.register_extension_module(restconf_module_name)

    yd = (restconf_module_name, 'yang-data')
    statements.add_data_keyword(yd)
    statements.add_keyword_with_children(yd)
    statements.add_keywords_with_no_explicit_config(yd)

    # Register the special grammar
    for (stmt, occurance, (arg, rules), add_to_stmts) in restconf_stmts:
        grammar.add_stmt((restconf_module_name, stmt), (arg, rules))
        grammar.add_to_stmts_rules(add_to_stmts,
                                   [((restconf_module_name, stmt), occurance)])

    # Add validation functions
    statements.add_validation_fun('expand_2',
                                  [yd],
                                  v_yang_data)

    # Register special error codes
    error.add_error_code('RESTCONF_YANG_DATA_CHILD', 1,
                         "the 'yang-data' extension must have exactly one " +
                         "child that is a container")
Beispiel #3
0
def pyang_plugin_init():
    """Called by pyang plugin framework at to initialize the plugin."""

    # Register the plugin
    plugin.register_plugin(SMIPlugin())

    # Add our special argument syntax checkers
    syntax.add_arg_type('smi-oid', _chk_smi_oid)
    syntax.add_arg_type('smi-max-access', _chk_smi_max_access)

    # Register that we handle extensions from the YANG module 'smi'
    grammar.register_extension_module(smi_module_name)

    # Register the special grammar
    for (stmt, occurance, (arg, rules), add_to_stmts) in smi_stmts:
        grammar.add_stmt((smi_module_name, stmt), (arg, rules))
        grammar.add_to_stmts_rules(add_to_stmts,
                                   [((smi_module_name, stmt), occurance)])

    # Add validation step
    statements.add_validation_phase('smi_set_oid', after='inherit_properties')
    statements.add_validation_fun('smi_set_oid', [(smi_module_name, 'oid')],
                                  v_set_oid)
    statements.add_validation_fun('smi_set_oid', [(smi_module_name, 'subid')],
                                  v_set_subid)

    # Register special error codes
    error.add_error_code(
        'SMIv2_BAD_SUBID', 1,
        "subid needs an oid or subid statement in an ancestor")
    error.add_error_code('SMIv2_SUBID_AND_OID', 1,
                         "subid and oid cannot be given at the same time")
Beispiel #4
0
def pyang_plugin_init():
    """Called by pyang plugin framework at to initialize the plugin."""

    # Register the plugin
    plugin.register_plugin(RESTCONFPlugin())

    # Register that we handle extensions from the YANG module 'ietf-restconf'
    grammar.register_extension_module(restconf_module_name)

    yd = (restconf_module_name, 'yang-data')
    statements.add_data_keyword(yd)
    statements.add_keyword_with_children(yd)
    statements.add_keywords_with_no_explicit_config(yd)

    # Register the special grammar
    for (stmt, occurance, (arg, rules), add_to_stmts) in restconf_stmts:
        grammar.add_stmt((restconf_module_name, stmt), (arg, rules))
        grammar.add_to_stmts_rules(add_to_stmts,
                                   [((restconf_module_name, stmt), occurance)])

    # Add validation functions
    statements.add_validation_fun('expand_2', [yd], v_yang_data)

    # Register special error codes
    error.add_error_code(
        'RESTCONF_YANG_DATA_CHILD', 1,
        "the 'yang-data' extension must have exactly one " +
        "child that is a container")
Beispiel #5
0
    def setup_ctx(self, ctx):
        if not ctx.opts.ieee:
            return
        self._setup_ctx(ctx)

        error.add_error_code(
           'IEEE_BAD_NAMESPACE_VALUE', 4,
           'the namespace should be on the form '
           'urn:ieee:std:{IEEE standard designation}:yang:%s')

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: self.v_chk_namespace(ctx, s))
Beispiel #6
0
    def setup_ctx(self, ctx):
        if ctx.opts.ietf_help:
            print_help()
            sys.exit(0)
        if not ctx.opts.ietf:
            return
        self._setup_ctx(ctx)

        statements.add_validation_fun(
            'grammar', ['description'],
            lambda ctx, s: self.v_chk_description(ctx, s))

        # register our error codes
        error.add_error_code(
            'IETF_MISSING_RFC8174', 4,
            'the module seems to use RFC 2119 keywords, but the required' +
            ' text from RFC 8174 is not found or is not correct' +
            ' (see pyang --ietf-help for details).')

        error.add_error_code(
            'IETF_MISSING_TRUST_LEGAL_PROVISIONING', 4, 'RFC 8407: 3.1: ' +
            'The IETF Trust Copyright statement seems to be' +
            ' missing or is not correct' +
            ' (see pyang --ietf-help for details).')

        error.add_error_code(
            'IETF_MISSING_RFC_TEXT', 4, 'RFC 8407: Appendix B: ' +
            'The text about which RFC this module is part of seems to be' +
            ' missing or is not correct' +
            ' (see pyang --ietf-help for details).')
Beispiel #7
0
    def setup_ctx(self, ctx):
        if ctx.opts.ietf_help:
            print_help()
            sys.exit(0)
        if not ctx.opts.ietf:
            return
        self._setup_ctx(ctx)

        statements.add_validation_fun(
            'grammar', ['description'],
            lambda ctx, s: self.v_chk_description(ctx, s))

        # register our error codes
        error.add_error_code(
            'IETF_MISSING_RFC8174', 4,
            'the module seems to use RFC 2119 keywords, but the required'
            + ' text from RFC 8174 is not found'
            + ' (see pyang --ietf-help for details).')

        error.add_error_code(
            'IETF_MISSING_TRUST_LEGAL_PROVISIONING', 4,
            'RFC 8407: 3.1: '
            + 'The IETF Trust Copyright statement seems to be'
            + ' missing (see pyang --ietf-help for details).')
Beispiel #8
0
    def setup_ctx(self, ctx):

        statements.add_validation_fun('grammar', ['module'], v_chk_module)

        statements.add_validation_fun('grammar', ['submodule'],
                                      v_chk_submodule)

        statements.add_validation_fun('grammar', ['module', 'submodule'],
                                      v_chk_both)

        error.add_error_code('COMPOSE_MODULE_ONLY', 2,
                             'Module-only validation called for %s %s')

        error.add_error_code('COMPOSE_SUBMODULE_ONLY', 2,
                             'Submodule-only validation called for %s %s')

        error.add_error_code('COMPOSE_CALLED', 4, 'Check %s issued for %s %s')
Beispiel #9
0
    def add_opts(self, optparser):
        optlist = [
            optparse.make_option("--check-update-from",
                                 metavar="OLDMODULE",
                                 dest="check_update_from",
                                 help="Verify that upgrade from OLDMODULE" \
                                      " follows RFC 6020 and 7950 rules."),
            optparse.make_option("-P", "--check-update-from-path",
                                 dest="old_path",
                                 default=[],
                                 action="append",
                                 help=os.pathsep + "-separated search path" \
                                     " for yin and yang modules used by" \
                                     " OLDMODULE"),
            optparse.make_option("-D", "--check-update-from-deviation-module",
                                 dest="old_deviation",
                                 default=[],
                                 action="append",
                                 help="Old deviation module of the OLDMODULE." \
                                      " This option can be given multiple" \
                                      " times."),
            ]
        optparser.add_options(optlist)

        # register our error codes
        error.add_error_code(
            'CHK_INVALID_MODULENAME', 1,
            "the module's name MUST NOT be changed"
            + " (RFC 6020: 10, p3)")
        error.add_error_code(
            'CHK_INVALID_NAMESPACE', 1,
            "the module's namespace MUST NOT be changed"
            + " (RFC 6020: 10, p3)")
        error.add_error_code(
            'CHK_NO_REVISION', 1,
            "a revision statement MUST be present"
            + " (RFC 6020: 10, p2)")
        error.add_error_code(
            'CHK_BAD_REVISION', 1,
            "new revision %s is not newer than old revision %s"
            + " (RFC 6020: 10, p2)")
        error.add_error_code(
            'CHK_DEF_REMOVED', 1,
            "the %s '%s', defined at %s is illegally removed")
        error.add_error_code(
            'CHK_DEF_ADDED', 1,
            "the %s '%s' is illegally added")
        error.add_error_code(
            'CHK_DEF_ADDED2', 1,
            "the %s '%s' is illegally added in %s %s")
        error.add_error_code(
            'CHK_DEF_CHANGED', 1,
            "the %s '%s' is illegally changed from '%s'")
        error.add_error_code(
            'CHK_INVALID_STATUS', 1,
            "new status %s is not valid since the old status was %s")
        error.add_error_code(
            'CHK_CHILD_KEYWORD_CHANGED', 1,
            "the %s '%s' is illegally changed to a %s")
        error.add_error_code(
            'CHK_MANDATORY_CONFIG', 1,
            "the node %s is changed to config true, but it is mandatory")
        error.add_error_code(
            'CHK_NEW_MANDATORY', 1,
            "the mandatory node %s is illegally added")
        error.add_error_code(
            'CHK_BAD_CONFIG', 1,
            "the node %s is changed to config false")
        error.add_error_code(
            'CHK_NEW_MUST', 1,
            "a new must expression cannot be added")
        error.add_error_code(
            'CHK_UNDECIDED_MUST', 4,
            "this must expression may be more constrained than before")
        error.add_error_code(
            'CHK_NEW_WHEN', 1,
            "a new when expression cannot be added")
        error.add_error_code(
            'CHK_UNDECIDED_WHEN', 4,
            "this when expression may be different than before")
        error.add_error_code(
            'CHK_UNDECIDED_PRESENCE', 4,
            "this presence expression may be different than before")
        error.add_error_code(
            'CHK_IMPLICIT_DEFAULT', 1,
            "the leaf had an implicit default")
        error.add_error_code(
            'CHK_BASE_TYPE_CHANGED', 1,
            "the base type has illegally changed from %s to %s")
        error.add_error_code(
            'CHK_LEAFREF_PATH_CHANGED', 1,
            "the leafref's path has illegally changed")
        error.add_error_code(
            'CHK_ENUM_VALUE_CHANGED', 1,
            "the value for enum '%s', has changed from %s to %s"
            + " (RFC 6020: 10, p5, bullet 1)")
        error.add_error_code(
            'CHK_BIT_POSITION_CHANGED', 1,
            "the position for bit '%s', has changed from %s to %s"
            + " (RFC 6020: 10, p5, bullet 2)")
        error.add_error_code(
            'CHK_RESTRICTION_CHANGED', 1,
            "the %s has been illegally restricted"
            + " (RFC 6020: 10, p5, bullet 3)")
        error.add_error_code(
            'CHK_UNION_TYPES', 1,
            "the member types in the union have changed")
Beispiel #10
0
    def add_opts(self, optparser):
        optlist = [
            optparse.make_option("--json-pretty",
                                 dest="json_pretty",
                                 action="store_true",
                                 help="""Pretty-print json-output"""),
            optparse.make_option(
                "--json-compact-need-when",
                dest="json_compact_when",
                action="store_true",
                help="""Include local when expressions in compact containers"""
            ),
            optparse.make_option(
                "--json-cli",
                dest="json_cli",
                action="store_true",
                help="""Process yang from CLI-parser perspective"""),
            optparse.make_option(
                "--json-fwhen",
                action="append",
                dest="json_fwhen",
                type="string",
                help=
                """One or more xpaths for which to force include of when-expression"""
            ),
            optparse.make_option(
                "--json-cli-module",
                action="store",
                dest="json_cli_module",
                type="string",
                help="""Name of module with cli-extensions"""),
            optparse.make_option(
                "--json-frelaxed",
                action="append",
                dest="json_frelaxed",
                type="string",
                help=
                """One or more xpaths for which to force relaxed-matching""")
        ]

        g = optparser.add_option_group("json format specific options")
        g.add_options(optlist)

        error.add_error_code('WAMBIGIOUS_NODE', 4,
                             "Suggest cli-disallow-value or pattern in %s")

        error.add_error_code('WUNHANDLED_NODE', 4, "Node type not handled %s")

        error.add_error_code(
            'BRACKETLEAFLIST_NODE', 4,
            "CLI-parser can't handle bracket leaf-lists currently, found here %s"
        )

        error.add_error_code(
            'EMPTYDROP_NODE', 4,
            "CLI-parser can't handle cli-drop-node-name in leaf of type empty currently, found here %s"
        )

        error.add_error_code(
            'UNSUPPORTED_CLIKEYFMT', 4,
            "CLI-parser can't handle the cli-key-format found here %s")

        error.add_error_code(
            'UNSUPPORTED_COMBO', 4,
            "CLI-parser can't handle cli-annotations found here %s")
Beispiel #11
0
def pyang_plugin_init():
    """Called by pyang plugin framework at to initialize the plugin."""
    # Register the plugin
    plugin.register_plugin(ComplexTypesPlugin())

    # check whether the plugin is enabled
    try:
        sys.argv.index("--enable-complex-types")
    except ValueError:
        return

   
    # Register that we handle extensions from the YANG module 'complex-types' 
    grammar.register_extension_module(ct_module_name)

    # Register the special grammar
    for (stmt, occurance, (arg, rules), add_to_stmts) in complex_types_stmts:
        grammar.add_stmt((ct_module_name, stmt), (arg, rules))
        grammar.add_to_stmts_rules(add_to_stmts,
                                   [((ct_module_name, stmt), occurance)])

    # Add validation steps
    # init phase: initalizes the module/submodule statements
    statements.add_validation_phase('init_complex_type', after='init2')
    # grammar phase:
    # verifies that all complex-types are unique within a parent node
    statements.add_validation_phase('post_grammar_complex_type',
                                        after='grammar')
    # include phase: loads complex-types from a submodule and
    # checks for complex-type collisions in a submodule
    statements.add_validation_phase('include_complex_type', after='import')
    # validate typed instance identifiers
    statements.add_validation_phase('instance_type', after='type')
    # expand the 'extends' statements;
    statements.add_validation_phase('instantiate_extends', after='expand_1')
    # instantiate all 'instance'/'instance-list' statements;
    # this phase should be marked as v_i_children (validate i_children
    # instead of substatemets) so that we could expand the 'instance'/
    # 'instance-list' created by augmentation nested into a 'uses' statement;
    statements.add_validation_phase('instantiate_instance',
                                        after='instantiate_extends')
    statements.set_phase_i_children('instantiate_instance')
    # inherit 'config' properties for statements nested into 'complex-type';
    # set 'i_config' values;
    statements.add_validation_phase('inherit_properties_complex_type',
                                        after='inherit_properties')
    # validate augmentation statements that refer to 'instace'/'instance-list'
    statements.add_validation_phase('pre_expand_2', before='expand_2')
    # unique names phase: checks for complex type collisions in submodules
    statements.add_validation_phase('unique_name_complex_type',
                                        before='unique_name')
    # expand all recursive datastructures reffered by deviation
    statements.add_validation_phase('pre_reference_2', before='reference_2')

    # Add functions to the validation map
    statements.add_validation_fun('init_complex_type',
                                  ['*'],
                                  v_init_complex_type)

    statements.add_validation_fun('post_grammar_complex_type',
                                  ['*'],
                                  v_post_grammar_complex_type)

    statements.add_validation_fun('include_complex_type',
                                  ['module', 'submodule'],
                                  v_include_complex_type)

    statements.add_validation_fun('type',
                                  [(ct_module_name, str_complex_type)],
                                  v_type_complex_type)

    statements.add_validation_fun('type',
                                  [(ct_module_name, str_instance),
                                  (ct_module_name, str_instance_list)],
                                  v_type_instance)

    statements.add_validation_fun('instance_type',
                                  [(ct_module_name, str_instance_type)],
                                  v_type_instance_type)

    statements.add_validation_fun('instantiate_extends',
                                  [(ct_module_name, str_complex_type)],
                                  v_instantiate_extends)

    statements.add_validation_fun('instantiate_instance',
                                  [(ct_module_name, str_instance),
                                  (ct_module_name, str_instance_list)],
                                  v_instantiate_instance)

    statements.add_validation_fun('inherit_properties_complex_type',
                                  [(ct_module_name, str_complex_type)],
                                  v_inherit_properties_complex_type)

    statements.add_validation_fun('pre_expand_2',
                                  ['augment'],
                                  v_pre_expand_2_augment)

    statements.add_validation_fun('unique_name_complex_type',
                                  ['module'],
                                  v_unique_name_complex_type)

    statements.add_validation_fun('pre_reference_2',
                                  ['deviation'],
                                  v_reference_load_recursive_nodes)

    statements.add_validation_fun('reference_1',
                                  [(ct_module_name, str_complex_type)],
                                  v_reference_complex_type)

    statements.add_validation_fun('reference_2',
                                  [(ct_module_name, str_instance_list)],
                                  v_reference_instance_list)

    statements.add_validation_fun('unused',
                                  [(ct_module_name, str_complex_type)],
                                  v_unused_complex_type)

    # Add 'complex-type'/'instance'/'instance-list' to keywords with children
    statements.add_keyword_with_children((ct_module_name, str_complex_type))
    statements.add_keyword_with_children((ct_module_name, str_instance))
    statements.add_keyword_with_children((ct_module_name, str_instance_list))

    # Add 'instance' and 'instance-list' to the data keywords
    statements.add_data_keyword((ct_module_name, str_instance))
    statements.add_data_keyword((ct_module_name, str_instance_list))

    # add 'instance'/'instance-list' to the possible refinements
    statements.add_refinement_element('description',
                                        (ct_module_name, str_instance))
    statements.add_refinement_element('description',
                                        (ct_module_name, str_instance_list))
    statements.add_refinement_element('reference',
                                        (ct_module_name, str_instance))
    statements.add_refinement_element('reference',
                                        (ct_module_name, str_instance_list))
    statements.add_refinement_element('config', (ct_module_name, str_instance))
    statements.add_refinement_element('config',
                                        (ct_module_name, str_instance_list))
    statements.add_refinement_element('must', (ct_module_name, str_instance))
    statements.add_refinement_element('must',
                                        (ct_module_name, str_instance_list))
    statements.add_refinement_element('mandatory',
                                        (ct_module_name, str_instance))
    statements.add_refinement_element('min-elements',
                                        (ct_module_name, str_instance_list))
    statements.add_refinement_element('max-elements',
                                        (ct_module_name, str_instance_list))

    # add possibale deviation types for 'instance'/'instance-list' statements
    statements.add_deviation_element('config', (ct_module_name, str_instance))
    statements.add_deviation_element('config',
                                        (ct_module_name, str_instance_list))
    statements.add_deviation_element('must', (ct_module_name, str_instance))
    statements.add_deviation_element('must',
                                        (ct_module_name, str_instance_list))
    statements.add_deviation_element('mandatory',
                                        (ct_module_name, str_instance))
    statements.add_deviation_element('min-elements',
                                        (ct_module_name, str_instance_list))
    statements.add_deviation_element('max-elements',
                                        (ct_module_name, str_instance_list))

    # define additional error messages:
    error.add_error_code('COMPLEX_TYPE_ALREADY_DEFINED', 1,
        'complex-type "%s" is already defined at %s')
    error.add_error_code('COMPLEX_TYPE_NOT_FOUND', 1,
        'complex type "%s" not found in module "%s"')
    error.add_error_code('ABSTRACT_NOT_ALLOWED', 1,
        'base complex type "%s" of abstract type "%s" must be abstract')
    error.add_error_code('ABSTRACT_NOT_INSTANTIATED', 1,
        'abstract complex type "%s" can not be instantiated')
    error.add_error_code('UNUSED_COMPLEX_TYPE', 4,
        'complex type "%s" not used')
    error.add_error_code('REDEFINED_KEY', 1,
        'key for complex type "%s" is already defined in base type "%s" at %s')
    error.add_error_code('KEY_REQUIRED', 1,
        'complex-type "%s" instantiated at %s with config true must have key')
    error.add_error_code('REFINE_NOT_INHERITED', 1,
        '"refine" can not be applied to non-inherited node "%s" defined at %s')
    error.add_error_code('BAD_REF_AUG', 1,
        'refinement and augmentation of instance "%s" at %s is not allowed')
    error.add_error_code('MANDATORY_AUGMENTATION', 1,
        'the node "%s" at %s added by the augmentation must not be mandatory')
    error.add_error_code('INSTANCE_IDENTIFIER_REQUIRED', 1,
        'instance-type may not be specified for "%s" type')
Beispiel #12
0
    def _setup_ctx(self, ctx):
        "Should be called by any derived plugin's setup_ctx() function."

        ctx.strict = True
        ctx.canonical = True
        ctx.max_identifier_len = 64
        ctx.implicit_errors = False

        # always add additional prefixes given on the command line
        self.namespace_prefixes.extend(ctx.opts.namespace_prefixes)
        self.modulename_prefixes.extend(ctx.opts.modulename_prefixes)

        # register our grammar validation funs

        statements.add_validation_var(
            '$chk_default', lambda keyword: keyword in _keyword_with_default)
        statements.add_validation_var(
            '$chk_required',
            lambda keyword: keyword in _required_substatements)

        statements.add_validation_var(
            '$chk_recommended',
            lambda keyword: keyword in _recommended_substatements)

        statements.add_validation_fun('grammar', ['$chk_default'],
                                      lambda ctx, s: v_chk_default(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_required'],
            lambda ctx, s: v_chk_required_substmt(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_recommended'],
            lambda ctx, s: v_chk_recommended_substmt(ctx, s))

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: v_chk_namespace(ctx, s, self.namespace_prefixes))

        statements.add_validation_fun(
            'grammar', ['module', 'submodule'],
            lambda ctx, s: v_chk_module_name(ctx, s, self.modulename_prefixes))

        # register our error codes
        error.add_error_code(
            'LINT_EXPLICIT_DEFAULT', 4, 'RFC 6087: 4.3: ' +
            'statement "%s" is given with its default value "%s"')
        error.add_error_code(
            'LINT_MISSING_REQUIRED_SUBSTMT', 3,
            '%s: ' + 'statement "%s" must have a "%s" substatement')
        error.add_error_code(
            'LINT_MISSING_RECOMMENDED_SUBSTMT', 4,
            '%s: ' + 'statement "%s" should have a "%s" substatement')
        error.add_error_code('LINT_BAD_NAMESPACE_VALUE', 4,
                             'RFC 6087: 4.8: namespace value should be "%s"')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_1', 4, 'RFC 6087: 4.1: ' +
            'the module name should start with the string %s')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_N', 4, 'RFC 6087: 4.1: ' +
            'the module name should start with one of the strings %s')
        error.add_error_code(
            'LINT_NO_MODULENAME_PREFIX', 4,
            'RFC 6087: 4.1: ' + 'no module name prefix string used')

        # override std error string
        error.add_error_code(
            'LONG_IDENTIFIER', 3,
            'RFC 6087: 4.2: identifier %s exceeds %s characters')
Beispiel #13
0
    def setup_ctx(self, ctx):
        if not ctx.opts.threegpp:
            return
        self._setup_ctx(ctx)

        error.add_error_code('3GPP_BAD_NAMESPACE_VALUE', 3,
                             '3GPP: the namespace should be urn:3gpp:sa5:%s')

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: self.v_chk_namespace(ctx, s))

        error.add_error_code('3GPP_BAD_PREFIX_VALUE', 3,
                             '3GPP: the prefix should end with 3gpp')

        error.add_error_code(
            '3GPP_TOO_LONG_PREFIX', 3,
            '3GPP: the prefix should not be longer than 13 characters')

        statements.add_validation_fun('grammar', ['prefix'],
                                      lambda ctx, s: self.v_chk_prefix(ctx, s))

        error.add_error_code('3GPP_BAD_YANG_VERSION', 3,
                             '3GPP: the yang-version should be 1.1')

        statements.add_validation_fun(
            'grammar', ['yang-version'],
            lambda ctx, s: self.v_chk_yang_version(ctx, s))

        # check that yang-version is present. If not,
        #  it defaults to 1. which is bad for 3GPP
        statements.add_validation_fun(
            'grammar', ['module'],
            lambda ctx, s: self.v_chk_yang_version_present(ctx, s))

        error.add_error_code(
            '3GPP_STATEMENT_NOT_ALLOWED', 3,
            ('3GPP: YANG statements anydata, anyxml, deviation, rpc '
             'should not be used'))

        statements.add_validation_fun(
            'grammar', ['anydata', 'anyxml', 'deviation', 'rpc'],
            lambda ctx, s: self.v_chk_not_allowed_statements(ctx, s))

        error.add_error_code('3GPP_BAD_ORGANIZATION', 3,
                             '3GPP: organization statement must include 3GPP')

        statements.add_validation_fun(
            'grammar', ['organization'],
            lambda ctx, s: self.v_chk_organization(ctx, s))

        error.add_error_code('3GPP_BAD_CONTACT', 3,
                             '3GPP: incorrect contact statement')

        statements.add_validation_fun(
            'grammar', ['contact'], lambda ctx, s: self.v_chk_contact(ctx, s))

        error.add_error_code(
            '3GPP_MISSING_MODULE_REFERENCE', 3,
            '3GPP: the module should have a reference substatement')

        statements.add_validation_fun(
            'grammar', ['module'],
            lambda ctx, s: self.v_chk_module_reference_present(ctx, s))

        error.add_error_code(
            '3GPP_BAD_MODULE_REFERENCE', 3,
            '3GPP: the module\'s reference substatement is incorrect')

        statements.add_validation_fun(
            'grammar', ['reference'],
            lambda ctx, s: self.v_chk_module_reference(ctx, s))

        error.add_error_code(
            '3GPP_TAB_IN_FILE', 3,
            '3GPP: tab characters should not be used in YANG modules')

        error.add_error_code(
            '3GPP_WHITESPACE_AT_END_OF_LINE', 3,
            '3GPP: extra whitespace should not be added at the end of the line'
        )

        error.add_error_code('3GPP_LONG_LINE', 3,
                             '3GPP: line longer than 80 characters')

        error.add_error_code(
            '3GPP_CR_IN_FILE', 3,
            ('3GPP: Carriage-return characters should not be used. '
             'End-of-line should be just one LF character'))

        error.add_error_code(
            '3GPP_NON_ASCII', 4,
            '3GPP: the module should only use ASCII characters')

        statements.add_validation_fun(
            'grammar', ['module'],
            lambda ctx, s: self.v_chk_3gpp_format(ctx, s))

        error.add_error_code(
            '3GPP_LIMITED_CONTAINER_USE', 4,
            ('3GPP: containers should only be used to contain the attributes '
             'of a class'))

        statements.add_validation_fun(
            'grammar', ['container'],
            lambda ctx, s: self.v_chk_limited_container_use(ctx, s))
Beispiel #14
0
    def _setup_ctx(self, ctx):
        "Should be called by any derived plugin's setup_ctx() function."

        ctx.strict = True
        ctx.canonical = True
        ctx.max_identifier_len = 64
        ctx.implicit_errors = False

        # always add additional prefixes given on the command line
        self.namespace_prefixes.extend(ctx.opts.lint_namespace_prefixes)
        self.modulename_prefixes.extend(ctx.opts.lint_modulename_prefixes)

        # register our grammar validation funs

        statements.add_validation_var(
            '$chk_default',
            lambda keyword: keyword in _keyword_with_default)
        statements.add_validation_var(
            '$chk_required',
            lambda keyword: keyword in _required_substatements)

        statements.add_validation_var(
            '$chk_recommended',
            lambda keyword: keyword in _recommended_substatements)

        statements.add_validation_fun(
            'grammar', ['$chk_default'],
            lambda ctx, s: v_chk_default(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_required'],
            lambda ctx, s: v_chk_required_substmt(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_recommended'],
            lambda ctx, s: v_chk_recommended_substmt(ctx, s))

        if ctx.opts.lint_ensure_hyphenated_names:
            statements.add_validation_fun(
                'grammar', ['*'],
                lambda ctx, s: v_chk_hyphenated_names(ctx, s))

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: v_chk_namespace(ctx, s, self.namespace_prefixes))

        statements.add_validation_fun(
            'grammar', ['module', 'submodule'],
            lambda ctx, s: v_chk_module_name(ctx, s, self.modulename_prefixes))

        statements.add_validation_fun(
            'strict', ['include'],
            lambda ctx, s: v_chk_include(ctx, s))

        statements.add_validation_fun(
            'strict', ['module'],
            lambda ctx, s: v_chk_mandatory_top_level(ctx, s))

        # register our error codes
        error.add_error_code(
            'LINT_EXPLICIT_DEFAULT', 4,
            'RFC 8407: 4.4: '
            + 'statement "%s" is given with its default value "%s"')
        error.add_error_code(
            'LINT_MISSING_REQUIRED_SUBSTMT', 3,
            '%s: '
            + 'statement "%s" must have a "%s" substatement')
        error.add_error_code(
            'LINT_MISSING_RECOMMENDED_SUBSTMT', 4,
            '%s: '
            + 'statement "%s" should have a "%s" substatement')
        error.add_error_code(
            'LINT_BAD_NAMESPACE_VALUE', 4,
            'RFC 8407: 4.9: namespace value should be "%s"')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_1', 4,
            'RFC 8407: 4.1: '
            + 'the module name should start with the string %s')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_N', 4,
            'RFC 8407: 4.1: '
            + 'the module name should start with one of the strings %s')
        error.add_error_code(
            'LINT_NO_MODULENAME_PREFIX', 4,
            'RFC 8407: 4.1: '
            + 'no module name prefix string used')
        error.add_error_code(
            'LINT_BAD_REVISION', 3,
            'RFC 8407: 4.7: '
            + 'the module\'s revision %s is older than '
            + 'submodule %s\'s revision %s')
        error.add_error_code(
            'LINT_TOP_MANDATORY', 3,
            'RFC 8407: 4.10: '
            + 'top-level node %s must not be mandatory')
        error.add_error_code(
            'LINT_NOT_HYPHENATED', 4,
            '%s is not hyphenated, e.g., using upper-case or underscore')

        # override std error string
        error.add_error_code(
            'LONG_IDENTIFIER', 3,
            'RFC 8407: 4.3: identifier %s exceeds %s characters')
Beispiel #15
0
    def setup_ctx(self, ctx):
        if not ctx.opts.ietf:
            return

        ctx.canonical = True;
        ctx.max_line_len = 70
        ctx.max_identifier_len = 64
        ctx.implicit_errors = False

        # register our grammar validation funs

        statements.add_validation_var(
            '$chk_default',
            lambda keyword: keyword in _keyword_with_default)
        statements.add_validation_var(
            '$chk_required',
            lambda keyword: keyword in _required_substatements)

        statements.add_validation_var(
            '$chk_recommended',
            lambda keyword: keyword in _recommended_substatements)
            
        statements.add_validation_fun(
            'grammar', ['$chk_default'],
            lambda ctx, s: v_chk_default(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_required'],
            lambda ctx, s: v_chk_required_substmt(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_recommended'],
            lambda ctx, s: v_chk_recommended_substmt(ctx, s))

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: v_chk_namespace(ctx, s))

        statements.add_validation_fun(
            'grammar', ['module', 'submodule'],
            lambda ctx, s: v_chk_module_name(ctx, s))        

        statements.add_validation_fun(
            'unique_name', ['module'],
            lambda ctx, s: v_chk_top_level_nodes(ctx, s))

        # register our error codes
        error.add_error_code(
            'IETF_EXPLICIT_DEFAULT', 4,
            'IETF rule: statement "%s" is given with its default value "%s"')
        error.add_error_code(
            'IETF_MISSING_REQUIRED_SUBSTMT', 3,
            'IETF rule: statement "%s" must have a "%s" substatement')
        error.add_error_code(
            'IETF_MISSING_RECOMMENDED_SUBSTMT', 4,
            'IETF rule: statement "%s" should have a "%s" substatement')
        error.add_error_code(
            'IETF_BAD_NAMESPACE_VALUE', 4,
            'IETF rule: namespace value should be "%s"')
        error.add_error_code(
            'IETF_TOO_MANY_TOP_LEVEL_NODES', 4,
            'IETF rule: too many top-level data nodes: %s')
        error.add_error_code(
            'IETF_NO_MODULE_PREFIX', 4,
            'IETF rule: no module name prefix used, suggest ietf-%s')

        # override std error string
        error.add_error_code(
            'LONG_LINE', 4,
            'IETF rule: line length %s exceeds %s characters')
        error.add_error_code(
            'LONG_IDENTIFIER', 3,
            'IETF rule: identifier %s exceeds %s characters')
Beispiel #16
0
    def setup_ctx(self, ctx):
        if not ctx.opts.threegpp:
            return
        self._setup_ctx(ctx)

        error.add_error_code(
            '3GPP_BAD_NAMESPACE_VALUE', 3,
            '3GPP: the namespace should be on the form '
            'urn:3gpp:sa5:%s')

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: self.v_chk_namespace(ctx, s))

        error.add_error_code('3GPP_BAD_PREFIX_VALUE', 3,
                             '3GPP: the prefix should end with 3gpp')

        error.add_error_code(
            '3GPP_TOO_LONG_PREFIX', 3,
            '3GPP: the prefix should not be longer than 10 characters')

        statements.add_validation_fun('grammar', ['prefix'],
                                      lambda ctx, s: self.v_chk_prefix(ctx, s))

        error.add_error_code('3GPP_BAD_YANG_VERSION', 3,
                             '3GPP: the yang-version should be 1.1')

        statements.add_validation_fun(
            'grammar', ['yang-version'],
            lambda ctx, s: self.v_chk_yang_version(ctx, s))

        # check that yang-version is present. If not,
        #  it defaults to 1. which is bad for 3GPP
        statements.add_validation_fun(
            'grammar', ['module'],
            lambda ctx, s: self.v_chk_yang_version_present(ctx, s))

        error.add_error_code(
            '3GPP_STATEMENT_NOT_ALLOWED', 3,
            ('3GPP: YANG statements anydata, anyxml, deviation, rpc '
             'should not be used'))

        error.add_error_code(
            '3GPP_LIMITED_CONTAINER_USE', 4,
            ('3GPP: containers should only be used to contain the attributes '
             'of a class'))

        statements.add_validation_fun(
            'grammar', ['anydata', 'anyxml', 'deviation', 'rpc'],
            lambda ctx, s: self.v_chk_not_allowed_statements(ctx, s))

        statements.add_validation_fun(
            'grammar', ['container'],
            lambda ctx, s: self.v_chk_limited_container_use(ctx, s))

        error.add_error_code('3GPP_BAD_CONTACT', 3,
                             '3GPP: incorrect contact statement')

        statements.add_validation_fun(
            'grammar', ['contact'], lambda ctx, s: self.v_chk_contact(ctx, s))

        error.add_error_code('3GPP_BAD_ORGANIZATION', 3,
                             '3GPP: incorrect organization statement')

        statements.add_validation_fun(
            'grammar', ['organization'],
            lambda ctx, s: self.v_chk_organization(ctx, s))

        error.add_error_code(
            '3GPP_MISSING_MODULE_REFERENCE', 3,
            '3GPP: the module should have a reference substatement')
Beispiel #17
0
    def post_validate_ctx(self, ctx, modules):
        if not ctx.opts.threegpp:
            return
        """Remove some lint errors that 3GPP considers acceptable"""
        for ctx_error in ctx.errors[:]:
            if ((ctx_error[1] == "LINT_MISSING_REQUIRED_SUBSTMT"
                 or ctx_error[1] == "LINT_MISSING_RECOMMENDED_SUBSTMT")
                    and ctx_error[2][2] == 'description' and
                (ctx_error[2][1] == 'enum' or ctx_error[2][1] == 'bit' or
                 ctx_error[2][1] == 'choice' or ctx_error[2][1] == 'container'
                 or ctx_error[2][1] == 'leaf-list' or ctx_error[2][1] == 'leaf'
                 or ctx_error[2][1] == 'typedef' or ctx_error[2][1]
                 == 'grouping' or ctx_error[2][1] == 'augment')):
                # remove error from ctx
                ctx.errors.remove(ctx_error)

        # check 3gpp format:
        error.add_error_code(
            '3GPP_TAB_IN_FILE', 3,
            '3GPP: tab characters should not be used in YANG modules')

        error.add_error_code(
            '3GPP_WHITESPACE_AT_END_OF_LINE', 3,
            '3GPP: extra whitespace should not be added at the end of the line'
        )

        error.add_error_code('3GPP_LONG_LINE', 3,
                             '3GPP: line longer than 80 characters')

        error.add_error_code(
            '3GPP_CR_IN_FILE', 3,
            ('3GPP: Carriage-return characters should not be used. '
             'End-of-line should be just one LF character'))

        error.add_error_code(
            '3GPP_NON_ASCII', 4,
            '3GPP: the module should only use ASCII characters')

        for module in modules:
            filename = module.pos.ref
            try:
                fd = io.open(filename, "r", encoding="utf-8", newline='')
                lineno = 0
                for line in fd:
                    lineno += 1
                    self.pos = error.Position(module.pos.ref)
                    self.pos.line = lineno
                    #  no tabs
                    if (line.find('\t') != -1):
                        err_add(ctx.errors, self.pos, '3GPP_TAB_IN_FILE', ())
                    #  no whitespace after the line
                    #  removed for now as there are just too many of these
                    #    errors
                    # if (re.search('.*\s+\n',line) != None ):
                    #    err_add(ctx.errors, self.pos,
                    #        '3GPP_WHITESPACE_AT_END_OF_LINE',())
                    #  lines shorter then 80 char
                    if (len(line) > 82):
                        err_add(ctx.errors, self.pos, '3GPP_LONG_LINE', ())
                    #  EOL should be just NL no CR
                    if (line.find('\r') != -1):
                        err_add(ctx.errors, self.pos, '3GPP_CR_IN_FILE', ())
                    #  only us-ascii chars
                    try:
                        line.encode('ascii')
                    except UnicodeEncodeError:
                        err_add(ctx.errors, self.pos, '3GPP_NON_ASCII', ())

            except IOError as ex:
                sys.stderr.write("error %s: %s\n" % (filename, ex))
                sys.exit(1)
            except UnicodeDecodeError as ex:
                s = str(ex).replace('utf-8', 'utf8')
                sys.stderr.write("%s: unicode error: %s\n" % (filename, s))
                sys.exit(1)

        return
Beispiel #18
0
  def setup_ctx(self, ctx):
    if not (ctx.opts.openconfig):
      return
    if (not ctx.opts.openconfig_only):
      # call the standard linter setup
      self._setup_ctx(ctx)
    else:
      # don't call standard linter but have to set up some of the same rules
      # ourselves
      statements.add_validation_fun(
        'grammar', ['module', 'submodule'],
        lambda ctx, s: lint.v_chk_module_name(ctx, s, self.modulename_prefixes))

      error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX', 4,
            'RFC 6087: 4.1: '
            + 'no module name prefix used, suggest %s-%s')


    # Add OpenConfig validation phase
    statements.add_validation_phase('preinit', before='init')

    # Add an expensive function which we call one per module to check
    # things that cannot be checked in the later phases (e.g., text
    # conventions).
    statements.add_validation_fun('preinit', ['module'],
      lambda ctx, s: v_preinit_module_checks(ctx, s))

    # add the OpenConfig validators

    # Check for all type statements
    statements.add_validation_fun(
      'type_2', ['type', 'identity', 'identityref'],
      lambda ctx, s: v_chk_octypes(ctx, s))

    # Checks module properties after the module has
    # been parsed
    statements.add_validation_fun(
      'type_2', ['module'],
      lambda ctx, s: v_chk_ocmodule(ctx, s))

    # Check for warnings that are style-guide specific
    statements.add_validation_fun(
      'type_2', ['presence', 'choice', 'feature', 'if-feature'],
      lambda ctx, s: v_styleguide_warnings(ctx, s))

    # Check properties that are related to data elements
    statements.add_validation_fun(
      'type_2', ['leaf', 'leaf-list', 'list', 'container'],
      lambda ctx, s: v_chk_data_elements(ctx, s))

    # Check grouping names
    statements.add_validation_fun(
      'type_2', ['container'],
      lambda ctx, s: v_chk_standard_grouping_naming(ctx, s))

    # Check the prefix of the module
    statements.add_validation_fun(
      'type_2', ['prefix'],
      lambda ctx, s: v_chk_prefix(ctx, s))

    # Checks relevant to placement of leaves and leaf lists within the
    # opstate structure
    statements.add_validation_fun(
      'reference_2', ['leaf', 'leaf-list'],
      lambda ctx, s: v_chk_opstate_paths(ctx,s))

    # Checks lists within the structure
    statements.add_validation_fun(
      'reference_4', ['list'],
      lambda ctx, s: v_chk_list_placement(ctx, s))

    # Checks relevant to the specifications of paths in the module
    statements.add_validation_fun(
      'reference_2', ['path', 'augment'],
      lambda ctx, s: v_chk_path_refs(ctx,s))

    # Check that leaves are mirrored between config and state containers
    statements.add_validation_fun(
      'reference_4', ['container'],
      lambda ctx, s: v_chk_leaf_mirroring(ctx,s))

    # add the OpenConfig error codes

    # capitalization of enumeration values
    error.add_error_code(
      'OC_ENUM_CASE', 3,
      'enum value' + ' "%s" should be all caps as "%s"')

    # UPPERCASE_WITH_UNDERSCORES required for enum values
    error.add_error_code(
      'OC_ENUM_UNDERSCORES', 3,
      'enum value ' + '"%s" should be of the form ' +
      'UPPERCASE_WITH_UNDERSCORES: "%s"')

    # capitalization of identity values
    error.add_error_code(
      'OC_IDENTITY_CASE', 3,
      'identity name' + ' "%s" should be all caps as "%s"')

    # UPPERCASE_WITH_UNDERSCORES required for identity values
    error.add_error_code(
      'OC_IDENTITY_UNDERSCORES', 3,
      'identity name ' + '"%s" should be of the form ' +
      'UPPERCASE_WITH_UNDERSCORES: "%s"')

    # single config / state container in the path
    error.add_error_code(
      'OC_OPSTATE_CONTAINER_COUNT', 3,
      'path "%s" should have a single "config" or "state" component')

    # leaves should be in a 'config' or 'state' container
    error.add_error_code(
      'OC_OPSTATE_CONTAINER_NAME', 3,
      'element "%s" at path "%s" should be in a "config" or "state" container')

    # list keys should be leafrefs to respective value in config / state
    error.add_error_code(
      'OC_OPSTATE_KEY_LEAFREF', 3,
      'list key "%s" should be type leafref with a reference to corresponding' +
      ' leaf in config or state container')

    # leaves in in config / state should have the correct config property
    error.add_error_code(
      'OC_OPSTATE_CONFIG_PROPERTY', 3,
      'element "%s" is in a "%s" container and should have config value %s')

    # references to nodes in the same module / namespace should use relative
    # paths
    error.add_error_code(
      'OC_RELATIVE_PATH', 4,
      '"%s" path reference "%s" is intra-module but uses absolute path')

    # a config leaf does not have a mirrored applied config leaf in the state
    # container
    error.add_error_code(
      'OC_OPSTATE_APPLIED_CONFIG', 3,
      '"%s" is not mirrored in the state container at %s')

    # a list is within a container that has elements other than the list within
    # it
    error.add_error_code(
      'OC_LIST_SURROUNDING_CONTAINER', 3,
      'List %s is within a container (%s) that has other elements ' +
          'within it: %s')

    # A list does not have an enclosing container
    error.add_error_code(
      'OC_LIST_NO_ENCLOSING_CONTAINER', 3,
      'List %s is directly within a config or state container (%s)')

    # a module defines data nodes at the top-level
    error.add_error_code(
      'OC_MODULE_DATA_DEFINITIONS', 3,
      'Module %s defines data definitions at the top level: %s')

    # a module is missing an openconfig-version statement
    error.add_error_code(
      'OC_MODULE_MISSING_VERSION', 3, 'Module %s is missing an ' +
      'openconfig-version statement')

    # a module uses the 'choice' keyword
    error.add_error_code(
      'OC_STYLE_AVOID_CHOICE', 4, 'Element %s uses the choice keyword, which ' +
        'should be avoided')

    # a module uses the 'presence' keyword
    error.add_error_code(
      'OC_STYLE_AVOID_PRESENCE', 4, 'Element %s uses the presence keyword, ' +
        'which should be avoided')

    # a module uses the 'if-feature' or 'feature' keyword
    error.add_error_code(
      'OC_STYLE_AVOID_FEATURES', 4, 'Element %s uses feature or if-feature ' +
        'which should be avoided')

    # invalid semantic version argument to openconfig-version
    error.add_error_code(
      'OC_INVALID_SEMVER', 3, 'Semantic version specified (%s) is invalid')

    # missing a revision statement that has a reference of the
    # current semantic version
    error.add_error_code(
      'OC_MISSING_SEMVER_REVISION', 4, 'Revision statement should contain' +
        'reference substatement corresponding to semantic version %s')

    # invalid data element naming
    error.add_error_code(
      'OC_DATA_ELEMENT_INVALID_NAME', 4, 'Invalid naming for element %s ' +
          'data elements should generally be lower-case-with-hypens')

    # the module uses an invalid form of prefix
    error.add_error_code(
      'OC_PREFIX_INVALID', 4, 'Prefix %s for module does not match the ' +
          'expected format - use the form oc-<shortdescription>')

    # the module is missing a standard grouping (e.g., -top)
    error.add_error_code(
      'OC_MISSING_STANDARD_GROUPING', 4, 'Module %s is missing a grouping suffixed ' +
        'with %s')

    # the module has a nonstandard grouping name
    error.add_error_code(
      'OC_GROUPING_NAMING_NONSTANDARD', 4, 'In container %s, grouping %s does not ' +
        'match standard naming - suffix with %s?')

    # key statements do not have quoted arguments
    error.add_error_code(
      'OC_KEY_ARGUMENT_UNQUOTED', 3, 'All key arguments of a list should be ' +
        'quoted (%s is not)')
Beispiel #19
0
  def setup_ctx(self, ctx):
    if not ctx.opts.openconfig:
      return
    if not ctx.opts.openconfig_only:
      # Support IETF as a prefix for modules
      self.modulename_prefixes.extend(["ietf", "iana"])

      # We do not want all RFC6087 rules, so we need to borrow some
      # from the standard linter. We cannot simply call the _setup_ctx
      # module as this adds rules that we do not want - this code block
      # is borrowed from that module.
      statements.add_validation_var(
          "$chk_default",
          lambda keyword: keyword in lint._keyword_with_default)
      statements.add_validation_var(
          "$chk_required",
          lambda keyword: keyword in
          ExternalValidationRules.required_substatements)

      statements.add_validation_var(
          "$chk_recommended",
          lambda keyword: keyword in lint._recommended_substatements)

      statements.add_validation_fun(
          "grammar", ["$chk_default"],
          lambda ctx, s: lint.v_chk_default(ctx, s))
      statements.add_validation_fun(
          "grammar", ["$chk_required"],
          OCLintStages.openconfig_override_base_linter)
      statements.add_validation_fun(
          "grammar", ["$chk_recommended"],
          OCLintStages.openconfig_override_base_linter)

      statements.add_validation_fun(
          "grammar", ["namespace"],
          lambda ctx, s: lint.v_chk_namespace(ctx, s,
                                              self.namespace_prefixes))

      statements.add_validation_fun(
          "grammar", ["module", "submodule"],
          lambda ctx, s:
          lint.v_chk_module_name(ctx, s, self.modulename_prefixes))

      statements.add_validation_fun(
          "strict", ["include"],
          lambda ctx, s: lint.v_chk_include(ctx, s))

      # Register the default linter error codes
      error.add_error_code(
          "LINT_EXPLICIT_DEFAULT", ErrorLevel.WARNING,
          "RFC 6087: 4.3: "
          "statement \"%s\" is given with its default value \"%s\"")
      error.add_error_code(
          "LINT_MISSING_REQUIRED_SUBSTMT", ErrorLevel.MINOR,
          "%s: "
          "statement \"%s\" must have a \"%s\" substatement")
      error.add_error_code(
          "LINT_MISSING_RECOMMENDED_SUBSTMT", ErrorLevel.WARNING,
          "%s: "
          "statement \"%s\" should have a \"%s\" substatement")
      error.add_error_code(
          "LINT_BAD_NAMESPACE_VALUE", ErrorLevel.WARNING,
          "RFC 6087: 4.8: namespace value should be \"%s\"")
      error.add_error_code(
          "LINT_BAD_MODULENAME_PREFIX_1", ErrorLevel.WARNING,
          "RFC 6087: 4.1: "
          "the module name should start with the string %s")
      error.add_error_code(
          "LINT_BAD_MODULENAME_PREFIX_N", ErrorLevel.WARNING,
          "RFC 6087: 4.1: "
          "the module name should start with one of the strings %s")
      error.add_error_code(
          "LINT_NO_MODULENAME_PREFIX", ErrorLevel.WARNING,
          "RFC 6087: 4.1: "
          "no module name prefix string used")
      error.add_error_code(
          "LINT_BAD_REVISION", ErrorLevel.MINOR,
          "RFC 6087: 4.6: "
          "the module's revision %s is older than "
          "submodule %s's revision %s")
      error.add_error_code(
          "LINT_TOP_MANDATORY", ErrorLevel.MINOR,
          "RFC 6087: 4.9: "
          "top-level node %s must not be mandatory")
      error.add_error_code(
          "LONG_IDENTIFIER", ErrorLevel.MINOR,
          "RFC 6087: 4.2: identifier %s exceeds %s characters")

    # Add a pre-initialisation phase where we can read the
    # modules before they have been parsed by pyang fully.
    statements.add_validation_phase("preinit", before="init")
    statements.add_validation_fun("preinit", ["*"],
                                  OCLintStages.preinitialisation)

    # Add an openconfig types validation phase where we can
    # get types and then validate them further.
    statements.add_validation_phase("openconfig_type", after="type_2")
    statements.add_validation_fun("openconfig_type", ["*"],
                                  OCLintStages.openconfig_type)

    # pyang manipulates the paths of elements during reference_2, such
    # that this is the only time that we get a chance to work
    statements.add_validation_fun("reference_2", ["*"],
                                  OCLintStages.openconfig_reference)

    # Error type for generic OpenConfig linter bugs - returned
    # when an error is encountered in linter logic.
    error.add_error_code(
        "OC_LINTER_ERROR", ErrorLevel.CRITICAL,
        "Linter error encountered: %s")

    # Enum values must be upper case
    error.add_error_code(
        "OC_ENUM_CASE", ErrorLevel.MAJOR,
        "enum value \"%s\" should be capitalised as \"%s\"")

    # Enum values must be of the form UPPERCASE_WITH_UNDERSCORES
    error.add_error_code(
        "OC_ENUM_UNDERSCORES", ErrorLevel.MAJOR,
        "enum value \"%s\" should be of the form "
        "UPPERCASE_WITH_UNDERSCORES: %s")

    # Identity values should be capitalised
    error.add_error_code(
        "OC_IDENTITY_CASE", ErrorLevel.MAJOR,
        "identity name \"%s\" should be capitalised as \"%s\"")

    # UPPERCASE_WITH_UNDERSCORES required for identity values
    error.add_error_code(
        "OC_IDENTITY_UNDERSCORES", ErrorLevel.MAJOR,
        "identity name \"%s\" should be of the form "
        "UPPERCASE_WITH_UNDERSCORES: \"%s\"")

    # There must be a single config / state container in the path
    error.add_error_code(
        "OC_OPSTATE_CONTAINER_COUNT", ErrorLevel.MAJOR,
        "path \"%s\" should have a single \"config\" or \"state\" component")

    # Leaves should be in a "config" or "state" container
    error.add_error_code(
        "OC_OPSTATE_CONTAINER_NAME", ErrorLevel.MAJOR,
        "element \"%s\" at path \"%s\" should be in a \"config\""
        "or \"state\" container")

    # list keys should be leafrefs to respective value in config / state
    error.add_error_code(
        "OC_OPSTATE_KEY_LEAFREF", ErrorLevel.MAJOR,
        "list key \"%s\" should be type leafref with a reference to"
        " the corresponding leaf in config or state container")

    # list keys should be leafrefs to direct children of config / state
    error.add_error_code(
        "OC_OPSTATE_KEY_LEAFREF_DIRECT", ErrorLevel.MAJOR,
        "list key \"%s\" should be type leafref with a path to a"
        " a direct child of the config or state container")

    # leaves in in config / state should have the correct config property
    error.add_error_code(
        "OC_OPSTATE_CONFIG_PROPERTY", ErrorLevel.MAJOR,
        "element \"%s\" is in a \"%s\" container and should have "
        "config value %s")

    # references to nodes in the same module / namespace should use relative
    # paths
    error.add_error_code(
        "OC_RELATIVE_PATH", ErrorLevel.WARNING,
        "\"%s\" path reference \"%s\" is intra-module but uses absolute path")

    # a config leaf does not have a mirrored applied config leaf in the state
    # container
    error.add_error_code(
        "OC_OPSTATE_APPLIED_CONFIG", ErrorLevel.MAJOR,
        "\"%s\" is not mirrored in the state container at %s")

    # a list is within a container that has elements other than the list
    # within it
    error.add_error_code(
        "OC_LIST_SURROUNDING_CONTAINER", ErrorLevel.MAJOR,
        "List %s is within a container (%s) that has other elements "
        "within it: %s")

    # a list that does not have a container above it
    error.add_error_code(
        "OC_LIST_NO_ENCLOSING_CONTAINER", ErrorLevel.MAJOR,
        "List %s does not have a surrounding container")

    # when path compression is performed, the containers surrounding
    # lists are removed, if there are two lists with the same name
    # this results in a name collision.
    error.add_error_code(
        "OC_LIST_DUPLICATE_COMPRESSED_NAME", ErrorLevel.MAJOR,
        "List %s has a duplicate name when the parent container %s" + \
        " is removed.")

    # a module defines data nodes at the top-level
    error.add_error_code(
        "OC_MODULE_DATA_DEFINITIONS", ErrorLevel.MAJOR,
        "Module %s defines data definitions at the top level: %s")

    # a module is missing an openconfig-version statement
    error.add_error_code(
        "OC_MODULE_MISSING_VERSION", ErrorLevel.MAJOR,
        "Module %s is missing an openconfig-version statement")

    # a module uses the "choice" keyword
    error.add_error_code(
        "OC_STYLE_AVOID_CHOICE", ErrorLevel.WARNING,
        "Element %s uses the choice keyword, which should be avoided")

    # a module uses the "presence" keyword
    error.add_error_code(
        "OC_STYLE_AVOID_PRESENCE", ErrorLevel.MINOR,
        "Element %s uses the presence keyword which should be avoided")

    # a module uses the "if-feature" or "feature" keyword
    error.add_error_code(
        "OC_STYLE_AVOID_FEATURES", ErrorLevel.MINOR,
        "Element %s uses feature or if-feature which should be avoided")

    # invalid semantic version argument to openconfig-version
    error.add_error_code(
        "OC_INVALID_SEMVER", ErrorLevel.MAJOR,
        "Semantic version specified (%s) is invalid")

    # missing a revision statement that has a reference of the
    # current semantic version
    error.add_error_code(
        "OC_MISSING_SEMVER_REVISION", ErrorLevel.MAJOR,
        "Revision statement should contain reference substatement "
        " corresponding to semantic version %s")

    # invalid data element naming
    error.add_error_code(
        "OC_DATA_ELEMENT_INVALID_NAME", ErrorLevel.MAJOR,
        "Invalid naming for element %s data elements should "
        " generally be lower-case-with-hypens")

    # the module uses an invalid form of prefix
    error.add_error_code(
        "OC_PREFIX_INVALID", ErrorLevel.MINOR,
        "Prefix %s for module does not match the expected "
        " format - use the form oc-<shortdescription>")

    # the module is missing a standard grouping (e.g., -top)
    error.add_error_code(
        "OC_MISSING_STANDARD_GROUPING", ErrorLevel.WARNING,
        "Module %s is missing a grouping suffixed with %s")

    # the module has a nonstandard grouping name
    error.add_error_code(
        "OC_GROUPING_NAMING_NONSTANDARD", ErrorLevel.WARNING,
        "In container %s, grouping %s does not match standard "
        "naming - suffix with %s?")

    # key statements do not have quoted arguments
    error.add_error_code(
        "OC_KEY_ARGUMENT_UNQUOTED", ErrorLevel.MINOR,
        "All key arguments of a list should be quoted (%s is not)")

    # bad type was used for a leaf or typedef
    error.add_error_code(
        "OC_BAD_TYPE", ErrorLevel.MAJOR,
        "Bad type %s used in leaf or typedef",
    )

    # unequal number of posix-pattern and pattern statements.
    error.add_error_code(
        "OC_POSIX_PATTERN_COUNT_UNEQUAL", ErrorLevel.MAJOR,
        "unequal number of posix-pattern statements (%d) to pattern "
        "statements (%d)",
    )
Beispiel #20
0
Datei: lint.py Projekt: SDTN/Test
    def _setup_ctx(self, ctx):
        "Should be called by any derived plugin's setup_ctx() function."

        ctx.strict = True
        ctx.canonical = True
        ctx.max_identifier_len = 64
        ctx.implicit_errors = False

        # always add additional prefixes given on the command line
        self.namespace_prefixes.extend(ctx.opts.namespace_prefixes)
        self.modulename_prefixes.extend(ctx.opts.modulename_prefixes)

        # register our grammar validation funs

        statements.add_validation_var(
            '$chk_default',
            lambda keyword: keyword in _keyword_with_default)
        statements.add_validation_var(
            '$chk_required',
            lambda keyword: keyword in _required_substatements)

        statements.add_validation_var(
            '$chk_recommended',
            lambda keyword: keyword in _recommended_substatements)

        statements.add_validation_fun(
            'grammar', ['$chk_default'],
            lambda ctx, s: v_chk_default(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_required'],
            lambda ctx, s: v_chk_required_substmt(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_recommended'],
            lambda ctx, s: v_chk_recommended_substmt(ctx, s))

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: v_chk_namespace(ctx, s, self.namespace_prefixes))

        statements.add_validation_fun(
            'grammar', ['module', 'submodule'],
            lambda ctx, s: v_chk_module_name(ctx, s, self.modulename_prefixes))

        # register our error codes
        error.add_error_code(
            'LINT_EXPLICIT_DEFAULT', 4,
            'RFC 6087: 4.3: '
            + 'statement "%s" is given with its default value "%s"')
        error.add_error_code(
            'LINT_MISSING_REQUIRED_SUBSTMT', 3,
            '%s: '
            + 'statement "%s" must have a "%s" substatement')
        error.add_error_code(
            'LINT_MISSING_RECOMMENDED_SUBSTMT', 4,
            '%s: '
            + 'statement "%s" should have a "%s" substatement')
        error.add_error_code(
            'LINT_BAD_NAMESPACE_VALUE', 4,
            'RFC 6087: 4.8: namespace value should be "%s"')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_1', 4,
            'RFC 6087: 4.1: '
            + 'the module name should start with the string %s')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_N', 4,
            'RFC 6087: 4.1: '
            + 'the module name should start with one of the strings %s')
        error.add_error_code(
            'LINT_NO_MODULENAME_PREFIX', 4,
            'RFC 6087: 4.1: '
            + 'no module name prefix string used')

        # override std error string
        error.add_error_code(
            'LONG_IDENTIFIER', 3,
            'RFC 6087: 4.2: identifier %s exceeds %s characters')
Beispiel #21
0
    def _setup_ctx(self, ctx):
        "Should be called by any derived plugin's setup_ctx() function."

        ctx.strict = True
        ctx.canonical = True
        ctx.max_identifier_len = 64
        ctx.implicit_errors = False

        # always add additional prefixes given on the command line
        self.namespace_prefixes.extend(ctx.opts.lint_namespace_prefixes)
        self.modulename_prefixes.extend(ctx.opts.lint_modulename_prefixes)

        # copy other lint options to instance variables, taking care not to
        # overwrite any settings from derived class constructors
        if ctx.opts.lint_ensure_hyphenated_names:
            self.ensure_hyphenated_names = True

        # register our grammar validation funs

        statements.add_validation_var(
            '$chk_default',
            lambda keyword: keyword in _keyword_with_default)
        statements.add_validation_var(
            '$chk_required',
            lambda keyword: keyword in _required_substatements)

        statements.add_validation_var(
            '$chk_recommended',
            lambda keyword: keyword in _recommended_substatements)

        statements.add_validation_fun(
            'grammar', ['$chk_default'],
            lambda ctx, s: v_chk_default(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_required'],
            lambda ctx, s: v_chk_required_substmt(ctx, s))
        statements.add_validation_fun(
            'grammar', ['$chk_recommended'],
            lambda ctx, s: v_chk_recommended_substmt(ctx, s))

        if self.ensure_hyphenated_names:
            statements.add_validation_fun(
                'grammar', ['*'],
                lambda ctx, s: v_chk_hyphenated_names(ctx, s))

        statements.add_validation_fun(
            'grammar', ['namespace'],
            lambda ctx, s: v_chk_namespace(ctx, s, self.namespace_prefixes))

        statements.add_validation_fun(
            'grammar', ['module', 'submodule'],
            lambda ctx, s: v_chk_module_name(ctx, s, self.modulename_prefixes))

        statements.add_validation_fun(
            'strict', ['include'],
            lambda ctx, s: v_chk_include(ctx, s))

        statements.add_validation_fun(
            'strict', ['module'],
            lambda ctx, s: v_chk_mandatory_top_level(ctx, s))

        # register our error codes
        error.add_error_code(
            'LINT_EXPLICIT_DEFAULT', 4,
            'RFC 8407: 4.4: '
            + 'statement "%s" is given with its default value "%s"')
        error.add_error_code(
            'LINT_MISSING_REQUIRED_SUBSTMT', 3,
            '%s: '
            + 'statement "%s" must have a "%s" substatement')
        error.add_error_code(
            'LINT_MISSING_RECOMMENDED_SUBSTMT', 4,
            '%s: '
            + 'statement "%s" should have a "%s" substatement')
        error.add_error_code(
            'LINT_BAD_NAMESPACE_VALUE', 4,
            'RFC 8407: 4.9: namespace value should be "%s"')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_1', 4,
            'RFC 8407: 4.1: '
            + 'the module name should start with the string %s')
        error.add_error_code(
            'LINT_BAD_MODULENAME_PREFIX_N', 4,
            'RFC 8407: 4.1: '
            + 'the module name should start with one of the strings %s')
        error.add_error_code(
            'LINT_NO_MODULENAME_PREFIX', 4,
            'RFC 8407: 4.1: '
            + 'no module name prefix string used')
        error.add_error_code(
            'LINT_BAD_REVISION', 3,
            'RFC 8407: 4.7: '
            + 'the module\'s revision %s is older than '
            + 'submodule %s\'s revision %s')
        error.add_error_code(
            'LINT_TOP_MANDATORY', 3,
            'RFC 8407: 4.10: '
            + 'top-level node %s must not be mandatory')
        error.add_error_code(
            'LINT_NOT_HYPHENATED', 4,
            '%s is not hyphenated, e.g., using upper-case or underscore')

        # override std error string
        error.add_error_code(
            'LONG_IDENTIFIER', 3,
            'RFC 8407: 4.3: identifier %s exceeds %s characters')
Beispiel #22
0
    def _setup_ctx(self, ctx):
        "Should be called by any derived plugin's setup_ctx() function."

        ctx.strict = True
        ctx.canonical = True
        ctx.max_identifier_len = 64
        ctx.implicit_errors = False

        # always add additional prefixes given on the command line
        self.namespace_prefixes.extend(ctx.opts.namespace_prefixes)
        self.modulename_prefixes.extend(ctx.opts.modulename_prefixes)

        # register our grammar validation funs

        statements.add_validation_var("$chk_default", lambda keyword: keyword in _keyword_with_default)
        statements.add_validation_var("$chk_required", lambda keyword: keyword in _required_substatements)

        statements.add_validation_var("$chk_recommended", lambda keyword: keyword in _recommended_substatements)

        statements.add_validation_fun("grammar", ["$chk_default"], lambda ctx, s: v_chk_default(ctx, s))
        statements.add_validation_fun("grammar", ["$chk_required"], lambda ctx, s: v_chk_required_substmt(ctx, s))
        statements.add_validation_fun("grammar", ["$chk_recommended"], lambda ctx, s: v_chk_recommended_substmt(ctx, s))

        statements.add_validation_fun(
            "grammar", ["namespace"], lambda ctx, s: v_chk_namespace(ctx, s, self.namespace_prefixes)
        )

        statements.add_validation_fun(
            "grammar", ["module", "submodule"], lambda ctx, s: v_chk_module_name(ctx, s, self.modulename_prefixes)
        )

        statements.add_validation_fun("strict", ["include"], lambda ctx, s: v_chk_include(ctx, s))

        statements.add_validation_fun("strict", ["module"], lambda ctx, s: v_chk_mandatory_top_level(ctx, s))

        # register our error codes
        error.add_error_code(
            "LINT_EXPLICIT_DEFAULT", 4, "RFC 6087: 4.3: " + 'statement "%s" is given with its default value "%s"'
        )
        error.add_error_code(
            "LINT_MISSING_REQUIRED_SUBSTMT", 3, "%s: " + 'statement "%s" must have a "%s" substatement'
        )
        error.add_error_code(
            "LINT_MISSING_RECOMMENDED_SUBSTMT", 4, "%s: " + 'statement "%s" should have a "%s" substatement'
        )
        error.add_error_code("LINT_BAD_NAMESPACE_VALUE", 4, 'RFC 6087: 4.8: namespace value should be "%s"')
        error.add_error_code(
            "LINT_BAD_MODULENAME_PREFIX_1", 4, "RFC 6087: 4.1: " + "the module name should start with the string %s"
        )
        error.add_error_code(
            "LINT_BAD_MODULENAME_PREFIX_N",
            4,
            "RFC 6087: 4.1: " + "the module name should start with one of the strings %s",
        )
        error.add_error_code("LINT_NO_MODULENAME_PREFIX", 4, "RFC 6087: 4.1: " + "no module name prefix string used")
        error.add_error_code(
            "LINT_BAD_REVISION",
            3,
            "RFC 6087: 4.6: " + "the module's revision %s is older than " + "submodule %s's revision %s",
        )
        error.add_error_code("LINT_TOP_MANDATORY", 3, "RFC 6087: 4.9: " + "top-level node %s must not be mandatory")

        # override std error string
        error.add_error_code("LONG_IDENTIFIER", 3, "RFC 6087: 4.2: identifier %s exceeds %s characters")
Beispiel #23
0
    def add_opts(self, optparser):
        optlist = [
            optparse.make_option("--check-update-from",
                                 metavar="OLDMODULE",
                                 dest="check_update_from",
                                 help="Verify that upgrade from OLDMODULE" \
                                      " follows RFC 6020 and 7950 rules."),
            optparse.make_option("-P", "--check-update-from-path",
                                 dest="old_path",
                                 default=[],
                                 action="append",
                                 help=os.pathsep + "-separated search path" \
                                     " for yin and yang modules used by" \
                                     " OLDMODULE"),
            optparse.make_option("-D", "--check-update-from-deviation-module",
                                 dest="old_deviation",
                                 default=[],
                                 action="append",
                                 help="Old deviation module of the OLDMODULE." \
                                      " This option can be given multiple" \
                                      " times."),
            ]
        optparser.add_options(optlist)

        # register our error codes
        error.add_error_code(
            'CHK_INVALID_MODULENAME', 1,
            "the module's name MUST NOT be changed"
            + " (RFC 6020: 10, p3)")
        error.add_error_code(
            'CHK_INVALID_NAMESPACE', 1,
            "the module's namespace MUST NOT be changed"
            + " (RFC 6020: 10, p3)")
        error.add_error_code(
            'CHK_NO_REVISION', 1,
            "a revision statement MUST be present"
            + " (RFC 6020: 10, p2)")
        error.add_error_code(
            'CHK_BAD_REVISION', 1,
            "new revision %s is not newer than old revision %s"
            + " (RFC 6020: 10, p2)")
        error.add_error_code(
            'CHK_DEF_REMOVED', 1,
            "the %s '%s', defined at %s is illegally removed")
        error.add_error_code(
            'CHK_DEF_ADDED', 1,
            "the %s '%s' is illegally added")
        error.add_error_code(
            'CHK_DEF_CHANGED', 1,
            "the %s '%s' is illegally changed from '%s'")
        error.add_error_code(
            'CHK_INVALID_STATUS', 1,
            "new status %s is not valid since the old status was %s")
        error.add_error_code(
            'CHK_CHILD_KEYWORD_CHANGED', 1,
            "the %s '%s' is illegally changed to a %s")
        error.add_error_code(
            'CHK_MANDATORY_CONFIG', 1,
            "the node %s is changed to config true, but it is mandatory")
        error.add_error_code(
            'CHK_NEW_MANDATORY', 1,
            "the mandatory node %s is illegally added")
        error.add_error_code(
            'CHK_BAD_CONFIG', 1,
            "the node %s is changed to config false")
        error.add_error_code(
            'CHK_NEW_MUST', 1,
            "a new must expression cannot be added")
        error.add_error_code(
            'CHK_UNDECIDED_MUST', 4,
            "this must expression may be more constrained than before")
        error.add_error_code(
            'CHK_NEW_WHEN', 1,
            "a new when expression cannot be added")
        error.add_error_code(
            'CHK_UNDECIDED_WHEN', 4,
            "this when expression may be different than before")
        error.add_error_code(
            'CHK_UNDECIDED_PRESENCE', 4,
            "this presence expression may be different than before")
        error.add_error_code(
            'CHK_IMPLICIT_DEFAULT', 1,
            "the leaf had an implicit default")
        error.add_error_code(
            'CHK_BASE_TYPE_CHANGED', 1,
            "the base type has illegally changed from %s to %s")
        error.add_error_code(
            'CHK_LEAFREF_PATH_CHANGED', 1,
            "the leafref's path has illegally changed")
        error.add_error_code(
            'CHK_ENUM_VALUE_CHANGED', 1,
            "the value for enum '%s', has changed from %s to %s"
            + " (RFC 6020: 10, p5, bullet 1)")
        error.add_error_code(
            'CHK_BIT_POSITION_CHANGED', 1,
            "the position for bit '%s', has changed from %s to %s"
            + " (RFC 6020: 10, p5, bullet 2)")
        error.add_error_code(
            'CHK_RESTRICTION_CHANGED', 1,
            "the %s has been illegally restricted"
            + " (RFC 6020: 10, p5, bullet 3)")
        error.add_error_code(
            'CHK_UNION_TYPES', 1,
            "the member types in the union have changed")
Beispiel #24
0
  def setup_ctx(self, ctx):
    if not ctx.opts.openconfig:
      return
    if not ctx.opts.openconfig_only:
      # Support IETF as a prefix for modules
      self.modulename_prefixes.extend(["ietf", "iana"])

      # We do not want all RFC6087 rules, so we need to borrow some
      # from the standard linter. We cannot simply call the _setup_ctx
      # module as this adds rules that we do not want - this code block
      # is borrowed from that module.
      statements.add_validation_var(
          "$chk_default",
          lambda keyword: keyword in lint._keyword_with_default)
      statements.add_validation_var(
          "$chk_required",
          lambda keyword: keyword in
          ExternalValidationRules.required_substatements)

      statements.add_validation_var(
          "$chk_recommended",
          lambda keyword: keyword in lint._recommended_substatements)

      statements.add_validation_fun(
          "grammar", ["$chk_default"],
          lambda ctx, s: lint.v_chk_default(ctx, s))
      statements.add_validation_fun(
          "grammar", ["$chk_required"],
          OCLintStages.openconfig_override_base_linter)
      statements.add_validation_fun(
          "grammar", ["$chk_recommended"],
          OCLintStages.openconfig_override_base_linter)

      statements.add_validation_fun(
          "grammar", ["namespace"],
          lambda ctx, s: lint.v_chk_namespace(ctx, s,
                                              self.namespace_prefixes))

      statements.add_validation_fun(
          "grammar", ["module", "submodule"],
          lambda ctx, s:
          lint.v_chk_module_name(ctx, s, self.modulename_prefixes))

      statements.add_validation_fun(
          "strict", ["include"],
          lambda ctx, s: lint.v_chk_include(ctx, s))

      # Register the default linter error codes
      error.add_error_code(
          "LINT_EXPLICIT_DEFAULT", ErrorLevel.WARNING,
          "RFC 6087: 4.3: "
          "statement \"%s\" is given with its default value \"%s\"")
      error.add_error_code(
          "LINT_MISSING_REQUIRED_SUBSTMT", ErrorLevel.MINOR,
          "%s: "
          "statement \"%s\" must have a \"%s\" substatement")
      error.add_error_code(
          "LINT_MISSING_RECOMMENDED_SUBSTMT", ErrorLevel.WARNING,
          "%s: "
          "statement \"%s\" should have a \"%s\" substatement")
      error.add_error_code(
          "LINT_BAD_NAMESPACE_VALUE", ErrorLevel.WARNING,
          "RFC 6087: 4.8: namespace value should be \"%s\"")
      error.add_error_code(
          "LINT_BAD_MODULENAME_PREFIX_1", ErrorLevel.WARNING,
          "RFC 6087: 4.1: "
          "the module name should start with the string %s")
      error.add_error_code(
          "LINT_BAD_MODULENAME_PREFIX_N", ErrorLevel.WARNING,
          "RFC 6087: 4.1: "
          "the module name should start with one of the strings %s")
      error.add_error_code(
          "LINT_NO_MODULENAME_PREFIX", ErrorLevel.WARNING,
          "RFC 6087: 4.1: "
          "no module name prefix string used")
      error.add_error_code(
          "LINT_BAD_REVISION", ErrorLevel.MINOR,
          "RFC 6087: 4.6: "
          "the module's revision %s is older than "
          "submodule %s's revision %s")
      error.add_error_code(
          "LINT_TOP_MANDATORY", ErrorLevel.MINOR,
          "RFC 6087: 4.9: "
          "top-level node %s must not be mandatory")
      error.add_error_code(
          "LONG_IDENTIFIER", ErrorLevel.MINOR,
          "RFC 6087: 4.2: identifier %s exceeds %s characters")

    # Add a pre-initialisation phase where we can read the
    # modules before they have been parsed by pyang fully.
    statements.add_validation_phase("preinit", before="init")
    statements.add_validation_fun("preinit", ["*"],
                                  OCLintStages.preinitialisation)

    # Add an openconfig types validation phase where we can
    # get types and then validate them further.
    statements.add_validation_phase("openconfig_type", after="type_2")
    statements.add_validation_fun("openconfig_type", ["*"],
                                  OCLintStages.openconfig_type)

    # pyang manipulates the paths of elements during reference_2, such
    # that this is the only time that we get a chance to work
    statements.add_validation_fun("reference_2", ["*"],
                                  OCLintStages.openconfig_reference)

    # Error type for generic OpenConfig linter bugs - returned
    # when an error is encountered in linter logic.
    error.add_error_code(
        "OC_LINTER_ERROR", ErrorLevel.CRITICAL,
        "Linter error encountered: %s")

    # Enum values must be upper case
    error.add_error_code(
        "OC_ENUM_CASE", ErrorLevel.MAJOR,
        "enum value \"%s\" should be capitalised as \"%s\"")

    # Enum values must be of the form UPPERCASE_WITH_UNDERSCORES
    error.add_error_code(
        "OC_ENUM_UNDERSCORES", ErrorLevel.MAJOR,
        "enum value \"%s\" should be of the form "
        "UPPERCASE_WITH_UNDERSCORES: %s")

    # Identity values should be capitalised
    error.add_error_code(
        "OC_IDENTITY_CASE", ErrorLevel.MAJOR,
        "identity name \"%s\" should be capitalised as \"%s\"")

    # UPPERCASE_WITH_UNDERSCORES required for identity values
    error.add_error_code(
        "OC_IDENTITY_UNDERSCORES", ErrorLevel.MAJOR,
        "identity name \"%s\" should be of the form "
        "UPPERCASE_WITH_UNDERSCORES: \"%s\"")

    # There must be a single config / state container in the path
    error.add_error_code(
        "OC_OPSTATE_CONTAINER_COUNT", ErrorLevel.MAJOR,
        "path \"%s\" should have a single \"config\" or \"state\" component")

    # Leaves should be in a "config" or "state" container
    error.add_error_code(
        "OC_OPSTATE_CONTAINER_NAME", ErrorLevel.MAJOR,
        "element \"%s\" at path \"%s\" should be in a \"config\""
        "or \"state\" container")

    # list keys should be leafrefs to respective value in config / state
    error.add_error_code(
        "OC_OPSTATE_KEY_LEAFREF", ErrorLevel.MAJOR,
        "list key \"%s\" should be type leafref with a reference to"
        " the corresponding leaf in config or state container")

    # leaves in in config / state should have the correct config property
    error.add_error_code(
        "OC_OPSTATE_CONFIG_PROPERTY", ErrorLevel.MAJOR,
        "element \"%s\" is in a \"%s\" container and should have "
        "config value %s")

    # references to nodes in the same module / namespace should use relative
    # paths
    error.add_error_code(
        "OC_RELATIVE_PATH", ErrorLevel.WARNING,
        "\"%s\" path reference \"%s\" is intra-module but uses absolute path")

    # a config leaf does not have a mirrored applied config leaf in the state
    # container
    error.add_error_code(
        "OC_OPSTATE_APPLIED_CONFIG", ErrorLevel.MAJOR,
        "\"%s\" is not mirrored in the state container at %s")

    # a list is within a container that has elements other than the list
    # within it
    error.add_error_code(
        "OC_LIST_SURROUNDING_CONTAINER", ErrorLevel.MAJOR,
        "List %s is within a container (%s) that has other elements "
        "within it: %s")

    # a list that does not have a container above it
    error.add_error_code(
        "OC_LIST_NO_ENCLOSING_CONTAINER", ErrorLevel.MAJOR,
        "List %s does not have a surrounding container")

    # when path compression is performed, the containers surrounding
    # lists are removed, if there are two lists with the same name
    # this results in a name collision.
    error.add_error_code(
        "OC_LIST_DUPLICATE_COMPRESSED_NAME", ErrorLevel.MAJOR,
        "List %s has a duplicate name when the parent container %s" + \
        " is removed.")

    # a module defines data nodes at the top-level
    error.add_error_code(
        "OC_MODULE_DATA_DEFINITIONS", ErrorLevel.MAJOR,
        "Module %s defines data definitions at the top level: %s")

    # a module is missing an openconfig-version statement
    error.add_error_code(
        "OC_MODULE_MISSING_VERSION", ErrorLevel.MAJOR,
        "Module %s is missing an openconfig-version statement")

    # a module uses the "choice" keyword
    error.add_error_code(
        "OC_STYLE_AVOID_CHOICE", ErrorLevel.WARNING,
        "Element %s uses the choice keyword, which should be avoided")

    # a module uses the "presence" keyword
    error.add_error_code(
        "OC_STYLE_AVOID_PRESENCE", ErrorLevel.MINOR,
        "Element %s uses the presence keyword which should be avoided")

    # a module uses the "if-feature" or "feature" keyword
    error.add_error_code(
        "OC_STYLE_AVOID_FEATURES", ErrorLevel.MINOR,
        "Element %s uses feature or if-feature which should be avoided")

    # invalid semantic version argument to openconfig-version
    error.add_error_code(
        "OC_INVALID_SEMVER", ErrorLevel.MAJOR,
        "Semantic version specified (%s) is invalid")

    # missing a revision statement that has a reference of the
    # current semantic version
    error.add_error_code(
        "OC_MISSING_SEMVER_REVISION", ErrorLevel.MAJOR,
        "Revision statement should contain reference substatement "
        " corresponding to semantic version %s")

    # invalid data element naming
    error.add_error_code(
        "OC_DATA_ELEMENT_INVALID_NAME", ErrorLevel.MAJOR,
        "Invalid naming for element %s data elements should "
        " generally be lower-case-with-hypens")

    # the module uses an invalid form of prefix
    error.add_error_code(
        "OC_PREFIX_INVALID", ErrorLevel.MINOR,
        "Prefix %s for module does not match the expected "
        " format - use the form oc-<shortdescription>")

    # the module is missing a standard grouping (e.g., -top)
    error.add_error_code(
        "OC_MISSING_STANDARD_GROUPING", ErrorLevel.WARNING,
        "Module %s is missing a grouping suffixed with %s")

    # the module has a nonstandard grouping name
    error.add_error_code(
        "OC_GROUPING_NAMING_NONSTANDARD", ErrorLevel.WARNING,
        "In container %s, grouping %s does not match standard "
        "naming - suffix with %s?")

    # key statements do not have quoted arguments
    error.add_error_code(
        "OC_KEY_ARGUMENT_UNQUOTED", ErrorLevel.MINOR,
        "All key arguments of a list should be quoted (%s is not)")

    # bad type was used for a leaf or typedef
    error.add_error_code(
        "OC_BAD_TYPE", ErrorLevel.MAJOR,
        "Bad type %s used in leaf or typedef",
    )