Basics

Let's start with some basics, we will use the following objects as the base for the rest of the tutorial.


In [1]:
from napalm import get_network_driver
import napalm_yang

import json

def use_mock_devices():
    junos_configuration = {
        'hostname': '127.0.0.1',
        'username': 'vagrant',
        'password': '',
        'optional_args': {'path': "./junos_mock/", 'profile': ['junos'],
                          'increase_count_on_error': False}
    }

    eos_configuration = {
        'hostname': '127.0.0.1',
        'username': 'vagrant',
        'password': 'vagrant',
        'optional_args': {'path': "./eos_mock", 'profile': ['eos'],
                          'increase_count_on_error': False}
    }

    junos = get_network_driver("mock")
    junos_device = junos(**junos_configuration)

    eos = get_network_driver("mock")
    eos_device = eos(**eos_configuration)
    return junos_device, eos_device

def use_real_devices():
    junos_configuration = {
        'hostname': '127.0.0.1',
        'username': 'vagrant',
        'password': '',
        'optional_args': {'port': 12203, 'config_lock': False}
    }

    eos_configuration = {
        'hostname': '127.0.0.1',
        'username': 'vagrant',
        'password': 'vagrant',
        'optional_args': {'port': 12443}
    }

    junos = get_network_driver("junos")
    junos_device = junos(**junos_configuration)
    junos_device.open()

    eos = get_network_driver("eos")
    eos_device = eos(**eos_configuration)
    eos_device.open()
    return junos_device, eos_device

def pretty_print(dictionary):
    print(json.dumps(dictionary, sort_keys=True, indent=4))

# Use real devices on your lab, tweak config
# junos_device, eos_device = use_real_devices()

# Use mocked devices intended for this test
junos_device, eos_device = use_mock_devices()

Creating a Binding

To work with YANG models you first create a root object with napalm_yang.base.Root() and then you add as many models as you want with the add_model method:


In [2]:
config = napalm_yang.base.Root()

# Adding models to the object
config.add_model(napalm_yang.models.openconfig_interfaces())
config.add_model(napalm_yang.models.openconfig_vlan())

At this point, you can use the "util" model_to_dict() to visualize the binding and the attached models:


In [3]:
# Printing the model in a human readable format
pretty_print(napalm_yang.utils.model_to_dict(config))


{
    "openconfig-interfaces:interfaces [rw]": {
        "interface [rw]": {
            "config [rw]": {
                "description [rw]": "string", 
                "enabled [rw]": "boolean", 
                "mtu [rw]": "uint16", 
                "name [rw]": "string", 
                "type [rw]": "identityref"
            }, 
            "hold_time [rw]": {
                "config [rw]": {
                    "down [rw]": "uint32", 
                    "up [rw]": "uint32"
                }, 
                "state [rw]": {
                    "down [ro]": "uint32", 
                    "up [ro]": "uint32"
                }
            }, 
            "name [rw]": "leafref", 
            "openconfig-if-aggregate:aggregation [rw]": {
                "config [rw]": {
                    "lag_type [rw]": "aggregation-type", 
                    "min_links [rw]": "uint16"
                }, 
                "openconfig-vlan:switched_vlan [rw]": {
                    "config [rw]": {
                        "access_vlan [rw]": "union", 
                        "interface_mode [rw]": "oc-vlan-types:vlan-mode-type", 
                        "native_vlan [rw]": "union", 
                        "trunk_vlans [rw]": "union"
                    }, 
                    "state [rw]": {
                        "access_vlan [ro]": "union", 
                        "interface_mode [ro]": "oc-vlan-types:vlan-mode-type", 
                        "native_vlan [ro]": "union", 
                        "trunk_vlans [ro]": "union"
                    }
                }, 
                "state [rw]": {
                    "lag_speed [ro]": "uint32", 
                    "lag_type [ro]": "aggregation-type", 
                    "member [ro]": "oc-if:base-interface-ref", 
                    "min_links [ro]": "uint16"
                }
            }, 
            "openconfig-if-ethernet:ethernet [rw]": {
                "config [rw]": {
                    "auto_negotiate [rw]": "boolean", 
                    "duplex_mode [rw]": "enumeration", 
                    "enable_flow_control [rw]": "boolean", 
                    "mac_address [rw]": "yang:mac-address", 
                    "openconfig-if-aggregate:aggregate_id [rw]": "leafref", 
                    "port_speed [rw]": "identityref"
                }, 
                "openconfig-vlan:switched_vlan [rw]": {
                    "config [rw]": {
                        "access_vlan [rw]": "union", 
                        "interface_mode [rw]": "oc-vlan-types:vlan-mode-type", 
                        "native_vlan [rw]": "union", 
                        "trunk_vlans [rw]": "union"
                    }, 
                    "state [rw]": {
                        "access_vlan [ro]": "union", 
                        "interface_mode [ro]": "oc-vlan-types:vlan-mode-type", 
                        "native_vlan [ro]": "union", 
                        "trunk_vlans [ro]": "union"
                    }
                }, 
                "state [rw]": {
                    "auto_negotiate [ro]": "boolean", 
                    "counters [ro]": {
                        "in_8021q_frames [ro]": "yang:counter64", 
                        "in_crc_errors [ro]": "yang:counter64", 
                        "in_fragment_frames [ro]": "yang:counter64", 
                        "in_jabber_frames [ro]": "yang:counter64", 
                        "in_mac_control_frames [ro]": "yang:counter64", 
                        "in_mac_pause_frames [ro]": "yang:counter64", 
                        "in_oversize_frames [ro]": "yang:counter64", 
                        "out_8021q_frames [ro]": "yang:counter64", 
                        "out_mac_control_frames [ro]": "yang:counter64", 
                        "out_mac_pause_frames [ro]": "yang:counter64"
                    }, 
                    "duplex_mode [ro]": "enumeration", 
                    "effective_speed [ro]": "uint32", 
                    "enable_flow_control [ro]": "boolean", 
                    "hw_mac_address [ro]": "yang:mac-address", 
                    "mac_address [ro]": "yang:mac-address", 
                    "negotiated_duplex_mode [ro]": "enumeration", 
                    "negotiated_port_speed [ro]": "identityref", 
                    "openconfig-if-aggregate:aggregate_id [ro]": "leafref", 
                    "port_speed [ro]": "identityref"
                }
            }, 
            "openconfig-vlan:routed_vlan [rw]": {
                "config [rw]": {
                    "vlan [rw]": "union"
                }, 
                "openconfig-if-ip:ipv4 [rw]": {
                    "addresses [rw]": {
                        "address [rw]": {
                            "config [rw]": {
                                "ip [rw]": "inet:ipv4-address-no-zone", 
                                "napalm-if-ip:secondary [rw]": "boolean", 
                                "prefix_length [rw]": "uint8"
                            }, 
                            "ip [rw]": "leafref", 
                            "state [rw]": {
                                "ip [ro]": "inet:ipv4-address-no-zone", 
                                "origin [ro]": "ip-address-origin", 
                                "prefix_length [ro]": "uint8"
                            }, 
                            "vrrp [rw]": {
                                "vrrp_group [rw]": {
                                    "config [rw]": {
                                        "accept_mode [rw]": "boolean", 
                                        "advertisement_interval [rw]": "uint16", 
                                        "preempt [rw]": "boolean", 
                                        "preempt_delay [rw]": "uint16", 
                                        "priority [rw]": "uint8", 
                                        "virtual_address [rw]": "inet:ip-address", 
                                        "virtual_router_id [rw]": "uint8"
                                    }, 
                                    "interface_tracking [rw]": {
                                        "config [rw]": {
                                            "priority_decrement [rw]": "uint8", 
                                            "track_interface [rw]": "leafref"
                                        }, 
                                        "state [rw]": {
                                            "priority_decrement [ro]": "uint8", 
                                            "track_interface [ro]": "leafref"
                                        }
                                    }, 
                                    "state [rw]": {
                                        "accept_mode [ro]": "boolean", 
                                        "advertisement_interval [ro]": "uint16", 
                                        "current_priority [ro]": "uint8", 
                                        "preempt [ro]": "boolean", 
                                        "preempt_delay [ro]": "uint16", 
                                        "priority [ro]": "uint8", 
                                        "virtual_address [ro]": "inet:ip-address", 
                                        "virtual_router_id [ro]": "uint8"
                                    }, 
                                    "virtual_router_id [rw]": "leafref"
                                }
                            }
                        }
                    }, 
                    "config [rw]": {
                        "enabled [rw]": "boolean", 
                        "mtu [rw]": "uint16"
                    }, 
                    "neighbors [rw]": {
                        "neighbor [rw]": {
                            "config [rw]": {
                                "ip [rw]": "inet:ipv4-address-no-zone", 
                                "link_layer_address [rw]": "yang:phys-address"
                            }, 
                            "ip [rw]": "leafref", 
                            "state [rw]": {
                                "ip [ro]": "inet:ipv4-address-no-zone", 
                                "link_layer_address [ro]": "yang:phys-address", 
                                "origin [ro]": "neighbor-origin"
                            }
                        }
                    }, 
                    "state [rw]": {
                        "enabled [ro]": "boolean", 
                        "mtu [ro]": "uint16"
                    }, 
                    "unnumbered [rw]": {
                        "config [rw]": {
                            "enabled [rw]": "boolean"
                        }, 
                        "interface_ref [rw]": {
                            "config [rw]": {
                                "interface [rw]": "leafref", 
                                "subinterface [rw]": "leafref"
                            }, 
                            "state [rw]": {
                                "interface [ro]": "leafref", 
                                "subinterface [ro]": "leafref"
                            }
                        }, 
                        "state [rw]": {
                            "enabled [ro]": "boolean"
                        }
                    }
                }, 
                "openconfig-if-ip:ipv6 [rw]": {
                    "addresses [rw]": {
                        "address [rw]": {
                            "config [rw]": {
                                "ip [rw]": "inet:ipv6-address-no-zone", 
                                "prefix_length [rw]": "uint8"
                            }, 
                            "ip [rw]": "leafref", 
                            "state [rw]": {
                                "ip [ro]": "inet:ipv6-address-no-zone", 
                                "origin [ro]": "ip-address-origin", 
                                "prefix_length [ro]": "uint8", 
                                "status [ro]": "enumeration"
                            }, 
                            "vrrp [rw]": {
                                "vrrp_group [rw]": {
                                    "config [rw]": {
                                        "accept_mode [rw]": "boolean", 
                                        "advertisement_interval [rw]": "uint16", 
                                        "preempt [rw]": "boolean", 
                                        "preempt_delay [rw]": "uint16", 
                                        "priority [rw]": "uint8", 
                                        "virtual_address [rw]": "inet:ip-address", 
                                        "virtual_link_local [rw]": "inet:ip-address", 
                                        "virtual_router_id [rw]": "uint8"
                                    }, 
                                    "interface_tracking [rw]": {
                                        "config [rw]": {
                                            "priority_decrement [rw]": "uint8", 
                                            "track_interface [rw]": "leafref"
                                        }, 
                                        "state [rw]": {
                                            "priority_decrement [ro]": "uint8", 
                                            "track_interface [ro]": "leafref"
                                        }
                                    }, 
                                    "state [rw]": {
                                        "accept_mode [ro]": "boolean", 
                                        "advertisement_interval [ro]": "uint16", 
                                        "current_priority [ro]": "uint8", 
                                        "preempt [ro]": "boolean", 
                                        "preempt_delay [ro]": "uint16", 
                                        "priority [ro]": "uint8", 
                                        "virtual_address [ro]": "inet:ip-address", 
                                        "virtual_link_local [ro]": "inet:ip-address", 
                                        "virtual_router_id [ro]": "uint8"
                                    }, 
                                    "virtual_router_id [rw]": "leafref"
                                }
                            }
                        }
                    }, 
                    "config [rw]": {
                        "dup_addr_detect_transmits [rw]": "uint32", 
                        "enabled [rw]": "boolean", 
                        "mtu [rw]": "uint32"
                    }, 
                    "neighbors [rw]": {
                        "neighbor [rw]": {
                            "config [rw]": {
                                "ip [rw]": "inet:ipv6-address-no-zone", 
                                "link_layer_address [rw]": "yang:phys-address"
                            }, 
                            "ip [rw]": "leafref", 
                            "state [rw]": {
                                "ip [ro]": "inet:ipv6-address-no-zone", 
                                "is_router [ro]": "empty", 
                                "link_layer_address [ro]": "yang:phys-address", 
                                "neighbor_state [ro]": "enumeration", 
                                "origin [ro]": "neighbor-origin"
                            }
                        }
                    }, 
                    "state [rw]": {
                        "dup_addr_detect_transmits [ro]": "uint32", 
                        "enabled [ro]": "boolean", 
                        "mtu [ro]": "uint32"
                    }, 
                    "unnumbered [rw]": {
                        "config [rw]": {
                            "enabled [rw]": "boolean"
                        }, 
                        "interface_ref [rw]": {
                            "config [rw]": {
                                "interface [rw]": "leafref", 
                                "subinterface [rw]": "leafref"
                            }, 
                            "state [rw]": {
                                "interface [ro]": "leafref", 
                                "subinterface [ro]": "leafref"
                            }
                        }, 
                        "state [rw]": {
                            "enabled [ro]": "boolean"
                        }
                    }
                }, 
                "state [rw]": {
                    "vlan [ro]": "union"
                }
            }, 
            "state [rw]": {
                "admin_status [ro]": "enumeration", 
                "counters [ro]": {
                    "in_broadcast_pkts [ro]": "yang:counter64", 
                    "in_discards [ro]": "yang:counter64", 
                    "in_errors [ro]": "yang:counter64", 
                    "in_multicast_pkts [ro]": "yang:counter64", 
                    "in_octets [ro]": "yang:counter64", 
                    "in_unicast_pkts [ro]": "yang:counter64", 
                    "in_unknown_protos [ro]": "yang:counter32", 
                    "last_clear [ro]": "yang:date-and-time", 
                    "out_broadcast_pkts [ro]": "yang:counter64", 
                    "out_discards [ro]": "yang:counter64", 
                    "out_errors [ro]": "yang:counter64", 
                    "out_multicast_pkts [ro]": "yang:counter64", 
                    "out_octets [ro]": "yang:counter64", 
                    "out_unicast_pkts [ro]": "yang:counter64"
                }, 
                "description [ro]": "string", 
                "enabled [ro]": "boolean", 
                "ifindex [ro]": "uint32", 
                "last_change [ro]": "yang:timeticks", 
                "mtu [ro]": "uint16", 
                "name [ro]": "string", 
                "openconfig-platform-transceiver:physical_channel [ro]": "leafref", 
                "openconfig-platform:hardware_port [ro]": "leafref", 
                "oper_status [ro]": "enumeration", 
                "type [ro]": "identityref"
            }, 
            "subinterfaces [rw]": {
                "subinterface [rw]": {
                    "config [rw]": {
                        "description [rw]": "string", 
                        "enabled [rw]": "boolean", 
                        "index [rw]": "uint32", 
                        "name [rw]": "string"
                    }, 
                    "index [rw]": "leafref", 
                    "openconfig-if-ip:ipv4 [rw]": {
                        "addresses [rw]": {
                            "address [rw]": {
                                "config [rw]": {
                                    "ip [rw]": "inet:ipv4-address-no-zone", 
                                    "napalm-if-ip:secondary [rw]": "boolean", 
                                    "prefix_length [rw]": "uint8"
                                }, 
                                "ip [rw]": "leafref", 
                                "state [rw]": {
                                    "ip [ro]": "inet:ipv4-address-no-zone", 
                                    "origin [ro]": "ip-address-origin", 
                                    "prefix_length [ro]": "uint8"
                                }, 
                                "vrrp [rw]": {
                                    "vrrp_group [rw]": {
                                        "config [rw]": {
                                            "accept_mode [rw]": "boolean", 
                                            "advertisement_interval [rw]": "uint16", 
                                            "preempt [rw]": "boolean", 
                                            "preempt_delay [rw]": "uint16", 
                                            "priority [rw]": "uint8", 
                                            "virtual_address [rw]": "inet:ip-address", 
                                            "virtual_router_id [rw]": "uint8"
                                        }, 
                                        "interface_tracking [rw]": {
                                            "config [rw]": {
                                                "priority_decrement [rw]": "uint8", 
                                                "track_interface [rw]": "leafref"
                                            }, 
                                            "state [rw]": {
                                                "priority_decrement [ro]": "uint8", 
                                                "track_interface [ro]": "leafref"
                                            }
                                        }, 
                                        "state [rw]": {
                                            "accept_mode [ro]": "boolean", 
                                            "advertisement_interval [ro]": "uint16", 
                                            "current_priority [ro]": "uint8", 
                                            "preempt [ro]": "boolean", 
                                            "preempt_delay [ro]": "uint16", 
                                            "priority [ro]": "uint8", 
                                            "virtual_address [ro]": "inet:ip-address", 
                                            "virtual_router_id [ro]": "uint8"
                                        }, 
                                        "virtual_router_id [rw]": "leafref"
                                    }
                                }
                            }
                        }, 
                        "config [rw]": {
                            "enabled [rw]": "boolean", 
                            "mtu [rw]": "uint16"
                        }, 
                        "neighbors [rw]": {
                            "neighbor [rw]": {
                                "config [rw]": {
                                    "ip [rw]": "inet:ipv4-address-no-zone", 
                                    "link_layer_address [rw]": "yang:phys-address"
                                }, 
                                "ip [rw]": "leafref", 
                                "state [rw]": {
                                    "ip [ro]": "inet:ipv4-address-no-zone", 
                                    "link_layer_address [ro]": "yang:phys-address", 
                                    "origin [ro]": "neighbor-origin"
                                }
                            }
                        }, 
                        "state [rw]": {
                            "enabled [ro]": "boolean", 
                            "mtu [ro]": "uint16"
                        }, 
                        "unnumbered [rw]": {
                            "config [rw]": {
                                "enabled [rw]": "boolean"
                            }, 
                            "interface_ref [rw]": {
                                "config [rw]": {
                                    "interface [rw]": "leafref", 
                                    "subinterface [rw]": "leafref"
                                }, 
                                "state [rw]": {
                                    "interface [ro]": "leafref", 
                                    "subinterface [ro]": "leafref"
                                }
                            }, 
                            "state [rw]": {
                                "enabled [ro]": "boolean"
                            }
                        }
                    }, 
                    "openconfig-if-ip:ipv6 [rw]": {
                        "addresses [rw]": {
                            "address [rw]": {
                                "config [rw]": {
                                    "ip [rw]": "inet:ipv6-address-no-zone", 
                                    "prefix_length [rw]": "uint8"
                                }, 
                                "ip [rw]": "leafref", 
                                "state [rw]": {
                                    "ip [ro]": "inet:ipv6-address-no-zone", 
                                    "origin [ro]": "ip-address-origin", 
                                    "prefix_length [ro]": "uint8", 
                                    "status [ro]": "enumeration"
                                }, 
                                "vrrp [rw]": {
                                    "vrrp_group [rw]": {
                                        "config [rw]": {
                                            "accept_mode [rw]": "boolean", 
                                            "advertisement_interval [rw]": "uint16", 
                                            "preempt [rw]": "boolean", 
                                            "preempt_delay [rw]": "uint16", 
                                            "priority [rw]": "uint8", 
                                            "virtual_address [rw]": "inet:ip-address", 
                                            "virtual_link_local [rw]": "inet:ip-address", 
                                            "virtual_router_id [rw]": "uint8"
                                        }, 
                                        "interface_tracking [rw]": {
                                            "config [rw]": {
                                                "priority_decrement [rw]": "uint8", 
                                                "track_interface [rw]": "leafref"
                                            }, 
                                            "state [rw]": {
                                                "priority_decrement [ro]": "uint8", 
                                                "track_interface [ro]": "leafref"
                                            }
                                        }, 
                                        "state [rw]": {
                                            "accept_mode [ro]": "boolean", 
                                            "advertisement_interval [ro]": "uint16", 
                                            "current_priority [ro]": "uint8", 
                                            "preempt [ro]": "boolean", 
                                            "preempt_delay [ro]": "uint16", 
                                            "priority [ro]": "uint8", 
                                            "virtual_address [ro]": "inet:ip-address", 
                                            "virtual_link_local [ro]": "inet:ip-address", 
                                            "virtual_router_id [ro]": "uint8"
                                        }, 
                                        "virtual_router_id [rw]": "leafref"
                                    }
                                }
                            }
                        }, 
                        "config [rw]": {
                            "dup_addr_detect_transmits [rw]": "uint32", 
                            "enabled [rw]": "boolean", 
                            "mtu [rw]": "uint32"
                        }, 
                        "neighbors [rw]": {
                            "neighbor [rw]": {
                                "config [rw]": {
                                    "ip [rw]": "inet:ipv6-address-no-zone", 
                                    "link_layer_address [rw]": "yang:phys-address"
                                }, 
                                "ip [rw]": "leafref", 
                                "state [rw]": {
                                    "ip [ro]": "inet:ipv6-address-no-zone", 
                                    "is_router [ro]": "empty", 
                                    "link_layer_address [ro]": "yang:phys-address", 
                                    "neighbor_state [ro]": "enumeration", 
                                    "origin [ro]": "neighbor-origin"
                                }
                            }
                        }, 
                        "openconfig-if-ip-ext:autoconf [rw]": {
                            "config [rw]": {
                                "create_global_addresses [rw]": "boolean", 
                                "create_temporary_addresses [rw]": "boolean", 
                                "temporary_preferred_lifetime [rw]": "uint32", 
                                "temporary_valid_lifetime [rw]": "uint32"
                            }, 
                            "state [rw]": {
                                "create_global_addresses [ro]": "boolean", 
                                "create_temporary_addresses [ro]": "boolean", 
                                "temporary_preferred_lifetime [ro]": "uint32", 
                                "temporary_valid_lifetime [ro]": "uint32"
                            }
                        }, 
                        "state [rw]": {
                            "dup_addr_detect_transmits [ro]": "uint32", 
                            "enabled [ro]": "boolean", 
                            "mtu [ro]": "uint32"
                        }, 
                        "unnumbered [rw]": {
                            "config [rw]": {
                                "enabled [rw]": "boolean"
                            }, 
                            "interface_ref [rw]": {
                                "config [rw]": {
                                    "interface [rw]": "leafref", 
                                    "subinterface [rw]": "leafref"
                                }, 
                                "state [rw]": {
                                    "interface [ro]": "leafref", 
                                    "subinterface [ro]": "leafref"
                                }
                            }, 
                            "state [rw]": {
                                "enabled [ro]": "boolean"
                            }
                        }
                    }, 
                    "openconfig-vlan:vlan [rw]": {
                        "config [rw]": {
                            "vlan_id [rw]": "union"
                        }, 
                        "state [rw]": {
                            "vlan_id [ro]": "union"
                        }
                    }, 
                    "state [rw]": {
                        "admin_status [ro]": "enumeration", 
                        "counters [ro]": {
                            "in_broadcast_pkts [ro]": "yang:counter64", 
                            "in_discards [ro]": "yang:counter64", 
                            "in_errors [ro]": "yang:counter64", 
                            "in_multicast_pkts [ro]": "yang:counter64", 
                            "in_octets [ro]": "yang:counter64", 
                            "in_unicast_pkts [ro]": "yang:counter64", 
                            "in_unknown_protos [ro]": "yang:counter32", 
                            "last_clear [ro]": "yang:date-and-time", 
                            "out_broadcast_pkts [ro]": "yang:counter64", 
                            "out_discards [ro]": "yang:counter64", 
                            "out_errors [ro]": "yang:counter64", 
                            "out_multicast_pkts [ro]": "yang:counter64", 
                            "out_octets [ro]": "yang:counter64", 
                            "out_unicast_pkts [ro]": "yang:counter64"
                        }, 
                        "description [ro]": "string", 
                        "enabled [ro]": "boolean", 
                        "ifindex [ro]": "uint32", 
                        "index [ro]": "uint32", 
                        "last_change [ro]": "yang:timeticks", 
                        "name [ro]": "string", 
                        "oper_status [ro]": "enumeration"
                    }
                }
            }
        }
    }, 
    "openconfig-vlan:vlans [rw]": {
        "vlan [rw]": {
            "config [rw]": {
                "name [rw]": "string", 
                "status [rw]": "enumeration", 
                "tpid [rw]": "identityref", 
                "vlan_id [rw]": "oc-vlan-types:vlan-id"
            }, 
            "members [rw]": {
                "member [rw]": {
                    "interface_ref [ro]": {
                        "state [ro]": {
                            "interface [ro]": "leafref", 
                            "subinterface [ro]": "leafref"
                        }
                    }
                }
            }, 
            "state [rw]": {
                "name [ro]": "string", 
                "status [ro]": "enumeration", 
                "tpid [ro]": "identityref", 
                "vlan_id [ro]": "oc-vlan-types:vlan-id"
            }, 
            "vlan_id [rw]": "leafref"
        }
    }
}

Populating models

Now that you have the models loaded, there are different ways to populate them.

Populating the model programatically

You can populate the model programmatically by navigating the model following its specifications. Some notes:

  1. Containers and leafs are attributes, which means you access them with a '.'. For example, interface.config.description.
  2. YANG lists have the following list of methods:
    1. iter to iterate over elements in a key, value pair fashion.
    2. keys to get list of elements.
    3. add to create and add a new element.
    4. delete to delete an element.
    5. _new_item to create an element detached from the list.
    6. append to add an existing element to a list.
  3. Values can be defaulted by using a special method _unset_$attribute. For example. config._unset_mtu()

Note that models are compiled with pyangbind so refer to its documentation for more details: http://pynms.io/pyangbind/


In [4]:
# We create an interface and set the description and the mtu
et1 = config.interfaces.interface.add("et1")
et1.config.description = "My description"
et1.config.mtu = 1500
print(et1.config.description)
print(et1.config.mtu)


My description
1500

In [5]:
# Let's create a second interface, this time accessing it from the root
config.interfaces.interface.add("et2")
config.interfaces.interface["et2"].config.description = "Another description"
config.interfaces.interface["et2"].config.mtu = 9000
print(config.interfaces.interface["et2"].config.description)
print(config.interfaces.interface["et2"].config.mtu)


Another description
9000

In [6]:
# You can also get the contents as a dict with the ``get`` method.
# ``filter`` let's you decide whether you want to show empty fields or not.
pretty_print(config.get(filter=True))


{
    "interfaces": {
        "interface": {
            "et1": {
                "config": {
                    "description": "My description", 
                    "mtu": 1500
                }, 
                "name": "et1"
            }, 
            "et2": {
                "config": {
                    "description": "Another description", 
                    "mtu": 9000
                }, 
                "name": "et2"
            }
        }
    }
}

In [7]:
# If the value is not valid things will break
try:
    et1.config.mtu = -1
except ValueError as e:
    print(e)


{'error-string': 'mtu must be of a type compatible with uint16', 'generated-type': 'YANGDynClass(base=RestrictedClassType(base_type=int, restriction_dict={\'range\': [\'0..65535\']},int_size=16), is_leaf=True, yang_name="mtu", parent=self, path_helper=self._path_helper, extmethods=self._extmethods, register_paths=True, namespace=\'http://openconfig.net/yang/interfaces\', defining_module=\'openconfig-interfaces\', yang_type=\'uint16\', is_config=True)', 'defined-type': 'uint16'}

Let's work through the interface list:


In [8]:
# Iterating
for iface, data in config.interfaces.interface.items():
    print(iface, data.config.description)


('et1', u'My description')
('et2', u'Another description')

In [9]:
# We can also delete interfaces
print(config.interfaces.interface.keys())
config.interfaces.interface.delete("et1")
print(config.interfaces.interface.keys())


['et1', 'et2']
['et2']

Populating the model from a dict

You can load a dictionary into the object.


In [10]:
vlans_dict = {
    "vlans": { "vlan": { 100: {
                            "config": {
                                "vlan_id": 100, "name": "production"}},
                         200: {
                            "config": {
                                "vlan_id": 200, "name": "dev"}}}}}
config.load_dict(vlans_dict)
print(config.vlans.vlan.keys())
print(100, config.vlans.vlan[100].config.name)
print(200, config.vlans.vlan[200].config.name)


[200, 100]
(100, u'production')
(200, u'dev')

Populating the model from a device

You can also load the native configuration of a device into a model.


In [11]:
with eos_device as d:
    running_config = napalm_yang.base.Root()
    running_config.add_model(napalm_yang.models.openconfig_interfaces)
    running_config.parse_config(device=d)

pretty_print(running_config.get(filter=True))


No handlers could be found for logger "napalm-yang"
{
    "interfaces": {
        "interface": {
            "Ethernet1": {
                "config": {
                    "description": "This is a description", 
                    "enabled": True, 
                    "type": "ethernetCsmacd"
                }, 
                "ethernet": {
                    "switched-vlan": {
                        "config": {
                            "access-vlan": 1, 
                            "interface-mode": "ACCESS", 
                            "native-vlan": 1, 
                            "trunk-vlans": [
                                "1..4094"
                            ]
                        }
                    }
                }, 
                "name": "Ethernet1", 
                "routed-vlan": {
                    "ipv4": {
                        "config": {
                            "enabled": False
                        }
                    }
                }
            }, 
            "Ethernet2": {
                "config": {
                    "description": "so much oc", 
                    "enabled": False, 
                    "mtu": 1500, 
                    "type": "ethernetCsmacd"
                }, 
                "name": "Ethernet2", 
                "routed-vlan": {
                    "ipv4": {
                        "addresses": {
                            "address": {
                                "192.168.0.1": {
                                    "config": {
                                        "ip": "192.168.0.1", 
                                        "prefix-length": 24, 
                                        "secondary": False
                                    }, 
                                    "ip": "192.168.0.1"
                                }
                            }
                        }, 
                        "config": {
                            "enabled": True
                        }
                    }
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "1": {
                            "config": {
                                "description": "another subiface", 
                                "enabled": True, 
                                "name": "Ethernet2.1"
                            }, 
                            "index": "1", 
                            "ipv4": {
                                "addresses": {
                                    "address": {
                                        "172.20.0.1": {
                                            "config": {
                                                "ip": "172.20.0.1", 
                                                "prefix-length": 24, 
                                                "secondary": True
                                            }, 
                                            "ip": "172.20.0.1"
                                        }, 
                                        "192.168.1.1": {
                                            "config": {
                                                "ip": "192.168.1.1", 
                                                "prefix-length": 24, 
                                                "secondary": False
                                            }, 
                                            "ip": "192.168.1.1"
                                        }
                                    }
                                }, 
                                "config": {
                                    "enabled": True
                                }
                            }, 
                            "vlan": {
                                "config": {
                                    "vlan-id": 1
                                }
                            }
                        }, 
                        "2": {
                            "config": {
                                "description": "asdasdasd", 
                                "enabled": True, 
                                "name": "Ethernet2.2"
                            }, 
                            "index": "2", 
                            "ipv4": {
                                "addresses": {
                                    "address": {
                                        "192.168.2.1": {
                                            "config": {
                                                "ip": "192.168.2.1", 
                                                "prefix-length": 24, 
                                                "secondary": False
                                            }, 
                                            "ip": "192.168.2.1"
                                        }
                                    }
                                }, 
                                "config": {
                                    "enabled": True
                                }
                            }, 
                            "vlan": {
                                "config": {
                                    "vlan-id": 2
                                }
                            }
                        }
                    }
                }
            }, 
            "Loopback1": {
                "config": {
                    "description": "a loopback", 
                    "enabled": True, 
                    "mtu": 1500, 
                    "type": "softwareLoopback"
                }, 
                "name": "Loopback1", 
                "routed-vlan": {
                    "ipv4": {
                        "config": {
                            "enabled": True
                        }
                    }
                }
            }, 
            "Management1": {
                "config": {
                    "enabled": True, 
                    "mtu": 1500, 
                    "type": "ethernetCsmacd"
                }, 
                "name": "Management1", 
                "routed-vlan": {
                    "ipv4": {
                        "addresses": {
                            "address": {
                                "10.0.2.15": {
                                    "config": {
                                        "ip": "10.0.2.15", 
                                        "prefix-length": 24, 
                                        "secondary": False
                                    }, 
                                    "ip": "10.0.2.15"
                                }
                            }
                        }, 
                        "config": {
                            "enabled": True
                        }
                    }
                }
            }, 
            "Port-Channel1": {
                "config": {
                    "description": "blah", 
                    "enabled": True, 
                    "mtu": 9000, 
                    "type": "ieee8023adLag"
                }, 
                "name": "Port-Channel1", 
                "routed-vlan": {
                    "ipv4": {
                        "config": {
                            "enabled": True
                        }
                    }
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "1": {
                            "config": {
                                "enabled": True, 
                                "name": "Port-Channel1.1"
                            }, 
                            "index": "1", 
                            "ipv4": {
                                "config": {
                                    "enabled": True
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Populating from a file

Or from a configuration file stored on disk. The only catch is that you will have to tell parse_config which profile to use to parse it.


In [12]:
with open("junos.config", "r") as f:
    config = f.read()

running_config = napalm_yang.base.Root()
running_config.add_model(napalm_yang.models.openconfig_interfaces)
running_config.parse_config(native=[config], profile=["junos"])

pretty_print(running_config.get(filter=True))


{
    "interfaces": {
        "interface": {
            "ae0": {
                "config": {
                    "enabled": True, 
                    "name": "ae0", 
                    "type": "ieee8023adLag"
                }, 
                "name": "ae0", 
                "routed-vlan": {
                    "ipv4": {
                        "config": {
                            "enabled": False
                        }
                    }
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "0": {
                            "config": {
                                "description": "ASDASDASD", 
                                "enabled": True, 
                                "name": "0"
                            }, 
                            "index": "0", 
                            "ipv4": {
                                "addresses": {
                                    "address": {
                                        "172.20.100.1": {
                                            "config": {
                                                "ip": "172.20.100.1", 
                                                "prefix-length": 24
                                            }, 
                                            "ip": "172.20.100.1"
                                        }, 
                                        "192.168.100.1": {
                                            "config": {
                                                "ip": "192.168.100.1", 
                                                "prefix-length": 24
                                            }, 
                                            "ip": "192.168.100.1"
                                        }
                                    }
                                }, 
                                "config": {
                                    "enabled": True
                                }
                            }, 
                            "vlan": {
                                "config": {
                                    "vlan-id": 100
                                }
                            }
                        }, 
                        "1": {
                            "config": {
                                "description": "ae0.1", 
                                "enabled": True, 
                                "name": "1"
                            }, 
                            "index": "1", 
                            "ipv4": {
                                "addresses": {
                                    "address": {
                                        "192.168.101.1": {
                                            "config": {
                                                "ip": "192.168.101.1", 
                                                "prefix-length": 24
                                            }, 
                                            "ip": "192.168.101.1"
                                        }
                                    }
                                }, 
                                "config": {
                                    "enabled": True
                                }
                            }, 
                            "vlan": {
                                "config": {
                                    "vlan-id": 1
                                }
                            }
                        }, 
                        "2": {
                            "config": {
                                "description": "ae0.2", 
                                "enabled": True, 
                                "name": "2"
                            }, 
                            "index": "2", 
                            "ipv4": {
                                "addresses": {
                                    "address": {
                                        "192.168.102.1": {
                                            "config": {
                                                "ip": "192.168.102.1", 
                                                "prefix-length": 24
                                            }, 
                                            "ip": "192.168.102.1"
                                        }
                                    }
                                }, 
                                "config": {
                                    "enabled": True
                                }
                            }, 
                            "vlan": {
                                "config": {
                                    "vlan-id": 2
                                }
                            }
                        }
                    }
                }
            }, 
            "ge-0/0/0": {
                "config": {
                    "description": "management interface", 
                    "enabled": True, 
                    "mtu": 1400, 
                    "name": "ge-0/0/0", 
                    "type": "ethernetCsmacd"
                }, 
                "name": "ge-0/0/0", 
                "routed-vlan": {
                    "ipv4": {
                        "config": {
                            "enabled": False
                        }
                    }
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "0": {
                            "config": {
                                "description": "ge-0/0/0.0", 
                                "enabled": True, 
                                "name": "0"
                            }, 
                            "index": "0", 
                            "ipv4": {
                                "config": {
                                    "enabled": True
                                }
                            }
                        }
                    }
                }
            }, 
            "ge-0/0/1": {
                "config": {
                    "description": "ge-0/0/1", 
                    "enabled": False, 
                    "name": "ge-0/0/1", 
                    "type": "ethernetCsmacd"
                }, 
                "name": "ge-0/0/1", 
                "routed-vlan": {
                    "ipv4": {
                        "config": {
                            "enabled": False
                        }
                    }
                }
            }, 
            "lo0": {
                "config": {
                    "description": "lo0", 
                    "enabled": True, 
                    "name": "lo0", 
                    "type": "softwareLoopback"
                }, 
                "name": "lo0", 
                "routed-vlan": {
                    "ipv4": {
                        "config": {
                            "enabled": False
                        }
                    }
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "0": {
                            "config": {
                                "description": "lo0.0", 
                                "enabled": True, 
                                "name": "0"
                            }, 
                            "index": "0", 
                            "ipv4": {
                                "config": {
                                    "enabled": False
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Translating models

Now we know how to populate models, let's translate them into native configuration.


In [13]:
# Let's create a candidate configuration

candidate = napalm_yang.base.Root()
candidate.add_model(napalm_yang.models.openconfig_interfaces())

def create_iface(candidate, name, description, mtu, prefix, prefix_length):
    interface = candidate.interfaces.interface.add(name)
    interface.config.description = description
    interface.config.mtu = mtu
    ip = interface.routed_vlan.ipv4.addresses.address.add(prefix)
    ip.config.ip = prefix
    ip.config.prefix_length = prefix_length

create_iface(candidate, "et1", "Uplink1", 9000, "192.168.1.1", 24)
create_iface(candidate, "et2", "Uplink2", 9000, "192.168.2.1", 24)

pretty_print(candidate.get(filter=True))


{
    "interfaces": {
        "interface": {
            "et1": {
                "config": {
                    "description": "Uplink1", 
                    "mtu": 9000
                }, 
                "name": "et1", 
                "routed-vlan": {
                    "ipv4": {
                        "addresses": {
                            "address": {
                                "192.168.1.1": {
                                    "config": {
                                        "ip": "192.168.1.1", 
                                        "prefix-length": 24
                                    }, 
                                    "ip": "192.168.1.1"
                                }
                            }
                        }
                    }
                }
            }, 
            "et2": {
                "config": {
                    "description": "Uplink2", 
                    "mtu": 9000
                }, 
                "name": "et2", 
                "routed-vlan": {
                    "ipv4": {
                        "addresses": {
                            "address": {
                                "192.168.2.1": {
                                    "config": {
                                        "ip": "192.168.2.1", 
                                        "prefix-length": 24
                                    }, 
                                    "ip": "192.168.2.1"
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

In [14]:
# Now let's translate the object to JunOS

print(candidate.translate_config(profile=junos_device.profile))


<configuration>
  <interfaces>
    <interface>
      <name>et1</name>
      <family>
        <inet>
          <address>
            <name>192.168.1.1/24</name>
          </address>
        </inet>
      </family>
      <description>Uplink1</description>
      <mtu>9000</mtu>
    </interface>
    <interface>
      <name>et2</name>
      <family>
        <inet>
          <address>
            <name>192.168.2.1/24</name>
          </address>
        </inet>
      </family>
      <description>Uplink2</description>
      <mtu>9000</mtu>
    </interface>
  </interfaces>
</configuration>


In [15]:
# And now to EOS

print(candidate.translate_config(eos_device.profile))


interface et1
    ip address 192.168.1.1/24 
    description Uplink1
    mtu 9000
    exit
interface et2
    ip address 192.168.2.1/24 
    description Uplink2
    mtu 9000
    exit

But this is just the begining, the fun part is yet to come : )

Advanced manipulation of the configuration

Generating configuration is cool but sometimes is not enough. Let's now see how we can use OpenConfig to make some changes to an existing configuration and generate a "replacement" of the configuration or a "merge".

  • A configuration replacement will replace the entire section. For example, if you are manipulating interfaces, all interfaces' configuration will be what's in the model you have. If some configuration parameter is not there, it will be wiped out.
  • A configuration merge is a bit different. Lists of elements are synchronized, which means that if you have one or more interfaces in the running configuration that don't exist in the candidate, they will be removed. This will happen to any list of elements. However, elements that exist in both the candidate and the running configuration will be merged, which means that if some attribute is not set in the candidate but is set in the running, it will not be modified.

In [16]:
with junos_device as device:
    # first let's create a candidate config by retrieving the current state of the device
    candidate = napalm_yang.base.Root()
    candidate.add_model(napalm_yang.models.openconfig_interfaces)
    candidate.parse_config(device=junos_device)

    # now let's do a few changes, let's remove lo0.0 and create lo0.1
    candidate.interfaces.interface["lo0"].subinterfaces.subinterface.delete("0")
    lo1 = candidate.interfaces.interface["lo0"].subinterfaces.subinterface.add("1")
    lo1.config.description = "new loopback"

    # Let's also default the mtu of ge-0/0/0 which is set to 1400
    candidate.interfaces.interface["ge-0/0/0"].config._unset_mtu()

    # We will also need a running configuration to compare against
    running = napalm_yang.base.Root()
    running.add_model(napalm_yang.models.openconfig_interfaces)
    running.parse_config(device=junos_device)

In [17]:
# Now let's see how the merge configuration would be
config = candidate.translate_config(profile=junos_device.profile, merge=running)
print(config)


<configuration>
  <interfaces>
    <interface>
      <name>ge-0/0/0</name>
      <unit>
        <name>0</name>
        <family>
          <inet/>
        </family>
        <description>ge-0/0/0.0</description>
      </unit>
      <description>management interface</description>
      <mtu delete="delete"/>
    </interface>
    <interface>
      <name>ge-0/0/1</name>
      <disable/>
      <description>ge-0/0/1</description>
    </interface>
    <interface>
      <name>ae0</name>
      <unit>
        <name>0</name>
        <vlan-id>100</vlan-id>
        <family>
          <inet>
            <address>
              <name>192.168.100.1/24</name>
            </address>
            <address>
              <name>172.20.100.1/24</name>
            </address>
          </inet>
        </family>
        <description>ASDASDASD</description>
      </unit>
      <vlan-tagging/>
      <unit>
        <name>1</name>
        <vlan-id>1</vlan-id>
        <family>
          <inet>
            <address>
              <name>192.168.101.1/24</name>
            </address>
          </inet>
        </family>
        <description>ae0.1</description>
      </unit>
      <vlan-tagging/>
      <unit>
        <name>2</name>
        <vlan-id>2</vlan-id>
        <family>
          <inet>
            <address>
              <name>192.168.102.1/24</name>
            </address>
          </inet>
        </family>
        <description>ae0.2</description>
      </unit>
      <vlan-tagging/>
    </interface>
    <interface>
      <name>lo0</name>
      <unit>
        <name>1</name>
        <description>new loopback</description>
      </unit>
      <unit delete="delete">
        <name>0</name>
      </unit>
      <description>lo0</description>
    </interface>
  </interfaces>
</configuration>

Note the "delete" tags. Let's actually load the configuration in the device and see which changes are reported.


In [18]:
with junos_device as d:
    d.load_merge_candidate(config=config)
    print(d.compare_config())
    d.discard_config()


[edit interfaces ge-0/0/0]
-   mtu 1400;
[edit interfaces lo0]
-    unit 0 {
-        description lo0.0;
-    }
+    unit 1 {
+        description "new loopback";
+    }

You can see that the device is reporting the changes we expected. Let's try now a replace instead.


In [19]:
config = candidate.translate_config(profile=junos_device.profile, replace=running)
print(config)


<configuration>
  <interfaces replace="replace">
    <interface>
      <name>ge-0/0/0</name>
      <unit>
        <name>0</name>
        <family>
          <inet/>
        </family>
        <description>ge-0/0/0.0</description>
      </unit>
      <description>management interface</description>
    </interface>
    <interface>
      <name>ge-0/0/1</name>
      <disable/>
      <description>ge-0/0/1</description>
    </interface>
    <interface>
      <name>ae0</name>
      <unit>
        <name>0</name>
        <vlan-id>100</vlan-id>
        <family>
          <inet>
            <address>
              <name>192.168.100.1/24</name>
            </address>
            <address>
              <name>172.20.100.1/24</name>
            </address>
          </inet>
        </family>
        <description>ASDASDASD</description>
      </unit>
      <vlan-tagging/>
      <unit>
        <name>1</name>
        <vlan-id>1</vlan-id>
        <family>
          <inet>
            <address>
              <name>192.168.101.1/24</name>
            </address>
          </inet>
        </family>
        <description>ae0.1</description>
      </unit>
      <vlan-tagging/>
      <unit>
        <name>2</name>
        <vlan-id>2</vlan-id>
        <family>
          <inet>
            <address>
              <name>192.168.102.1/24</name>
            </address>
          </inet>
        </family>
        <description>ae0.2</description>
      </unit>
      <vlan-tagging/>
    </interface>
    <interface>
      <name>lo0</name>
      <unit>
        <name>1</name>
        <description>new loopback</description>
      </unit>
      <description>lo0</description>
    </interface>
  </interfaces>
</configuration>

Note that instead of "delete", now we have a replace in one of the top containers, indicating to the device we want to replace everything underneath. Let's merge and see what happens:


In [20]:
with junos_device as d:
    d.load_merge_candidate(config=config)
    print(d.compare_config())
    d.discard_config()


[edit interfaces ge-0/0/0]
-   mtu 1400;
[edit interfaces ge-0/0/0 unit 0 family inet]
-       dhcp;
[edit interfaces lo0]
-    unit 0 {
-        description lo0.0;
-    }
+    unit 1 {
+        description "new loopback";
+    }

Interestingly, there is an extra change. That is due to the fact that the dhcp parameter is outside our model's control.

Not so friendly platforms

This also works with not so friendly platforms. Let's do the same we did in the previous section with an EOS device.


In [21]:
with eos_device as device:
    # first let's create a candidate config by retrieving the current state of the device
    candidate = napalm_yang.base.Root()
    candidate.add_model(napalm_yang.models.openconfig_interfaces)
    candidate.parse_config(device=device)

    # now let's do a few changes, let's remove lo1 and create lo0
    candidate.interfaces.interface.delete("Loopback1")
    lo0 = candidate.interfaces.interface.add("Loopback0")
    lo0.config.description = "new loopback"

    # Let's also default the mtu of ge-0/0/0 which is set to 1400
    candidate.interfaces.interface["Port-Channel1"].config._unset_mtu()

    # We will also need a running configuration to compare against
    running = napalm_yang.base.Root()
    running.add_model(napalm_yang.models.openconfig_interfaces)
    running.parse_config(device=device)

In [22]:
# Now let's see how the merge configuration would be
config = candidate.translate_config(profile=eos_device.profile, merge=running)
print(config)


interface Port-Channel1
    default mtu
    exit
interface Loopback0
    description new loopback
    exit
no interface Loopback1


In [23]:
with eos_device as d:
    d.load_merge_candidate(config=config)
    print(d.compare_config())
    d.discard_config()


@@ -19,7 +19,6 @@
 !
 interface Port-Channel1
    description blah
-   mtu 9000
    no switchport
 !
 interface Port-Channel1.1
@@ -46,8 +45,8 @@
    encapsulation dot1q vlan 2
    ip address 192.168.2.1/24
 !
-interface Loopback1
-   description a loopback
+interface Loopback0
+   description new loopback
 !
 interface Management1
    ip address 10.0.2.15/24

As in the previous example, we got exactly the same changes we were expecting.


In [24]:
config = candidate.translate_config(profile=eos_device.profile, replace=running)
print(config)


no interface Port-Channel1
interface Port-Channel1
    no switchport
    no switchport
    description blah
    exit
no interface Port-Channel1.1
interface Port-Channel1.1
    exit
default interface Ethernet1
interface Ethernet1
    switchport native vlan 1
    switchport access vlan 1
    switchport trunk vlan 1-4094
    switchport mode access
    description This is a description
    exit
default interface Ethernet2
interface Ethernet2
    no switchport
    ip address 192.168.0.1/24 
    no switchport
    no switchport
    shutdown
    description so much oc
    mtu 1500
    exit
no interface Ethernet2.1
interface Ethernet2.1
    encapsulation dot1q vlan 1
    ip address 192.168.1.1/24 
    ip address 172.20.0.1/24 secondary
    description another subiface
    exit
no interface Ethernet2.2
interface Ethernet2.2
    encapsulation dot1q vlan 2
    ip address 192.168.2.1/24 
    description asdasdasd
    exit
default interface Management1
interface Management1
    ip address 10.0.2.15/24 
    mtu 1500
    exit
no interface Loopback0
interface Loopback0
    description new loopback
    exit
no interface Loopback1


In [25]:
with eos_device as d:
    d.load_merge_candidate(config=config)
    print(d.compare_config())
    d.discard_config()


@@ -19,15 +19,12 @@
 !
 interface Port-Channel1
    description blah
-   mtu 9000
    no switchport
 !
 interface Port-Channel1.1
 !
 interface Ethernet1
    description This is a description
-   dcbx mode ieee
-   channel-group 1 mode active
 !
 interface Ethernet2
    description so much oc
@@ -46,8 +43,8 @@
    encapsulation dot1q vlan 2
    ip address 192.168.2.1/24
 !
-interface Loopback1
-   description a loopback
+interface Loopback0
+   description new loopback
 !
 interface Management1
    ip address 10.0.2.15/24

With the replace instead, we got some extra changes as some things are outside our model's control.

Generate config, merge or replace

Which of the three methods to choose is very subjective and it will depend on your operations:

  • Generating configuration. The drawback of this one is that configuration is only applied, never removed so it's good for places where you don't know or control most of your configuration.
  • "Merge" configuration. This one is good to keep some configuration in a known state while leaving other outside it.
  • "Replace" configuration. This one allows you to fully control the configuration. If you can use this, it means you dictate the fate of your network and not the other way around.

Getting state

Getting state from a device works pretty much like getting configuration.


In [26]:
state = napalm_yang.base.Root()
state.add_model(napalm_yang.models.openconfig_interfaces)

with junos_device as d:
    state.parse_state(device=d)

pretty_print(state.get(filter=True))


{
    "interfaces": {
        "interface": {
            ".local.": {
                "name": ".local.", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 0, 
                    "last-change": 0, 
                    "oper-status": "UP", 
                    "type": "softwareLoopback"
                }, 
                "subinterfaces": {
                    "subinterface": {
                        ".local..0": {
                            "index": ".local..0", 
                            "state": {
                                "ifindex": 0, 
                                "name": ".local..0"
                            }
                        }, 
                        ".local..1": {
                            "index": ".local..1", 
                            "state": {
                                "ifindex": 0, 
                                "name": ".local..1"
                            }
                        }, 
                        ".local..2": {
                            "index": ".local..2", 
                            "state": {
                                "ifindex": 0, 
                                "name": ".local..2"
                            }
                        }, 
                        ".local..3": {
                            "index": ".local..3", 
                            "state": {
                                "ifindex": 0, 
                                "name": ".local..3"
                            }
                        }, 
                        ".local..4": {
                            "index": ".local..4", 
                            "state": {
                                "ifindex": 0, 
                                "name": ".local..4"
                            }
                        }
                    }
                }
            }, 
            "ae0": {
                "name": "ae0", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 531, 
                    "last-change": 250256, 
                    "mtu": 1518, 
                    "oper-status": "DOWN"
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "ae0.0": {
                            "index": "ae0.0", 
                            "state": {
                                "description": "ASDASDASD", 
                                "ifindex": 532, 
                                "name": "ae0.0"
                            }
                        }, 
                        "ae0.1": {
                            "index": "ae0.1", 
                            "state": {
                                "description": "ae0.1", 
                                "ifindex": 533, 
                                "name": "ae0.1"
                            }
                        }, 
                        "ae0.2": {
                            "index": "ae0.2", 
                            "state": {
                                "description": "ae0.2", 
                                "ifindex": 534, 
                                "name": "ae0.2"
                            }
                        }, 
                        "ae0.32767": {
                            "index": "ae0.32767", 
                            "state": {
                                "ifindex": 535, 
                                "name": "ae0.32767"
                            }
                        }
                    }
                }
            }, 
            "dsc": {
                "name": "dsc", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 5, 
                    "last-change": 0, 
                    "oper-status": "UP"
                }
            }, 
            "ge-0/0/0": {
                "name": "ge-0/0/0", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-broadcast-pkts": 0, 
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "in-multicast-pkts": 0, 
                        "in-unicast-pkts": 11627, 
                        "out-broadcast-pkts": 0, 
                        "out-errors": 0, 
                        "out-multicast-pkts": 0, 
                        "out-unicast-pkts": 10927
                    }, 
                    "description": "management interface", 
                    "enabled": True, 
                    "ifindex": 507, 
                    "last-change": 253520, 
                    "mtu": 1400, 
                    "oper-status": "UP"
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "ge-0/0/0.0": {
                            "index": "ge-0/0/0.0", 
                            "state": {
                                "description": "ge-0/0/0.0", 
                                "ifindex": 521, 
                                "name": "ge-0/0/0.0"
                            }
                        }
                    }
                }
            }, 
            "ge-0/0/1": {
                "name": "ge-0/0/1", 
                "state": {
                    "admin-status": "DOWN", 
                    "counters": {
                        "in-broadcast-pkts": 0, 
                        "in-discards": 1, 
                        "in-errors": 0, 
                        "in-multicast-pkts": 0, 
                        "in-unicast-pkts": 2931, 
                        "out-broadcast-pkts": 0, 
                        "out-errors": 0, 
                        "out-multicast-pkts": 0, 
                        "out-unicast-pkts": 0
                    }, 
                    "description": "ge-0/0/1", 
                    "enabled": False, 
                    "ifindex": 508, 
                    "last-change": 250254, 
                    "mtu": 1514, 
                    "oper-status": "DOWN"
                }
            }, 
            "ge-0/0/2": {
                "name": "ge-0/0/2", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-broadcast-pkts": 0, 
                        "in-discards": 2, 
                        "in-errors": 0, 
                        "in-multicast-pkts": 0, 
                        "in-unicast-pkts": 371, 
                        "out-broadcast-pkts": 0, 
                        "out-errors": 0, 
                        "out-multicast-pkts": 0, 
                        "out-unicast-pkts": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 509, 
                    "last-change": 253520, 
                    "mtu": 1514, 
                    "oper-status": "UP"
                }
            }, 
            "gr-0/0/0": {
                "name": "gr-0/0/0", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 516, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "gre": {
                "name": "gre", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 8, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "ip-0/0/0": {
                "name": "ip-0/0/0", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 517, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "ipip": {
                "name": "ipip", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 9, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "irb": {
                "name": "irb", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 502, 
                    "last-change": 0, 
                    "mtu": 1514, 
                    "oper-status": "UP", 
                    "type": "ethernetCsmacd"
                }
            }, 
            "lo0": {
                "name": "lo0", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "description": "lo0", 
                    "enabled": True, 
                    "ifindex": 6, 
                    "last-change": 0, 
                    "oper-status": "UP", 
                    "type": "softwareLoopback"
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "lo0.0": {
                            "index": "lo0.0", 
                            "state": {
                                "description": "lo0.0", 
                                "ifindex": 16, 
                                "name": "lo0.0"
                            }
                        }, 
                        "lo0.16384": {
                            "index": "lo0.16384", 
                            "state": {
                                "ifindex": 21, 
                                "name": "lo0.16384"
                            }
                        }, 
                        "lo0.16385": {
                            "index": "lo0.16385", 
                            "state": {
                                "ifindex": 22, 
                                "name": "lo0.16385"
                            }
                        }, 
                        "lo0.32768": {
                            "index": "lo0.32768", 
                            "state": {
                                "ifindex": 248, 
                                "name": "lo0.32768"
                            }
                        }
                    }
                }
            }, 
            "lsi": {
                "name": "lsi", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 4, 
                    "last-change": 0, 
                    "mtu": 1496, 
                    "oper-status": "UP"
                }
            }, 
            "lsq-0/0/0": {
                "name": "lsq-0/0/0", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 518, 
                    "last-change": 253521, 
                    "mtu": 1504, 
                    "oper-status": "UP"
                }
            }, 
            "lt-0/0/0": {
                "name": "lt-0/0/0", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 520, 
                    "last-change": 0, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "mt-0/0/0": {
                "name": "mt-0/0/0", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 519, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "mtun": {
                "name": "mtun", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 12, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "pimd": {
                "name": "pimd", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 11, 
                    "oper-status": "UP"
                }
            }, 
            "pime": {
                "name": "pime", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 10, 
                    "oper-status": "UP"
                }
            }, 
            "pp0": {
                "name": "pp0", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 501, 
                    "mtu": 1532, 
                    "oper-status": "UP"
                }
            }, 
            "ppd0": {
                "name": "ppd0", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 504, 
                    "oper-status": "UP"
                }
            }, 
            "ppe0": {
                "name": "ppe0", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 505, 
                    "oper-status": "UP"
                }
            }, 
            "sp-0/0/0": {
                "name": "sp-0/0/0", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 515, 
                    "last-change": 253521, 
                    "mtu": 9192, 
                    "oper-status": "UP"
                }, 
                "subinterfaces": {
                    "subinterface": {
                        "sp-0/0/0.0": {
                            "index": "sp-0/0/0.0", 
                            "state": {
                                "ifindex": 522, 
                                "name": "sp-0/0/0.0"
                            }
                        }, 
                        "sp-0/0/0.16383": {
                            "index": "sp-0/0/0.16383", 
                            "state": {
                                "ifindex": 523, 
                                "name": "sp-0/0/0.16383"
                            }
                        }
                    }
                }
            }, 
            "st0": {
                "name": "st0", 
                "state": {
                    "admin-status": "UP", 
                    "enabled": True, 
                    "ifindex": 503, 
                    "mtu": 9192, 
                    "oper-status": "UP", 
                    "type": "tunnel"
                }
            }, 
            "tap": {
                "name": "tap", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 7, 
                    "last-change": 0, 
                    "oper-status": "UP"
                }
            }, 
            "vlan": {
                "name": "vlan", 
                "state": {
                    "admin-status": "UP", 
                    "counters": {
                        "in-discards": 0, 
                        "in-errors": 0, 
                        "out-errors": 0
                    }, 
                    "enabled": True, 
                    "ifindex": 506, 
                    "last-change": 253529, 
                    "mtu": 1518, 
                    "oper-status": "DOWN", 
                    "type": "l2vlan"
                }
            }
        }
    }
}

Note that parse_state accepts the same parameters as parse_config which means you can override profiles or even parse from files.

Diffing objects

Right now we have seen we can rely on the on-box diff to see the changes to the device. However, you might want to diff the objects directly in certain cases. You can do that with the diff method. Note that the method will tell you only which changes are to be performed for the models that are known to your binding.


In [27]:
diff = napalm_yang.utils.diff(candidate, running)
pretty_print(diff)


{
    "interfaces": {
        "interface": {
            "both": {
                "Port-Channel1": {
                    "config": {
                        "mtu": {
                            "first": "0", 
                            "second": "9000"
                        }
                    }
                }
            }, 
            "first_only": [
                "Loopback0"
            ], 
            "second_only": [
                "Loopback1"
            ]
        }
    }
}

Diff'ing models with state is also supported.

Compliance Report

This feature also works with YANG models. Let's assume we want to verify we have set the MTU of all of our interfaces to 9000.


In [28]:
data = {
    "interfaces": {
        "interface":{
            "Et1": {
                "config": {
                    "mtu": 9000
                },
            },
            "Et2": {
                "config": {
                    "mtu": 1500
                }
            }
        }
    }
}
# We load a dict for convenience, any source will do
config = napalm_yang.base.Root()
config.add_model(napalm_yang.models.openconfig_interfaces())
config.load_dict(data)

Now we can load the validation file. Here is the content for reference:

---
- to_dict:
    _kwargs:
        filter: true
    interfaces:
        interface:
            Et1:
                config:
                    mtu: 9000
            Et2:
                config:
                    mtu: 9000
            _mode: strict

Note that there is a major difference between using the compliance_report method on getters and on YANG objects. With the former you have to specify how to get the data, with the later you have to get the data yourself by any means and then specify you want to convert the data into a dict with the to_dict method.


In [29]:
report = config.compliance_report("validate.yaml")
pretty_print(report)


{
    "complies": false, 
    "skipped": [], 
    "to_dict": {
        "complies": false, 
        "extra": [], 
        "missing": [], 
        "present": {
            "interfaces": {
                "complies": false, 
                "diff": {
                    "complies": false, 
                    "extra": [], 
                    "missing": [], 
                    "present": {
                        "interface": {
                            "complies": false, 
                            "diff": {
                                "complies": false, 
                                "extra": [], 
                                "missing": [], 
                                "present": {
                                    "Et1": {
                                        "complies": true, 
                                        "nested": true
                                    }, 
                                    "Et2": {
                                        "complies": false, 
                                        "diff": {
                                            "complies": false, 
                                            "extra": [], 
                                            "missing": [], 
                                            "present": {
                                                "config": {
                                                    "complies": false, 
                                                    "diff": {
                                                        "complies": false, 
                                                        "extra": [], 
                                                        "missing": [], 
                                                        "present": {
                                                            "mtu": {
                                                                "actual_value": 1500, 
                                                                "complies": false, 
                                                                "nested": false
                                                            }
                                                        }
                                                    }, 
                                                    "nested": true
                                                }
                                            }
                                        }, 
                                        "nested": true
                                    }
                                }
                            }, 
                            "nested": true
                        }
                    }
                }, 
                "nested": true
            }
        }
    }
}

We can see it's complaining that the value of Et2's MTU is 1500. Let's fix it and try again:


In [30]:
config.interfaces.interface["Et2"].config.mtu = 9000
report = config.compliance_report("validate.yaml")
pretty_print(report)


{
    "complies": true, 
    "skipped": [], 
    "to_dict": {
        "complies": true, 
        "extra": [], 
        "missing": [], 
        "present": {
            "interfaces": {
                "complies": true, 
                "nested": true
            }
        }
    }
}

Now we can see in the first complies element of the report that we are complying. This works for state as the rest of the features too.

Ansible

We have also included new modules to be able to use napalm-yang with ansible:

  • napalm_parse_yang - Parses configuration from a device or configuration file and returns a dictionary that represents a YANG object.
  • napalm_diff_yang - Allows you to diff two YANG objects. Useful to see the difference between two states (for example one gathered before a maintenance and another one post-maintenance) or two configurations (for example, a candidate and a running for those systems without on-box diff or in the situation where you want to have a structured diff that is consistent across platforms).
  • napalm_translate_yang - Translates a YANG object into native configuration. Useful to deploy configuration in combination with napalm_install_config.

Examples

There are two examples included:

Configuration

In the following playbook you can notice the following:

  1. We are gathering the data from the same datastructure as seen here and here
  2. We can see in the first debug action a diff generated by napalm-yang
  3. Second debug is showing us the needed native configuration to merge the configuration we want into the current running configuration.
  4. Finally, last task is showing us an on-box diff, which as you can see agrees with the diff we generated with napalm-yang.
# ansible-playbook playbook_configure.yaml
# Let's gather config of interfaces from device ***************************************
  * eos                        - changed=False --  ------------------------------------
  * junos                      - changed=False --  ------------------------------------
# Let's diff our candidate and running ************************************************
  * junos                      - changed=False --  ------------------------------------
  * eos                        - changed=False --  ------------------------------------
# debug *******************************************************************************
  * junos                      - changed=False ----------------------------------------
    {
        "changed": false,
        "yang_diff": {
            "interfaces": {
                "interface": {
                    "both": {
                        "ae0": {
                            "subinterfaces": {
                                "subinterface": {
                                    "both": {
                                        "0": {
                                            "config": {
                                                "description": {
                                                    "first": "A new description",
                                                    "second": "ASDASDASD"
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
  * eos                        - changed=False ----------------------------------------
    {
        "changed": false,
        "yang_diff": {
            "interfaces": {
                "interface": {
                    "both": {
                        "Ethernet2": {
                            "subinterfaces": {
                                "subinterface": {
                                    "both": {
                                        "1": {
                                            "ipv4": {
                                                "addresses": {
                                                    "address": {
                                                        "first_only": [
                                                            "172.20.1.1"
                                                        ],
                                                        "second_only": [
                                                            "172.20.0.1"
                                                        ]
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
# Let's translate the YANG object to native config ************************************
  * eos                        - changed=False --  ------------------------------------
  * junos                      - changed=False --  ------------------------------------
# debug *******************************************************************************
  * junos                      - changed=False ----------------------------------------
    <configuration>
      <interfaces>
        <interface>
          <name>ae0</name>
          <unit>
            <name>1</name>
            <vlan-id>1</vlan-id>
            <family>
              <inet>
                <address>
                  <name>192.168.101.1/24</name>
                </address>
              </inet>
            </family>
            <disable/>
            <description>ae0.1</description>
          </unit>
          <vlan-tagging/>
          <unit>
            <name>0</name>
            <vlan-id>100</vlan-id>
            <family>
              <inet>
                <address>
                  <name>192.168.100.1/24</name>
                </address>
                <address>
                  <name>172.20.100.1/24</name>
                </address>
              </inet>
            </family>
            <description>A new description</description>
          </unit>
          <vlan-tagging/>
          <unit>
            <name>2</name>
            <vlan-id>2</vlan-id>
            <family>
              <inet>
                <address>
                  <name>192.168.102.1/24</name>
                </address>
              </inet>
            </family>
            <description>ae0.2</description>
          </unit>
          <vlan-tagging/>
        </interface>
        <interface>
          <name>lo0</name>
          <unit>
            <name>0</name>
            <description>lo0.0</description>
          </unit>
          <description>lo0</description>
        </interface>
        <interface>
          <name>ge-0/0/1</name>
          <disable/>
          <description>ge-0/0/1</description>
        </interface>
        <interface>
          <name>ge-0/0/0</name>
          <unit>
            <name>0</name>
            <family>
              <inet/>
            </family>
            <description>ge-0/0/0.0</description>
          </unit>
          <description>management interface</description>
          <mtu>1400</mtu>
        </interface>
      </interfaces>
    </configuration>

  * eos                        - changed=False ----------------------------------------
    interface Ethernet2
    interface Ethernet2.1
        ip address 172.20.1.1/24 secondary
        default ip address 172.20.0.1/24 secondary

# Install Config and save diff ********************************************************
  * eos                        - changed=True -----------------------------------------
    @@ -39,7 +39,7 @@
        description another subiface
        encapsulation dot1q vlan 1
        ip address 192.168.1.1/24
    -   ip address 172.20.0.1/24 secondary
    +   ip address 172.20.1.1/24 secondary
     !
     interface Ethernet2.2
        description asdasdasd
  * junos                      - changed=True -----------------------------------------
    [edit interfaces ae0 unit 0]
    -    description ASDASDASD;
    +    description "A new description";

# STATS *******************************************************************************
eos    : ok=6   changed=1   failed=0    unreachable=0
junos    : ok=6 changed=1   failed=0    unreachable=0

State validation

  1. We want to validate state.
  2. We want to validate that all interfaces are UP and has the MTU set to 1514 as seen here
  3. As our last action shows, we are not in compliance; ge-0/0/0 has mtu 1400 and ge-0/0/1 is down.
# ansible-playbook playbook_validate_state.yaml
# Let's gather state of interfaces ***************************************************
  * junos                      - changed=False --  -----------------------------------
# Check all interfaces are up **************************************************************************************
  * junos                      - changed=False --  -----------------------------------
# Let's verify the report complies **************************************************************************************
  * junos                      - FAILED!!! -------------------------------------------
    {
        "complies": false,
        "skipped": [],
        "to_dict": {
            "complies": false,
            "extra": [],
            "missing": [],
            "present": {
                "interfaces": {
                    "complies": false,
                    "diff": {
                        "complies": false,
                        "extra": [],
                        "missing": [],
                        "present": {
                            "interface": {
                                "complies": false,
                                "diff": {
                                    "complies": false,
                                    "extra": [],
                                    "missing": [],
                                    "present": {
                                        "ge-0/0/0": {
                                            "complies": false,
                                            "diff": {
                                                "complies": false,
                                                "extra": [],
                                                "missing": [],
                                                "present": {
                                                    "state": {
                                                        "complies": false,
                                                        "diff": {
                                                            "complies": false,
                                                            "extra": [],
                                                            "missing": [],
                                                            "present": {
                                                                "mtu": {
                                                                    "actual_value": 1400,
                                                                    "complies": false,
                                                                    "nested": false
                                                                },
                                                                "oper_status": {
                                                                    "complies": true,
                                                                    "nested": false
                                                                }
                                                            }
                                                        },
                                                        "nested": true
                                                    }
                                                }
                                            },
                                            "nested": true
                                        },
                                        "ge-0/0/1": {
                                            "complies": false,
                                            "diff": {
                                                "complies": false,
                                                "extra": [],
                                                "missing": [],
                                                "present": {
                                                    "state": {
                                                        "complies": false,
                                                        "diff": {
                                                            "complies": false,
                                                            "extra": [],
                                                            "missing": [],
                                                            "present": {
                                                                "mtu": {
                                                                    "complies": true,
                                                                    "nested": false
                                                                },
                                                                "oper_status": {
                                                                    "actual_value": "DOWN",
                                                                    "complies": false,
                                                                    "nested": false
                                                                }
                                                            }
                                                        },
                                                        "nested": true
                                                    }
                                                }
                                            },
                                            "nested": true
                                        },
                                        "ge-0/0/2": {
                                            "complies": true,
                                            "nested": true
                                        }
                                    }
                                },
                                "nested": true
                            }
                        }
                    },
                    "nested": true
                }
            }
        }
    }

# STATS *****************************************************************************

junos    : ok=2 changed=0   failed=1    unreachable=0

In [ ]:

Salt

napalm-yang is also integrated in the official SaltStack releases, beginning with Nitrogen.

For complete documentation and usages examples, please check:

They can be used like any other Salt native module, as long as the credentials have been declared in the pillar (either file or external service). See the proxy documentation for more details.