Example #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 '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")
Example #2
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 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)
Example #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 '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")
Example #4
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 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)
Example #5
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)",
    )
Example #6
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')
Example #7
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)')
Example #8
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",
    )