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")
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 checker syntax.add_arg_type('smi-oid', _chk_smi_oid) # 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_fun('type', [(smi_module_name, 'oid')], v_parse_oid) statements.add_validation_phase('smi_set_oid', after='inherit_properties') statements.add_validation_fun('smi_set_oid', ['module', 'submodule'], v_set_oid)
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")
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 checker syntax.add_arg_type('smi-oid', _chk_smi_oid) # 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_fun('type', [(smi_module_name, 'oid')], v_parse_oid) statements.add_validation_phase('smi_set_oid', after='inherit_properties') statements.add_validation_fun('smi_set_oid', ['module', 'submodule'], v_set_oid)
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)", )
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')
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)')
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", )