Skip to content

Datasource Reference

The Operational Compliance app registers two Git datasource content types with Nautobot, allowing you to manage validation rules, rule groups, and command parser templates entirely from Git repositories. When a Git repository is synced, the app automatically creates or updates the corresponding database objects.

Datasource Content Types

Content Type Identifier Purpose
Validation Rules nautobot_operational_compliance.validation_rules Syncs validation rules, their command parsers (collectors), and rule groups from YAML files
Command Parsers nautobot_operational_compliance.command_parsers Provides custom TextFSM and TTP parser templates for command output parsing

To use either datasource, create a Git Repository in Nautobot (Extensibility > Git Repositories) and select the appropriate content type under Provided Contents.

Validation Rules Datasource

This datasource loads validation rules, their associated command parsers (called "collectors" in the YAML files), and validation rule groups from YAML files in a Git repository.

Directory Structure

The app supports two directory layout conventions. It checks for oc/ first, then falls back to operational-compliance/:

repository_root/
├── oc/                              # or operational-compliance/
│   ├── rules/
│   │   ├── routing.yml              # one or more YAML files
│   │   ├── interfaces.yml
│   │   └── system.yml
│   └── rule-groups/
│       ├── pre_change.yml
│       └── post_change.yml
  • All .yml and .yaml files in the rules/ directory (and subdirectories) are loaded recursively.
  • Files containing sample in the filename are skipped.
  • The rule-groups/ directory is optional. If it does not exist, only rules are synced.

Validation Rules YAML Format

Each YAML file in the rules/ directory contains one or more rules as top-level keys. The key is a slug used to derive the display name if display_name is not provided.

---
# Key: rule slug (underscores become spaces, then title-cased for display_name)
bgp_neighbor_state:
  display_name: "BGP Neighbor State"            # optional, overrides slug-derived name
  rule_type: "exact_match"                      # required: exact_match, tolerance, parameter_match, regex, or operator
  description: "Verify BGP neighbor states"     # optional
  evaluate_args:                                # optional: kwargs passed to the jdiff comparison engine
    tolerance: 5
  collectors:                                   # optional: list of command parsers to create
    - name: "textfsm"                           # parser type: textfsm, napalm, ttp, or json
      platform: "cisco_ios"                     # network_driver value of a Nautobot Platform
      command: "show ip bgp summary"            # CLI command to run on the device
      jmespath: "[*].[$neighbor$, state_pfxrcd]"  # JMESPath expression for data extraction
    - name: "textfsm"
      platform: "arista_eos"
      command: "show ip bgp summary"
      jmespath: "[*].[$bgp_neigh$, state_pfxrcd]"

Rule Fields

YAML Field Required Model Field Description
display_name No ValidationRule.name Human-readable name. Defaults to the slug with underscores replaced by spaces and title-cased.
rule_type Yes ValidationRule.rule_type One of: exact_match, tolerance, parameter_match, regex, operator
description No ValidationRule.description Free-text description of the rule
evaluate_args No ValidationRule.rule_options Dict of kwargs passed to jdiff for comparison. Required for tolerance rules (must include tolerance key). See the Rule Types Reference.
collectors No Creates CommandParser objects List of platform-specific command definitions (see below)

Collector Fields

Each entry in the collectors list creates a CommandParser object linked to the parent validation rule.

YAML Field Required Model Field Description
name Yes CommandParser.parser Parser type: textfsm, napalm, ttp, or json
platform Yes CommandParser.platform The network_driver value of a Nautobot Platform (e.g., cisco_ios, arista_eos, juniper_junos). If no matching Platform exists, the collector is skipped with a warning.
command No CommandParser.command CLI command to execute on the device
jmespath No CommandParser.path JMESPath expression to extract data from parsed output
napalm_getter No CommandParser.napalm_getter NAPALM getter method name (e.g., get_facts, get_interfaces). Used when name is napalm.
exclude No CommandParser.exclude List of keys to exclude from comparison. Only valid with exact_match rule type. Cannot be combined with jmespath.

Note

Each validation rule can have at most one collector per platform. The combination of (validation_rule, platform) must be unique.

Example: Validation Rules YAML Files

File: oc/rules/routing.yml

---
bgp_neighbor_state:
  display_name: "BGP Neighbor State"
  rule_type: "exact_match"
  description: "Verify all BGP neighbor sessions remain in the same state"
  collectors:
    - name: "textfsm"
      platform: "cisco_ios"
      command: "show ip bgp summary"
      jmespath: "[*].[$bgp_neigh$, state_pfxrcd]"
    - name: "textfsm"
      platform: "arista_eos"
      command: "show ip bgp summary"
      jmespath: "[*].[$bgp_neigh$, state_pfxrcd]"
    - name: "textfsm"
      platform: "juniper_junos"
      command: "show bgp summary"
      jmespath: "[*].[$peer_address$, received_routes]"

bgp_prefix_tolerance:
  display_name: "BGP Prefix Count"
  rule_type: "tolerance"
  description: "Allow BGP received prefix counts to fluctuate within tolerance"
  evaluate_args:
    tolerance: 10
  collectors:
    - name: "textfsm"
      platform: "cisco_ios"
      command: "show ip bgp summary"
      jmespath: "[*].[$bgp_neigh$, state_pfxrcd]"

ospf_neighbor_state:
  display_name: "OSPF Neighbor State"
  rule_type: "exact_match"
  description: "Ensure OSPF adjacencies remain stable"
  collectors:
    - name: "textfsm"
      platform: "cisco_ios"
      command: "show ip ospf neighbor"
      jmespath: "[*].[$neighbor_id$, state]"
    - name: "textfsm"
      platform: "arista_eos"
      command: "show ip ospf neighbor"
      jmespath: "[*].[$neighbor_id$, state]"

File: oc/rules/interfaces.yml

---
interface_status:
  display_name: "Interface Status"
  rule_type: "exact_match"
  description: "Monitor interface operational state"
  collectors:
    - name: "napalm"
      platform: "cisco_ios"
      napalm_getter: "get_interfaces"
      jmespath: "*.{is_up: is_up, is_enabled: is_enabled}"
    - name: "napalm"
      platform: "arista_eos"
      napalm_getter: "get_interfaces"
      jmespath: "*.{is_up: is_up, is_enabled: is_enabled}"

interface_counters:
  display_name: "Interface Counters"
  rule_type: "exact_match"
  description: "Compare interface data excluding volatile statistics"
  collectors:
    - name: "napalm"
      platform: "cisco_ios"
      napalm_getter: "get_interfaces"
      exclude:
        - "tx_errors"
        - "rx_errors"
        - "tx_discards"
        - "rx_discards"

File: oc/rules/system.yml

---
device_facts:
  display_name: "Device Facts"
  rule_type: "exact_match"
  description: "Verify device facts have not changed"
  collectors:
    - name: "napalm"
      platform: "cisco_ios"
      napalm_getter: "get_facts"
      jmespath: "{hostname: hostname, model: model, os_version: os_version}"
    - name: "napalm"
      platform: "arista_eos"
      napalm_getter: "get_facts"
      jmespath: "{hostname: hostname, model: model, os_version: os_version}"

ntp_sync:
  display_name: "NTP Synchronization"
  rule_type: "exact_match"
  description: "Ensure NTP peers remain consistent"
  collectors:
    - name: "textfsm"
      platform: "cisco_ios"
      command: "show ntp associations"
      jmespath: "[*].[$address$, ref_clock]"
    - name: "textfsm"
      platform: "juniper_junos"
      command: "show ntp associations"
      jmespath: "[*].[$remote$, refid]"

os_version_compliance:
  display_name: "OS Version Compliance"
  rule_type: "parameter_match"
  description: "Check devices are running approved OS version"
  evaluate_args:
    params:
      os_version: "17.12.2"
    mode: "match"
  collectors:
    - name: "napalm"
      platform: "cisco_ios"
      napalm_getter: "get_facts"
      jmespath: "os_version"

Validation Rule Groups YAML Format

Each YAML file in the rule-groups/ directory contains one or more groups as top-level keys. Groups reference validation rules by their display name (not the slug).

---
pre_change_checks:
  display_name: "Pre-Change Validation"          # optional, defaults to slug-derived name
  description: "Rules to run before changes"     # optional
  validation_rules:                              # list of validation rule display names
    - "BGP Neighbor State"
    - "OSPF Neighbor State"
    - "Interface Status"
    - "Device Facts"

Warning

Rules referenced in a group must already exist in the database (i.e., the rules YAML files are processed before groups). If a referenced rule name is not found, a warning is logged and the rule is skipped — the group is still created with the remaining rules.

Group Fields

YAML Field Required Model Field Description
display_name No ValidationRuleGroup.name Human-readable name. Defaults to the slug with underscores replaced by spaces and title-cased.
description No ValidationRuleGroup.description Free-text description of the group
validation_rules No ValidationRuleGroup.validation_rules (M2M) List of validation rule display names to include in the group

Example: Validation Rule Groups YAML Files

File: oc/rule-groups/change_management.yml

---
pre_change_validation:
  display_name: "Pre-Change Validation"
  description: "Comprehensive checks to run before a maintenance window"
  validation_rules:
    - "BGP Neighbor State"
    - "OSPF Neighbor State"
    - "Interface Status"
    - "Device Facts"
    - "NTP Synchronization"

routing_health:
  display_name: "Routing Health"
  description: "Focused routing protocol validation"
  validation_rules:
    - "BGP Neighbor State"
    - "BGP Prefix Count"
    - "OSPF Neighbor State"

platform_baseline:
  display_name: "Platform Baseline"
  description: "Hardware and software compliance checks"
  validation_rules:
    - "Device Facts"
    - "OS Version Compliance"

Command Parsers Datasource

This datasource provides custom TextFSM and TTP parser templates that the app uses at runtime to parse CLI command output. This is useful when:

  • You need a custom parser not available in ntc-templates
  • You want to override an existing ntc-templates parser with a custom version
  • You are using TTP templates (which are not included in ntc-templates)

Directory Structure

repository_root/
├── parsers/
│   ├── cisco_ios/
│   │   ├── show_version.textfsm
│   │   ├── show_ip_bgp_summary.textfsm
│   │   └── show_interfaces.ttp
│   ├── arista_eos/
│   │   ├── show_version.textfsm
│   │   └── show_ip_bgp_summary.ttp
│   └── juniper_junos/
│       └── show_bgp_summary.ttp

File Naming Convention

The app converts the CLI command to a filename by replacing spaces with underscores:

CLI Command Expected Filename
show version show_version.textfsm or show_version.ttp
show ip bgp summary show_ip_bgp_summary.textfsm or show_ip_bgp_summary.ttp
show interfaces show_interfaces.textfsm or show_interfaces.ttp

The file extension (.textfsm or .ttp) must match the parser type configured on the CommandParser object.

Parser File Path Resolution

At runtime, the app resolves parser file paths using a Jinja2 template. The default template renders to a path like cisco_ios/show_version, which is then appended to the parsers/ directory in the Git repository and given the appropriate file extension.

The full resolution path is: <repo>/parsers/<network_driver>/<command_filename>.<parser_type>

Example: For a device with platform cisco_ios running show ip bgp summary with a textfsm parser:

<repo>/parsers/cisco_ios/show_ip_bgp_summary.textfsm

Customizing the Path Template

The path template can be customized via the GIT_PARSERS_PATH setting in your Nautobot configuration or via the Constance admin UI. Available template variables:

Variable Description
{{ obj }} The device object
{{ obj.platform.network_driver }} The platform's network driver (e.g., cisco_ios)
{{ cmd }} The command converted to a filename (spaces replaced with underscores)

Parser Lookup Behavior

When the app needs to parse command output, it follows this lookup order:

Parser Type Custom Git Template Fallback
TextFSM Checks Git repos for .textfsm file Falls back to ntc-templates built-in templates
TTP Checks Git repos for .ttp file No fallback — fails if not found in a Git repo
NAPALM N/A Uses NAPALM getter directly
JSON N/A Parses JSON output directly

Warning

TTP parsers must be provided through a Git repository. There is no built-in fallback for TTP templates. If a TTP template is not found, the command output parsing will fail.

Complete Example: Setting Up Both Datasources

Here is a complete example showing how to set up a single Git repository for validation rules, and a second repository for custom parser templates.

Repository 1: Validation Rules

Git Repository Configuration in Nautobot:

  • Name: Compliance Rules
  • Provided Contents: Operational Compliance App Validation Rules

Repository layout:

compliance-rules/
├── oc/
│   ├── rules/
│   │   ├── routing.yml
│   │   ├── interfaces.yml
│   │   └── system.yml
│   └── rule-groups/
│       └── change_management.yml

Repository 2: Custom Parser Templates

Git Repository Configuration in Nautobot:

  • Name: Compliance Parsers
  • Provided Contents: Operational Compliance App Command Parsers

Repository layout:

compliance-parsers/
├── parsers/
│   ├── cisco_ios/
│   │   ├── show_ip_bgp_summary.textfsm
│   │   └── show_ip_ospf_neighbor.textfsm
│   ├── arista_eos/
│   │   ├── show_ip_bgp_summary.textfsm
│   │   └── show_ip_ospf_neighbor.ttp
│   └── juniper_junos/
│       └── show_bgp_summary.ttp

Tip

You can also combine both content types into a single Git repository by selecting both Operational Compliance App Validation Rules and Operational Compliance App Command Parsers under Provided Contents when configuring the repository. In that case, the repository would contain both the oc/ directory and the parsers/ directory at the root level.