• In this example I want to connect to a router in cisco sandbox and get the interface gig1 data.

    If we want to use the Python we should install ncclient library at first with pip install ncclient. on the router netconf ans ssh in enabled. I would also use xmltodict library in order to be able to convert the xml data format to python dictionary. and in order to convert the xml string into xml object I use etree module from lxml library so that we can make an xml object to sent to the device. xml.dom.minidom is for have a pretty view of the xml output.

    from ncclient import manager
    import xmltodict
    from lxml import etree
    import xml.dom.minidom
    

    I am goning to use a dictionary for user credentials here for our test.

    IOS_XE_LAB = {
        "HOST" : "10.10.20.48",
        "PORT" : 830,
        "USER" : "developer",
        "PASS" : "C1sco12345"
    
    }
    

    On order to get, edit, delete or.. we need to specify that. The way to do this is using filter in NETCONF. So for example here we want to get the interface Gig1 of the router. In netconf filter we should specify the Data model (YANG), container and also Module name and .

    filter_str = """
    <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
      <interface>
        <name>GigabitEthernet1</name>
      </interface>
    </interfaces>
    """
    

    Now with this code we are connecting to the device using ncclient Manager module. We are sending the User Credentials to make a Netconf session which is a SSH connection on port 830. Then we are saving the get method output in result. Filter is used as a input in get method.

    with manager.connect(host=IOS_XE_LAB["HOST"], port=IOS_XE_LAB["PORT"], username=IOS_XE_LAB["USER"],
                         password=IOS_XE_LAB["PASS"], hostkey_verify=False) as m:
        # Retrieve the operational data
        result = m.get(filter=('subtree', etree.fromstring(filter_str)))
    
    
        Pretty_xml = xml.dom.minidom.parseString(result.xml).toprettyxml()
    
    print(Pretty_xml)
    
    Output:
    
    <?xml version="1.0" ?>
    <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:ad59644e-b1fb-4b8f-97ca-28847aef11af">
            <data>
                    <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
                            <interface>
                                    <name>GigabitEthernet1</name>
                                    <description>MANAGEMENT INTERFACE - DON'T TOUCH ME</description>
                                    <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">ianaift:ethernetCsmacd</type>
                                    <enabled>true</enabled>
                                    <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
                                            <address>
                                                    <ip>10.10.20.48</ip>
                                                    <netmask>255.255.255.0</netmask>
                                            </address>
                                    </ipv4>
                                    <ipv6 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"/>
                            </interface>
                    </interfaces>
            </data>
    </rpc-reply>
    


    Now if we want to add an ip address on interface Gig 2 and also turn the interface on we can use the same filter but instead of the GET request we should use edit.

    Current Status:
    cat8000v#sh ip int brie
    Interface              IP-Address      OK? Method Status                Protocol
    GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
    GigabitEthernet2       unassigned      YES NVRAM  administratively down down
    GigabitEthernet3       unassigned      YES NVRAM  administratively down down
    Loopback0              10.0.0.1        YES NVRAM  up                    up
    Loopback10             unassigned      YES unset  up                    up
    Loopback109            10.255.255.9    YES NVRAM  up                    up
    VirtualPortGroup0      192.168.1.1     YES NVRAM  up                    up
    
    
    config_payload = """
    <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>GigabitEthernet2</name>
          <enabled>true</enabled>
          <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
            <address>
              <ip>1.1.1.1</ip>
              <netmask>255.255.255.0</netmask>
            </address>
          </ipv4>
        </interface>
      </interfaces>
    </config>
    """
    
    with manager.connect(host=IOS_XE_LAB["HOST"], port=IOS_XE_LAB["PORT"], username=IOS_XE_LAB["USER"],
                         password=IOS_XE_LAB["PASS"], hostkey_verify=False) as m:
        # Retrieve the operational data
        result = m.edit_config(target="running", config=config_payload)
    

    As you can see this time we are using edit_config method to edit the running configuration based on the config payload. hostkey_verify=False is for not asking the ssh key verification when it wants to do ssh.

    Output:
    
    <?xml version="1.0" ?>
    <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:7e3b35f5-21d7-4a19-9310-22a6b6023aa5">
            <ok/>
    </rpc-reply>
    
    On the router:
    
    *Jan 31 11:22:58.393: %SYS-5-CONFIG_P: Configured programmatically by process io                               sp_dmiauthd_conn_100001_vty_100001 from console as developer on vty4294966926
    *Jan 31 11:22:58.379: %DMI-5-CONFIG_I: R0/0: dmiauthd: Configured from NETCONF/R                               ESTCONF by developer, transaction-id 25
    cat8000v#
    
    cat8000v#sh ip int brie
    Interface              IP-Address      OK? Method Status                Protocol
    GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
    GigabitEthernet2       1.1.1.1         YES other  down                  down
    GigabitEthernet3       unassigned      YES NVRAM  administratively down down
    Loopback0              10.0.0.1        YES NVRAM  up                    up
    Loopback10             unassigned      YES unset  up                    up
    Loopback109            10.255.255.9    YES NVRAM  up                    up
    VirtualPortGroup0      192.168.1.1     YES NVRAM  up                    up
    cat8000v#
    
    

    With the same code and the config below we can set the secondary IP address on the interface:

    config_payload = """
    <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>GigabitEthernet2</name>
          <enabled>true</enabled>
    
          <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
            <!-- Primary IP -->
            <address>
              <ip>1.1.1.1</ip>
              <netmask>255.255.255.0</netmask>
            </address>
    
            <!-- Secondary IP (2nd address on same interface) -->
            <address>
              <ip>2.2.2.2</ip>
              <netmask>255.255.255.0</netmask>
            </address>
          </ipv4>
    
        </interface>
      </interfaces>
    </config>
    """
    
    Output:
    <?xml version="1.0" ?>
    <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:847272bd-10da-4b73-8cf0-a5183300f27b">
            <ok/>
    </rpc-reply>
    
    and on the router:
    cat8000v#
    *Jan 31 11:31:35.734: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User 'developer' authenticated successfully from 192.168.254.11:52608  for netconf over ssh. External groups: PRIV15
    *Jan 31 11:31:37.484: %SYS-5-CONFIG_P: Configured programmatically by process iosp_dmiauthd_conn_100001_vty_100001 from console as developer on vty4294966926
    *Jan 31 11:31:37.476: %DMI-5-CONFIG_I: R0/0: dmiauthd: Configured from NETCONF/RESTCONF by developer, transaction-id 37
    cat8000v#
    cat8000v#sh run int GigabitEthernet2
    Building configuration...
    
    Current configuration : 161 bytes
    !
    interface GigabitEthernet2
     description Network Interface
     ip address 2.2.2.2 255.255.255.0 secondary
     ip address 1.1.1.1 255.255.255.0
     negotiation auto
    end
    
    cat8000v#
    
    

    If we want to delete the secodary IP address we can use the operation in xml code:

    config_payload = """
    <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>GigabitEthernet2</name>
          <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
            <address nc:operation="delete"
                     xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
              <ip>2.2.2.2</ip>
              <netmask>255.255.255.0</netmask>
            </address>
          </ipv4>
        </interface>
      </interfaces>
    </config>
    """
    
    
    

    We can also get the Data from the user, for example to creating a new loop back, we can use input function and save the Data then with format method insert them in the xml string.

    
    # ---- Ask user for values ----
    loop_num = input("Which Loopback number to add? (e.g. 10): ").strip()
    desc = input("Description (optional): ").strip()
    ip_addr = input("IPv4 address (e.g. 10.10.10.10): ").strip()
    mask = input("Netmask (e.g. 255.255.255.255): ").strip()
    
    
    # XML template with placeholders (similar to your screenshot)
    netconf_interface_template = """
    <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
      <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>{name}</name>
    
          <!-- REQUIRED for new interfaces -->
          <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
            ianaift:softwareLoopback
          </type>
    
          <description>{desc}</description>
          <enabled>true</enabled>
    
          <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
            <address>
              <ip>{ip}</ip>
              <netmask>{mask}</netmask>
            </address>
          </ipv4>
        </interface>
      </interfaces>
    </config>
    """
    
    # Build the final XML payload
    payload = netconf_interface_template.format(
        name=f"Loopback{loop_num}",
        desc=desc,
        enabled="true",
        ip=ip_addr,
        mask=mask
    )
    
    
    Output:
    
    Which Loopback number to add? (e.g. 10): 11
    Description (optional): 11
    IPv4 address (e.g. 10.10.10.10): 11.11.11.11
    Netmask (e.g. 255.255.255.255): 255.255.255.0
    <?xml version="1.0" ?>
    <rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:0d1140cd-3456-4ad7-b2f4-59dfcb96dd72">
            <ok/>
    </rpc-reply>
    
    
    *Jan 31 12:00:05.129: %DMI-5-AUTH_PASSED: R0/0: dmiauthd: User 'developer' authenticated successfully from 192.168.254.11:53103  for netconf over ssh. External groups: PRIV15
    *Jan 31 12:00:07.465: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback11, changed state to up
    *Jan 31 12:00:07.497: %SYS-5-CONFIG_P: Configured programmatically by process iosp_dmiauthd_conn_100001_vty_100001 from console as developer on vty4294966926
    *Jan 31 12:00:07.484: %DMI-5-CONFIG_I: R0/0: dmiauthd: Configured from NETCONF/RESTCONF by developer, transaction-id 45
    cat8000v#
    cat8000v#
    cat8000v#sh ip int brie
    Interface              IP-Address      OK? Method Status                Protocol
    GigabitEthernet1       10.10.20.48     YES NVRAM  up                    up
    GigabitEthernet2       1.1.1.1         YES other  up                    up
    GigabitEthernet3       unassigned      YES NVRAM  administratively down down
    Loopback0              10.0.0.1        YES NVRAM  up                    up
    Loopback10             unassigned      YES unset  up                    up
    Loopback11             11.11.11.11     YES other  up                    up
    Loopback109            10.255.255.9    YES NVRAM  up                    up
    
    
    
    

    With shh on port 830 we can sent/receive the xml config file to the device.

    ssh -s developer@10.10.20.48 -p 830 netconf
    after 
    ]]>]]> 
    we can paste the xml string.
    
    <rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101">
      <edit-config>
        <target>
          <running/>
        </target>
        <config>
          <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
            <interface>
              <name>Loopback11</name>
    
              <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type">
                ianaift:softwareLoopback
              </type>
    
              <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip">
                <address>
                  <ip>22.22.22.22</ip>
                  <netmask>255.255.255.255</netmask>
                </address>
              </ipv4>
    
            </interface>
          </interfaces>
        </config>
      </edit-config>
    </rpc>
    ]]>]]>
    
    
  • YANG (Yet Another Next Generation) is a data modeling language used to describe the structure and configuration of network devices. A data model is a well understood and agreed upon method to describe something.

    Data models may describe some aspect of a network device, or a network service. Network servies like Interface, vlan,OSPF.. and Network services like VRF, ACL..

    It does not configure devices directly, but defines how configuration and state data are structured, so tools like NETCONF / RESTCONF /grpc can read or modify them in a standardized way.

    Simple YANG Example
    module simple-interface {
      namespace "urn:example:interface";
      prefix if;
    
      container interfaces {
        list interface {
          key "name";
    
          leaf name {
            type string;
          }
    
          leaf description {
            type string;
          }
    
          leaf enabled {
            type boolean;
            default true;
          }
    
          leaf ip-address {
            type string;
          }
        }
      }
    }
    
    

    This means: A device has interfaces, Each interface has: name, description, enabled / disabled and IP address.

    You can find the Yang data model here: https://github.com/YangModels/yang

    There are standard and also vendor base Yang data models.

    Core YANG Concepts

    A module is the top-level file in YANG. Everything lives inside a module. Think of it as: A project folder that contains everything related to this model.

    module router-config {
      namespace "urn:example:router";
      prefix rt;
    
    

    A container groups related configuration items. For example here this container holds all interface-related data.

    container interfaces {
    

    A list is used when something can appear multiple times(e.g., multiple interfaces). GigabitEthernet0/0, GigabitEthernet0/1, Loopback0, Each one is an entry in this list.

    list interface {
      key "name";
    
    

    A leaf holds one value only. for example name = "GigabitEthernet0/0", ip-address = "192.168.1.1" ,enabled = true

    leaf name {
      type string;
    }
    
    leaf ip-address {
      type string;
    }
    
    leaf enabled {
      type boolean;
    }
    
    

    A leaf-list holds multiple values of the same type. Unlike list, it has no keys, only values.

    leaf-list dns-servers {
      type string;
    }
    
    

    typedef is used to define reusable data types.

    typedef ipv4-address {
      type string {
        pattern "([0-9]{1,3}\\.){3}[0-9]{1,3}";
      }
    }
    
    

    rpc Remote Procedure Call is for actions, not configuration. For example Reset interface, clear counters..

    rpc restart-interface {
      input {
        leaf name {
          type string;
        }
      }
    }
    
    
    Full Example:
    module router-config {
      namespace "urn:example:router";
      prefix rt;
    
      typedef ipv4-address {
        type string;
      }
    
      container interfaces {
        list interface {
          key "name";
    
          leaf name {
            type string;
          }
    
          leaf ip-address {
            type ipv4-address;
          }
    
          leaf enabled {
            type boolean;
          }
        }
      }
    
      rpc restart-interface {
        input {
          leaf name {
            type string;
          }
        }
      }
    
      notification interface-down {
        leaf name {
          type string;
        }
      }
    }
    
    

    We can also open a yang file with pyang in linux, so we can have a better look:

    $pyang -f tree router-config.yang
    module: router-config
      +--rw interfaces
         +--rw interface* [name]
            +--rw name          string
            +--rw ip-address   ipv4-address
            +--rw enabled      boolean
      +---x restart-interface
         +--rw input
            +--rw name   string
      +---n interface-down
         +--rw name   string
    
    
  • Jinja2 is a template processing toolkit which allows us to create and render text templates.
    It is a text based templating system. It renders a template using variable replacement, tags (conditional, lopping, inheritance, macros) and filters.

    In this example, I will use Jinja2 to automatically generate a network switch configuration file.

    Folder and file Structure
    project/
    │
    ├── render_config.py
    ├── templates/
    │   └── switch_interfaces.j2
    └── output/
    
    
    Jinja2 Template
    hostname {{ hostname }}
    
    {% for intf in interfaces %}
    interface {{ intf.name }}
     description {{ intf.desc }}
     switchport mode {{ intf.mode }}
    {% if intf.vlan is defined %}
     switchport access vlan {{ intf.vlan }}
    spanning-tree portfast
    {% endif %}
    !
    {% endfor %}
    
    

    {{ hostname }} is replaced with a value from Python. for example if hostname = "SW-BR-01", the output becomes:

    hostname SW-BR-01
    
    For Loop ({% for %})
    {% for intf in interfaces %}
    ...
    {% endfor %}
    
    

    This loop Iterates over a list of interfaces and replace the block once for each interface. we can also have loops in Python code. but I think the loops and Conditions in jibja2 templates are better because they are simple and also we can use the same template with Ansible too.

    Conditional Logic ({% if %})
    {% if intf.vlan is defined %}
     switchport access vlan {{ intf.vlan }}
    {% endif %}
    
    

    This means only add the VLAN line if the VLAN exists and prevents invalid configs for trunk ports.

    Python Script
    # you should install Jinja2 module firs: ~ python -m pip install jinja2 
    
    from jinja2 import Environment, FileSystemLoader
    
    data = {
        "hostname": "SW-BR-01",
        "interfaces": [
            {"name": "GigabitEthernet1/0/1", "desc": "POS terminal", "mode": "access", "vlan": 10},
            {"name": "GigabitEthernet1/0/2", "desc": "Printer", "mode": "access", "vlan": 20},
            {"name": "GigabitEthernet1/0/48", "desc": "Uplink to core", "mode": "trunk"},
        ],
    }
    
    env = Environment(
        loader=FileSystemLoader("templates"),  # tells Jinja where templates are
        trim_blocks=True,  #removes empty lines
        lstrip_blocks=True  #cleans indentation
    )
    
    template = env.get_template("switch_interfaces.j2")
    
    rendered = template.render(data)  #Replaces variables, executes loops+conditions & Produces result
    
    with open("output/SW-BR-01.cfg", "w") as f:
        f.write(rendered)
    
    print("Configuration generated successfully.")
    
    
    Output
    hostname SW-BR-01
    
    interface GigabitEthernet1/0/1
     description POS terminal
     switchport mode access
     switchport access vlan 10
     spanning-tree portfast
    !
    interface GigabitEthernet1/0/2
     description Printer
     switchport mode access
     switchport access vlan 20
     spanning-tree portfast
    !
    interface GigabitEthernet1/0/48
     description Uplink to core
     switchport mode trunk
    !
    
    
  • XML (eXtensible Markup Language) is a data format used to store and exchange structured data. Unlike JSON and YAML, XML uses tags to define data. It also works with YANG models.

    XML Syntax

    XML uses opening and closing tags to describe data.

    Basic Rules:

    Data is stored between tags

    Every tag must have a closing tag

    Tags are case-sensitive

    Elements must be properly nested

    Attributes are optional

    XML Element

    An XML element is the basic building block of XML.

    <hostname>R1</hostname>
    

    <hostname> → opening tag

    R1 → value

    </hostname> → closing tag

    XML Attributes

    Attributes provide additional information inside a tag. Attributes are optional and Values must be in quotes.

    <interface name="GigabitEthernet0/1" status="up">
      <ip>192.168.1.1</ip>
    </interface>
    
    
    XML Nested Structures

    Like JSON and YAML, XML supports nested structures.

    <device>
      <hostname>SW1</hostname>
      <interfaces>
        <interface>
          <name>GigabitEthernet0/1</name>
          <ip>192.168.1.1</ip>
          <vlan>10</vlan>
        </interface>
        <interface>
          <name>GigabitEthernetnet0/2</name>
          <ip>192.168.2.1</ip>
          <vlan>20</vlan>
        </interface>
      </interfaces>
    </device>
    
    
    XML List (Array of Objects)

    XML does not have arrays explicitly, but repeated tags act like lists.

    <interfaces>
      <interface>
        <name>GigabitEthernet0/1</name>
      </interface>
      <interface>
        <name>GigabitEthernet0/2</name>
      </interface>
    </interfaces>
    
    
    Converting XML into Python dictionary

    If we want to convert the XML code into Python dict. we can use xmltodict library. Here is a sample XML file:

    <?xml version="1.0" encoding="UTF-8"?>
    <interfaces xmlns="ietf-interfaces">
      <interface>
        <name>GigabitEthernet2</name>
        <description>Wide Area Network</description>
        <enabled>true</enabled>
        <ipv4>
          <address>
            <ip>172.16.0.2</ip>
            <netmask>255.255.255.0</netmask>
          </address>
        </ipv4>
      </interface>
    
      <interface>
        <name>GigabitEthernet3</name>
        <description>LAN Users</description>
        <enabled>true</enabled>
        <ipv4>
          <address>
            <ip>10.10.10.1</ip>
            <netmask>255.255.255.0</netmask>
          </address>
        </ipv4>
      </interface>
    
      <interface>
        <name>Loopback0</name>
        <description>Router-ID</description>
        <enabled>true</enabled>
        <ipv4>
          <address>
            <ip>192.0.2.1</ip>
            <netmask>255.255.255.255</netmask>
          </address>
        </ipv4>
      </interface>
    </interfaces>
    
    
    #Install xmltodict with pip
    
    import xmltodict
    from pprint import pprint
    
    xml_example = open ("xml_example.xml").read()
    
    xml_dict = xmltodict.parse(xml_example)
    
    pprint(xml_dict)
    
    Output:
    
    {'interfaces': {'@xmlns': 'ietf-interfaces',
    'interface': [{'description': 'Wide Area Network',
    'enabled': 'true',
    'ipv4': {'address': {'ip': '172.16.0.2',
    'netmask': '255.255.255.0'}},
    'name': 'GigabitEthernet2'},
    {'description': 'LAN Users',
    'enabled': 'true',
    'ipv4': {'address': {'ip': '10.10.10.1',
    'netmask': '255.255.255.0'}},
    'name': 'GigabitEthernet3'},
    {'description': 'Router-ID',
    'enabled': 'true',
    'ipv4': {'address': {'ip': '192.0.2.1',
    'netmask': '255.255.255.255'}},
    'name': 'Loopback0'}]}}
    
  • YAML (YAML Ain’t Markup Language) is a human-readable data format widely used in network automation. Compared to JSON, YAML is easier to read and write, especially for large configurations.

    YAML Syntax

    YAML uses indentation instead of brackets to define structure.

    Key Rules:

    Case-sensitive

    Indentation is very important

    No { } or [ ]

    Uses : for key–value pairs

    Spaces are required (tabs are not allowed)

    YAML Mapping (Key–Value Structure)

    A mapping in YAML is similar to:

    An object in JSON

    A dictionary in Python

    device:
      hostname: SW1
      model: Cisco Catalyst 9300
      location: DataCenter-1
    
    
    YAML Sequence (List)

    A sequence is a list of values.
    Each item starts with a dash (-).

    interfaces:
      - GigabitEthernet0/0
      - GigabitEthernet0/1
      - GigabitEthernet0/2
    
    

    YAML Array of Objects

    This is one of the most important YAML structures for automation.

    Each list item is a full object.

    devices:
      - hostname: R1
        ip: 10.1.1.1
        role: core
      - hostname: R2
        ip: 10.1.1.2
        role: access
    
    

    YAML Nested Structures (Very Important)

    Nested YAML is used in real network configurations.

    device:
      hostname: SW1
      interfaces:
        - name: GigabitEthernet0/1
          ip: 192.168.1.1
          vlan: 10
        - name: GigabitEthernet0/2
          ip: 192.168.2.1
          vlan: 20
      routing:
        ospf:
          process_id: 1
          area: 0
    
    
    device
     ├── hostname
     ├── interfaces (list)
     │    ├── interface 1
     │    └── interface 2
     └── routing
          └── ospf
    
    
    Converting Yaml into Python dict.
    interfaces:
      interface:
        - name: GigabitEthernet2
          description: Wide Area Network
          enabled: true
          ipv4:
            address:
              ip: 172.16.0.2
              netmask: 255.255.255.0
    
        - name: GigabitEthernet3
          description: LAN Users
          enabled: true
          ipv4:
            address:
              ip: 10.10.10.1
              netmask: 255.255.255.0
    
        - name: Loopback0
          description: Router-ID
          enabled: true
          ipv4:
            address:
              ip: 192.0.2.1
              netmask: 255.255.255.255
    
    
    #pip install pyyaml
    import yaml
    from pprint import pprint
    
    with open("yaml_example.yaml", "r") as f:
        yaml_dict = yaml.safe_load(f)
    
    
    pprint(yaml_dict)
    
    
    
    Output:
    {'interfaces': {'interface': [{'description': 'Wide Area Network',
                                   'enabled': True,
                                   'ipv4': {'address': {'ip': '172.16.0.2',
                                                        'netmask': '255.255.255.0'}},
                                   'name': 'GigabitEthernet2'},
                                  {'description': 'LAN Users',
                                   'enabled': True,
                                   'ipv4': {'address': {'ip': '10.10.10.1',
                                                        'netmask': '255.255.255.0'}},
                                   'name': 'GigabitEthernet3'},
                                  {'description': 'Router-ID',
                                   'enabled': True,
                                   'ipv4': {'address': {'ip': '192.0.2.1',
                                                        'netmask': '255.255.255.255'}},
                                   'name': 'Loopback0'}]}}
    
  • JSON (JavaScript Object Notation) is one of the most important data formats in modern networking.
    It is widely used in REST APIs, SD-WAN controllers, automation tools, and network management systems.

    In lists, we can have multiple entries that are indexed starting from 0 up to n.
    Access to list elements is based on their index number.

    Another data type is the dictionary, which uses a key–value structure instead of indexes.

    JSON follows the same key–value concept as dictionaries. We can access values using their keys, but we cannot directly access a key if we only know the value.

    JSON Syntax

    JSON uses key–value pairs.

    Rules:
    • Keys must be in double quotes
    • Values can be:
      • String
      • Number
      • Boolean
      • Object
      • Array
    • Objects use { }
    • Arrays use [ ]
    
    
    
    
    
    JSON Object

    A JSON object represents a single entity.

    Similar to a Python dictionary
    Commonly used to describe a device or configuration block.

    {
      "device": "SW1",
      "model": "Cisco Catalyst 9300",
      "mgmt_ip": "192.168.10.10",
      "location": "DataCenter-1"
    }
    
    JSON Array

    A JSON array is a list of values.

    [
      "GigabitEthernet0/0",
      "GigabitEthernet0/1",
      "GigabitEthernet0/2"
    ]
    or
    [
      "10.0.0.1",
      "10.0.0.2",
      "10.0.0.3"
    ]
    
    JSON Array of Objects

    This is one of the most important structures in networking automation.

    It represents multiple devices or interfaces.

    [
      {
        "hostname": "R1",
        "ip": "10.1.1.1",
        "role": "core"
      },
      {
        "hostname": "R2",
        "ip": "10.1.1.2",
        "role": "distribution"
      }
    ]
    
    Nested JSON Structures

    Nested JSON means:

    • Objects inside objects
    • Arrays inside objects
    • Objects inside arrays
    Example:
    {
      "device": {
        "hostname": "SW1",
        "interfaces": [
          {
            "name": "GigabitEthernet0/1",
            "ip": "192.168.1.1",
            "vlan": 10
          },
          {
            "name": "GigabitEthernet0/2",
            "ip": "192.168.2.1",
            "vlan": 20
          }
        ],
        "routing": {
          "ospf": {
            "process_id": 1,
            "area": 0
          }
        }
      }
    }
    
    device
     ├── hostname
     ├── interfaces (array)
     │         ├── interface 1
     │         └── interface 2
     └── routing
                └── ospf
    
    Converting Json into dict in Python

    here is an example of Json which I want to converting to dict in python. We should use Json library for that.

    {
      "interfaces": {
        "interface": [
          {
            "name": "GigabitEthernet2",
            "description": "Wide Area Network",
            "enabled": true,
            "ipv4": {
              "address": {
                "ip": "172.16.0.2",
                "netmask": "255.255.255.0"
              }
            }
          },
          {
            "name": "GigabitEthernet3",
            "description": "LAN Users",
            "enabled": true,
            "ipv4": {
              "address": {
                "ip": "10.10.10.1",
                "netmask": "255.255.255.0"
              }
            }
          },
          {
            "name": "Loopback0",
            "description": "Router-ID",
            "enabled": true,
            "ipv4": {
              "address": {
                "ip": "192.0.2.1",
                "netmask": "255.255.255.255"
              }
            }
          }
        ]
      }
    }
    
    
    #Python code:
    
    import json
    
    from pprint import pprint
    
    jason_example = open("Json_example.json").read()
    
    jason_dict = json.loads(jason_example)
    
    pprint (jason_dict)
    

    Output:
    {'interfaces': {'interface': [{'description': 'Wide Area Network',
                                   'enabled': True,
                                   'ipv4': {'address': {'ip': '172.16.0.2',
                                                        'netmask': '255.255.255.0'}},
                                   'name': 'GigabitEthernet2'},
                                  {'description': 'LAN Users',
                                   'enabled': True,
                                   'ipv4': {'address': {'ip': '10.10.10.1',
                                                        'netmask': '255.255.255.0'}},
                                   'name': 'GigabitEthernet3'},
                                  {'description': 'Router-ID',
                                   'enabled': True,
                                   'ipv4': {'address': {'ip': '192.0.2.1',
                                                        'netmask': '255.255.255.255'}},
                                   'name': 'Loopback0'}]}}