### IOS Configuration Example Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html This is an example of an IOS configuration file containing interface and VLAN definitions. ```text interface FastEthernet1 description This is Fa1 shutdown exit ! interface FastEthernet1.1 description This is Fa1.1 exit ! interface FastEthernet1.2 description This is Fa1.2 exit ! interface FastEthernet3 description This is Fa3 no shutdown exit ! interface FastEthernet4 shutdown exit ! vlan 10 name prod no shutdown exit ! vlan 20 name dev shutdown exit ! ``` -------------------------------- ### Example Parsed IOS Configuration Source: https://yangify.readthedocs.io/en/latest/tutorials/intro.html This is an example of the output after parsing an IOS configuration file using Yangify. It shows the data structured according to YANG models for interfaces and VLANs. ```json { "openconfig-interfaces:interfaces": { "interface": [ { "name": "FastEthernet1", "config": { "name": "FastEthernet1", "type": "iana-if-type:ethernetCsmacd", "description": "This is Fa1", "enabled": false }, "subinterfaces": { "subinterface": [ { "index": 1, "config": { "index": 1, "description": "This is Fa1.1" } }, { "index": 2, "config": { "index": 2, "description": "This is Fa1.2" } } ] } }, { "name": "FastEthernet3", "config": { "name": "FastEthernet3", "type": "iana-if-type:ethernetCsmacd", "description": "This is Fa3", "enabled": true } }, { "name": "FastEthernet4", "config": { "name": "FastEthernet4", "type": "iana-if-type:ethernetCsmacd", "enabled": false } } ] }, "openconfig-vlan:vlans": { "vlan": [ { "vlan-id": 10, "config": { "vlan-id": 10, "name": "prod", "status": "ACTIVE" } }, { "vlan-id": 20, "config": { "vlan-id": 20, "name": "dev", "status": "SUSPENDED" } } ] } } ``` -------------------------------- ### Example Processed Configuration Output Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html This is an example of the structured output after processing a network device configuration. ```json { "openconfig-interfaces:interfaces": { "interface": [ { "name": "FastEthernet1", "config": { "name": "FastEthernet1", "type": "iana-if-type:ethernetCsmacd", "description": "This is Fa1", "enabled": false }, "subinterfaces": { "subinterface": [ { "index": 1, "config": { "index": 1, "description": "This is Fa1.1" } }, { "index": 2, "config": { "index": 2, "description": "This is Fa1.2" } } ] } }, { "name": "FastEthernet3", "config": { "name": "FastEthernet3", "type": "iana-if-type:ethernetCsmacd", "description": "This is Fa3", "enabled": true } }, { "name": "FastEthernet4", "config": { "name": "FastEthernet4", "type": "iana-if-type:ethernetCsmacd", "enabled": false } } ] } } ``` -------------------------------- ### Example Output with Replace Mode Source: https://yangify.readthedocs.io/en/latest/tutorials/translating.html This output demonstrates the 'replace' mode, where configurations are defaulted (using 'default' or 'no' prefixes) before applying the new configuration. ```text default interface FastEthernet1 interface FastEthernet1 description This is Fa1 shutdown exit ! no interface FastEthernet1.1 interface FastEthernet1.1 description This is Fa1.1 exit ! no interface FastEthernet1.2 interface FastEthernet1.2 description This is Fa1.2 exit ! default interface FastEthernet3 interface FastEthernet3 description This is Fa3 no shutdown exit ! default interface FastEthernet4 interface FastEthernet4 shutdown exit ! no vlan 10 vlan 10 name prod no shutdown exit ! no vlan 20 vlan 20 name dev shutdown exit ! ``` -------------------------------- ### Instantiate and Process with IOSParser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Instantiates the IOSParser with a DataModel and data, then attempts to process it. Includes error handling for SchemaError, which is expected in the initial setup. ```python from yangson.exceptions import SchemaError p = IOSParser(dm, native=data) try: result = p.process() print(json.dumps(result.raw_value(), indent=4)) except SchemaError as e: print("Supressing output for readability:") print(f"error: {e}") ``` -------------------------------- ### Example Translated Output (Interfaces) Source: https://yangify.readthedocs.io/en/latest/tutorials/translating.html This is an example of the output generated by the IOSTranslator, showing translated interface configurations. ```text interface FastEthernet1 description This is Fa1 shutdown exit ! interface FastEthernet1.1 description This is Fa1.1 exit ! interface FastEthernet1.2 description This is Fa1.2 exit ! interface FastEthernet3 description This is Fa3 no shutdown exit ! interface FastEthernet4 shutdown exit ! ``` -------------------------------- ### Example Parsed LLDP Data Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This is an example of the structured data output after parsing LLDP information, including interface configurations and neighbor details. ```json { "openconfig-interfaces:interfaces": { "interface": [ { "name": "GigabitEthernet1", "config": { "name": "GigabitEthernet1", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE1", "enabled": false } }, { "name": "GigabitEthernet2", "config": { "name": "GigabitEthernet2", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE2", "enabled": true } }, { "name": "GigabitEthernet3", "config": { "name": "GigabitEthernet3", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE3", "enabled": true } }, { "name": "GigabitEthernet4", "config": { "name": "GigabitEthernet4", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE4", "enabled": true } }, { "name": "GigabitEthernet5", "config": { "name": "GigabitEthernet5", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE5", "enabled": true } }, { "name": "Loopback100", "config": { "name": "Loopback100", "type": "iana-if-type:softwareLoopback", "loopback-mode": true, "description": "this is loopy100", "enabled": true } } ] }, "openconfig-lldp:lldp": { "config": { "system-name": "ntc-r1" }, "interfaces": { "interface": [ { "name": "GigabitEthernet1", "config": { "name": "GigabitEthernet1" }, "neighbors": { "neighbor": [ { "id": "ntc-r6" }, { "id": "ntc-r7" }, { "id": "ntc-r8" } ] } }, { "name": "GigabitEthernet2", "config": { "name": "GigabitEthernet2" }, "neighbors": { "neighbor": [ { "id": "ntc-r2" }, { "id": "ntc-s2" } ] } }, { "name": "GigabitEthernet3", "config": { "name": "GigabitEthernet3" }, "neighbors": { "neighbor": [ { "id": "ntc-r3" }, { "id": "ntc-r5" } ] } }, { "name": "GigabitEthernet5", "config": { "name": "GigabitEthernet5" } } ] } } } ``` -------------------------------- ### Example of Keys Dictionary Source: https://yangify.readthedocs.io/en/latest/api/translator.html Illustrates the structure of the keys dictionary used to track YANG list keys during translation. ```json { "openconfig-interfaces:interfaces/interface": "FastEthernet1", "openconfig-interfaces:interfaces/interface/subinterfaces/subinterface": 1, } ``` -------------------------------- ### Initialize DataModel and Custom Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This script initializes the DataModel with YANG modules and defines a custom IOSParser that processes 'show run' configuration. It's used as a starting point for parsing network data. ```python import json from yangify import parser from yangify.parser.text_tree import parse_indented_config from yangson.datamodel import DataModel import task1_lldp_parser dm = DataModel.from_file("../yang/yang-library-data.json", ["../yang/yang-modules/ietf", "../yang/yang-modules/openconfig"]) class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = {} self.root_native["show run"] = parse_indented_config( self.native["show run"].splitlines() ) self.native = self.root_native # interfaces is YANG container. Variable names are always # YANG containers or lists interfaces = task1_lldp_parser.Interfaces with open("../data/ios/ntc-r1/config.txt", "r") as f: config = f.read() data = {} data["show run"] = config ``` -------------------------------- ### Example IOS Configuration Output Source: https://yangify.readthedocs.io/en/latest/tutorials/intro.html This is the resulting IOS configuration generated after processing the input data with the custom translator. It includes interface and VLAN configurations. ```text interface FastEthernet1 description This is Fa1 shutdown exit ! interface FastEthernet1.1 description This is Fa1.1 exit ! interface FastEthernet1.2 description This is Fa1.2 exit ! interface FastEthernet3 description This is Fa3 no shutdown exit ! interface FastEthernet4 shutdown exit ! vlan 10 name prod no shutdown exit ! vlan 20 name dev shutdown exit ! ``` -------------------------------- ### Interface Parser Implementation Source: https://yangify.readthedocs.io/en/latest/api/parser.html Example of implementing a custom parser for the openconfig-interfaces:interfaces/interface model by inheriting from Parser and defining a Yangify class. ```python class Interface(parser.Parser): class Yangify(ParserData): def extract_elements(self) -> Iterator[Tuple[str, Dict[str, Any]]]: for k, v in interfaces_magic: yield k, v ``` -------------------------------- ### View Cisco IOS Configuration Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Displays the baseline configuration of a Cisco IOS device. This is useful for understanding the starting point before parsing. ```bash %cat ../data/ios/ntc-r1/config.txt ``` ```text hostname ntc-r1 ! interface GigabitEthernet1 description Hello GigE1 shutdown ! interface GigabitEthernet2 description Hello GigE2 ! interface GigabitEthernet3 description Hello GigE3 ! interface GigabitEthernet4 description Hello GigE4 no lldp enable ! interface GigabitEthernet5 description Hello GigE5 ! interface Loopback100 description this is loopy100 ! vlan 10 vlan 20 name web_vlan vlan 30 name test_vlan ! ``` -------------------------------- ### Display YANG Tree Structure Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Shows the tree output of a YANG model, useful for visualizing the structure of network configurations. This example displays the OpenConfig LLDP YANG model. ```text +--ro state | +--ro id? string | +--ro port-id? string ``` -------------------------------- ### Full OpenConfig LLDP YANG Model Tree Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Displays the complete tree structure of the OpenConfig LLDP YANG model. Install pyang with pip to generate similar outputs. ```text ntc@nautobot:models (master)$ pyang -f tree lldp/openconfig-lldp.yang module: openconfig-lldp +--rw lldp +--rw config | +--rw enabled? boolean | +--rw hello-timer? uint64 | +--rw suppress-tlv-advertisement* identityref | +--rw system-name? string | +--rw system-description? string | +--rw chassis-id? string | +--rw chassis-id-type? oc-lldp-types:chassis-id-type +--ro state | +--ro enabled? boolean | +--ro hello-timer? uint64 | +--ro suppress-tlv-advertisement* identityref | +--ro system-name? string | +--ro system-description? string | +--ro chassis-id? string | +--ro chassis-id-type? oc-lldp-types:chassis-id-type | +--ro counters | +--ro frame-in? yang:counter64 | +--ro frame-out? yang:counter64 | +--ro frame-error-in? yang:counter64 | +--ro frame-discard? yang:counter64 | +--ro tlv-discard? yang:counter64 | +--ro tlv-unknown? yang:counter64 | +--ro last-clear? yang:date-and-time | +--ro tlv-accepted? yang:counter64 | +--ro entries-aged-out? yang:counter64 +--rw interfaces +--rw interface* [name] +--rw name -> ../config/name +--rw config | +--rw name? oc-if:base-interface-ref | +--rw enabled? boolean +--ro state | +--ro name? oc-if:base-interface-ref | +--ro enabled? boolean | +--ro counters | +--ro frame-in? yang:counter64 | +--ro frame-out? yang:counter64 | +--ro frame-error-in? yang:counter64 | +--ro frame-discard? yang:counter64 | +--ro tlv-discard? yang:counter64 | +--ro tlv-unknown? yang:counter64 | +--ro last-clear? yang:date-and-time | +--ro frame-error-out? yang:counter64 +--ro neighbors +--ro neighbor* [id] +--ro id -> ../state/id +--ro config +--ro state | +--ro system-name? string | +--ro system-description? string | +--ro chassis-id? string | +--ro chassis-id-type? oc-lldp-types:chassis-id-type | +--ro id? string | +--ro age? uint64 | +--ro last-update? int64 | +--ro ttl? uint16 | +--ro port-id? string | +--ro port-id-type? oc-lldp-types:port-id-type | +--ro port-description? string | +--ro management-address? string | +--ro management-address-type? string +--ro custom-tlvs | +--ro tlv* [type oui oui-subtype] | +--ro type -> ../state/type | +--ro oui -> ../state/oui | +--ro oui-subtype -> ../state/oui-subtype | +--ro config | +--ro state | +--ro type? int32 | +--ro oui? string | +--ro oui-subtype? string | +--ro value? binary +--ro capabilities +--ro capability* [name] +--ro name -> ../state/name +--ro config +--ro state +--ro name? identityref +--ro enabled? boolean ntc@nautobot:models (master)$ ``` -------------------------------- ### OpenConfig Interfaces JSON Data Source: https://yangify.readthedocs.io/en/latest/tutorials/translating.html Example JSON structure for OpenConfig interfaces and VLANs. ```json { "openconfig-interfaces:interfaces": { "interface": [ { "name": "FastEthernet1", "config": { "name": "FastEthernet1", "type": "iana-if-type:ethernetCsmacd", "description": "This is Fa1", "enabled": false }, "subinterfaces": { "subinterface": [ { "index": 1, "config": { "index": 1, "description": "This is Fa1.1" } }, { "index": 2, "config": { "index": 2, "description": "This is Fa1.2" } } ] } }, { "name": "FastEthernet3", "config": { "name": "FastEthernet3", "type": "iana-if-type:ethernetCsmacd", "description": "This is Fa3", "enabled": true } }, { "name": "FastEthernet4", "config": { "name": "FastEthernet4", "type": "iana-if-type:ethernetCsmacd", "enabled": false } } ] }, "openconfig-vlan:vlans": { "vlan": [ { "vlan-id": 10, "config": { "vlan-id": 10, "name": "prod", "status": "ACTIVE" } }, { "vlan-id": 20, "config": { "vlan-id": 20, "name": "dev", "status": "SUSPENDED" } } ] } } ``` -------------------------------- ### Parsed Interface Data Example Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This JSON output represents the parsed interface data, including names and configuration details, conforming to the openconfig-interfaces YANG model. ```json { "openconfig-interfaces:interfaces": { "interface": [ { "name": "GigabitEthernet1", "config": { "name": "GigabitEthernet1", "enabled": false } }, { "name": "GigabitEthernet2", "config": { "name": "GigabitEthernet2", "enabled": true } }, { "name": "GigabitEthernet3", "config": { "name": "GigabitEthernet3", "enabled": true } }, { "name": "GigabitEthernet4", "config": { "name": "GigabitEthernet4", "enabled": true } }, { "name": "GigabitEthernet5", "config": { "name": "GigabitEthernet5", "enabled": true } }, { "name": "Loopback100", "config": { "name": "Loopback100", "enabled": true } } ] } } ``` -------------------------------- ### Parsed Interface Data Example Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This JSON output represents the parsed data for network interfaces, including details for GigabitEthernet and Loopback interfaces. ```json { "openconfig-interfaces:interfaces": { "interface": [ { "name": "GigabitEthernet1", "config": { "name": "GigabitEthernet1", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE1", "enabled": false } }, { "name": "GigabitEthernet2", "config": { "name": "GigabitEthernet2", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE2", "enabled": true } }, { "name": "GigabitEthernet3", "config": { "name": "GigabitEthernet3", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE3", "enabled": true } }, { "name": "GigabitEthernet4", "config": { "name": "GigabitEthernet4", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE4", "enabled": true } }, { "name": "GigabitEthernet5", "config": { "name": "GigabitEthernet5", "type": "iana-if-type:ethernetCsmacd", "loopback-mode": false, "description": "Hello GigE5", "enabled": true } }, { "name": "Loopback100", "config": { "name": "Loopback100", "type": "iana-if-type:softwareLoopback", "loopback-mode": true, "description": "this is loopy100", "enabled": true } } ] } } ``` -------------------------------- ### Import Tutorial Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html Import the necessary tutorial parser module to begin parsing. ```python import tutorial_parser ``` -------------------------------- ### Instantiate and Process Configuration Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html Creates an instance of the custom parser with the datamodel and native configuration, then processes the configuration. ```python p = IOSParser(dm, native=config) result = p.process() ``` -------------------------------- ### Process Configuration with the New Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html Instantiate the newly defined parser with your data models and configuration, then call the process method to parse the data. ```python p = IOSParser2(dm, native=config) result = p.process() ``` -------------------------------- ### Define a custom IOSParser Source: https://yangify.readthedocs.io/en/latest/tutorials/filtering.html Defines a custom parser class inheriting from `parser.RootParser`. This setup is necessary for processing indented configuration text. ```python from yangify import parser from yangify.parser.text_tree import parse_indented_config class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = parse_indented_config(self.native.splitlines()) self.native = self.root_native interfaces = tutorial_parser.Interfaces vlans = tutorial_parser.Vlans ``` -------------------------------- ### Initialize IOSParser with Parsed Data Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Initializes the IOSParser by parsing the 'show run' command output into an indented configuration and storing 'lldp_data'. This sets up the root native data for subsequent parsing. ```python import json from yangify import parser from yangify.parser.text_tree import parse_indented_config import textfsm import task7_lldp_parser class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = {} self.root_native["show run"] = parse_indented_config( self.native["show run"].splitlines() ) self.root_native["lldp_data"] = self.native["lldp_data"] self.native = self.root_native ``` -------------------------------- ### Load parser, data model, and configuration Source: https://yangify.readthedocs.io/en/latest/tutorials/filtering.html Imports necessary libraries and loads the configuration data and data model. Ensure the data model and module paths are correctly specified. ```python import json import tutorial_parser with open("data/ios/config.txt", "r") as f: config = f.read() from yangson.datamodel import DataModel dm = DataModel.from_file("yang/yang-library-data.json", ["yang/yang-modules/ietf", "yang/yang-modules/openconfig"]) ``` -------------------------------- ### Process Data with IOSTranslator Source: https://yangify.readthedocs.io/en/latest/tutorials/translating.html Instantiate the custom translator with the DataModel and candidate data, then call the process method to get the translated result. ```python p = IOSTranslator(dm, candidate=data) result = p.process() ``` -------------------------------- ### Display Configuration File Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This command displays the content of the configuration file that will be parsed. ```bash %cat ../data/ios/ntc-r1/config.txt ``` -------------------------------- ### IOSParser Initialization and Processing Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Initializes the IOSParser with data and processes it to generate a parsed output. The `init` method in `Yangify` prepares the native data for parsing. ```python import task2_lldp_parser class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = {} self.root_native["show run"] = parse_indented_config( self.native["show run"].splitlines() ) self.native = self.root_native interfaces = task2_lldp_parser.Interfaces p = IOSParser(dm, native=data) result = p.process(validate=False) print(json.dumps(result.raw_value(), indent=4)) ``` -------------------------------- ### Initialize and Process Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Initializes the IOSParser with data and processes it, then prints the raw result. Ensure 'dm', 'data', and 'json' are imported. ```python p = IOSParser(dm, native=data, state=True) result = p.process(validate=True) print(json.dumps(result.raw_value(), indent=4)) ``` -------------------------------- ### Parse IOS Configuration and Print Result Source: https://yangify.readthedocs.io/en/latest/tutorials/intro.html Instantiates the IOSParser with the datamodel and configuration, processes the configuration, and prints the resulting YANG-modelled data in JSON format with indentation. ```python p = IOSParser(dm, native=config) result = p.process() import json print(json.dumps(result.raw_value(), indent=4)) ``` -------------------------------- ### Display Initial Data Source: https://yangify.readthedocs.io/en/latest/tutorials/merging.html Displays the initial JSON data from data/ios/data.json, which serves as the 'running' configuration. ```bash %cat data/ios/data.json ``` -------------------------------- ### Define Custom IOS Translator Source: https://yangify.readthedocs.io/en/latest/tutorials/intro.html Define a custom translator class inheriting from Yangify's RootTranslator to process data models. This example sets up the structure for translating interfaces and VLANs. ```python import tutorial_translator from yangify import translator from yangify.translator.config_tree import ConfigTree class IOSTranslator(translator.RootTranslator): class Yangify(translator.TranslatorData): def init(self) -> None: self.root_result = ConfigTree() self.result = self.root_result def post(self) -> None: self.root_result = self.root_result.to_string() interfaces = tutorial_translator.Interfaces vlans = tutorial_translator.Vlans ``` -------------------------------- ### Initialize DataModel Source: https://yangify.readthedocs.io/en/latest/tutorials/merging.html Initializes the DataModel from specified YANG library and module files, required for configuration processing. ```python from yangson.datamodel import DataModel dm = DataModel.from_file("yang/yang-library-data.json", ["yang/yang-modules/ietf", "yang/yang-modules/openconfig"]) ``` -------------------------------- ### JSON Representation of OpenConfig LLDP Data Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This JSON output represents OpenConfig LLDP data, mapping directly to YANG models. It's used as the starting point for Yangify to parse and translate data. ```json { "openconfig-lldp:lldp": { "config": { "system-name": "ntc-r1" }, "interfaces": { "interface": [ { "name": "GigabitEthernet1", "config": { "name": "GigabitEthernet1" }, "neighbors": { "neighbor": [ { "id": "ntc-r6", "state": { "id": "ntc-r6", "port-id": "Gi0/4" } } ] } }, { "name": "GigabitEthernet2", "config": { "name": "GigabitEthernet2" }, "neighbors": { "neighbor": [ { "id": "ntc-r2", "state": { "id": "ntc-r2", "port-id": "Gi0/1" } }, { "id": "ntc-s2", "state": { "id": "ntc-s2", "port-id": "Gi0/1" } } ] } } ] } } } ``` -------------------------------- ### Extract LLDP Interface Data Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Extracts LLDP interface data from 'show run' configuration. It skips interfaces with '#text', those containing dots, and specifically those where LLDP is not enabled or explicitly disabled. Interfaces starting with 'Loop' are also skipped. ```python class LLDPInterface(Parser): class Yangify(ParserData): # While we have LLDP structured data, that is only active # neighbors found from the show lldp neighbors command # This LLDP interface is defined as the following within the model # list interface { # key "name"; # description # "List of interfaces on which LLDP is enabled / available"; # # Because of this, we're using the show run command to build out # the LLDP interfaces accessed in self.native['show run'] again. def extract_elements(self) -> Iterator[Tuple[str, Dict[str, Any]]]: for interface, data in self.native["show run"]["interface"].items(): if interface == "#text": continue no_lldp_config = ( data.get("no", {}) .get("lldp", {}) .get("enable", {}) .get("#standalone") ) if no_lldp_config: continue # skip any interfaces you want to... if interface.startswith("Loop"): continue # `interface` is the interface name like GigabitEthernet1 # `data` is the value of the dictionary from the text tree yield interface, data ``` -------------------------------- ### IOSParser Initialization and Processing Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This code initializes the IOSParser with device data and processes it, enabling validation. The output is then printed in a JSON format. ```python import task3_lldp_parser class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = {} self.root_native["show run"] = parse_indented_config( self.native["show run"].splitlines() ) self.native = self.root_native interfaces = task3_lldp_parser.Interfaces p = IOSParser(dm, native=data) result = p.process(validate=True) print(json.dumps(result.raw_value(), indent=4)) ``` -------------------------------- ### Naive YANG Output Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This snippet shows a basic YANG container structure for LLDP configuration. It includes descriptions for the top-level container and a nested configuration container. ```yang container lldp { description "Top-level container for LLDP configuration and state data"; container config { // this is the container that'll hold the system-name description "Configuration data "; // shortened for brevity ``` -------------------------------- ### Import and Use LLDP Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Imports the custom LLDP parser and prepares to use it for creating the 'lldp' container within the Yangify data structure. ```python import task4_lldp_parser ``` -------------------------------- ### RootParser with Alternative Parser Source: https://yangify.readthedocs.io/en/latest/api/parser.html Shows how to specify an alternative custom parser class for a specific YANG model when using RootParser. ```python from yangify import parser class InterfacesAlt(parser.Parser): ... class Parser(parser.RootParser): interfaces = InterfacesAlt ``` -------------------------------- ### Building Hierarchical Configurations with ConfigTree Source: https://yangify.readthedocs.io/en/latest/api/translator.html The `ConfigTree` class allows for the construction of hierarchical configuration structures. Use `new_section` to create new hierarchical levels and `add_command` to add configuration lines within a section. ```python >>> config = ConfigTree() >>> gi1 = config.new_section("interface Gi1") >>> gi1.add_command(" description \"A description for Gi1\"") >>> gi1.add_command(" shutdown") >>> gi1.add_command(" exit") >>> gi1.add_command("!") >>> gi2 = config.new_section("interface Gi2") >>> gi2.add_command(" description \"A description for Gi2\"") >>> gi2.add_command(" exit") >>> gi2.add_command("!") >>> config.add_command("logging something something") >>> config.add_command("logging something else") ``` -------------------------------- ### Load Running Configuration Data Source: https://yangify.readthedocs.io/en/latest/tutorials/merging.html Loads the initial configuration data from a JSON file into the 'running' variable. ```python import json with open("data/ios/data.json", "r") as f: running = json.load(f) ``` -------------------------------- ### Execute IOSParser for LLDP data Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Instantiate and process data using the IOSParser to generate structured output, including LLDP configuration. ```python p = IOSParser(dm, native=data) result = p.process(validate=True) print(json.dumps(result.raw_value(), indent=4)) ``` -------------------------------- ### RootParser with Multiple Parsers Source: https://yangify.readthedocs.io/en/latest/api/parser.html Demonstrates how to configure RootParser to use different custom parser classes for different YANG models, such as openconfig-interfaces and openconfig-vlan. ```python from yangify import parser class Interfaces(parser.Parser): ... class Vlans(parser.Parser): ... class Parser(parser.RootParser): interfaces = Interfaces vlans = Vlans ``` -------------------------------- ### Display IOS Configuration Content Source: https://yangify.readthedocs.io/en/latest/tutorials/intro.html Displays the content of the IOS configuration file using the 'cat' command. This is useful for inspecting the raw configuration data. ```bash %cat data/ios/config.txt ``` -------------------------------- ### OpenConfig Interfaces and VLANs Model Structure Source: https://yangify.readthedocs.io/en/latest/tutorials/translating.html This ASCII tree represents the structure of the `openconfig-interfaces` and `openconfig-vlan` YANG models used in the translation tutorial. It outlines the configuration hierarchy and leaf nodes. ```text +--rw openconfig-interfaces:interfaces +--rw interface* [name] +--rw config | +--rw description? | +--rw enabled? | +--rw loopback-mode? | +--rw mtu? | +--rw name? | +--rw type +--rw name +--rw subinterfaces +--rw subinterface* [index] +--rw config | +--rw description? | +--rw enabled? | +--rw index? +--rw index +--rw openconfig-vlan:vlans +--rw vlan* [vlan-id] +--rw config | +--rw name? | +--rw status? | +--rw vlan-id? +--rw vlan-id ``` -------------------------------- ### to_string Source: https://yangify.readthedocs.io/en/latest/genindex.html Converts the configuration tree to a string representation. ```APIDOC ## Method: to_string ### Description Converts the configuration tree to a string representation. ### Class yangify.translator.config_tree.ConfigTree ``` -------------------------------- ### Import Yangify Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Imports the necessary parser module from the Yangify library. ```python import json from yangify import parser ``` -------------------------------- ### OpenConfig Interfaces Model Structure Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html ASCII tree representation of the `openconfig-interfaces` YANG model, illustrating its hierarchical structure including interfaces, configurations, and subinterfaces. ```text +--rw openconfig-interfaces:interfaces | +--rw interface* [name] | +--rw config | | +--rw description? | | +--rw enabled? | | +--rw loopback-mode? | | +--rw mtu? | | +--rw name? | | +--rw type | +--rw name | +--rw subinterfaces | +--rw subinterface* [index] | +--rw config | | +--rw description? | | +--rw enabled? | | +--rw index? | +--rw index +--rw openconfig-vlan:vlans +--rw vlan* [vlan-id] +--rw config | +--rw name? | +--rw status? | +--rw vlan-id? +--rw vlan-id ``` -------------------------------- ### Interface Configuration Parsing Logic Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Defines how to extract and parse interface configuration details, including name, type, description, and enabled status. ```python from typing import Any, Dict, Iterator, Optional, Tuple, cast from yangify.parser import Parser, ParserData class InterfaceConfig(Parser): """ Implements openconfig-interfaces:interfaces/interface/config """ def description(self) -> Optional[str]: return cast(Optional[str], self.yy.native.get("description", {}).get("#text")) def enabled(self) -> bool: shutdown = self.yy.native.get("shutdown", {}).get("#standalone") if shutdown: return False else: return True def name(self) -> str: return self.yy.key def type(self) -> str: if "Ethernet" in self.yy.key: return "iana-if-type:ethernetCsmacd" elif "Loopback" in self.yy.key: return "iana-if-type:softwareLoopback" else: raise ValueError(f"don't know type for interface {self.yy.key}") def loopback_mode(self) -> bool: if "Loopback" in self.yy.key: return True return False class Interface(Parser): """ Implements openconfig-interfaces:interfaces/interface """ class Yangify(ParserData): def extract_elements(self) -> Iterator[Tuple[str, Dict[str, Any]]]: for interface, data in self.native["show run"]["interface"].items(): if interface == "#text" or "." in interface: continue yield interface, data config = InterfaceConfig def name(self) -> str: return self.yy.key ``` -------------------------------- ### Accessing Candidate Data Source: https://yangify.readthedocs.io/en/latest/api/translator.html Demonstrates how to navigate and retrieve raw values from the candidate data using the TranslatorData.candidate attribute and its goto method. ```python self.candidate.goto(self.path[:-2]).raw_values() ``` -------------------------------- ### Process configuration with default parsing Source: https://yangify.readthedocs.io/en/latest/tutorials/filtering.html Processes the loaded configuration using the custom parser without any filters. The output includes the entire parsed data structure. ```python p = IOSParser(dm, native=config) result = p.process() print(json.dumps(result.raw_value(), indent=4)) ``` -------------------------------- ### Define LLDP Interface Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Implements openconfig-interfaces:interfaces and defines how to extract LLDP interface data from 'show run' commands, skipping specific interfaces like Loopback. ```python class Interfaces(Parser): """ Implements openconfig-interfaces:interfaces """ interface = Interface class LLDPInterface(Parser): class Yangify(ParserData): # While we have LLDP structured data, that is only active # neighbors found from the show lldp neighbors command # This LLDP interface is defined as the following within the model # list interface { # key "name"; # description # "List of interfaces on which LLDP is enabled / available"; # # Because of this, we're using the show run command to build out # the LLDP interfaces accessed in self.native['show run'] again. def extract_elements(self) -> Iterator[Tuple[str, Dict[str, Any]]]: for interface, data in self.native["show run"]["interface"].items(): if interface == "#text": continue no_lldp_config = ( data.get("no", {}) .get("lldp", {}) .get("enable", {}) .get("#standalone") ) if no_lldp_config: continue # skip any interfaces you want to... if interface.startswith("Loop"): continue # `interface` is the interface name like GigabitEthernet1 # `data` is the value of the dictionary from the text tree yield interface, data def name(self) -> str: # self.yy.key is equal to the key being returned # from the tuple in extract_elements return self.yy.key class LLDPInterfaces(Parser): interface = LLDPInterface class LldpConfigState(Parser): def system_name(self): return self.yy.native["show run"]["hostname"]["#text"] class LLdp(Parser): config = LldpConfigState interfaces = LLDPInterfaces ``` -------------------------------- ### SubinterfaceConfig Parser Class Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html Implements parsing for the configuration of a subinterface, extracting the description and index. The index is derived from the key by splitting on '.' and taking the last element. ```python class SubinterfaceConfig(Parser): """ Implements openconfig-interfaces:interfaces/interface/subinterfaces/subinterface/config """ def description(self) -> Optional[str]: return cast(Optional[str], self.yy.native.get("description", {}).get("#text")) def index(self) -> int: return int(self.yy.key.split(".")[-1]) ``` -------------------------------- ### Import LLDP Parser Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Imports necessary classes for parsing LLDP data, including Parser and ParserData from yangify. ```python from typing import Any, Dict, Iterator, Optional, Tuple, cast from yangify.parser import Parser, ParserData ``` -------------------------------- ### Initialize IOSParser with Indented Config Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing.html Subclass `RootParser` and use `parse_indented_config` to load and prepare the native configuration. The `native` attribute is updated with the parsed data. ```python from yangify import parser from yangify.parser.text_tree import parse_indented_config class IOSParser(parser.RootParser): class Yangify(parser.ParserData): def init(self) -> None: self.root_native = parse_indented_config(self.native.splitlines()) self.native = self.root_native interfaces = tutorial_parser.Interfaces ``` -------------------------------- ### Initialize DataModel with Yangson Source: https://yangify.readthedocs.io/en/latest/tutorials/intro.html Initializes a DataModel using yangson, specifying the library data file and paths to YANG modules. This datamodel can be reused across parsers and translators. ```python from yangson.datamodel import DataModel dm = DataModel.from_file("yang/yang-library-data.json", ["yang/yang-modules/ietf", "yang/yang-modules/openconfig"]) ``` -------------------------------- ### Parsing LLDP Data with Validation Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html Demonstrates parsing LLDP data and catching validation errors when required fields are missing. Use this to understand how yangify enforces data model constraints. ```python from yangson.exceptions import SemanticError p = IOSParser(dm, native=data) try: result = p.process(validate=True) print(json.dumps(result.raw_value(), indent=4)) except SemanticError as e: print("Supressing output for readability:") print(f"error: {e}") ``` -------------------------------- ### Deep Copy Running Configuration Source: https://yangify.readthedocs.io/en/latest/tutorials/merging.html Creates a deep copy of the running configuration to modify it as a candidate. This is a common practice before applying changes. ```python candidate = copy.deepcopy(running) vlan_30 = { 'vlan-id': 30, 'config': { 'vlan-id': 30, 'name': 'sales', 'status': 'ACTIVE' } } candidate["openconfig-vlan:vlans"]["vlan"].append(vlan_30) ``` -------------------------------- ### Parse Intended Configuration with Yangify Source: https://yangify.readthedocs.io/en/latest/tutorials/parsing-quickstart/parsing-quickstart.html This Python script reads a configuration file, parses it into a structured text tree using `parse_indented_config`, and prints the result as JSON. Ensure the configuration file exists at the specified path. ```python import json from yangify.parser.text_tree import parse_indented_config with open("../data/ios/ntc-r1/config.txt", "r") as f: config = f.read() parsed_config = parse_indented_config(config.splitlines()) print(json.dumps(parsed_config, indent=4)) ```