├── .gitattributes ├── .gitignore ├── Examples-XE.md ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── envvars.example ├── images ├── new.png └── updated.png ├── notebooks ├── CLEU-2020.ipynb ├── IOS-XE-CLEU-2018.ipynb ├── Locking And Saving.ipynb ├── NC-background.ipynb ├── Schema Fun.ipynb ├── Telemetry Scratch.ipynb ├── bgp-shenanigans.ipynb ├── big-acl.ipynb ├── coverage-xr.ipynb ├── gsp-sevt-demo.ipynb ├── ios-xe-16.5.1-demo.ipynb ├── jxmlease-sample.ipynb ├── live-coverage-xe.ipynb ├── live-coverage-xr.ipynb ├── more-ydk-play.ipynb ├── ned-xe.ipynb ├── paramiko-xe.ipynb ├── qos-play.ipynb ├── xe-candidate-demo.ipynb ├── xe-candidate-locking-and-syncing.ipynb ├── xe-datastore-locking.ipynb └── ydk-play.ipynb ├── poetry.lock ├── pyproject.toml ├── sample-ns.json ├── sample-subscriptions.md ├── snippets-cl ├── editconfigs │ ├── cl-bgp-basic.tmpl │ ├── cl-bgp-del.tmpl │ ├── cl-bgp-nbr-create.tmpl │ ├── cl-bgp-nbr-delete.tmpl │ ├── cl-bgp-nbr-merge.tmpl │ ├── cl-bgp-nbr-remove.tmpl │ ├── cl-intf-named-set-mtu.tmpl │ ├── cl-loop-merge.tmpl │ ├── cl-loop-remove.tmpl │ ├── cl-oc-bgp-nbr-merge.tmpl │ └── cl-oc-intf-named-set-mtu.tmpl └── filters │ ├── cl-fib-oper.tmpl │ ├── cl-ietf-intf-oper-stats.tmpl │ ├── cl-ietf-intf-oper.tmpl │ ├── cl-intf-oper-in-out-octets.tmpl │ ├── cl-intf-oper-named-in-out-octets.tmpl │ ├── cl-intf-oper-named-stats.tmpl │ ├── cl-intf-oper-named.tmpl │ ├── cl-intf-oper-stats.tmpl │ ├── cl-intf-oper.tmpl │ └── cl-oc-intf-named.tmpl ├── snippets-xe ├── editconfigs │ ├── 00-oper-data-enable-16.4.tmpl │ ├── 00-oper-data-enable.tmpl │ ├── 00-snmp-config.tmpl │ ├── 01-oper-data-disable.tmpl │ ├── 01-snmp-config-disable │ ├── native-acl-00-create.tmpl │ ├── native-acl-00-merge.tmpl │ ├── native-acl-01-replace.tmpl │ ├── native-acl-02-remove.tmpl │ ├── native-create-acl.tmpl │ ├── native-create-class-map.tmpl │ ├── native-create-policy-map.tmpl │ ├── native-create-vlan.tmpl │ ├── native-delete-acl.tmpl │ ├── native-delete-class-map.tmpl │ ├── native-delete-policy-map.tmpl │ ├── native-delete-vlan.tmpl │ ├── native-intf-add-acl.tmpl │ ├── native-intf-add-qos.tmpl │ ├── native-intf-delete-acl.tmpl │ ├── native-intf-delete-qos.tmpl │ ├── native-intf-no-shut.tmpl │ ├── native-intf-no-switchport.tmpl │ ├── native-intf-shutdown.tmpl │ ├── native-intf-switchport.tmpl │ ├── native-intf-vlan-change.tmpl │ ├── native-router-ospf-add-network.tmpl │ ├── native-router-ospf-delete-network.tmpl │ └── openconfig-intf-ip-address.tmpl └── filters │ ├── MIB-filter.tmpl │ ├── confd-state.tmpl │ ├── ietf-intf-named-description.tmpl │ ├── ietf-intf-named.tmpl │ ├── ietf-intf.tmpl │ ├── native-gig-interface-vlan.tmpl │ ├── native-intf-named.tmpl │ ├── netconf-state.tmpl │ └── openconfig-intf.tmpl ├── snippets ├── editconfigs │ ├── 00-loop-remove.tmpl │ ├── 00-loop.tmpl │ ├── add-loop.tmpl │ ├── add_neighbor.tmpl │ ├── add_static_route_default.tmpl │ ├── bdi-01-create-noshutdown.tmpl │ ├── bdi-01-create.tmpl │ ├── bdi-02-remove.tmpl │ ├── bdi-03-noshut.tmpl │ ├── bgp-01.tmpl │ ├── bgp-02.2.tmpl │ ├── bgp-02.tmpl │ ├── bgp-03.tmpl │ ├── class_dscp31_cr.tmpl │ ├── class_dscp31_del.tmpl │ ├── class_lots_of_dscp.tmpl │ ├── classmap_delete_einarnn_all.tmpl │ ├── classmap_einarnn_3.tmpl │ ├── classmap_einarnn_4.tmpl │ ├── classmap_einarnn_5.tmpl │ ├── classmap_einarnn_6.tmpl │ ├── create-arp-entry.tmpl │ ├── del-ipv6-acl-binding.tmpl │ ├── del_neighbor.tmpl │ ├── del_static_route_default.tmpl │ ├── delete-loopback1.tmpl │ ├── delete-update-source.tmpl │ ├── delete_autoneg.tmpl │ ├── delete_ebgp_multihop_enabled.tmpl │ ├── delete_l2vpn.tmpl │ ├── empty_l2vpn.tmpl │ ├── foo1_add_static_route_default.tmpl │ ├── foo2_add_static_route_default.tmpl │ ├── gs.tmpl │ ├── ietf-cr-loopback.tmpl │ ├── ietf-intf-add-ipv4.tmpl │ ├── l2vpn_bdgroups_cr.tmpl │ ├── l2vpn_bdgroups_del.tmpl │ ├── legacy-01.tmpl │ ├── lldp-basic-and-del.tmpl │ ├── lldp-basic.tmpl │ ├── lldp-del.tmpl │ ├── nacm-01-cr-other.tmpl │ ├── nacm-02-del-other.tmpl │ ├── nacm-03-add-group.tmpl │ ├── nacm-04-rm-group.tmpl │ ├── new-ip.tmpl │ ├── no_shut.tmpl │ ├── oc-set-descr-broken.tmpl │ ├── oc-set-descr.tmpl │ ├── oc_basic.tmpl │ ├── policy_test_cr.tmpl │ ├── policy_test_del.tmpl │ ├── redis-metric.tmpl │ ├── replace-lo.tmpl │ ├── restconf-enable.tmpl │ ├── set_autoneg_override.tmpl │ ├── set_autoneg_true.tmpl │ ├── set_ebgp_multihop_enabled_false.tmpl │ ├── set_ebgp_multihop_enabled_true.tmpl │ ├── shut.tmpl │ ├── simple_ospf.tmpl │ ├── telem-cr.tmpl │ ├── telem-del-ipv6-fails.tmpl │ ├── telem-del-ipv6-works.tmpl │ ├── two-roots.tmpl │ ├── vrf-01-replace.tmpl │ ├── xe-delete-ace.tmpl │ ├── xe-enable-polling.tmpl │ ├── xe-merge-ace.tmpl │ ├── xxx.tmpl │ └── xxx_del.tmpl └── filters │ ├── acl-666.tmpl │ ├── acls-all.tmpl │ ├── fivesecondcpu.tmpl │ ├── ietf-intf.tmpl │ ├── ietf-intfs-state.tmpl │ ├── installmgr-admin-oper.tmpl │ ├── intf-brief-all.tmpl │ ├── intf-brief.tmpl │ ├── intf-stats-limited.tmpl │ ├── intf-stats.tmpl │ ├── lldp-all.tmpl │ ├── mdtoper.tmpl │ ├── oc-bgp-neighbors.tmpl │ ├── oc-bgp.tmpl │ ├── oc-intf-named.tmpl │ ├── oc-intf.tmpl │ ├── oc-subintf-named-and-indexed.tmpl │ ├── oc-subintf-named.tmpl │ ├── platform.tmpl │ ├── qos-oper-all.tmpl │ ├── qos-oper-intf.tmpl │ ├── telem-all.tmpl │ ├── vrrp-ipv4-all.tmpl │ ├── xe-cpu-usage.tmpl │ ├── xe-memory-statistics.tmpl │ ├── xe-native-intf.tmpl │ ├── xe-native-ipv4-acl.tmpl │ ├── xe-native-ipv6-acl.tmpl │ ├── xe-native.tmpl │ ├── xr-value-detailed-specific.tmpl │ ├── xr-value-detailed-temp.tmpl │ └── xr-value-detailed.tmpl └── src ├── ncc └── __init__.py ├── nccutil ├── __init__.py ├── _version.py └── repoutil.py ├── redis-cb ├── __init__.py └── cb.py ├── redis-pub ├── __init__.py └── cb.py ├── sample ├── __init__.py └── cb.py └── scripts ├── ncc-async.py ├── ncc-establish-subscription.py ├── ncc-event-listener-demo.py ├── ncc-event-listener.py ├── ncc-filtered-get.py ├── ncc-locker.py ├── ncc-simple-locker.py ├── ncc-simple-poller.py ├── ncc-stress.py ├── ncc.py ├── ncc_capture_schema.py ├── ncc_get_all_schema.py ├── ncc_get_schema.py ├── ncc_yang_push.py └── rc-xr.py /.gitattributes: -------------------------------------------------------------------------------- 1 | nccutil/_version.py export-subst 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *~ 3 | v/ 4 | .ipynb_checkpoints/ 5 | .DS_Store 6 | .jython_cache/ 7 | .poetry/ 8 | -------------------------------------------------------------------------------- /Examples-XE.md: -------------------------------------------------------------------------------- 1 | # A bunch of examples for Using the XE filters and editconfigs 2 | 3 | ## Environment vars 4 | This will same specifying username and password. It also will point to the XE snippets directory. 5 | 6 | ```buildoutcfg 7 | source local_vars 8 | ``` 9 | This file contains the following shell environment variables 10 | ```buildoutcfg 11 | export NCC_USERNAME=myuser 12 | export NCC_PASSWORD=my-password 13 | export NCC_SNIPPETS=./ncc/snippets-xe 14 | ``` 15 | 16 | ## Basic Requests 17 | These will get the capabilities. 18 | ```buildoutcfg 19 | ./ncc/ncc.py --host=adam-csr --capabilities 20 | ./ncc/ncc.py --host=adam-csr --get-oper -x /netconf-state/schemas 21 | ./ncc/ncc.py --host=adam-csr --get-oper -x //schemas 22 | 23 | ``` 24 | 25 | ## oper-data 26 | A couple of requests for oper-data 27 | 28 | ```buildoutcfg 29 | ./ncc/ncc.py --host=adam-csr --get-oper -x /interfaces-state 30 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/interfaces-state/interface[name='GigabitEthernet1/0/1']" 31 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/interfaces-state/interface[substring(name,1, 7) = 'Gigabit']" 32 | ./ncc/ncc.py --host=adam-csr --get-oper -x "/IF-MIB/ifTable" 33 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/routing-state" 34 | ``` 35 | 36 | ## Interfaces 37 | ```buildoutcfg 38 | ./ncc/ncc.py --host=adam-csr --get-running -x /interfaces 39 | ./ncc/ncc.py --host=adam-csr --get-running -x /interfaces//name 40 | ./ncc/ncc.py --host=adam-3850 --get-running --named-filter ietf-intf-named --params='{ "INTF_NAME" : "GigabitEthernet1/0/1"}' 41 | ./ncc/ncc.py --host=adam-3850 --get-running --named-filter openconfig-intf --params='{ "INTF_NAME" : "GigabitEthernet1/0/1"}' 42 | ./ncc/ncc.py --host=adam-csr --get-running --named-filter openconfig-intf --params='{ "INTF_NAME" : "GigabitEthernet3"}' 43 | 44 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-shutdown --params '{"INTF_NAME" : "1/0/18"}' 45 | ./ncc/ncc.py --host=adam-3850 --get-running -x "/native/interface/GigabitEthernet[name='1/0/18']" 46 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-no-shut --params '{"INTF_NAME" : "1/0/18"}' 47 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-vlan-change --params '{"INTF_NAME" : "1/0/19", "VLAN" : "20"}' 48 | ``` 49 | ## vlan 50 | ```buildoutcfg 51 | ./ncc/ncc.py --host=adam-3850 --do-edits native-create-vlan --params '{"VLAN" : "120"}' 52 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/native/vlan" 53 | ./ncc/ncc.py --host=adam-3850 --do-edits native-delete-vlan --params '{"VLAN" : "120"}' 54 | 55 | ``` 56 | 57 | ## ACL 58 | 59 | ```buildoutcfg 60 | ./ncc/ncc.py --host=adam-3850 --do-edits native-create-acl --params '{"ACL_NAME": "canary_ip_in"}' 61 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/native/ip/access-list/extended[name='canary_ip_in']" 62 | ./ncc/ncc.py --host=adam-3850 --do-edits native-delete-acl --params '{"ACL_NAME": "canary_ip_in"}' 63 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-add-acl --params '{"INTF_NAME" : "1/0/18","ACL": "canary_ip_in"}' 64 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-delete-acl --params '{"INTF_NAME" : "1/0/18","ACL": "canary_ip_in"}' 65 | ./ncc.py --host=adam-csr --get-oper -x '/native/ip/object-group' 66 | ``` 67 | 68 | ## IP address / vlan change 69 | Remember you can only configure a switchport in L3 mode if you "no switchport" it. 70 | ```buildoutcfg 71 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-no-switchport --params '{"INTF_NAME" : "1/0/19"}' 72 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/native/interface/GigabitEthernet[name='1/0/19']" 73 | ./ncc/ncc.py --host=adam-3850 --do-edits openconfig-intf-ip-address --params '{"INTF_NAME" : "GigabitEthernet1/0/19", "IP_ADDR" : "12.12.12.2"}' 74 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-switchport --params '{"INTF_NAME" : "1/0/19"}' 75 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-vlan-change --params '{"INTF_NAME" : "1/0/19", "VLAN" : "20"}' 76 | ``` 77 | 78 | ## QOS 79 | ```buildoutcfg 80 | ./ncc/ncc.py --host=adam-3850 --do-edits native-create-class-map --params '{"C_NAME" : "prm-EZQOS_12C#BROADCAST"}' 81 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/native/policy/class-map[name='prm-EZQOS_12C#BROADCAST']" 82 | ./ncc/ncc.py --host=adam-3850 --do-edits native-create-policy-map --params '{"P_NAME": "prm-dscp#QUEUING_OUT","C_NAME" : "prm-EZQOS_12C#BROADCAST"}' 83 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/native/policy/policy-map[name='prm-dscp#QUEUING_OUT']" 84 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-add-qos --params '{"INTF_NAME" : "1/0/18","P_NAME": "prm-dscp#QUEUING_OUT"}' 85 | ./ncc/ncc.py --host=adam-3850 --do-edits native-intf-delete-qos --params '{"INTF_NAME" : "1/0/18","P_NAME": "prm-dscp#QUEUING_OUT"}' 86 | ./ncc/ncc.py --host=adam-3850 --do-edits native-delete-policy-map --params '{"P_NAME": "prm-dscp#QUEUING_OUT"}' 87 | ./ncc/ncc.py --host=adam-3850 --do-edits native-delete-class-map --params '{"C_NAME" : "prm-EZQOS_12C#BROADCAST"}' 88 | ``` 89 | 90 | ## OSPF 91 | ```buildoutcfg 92 | ./ncc/ncc.py --host=adam-3850 --do-edits native-router-ospf-add-network --params '{"ROUTER_ID" : "100", "NETWORK":"10.101.1.0", "MASK": "255.255.255.0"}' 93 | ./ncc/ncc.py --host=adam-3850 --get-oper -x "/native/router/ospf/network[ip='10.101.1.0']" 94 | ./ncc/ncc.py --host=adam-3850 --do-edits native-router-ospf-delete-network --params '{"ROUTER_ID" : "100", "NETWORK":"10.101.1.0","MASK": "255.255.255.0"}' 95 | ``` 96 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2018 Cisco and/or its affiliates 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # Include the license file 2 | include LICENSE.txt 3 | 4 | include versioneer.py 5 | include nccutil/_version.py 6 | -------------------------------------------------------------------------------- /envvars.example: -------------------------------------------------------------------------------- 1 | export NCC_HOST=127.0.0.1 2 | export NCC_PORT=2223 3 | export NCC_USERNAME=vagrant 4 | export NCC_PASSWORD=vagrant 5 | -------------------------------------------------------------------------------- /images/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CiscoDevNet/ncc/72fb19553d1ab27f99ce4a1212a7a1d047c51220/images/new.png -------------------------------------------------------------------------------- /images/updated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CiscoDevNet/ncc/72fb19553d1ab27f99ce4a1212a7a1d047c51220/images/updated.png -------------------------------------------------------------------------------- /notebooks/Locking And Saving.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# SAP Repro\n", 8 | "\n", 9 | "Trying to reproduce SAP issues." 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "## Constants & Functions" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 13, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "HOST = '127.0.0.1'\n", 26 | "PORT = 2223\n", 27 | "USER = 'vagrant'\n", 28 | "PASS = 'vagrant'" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 14, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "from ncclient import manager\n", 38 | "from lxml import etree\n", 39 | "\n", 40 | "def pretty_print(retval):\n", 41 | " print(etree.tostring(retval.data, pretty_print=True))\n", 42 | "\n", 43 | "def my_unknown_host_cb(host, fingerprint):\n", 44 | " return True\n", 45 | " \n", 46 | "m = manager.connect(host=HOST, port=PORT, username=USER, password=PASS,\n", 47 | " device_params={'name':'iosxe'},\n", 48 | " allow_agent=False,\n", 49 | " look_for_keys=False,\n", 50 | " hostkey_verify=False,\n", 51 | " unknown_host_cb=my_unknown_host_cb)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 15, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "vrf = '''\n", 61 | "\n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " TEST\n", 66 | " 100:100\n", 67 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | "\n", 74 | "'''\n", 75 | "\n", 76 | "vrf_del = '''\n", 77 | "\n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " TEST\n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | "\n", 86 | "'''\n", 87 | "\n", 88 | "def merge_vrf(conn):\n", 89 | " return conn.edit_config(vrf, format='xml', target='candidate')\n", 90 | "\n", 91 | "def delete_vrf(conn):\n", 92 | " return conn.edit_config(vrf_del, format='xml', target='candidate')" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 17, 98 | "metadata": {}, 99 | "outputs": [ 100 | { 101 | "name": "stdout", 102 | "output_type": "stream", 103 | "text": [ 104 | "True\n" 105 | ] 106 | }, 107 | { 108 | "data": { 109 | "text/plain": [ 110 | "\n", 111 | "" 112 | ] 113 | }, 114 | "execution_count": 17, 115 | "metadata": {}, 116 | "output_type": "execute_result" 117 | } 118 | ], 119 | "source": [ 120 | "#\n", 121 | "# loop creating & deleting the vrf TEST\n", 122 | "#\n", 123 | "m.lock(target='running')\n", 124 | "m.lock(target='candidate')\n", 125 | "for _ in range(0, 1):\n", 126 | " print(merge_vrf(m).ok)\n", 127 | " # print(delete_vrf(m).ok)\n", 128 | "m.commit()\n", 129 | "m.unlock(target='candidate')\n", 130 | "m.save_config()\n", 131 | "m.unlock(target='running')\n" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 32, 137 | "metadata": {}, 138 | "outputs": [], 139 | "source": [ 140 | "vrf_route = '''\n", 141 | "\n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " TEST\n", 147 | " \n", 148 | " 192.168.1.0\n", 149 | " 255.255.255.0\n", 150 | " \n", 151 | " 10.10.10.1\n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | "\n", 159 | "'''\n", 160 | "\n", 161 | "vrf_route_del = '''\n", 162 | "\n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " TEST\n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | "\n", 173 | "'''\n", 174 | "\n", 175 | "def merge_vrf_route(conn):\n", 176 | " return conn.edit_config(vrf_route, format='xml', target='running')\n", 177 | "\n", 178 | "def delete_vrf_route(conn):\n", 179 | " return conn.edit_config(vrf_route_del, format='xml', target='running')" 180 | ] 181 | }, 182 | { 183 | "cell_type": "code", 184 | "execution_count": 38, 185 | "metadata": {}, 186 | "outputs": [ 187 | { 188 | "data": { 189 | "text/plain": [ 190 | "\n", 191 | "" 192 | ] 193 | }, 194 | "execution_count": 38, 195 | "metadata": {}, 196 | "output_type": "execute_result" 197 | } 198 | ], 199 | "source": [ 200 | "merge_vrf(m)" 201 | ] 202 | }, 203 | { 204 | "cell_type": "code", 205 | "execution_count": 40, 206 | "metadata": {}, 207 | "outputs": [ 208 | { 209 | "data": { 210 | "text/plain": [ 211 | "\n", 212 | "" 213 | ] 214 | }, 215 | "execution_count": 40, 216 | "metadata": {}, 217 | "output_type": "execute_result" 218 | } 219 | ], 220 | "source": [ 221 | "delete_vrf(m)" 222 | ] 223 | }, 224 | { 225 | "cell_type": "code", 226 | "execution_count": 39, 227 | "metadata": {}, 228 | "outputs": [ 229 | { 230 | "data": { 231 | "text/plain": [ 232 | "\n", 233 | "" 234 | ] 235 | }, 236 | "execution_count": 39, 237 | "metadata": {}, 238 | "output_type": "execute_result" 239 | } 240 | ], 241 | "source": [ 242 | "merge_vrf_route(m)" 243 | ] 244 | }, 245 | { 246 | "cell_type": "code", 247 | "execution_count": 35, 248 | "metadata": {}, 249 | "outputs": [ 250 | { 251 | "data": { 252 | "text/plain": [ 253 | "\n", 254 | "" 255 | ] 256 | }, 257 | "execution_count": 35, 258 | "metadata": {}, 259 | "output_type": "execute_result" 260 | } 261 | ], 262 | "source": [ 263 | "delete_vrf_route(m)" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": null, 269 | "metadata": {}, 270 | "outputs": [], 271 | "source": [] 272 | } 273 | ], 274 | "metadata": { 275 | "kernelspec": { 276 | "display_name": "Python 3", 277 | "language": "python", 278 | "name": "python3" 279 | }, 280 | "language_info": { 281 | "codemirror_mode": { 282 | "name": "ipython", 283 | "version": 3 284 | }, 285 | "file_extension": ".py", 286 | "mimetype": "text/x-python", 287 | "name": "python", 288 | "nbconvert_exporter": "python", 289 | "pygments_lexer": "ipython3", 290 | "version": "3.6.5" 291 | } 292 | }, 293 | "nbformat": 4, 294 | "nbformat_minor": 2 295 | } 296 | -------------------------------------------------------------------------------- /notebooks/Schema Fun.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import requests\n", 12 | "from requests.auth import HTTPBasicAuth\n", 13 | "\n", 14 | "def send_request():\n", 15 | " # Get netconf-state schemas\n", 16 | " # GET http://172.16.1.222:8008/api/operational/netconf-state/schemas\n", 17 | "\n", 18 | " try:\n", 19 | " response = requests.get(\n", 20 | " url=\"http://172.16.1.222:8008/api/operational/netconf-state/schemas\",\n", 21 | " headers={\n", 22 | " \"Accept\": \"application/vnd.yang.data+json\",\n", 23 | " },\n", 24 | " auth=HTTPBasicAuth('cisco', 'cisco')\n", 25 | " )\n", 26 | " return response.content\n", 27 | " except requests.exceptions.RequestException:\n", 28 | " print('HTTP Request failed')" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": { 35 | "collapsed": false 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "content = send_request()" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": { 46 | "collapsed": false 47 | }, 48 | "outputs": [], 49 | "source": [ 50 | "import json\n", 51 | "\n", 52 | "r = json.loads(content)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": { 59 | "collapsed": false 60 | }, 61 | "outputs": [], 62 | "source": [ 63 | "module_names = [s['identifier'] for s in r['ietf-netconf-monitoring:schemas']['schema']]" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": { 70 | "collapsed": false 71 | }, 72 | "outputs": [], 73 | "source": [ 74 | "module_names" 75 | ] 76 | } 77 | ], 78 | "metadata": { 79 | "kernelspec": { 80 | "display_name": "Python 2", 81 | "language": "python", 82 | "name": "python2" 83 | }, 84 | "language_info": { 85 | "codemirror_mode": { 86 | "name": "ipython", 87 | "version": 2 88 | }, 89 | "file_extension": ".py", 90 | "mimetype": "text/x-python", 91 | "name": "python", 92 | "nbconvert_exporter": "python", 93 | "pygments_lexer": "ipython2", 94 | "version": "2.7.11" 95 | } 96 | }, 97 | "nbformat": 4, 98 | "nbformat_minor": 0 99 | } 100 | -------------------------------------------------------------------------------- /notebooks/Telemetry Scratch.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import collections\n", 12 | "import itertools" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": { 19 | "collapsed": false 20 | }, 21 | "outputs": [], 22 | "source": [ 23 | "i = itertools.count(1)\n", 24 | "d = collections.deque([], 3)" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": { 31 | "collapsed": false 32 | }, 33 | "outputs": [], 34 | "source": [ 35 | "d.appendleft(i.next())\n", 36 | "print d" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": { 43 | "collapsed": false 44 | }, 45 | "outputs": [], 46 | "source": [ 47 | "import json\n", 48 | "\n", 49 | "json.dumps(list(d))" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": { 56 | "collapsed": true 57 | }, 58 | "outputs": [], 59 | "source": [ 60 | "import pickle\n", 61 | "class PythonObjectEncoder(json.JSONEncoder):\n", 62 | " def default(self, obj):\n", 63 | " if isinstance(obj, (list, dict, str, unicode, int, float, bool, type(None))):\n", 64 | " return json.JSONEncoder.default(self, obj)\n", 65 | " return {'_python_object': pickle.dumps(obj.__str__())}\n" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": { 72 | "collapsed": false 73 | }, 74 | "outputs": [], 75 | "source": [ 76 | "p = PythonObjectEncoder()\n", 77 | "p.default(d)" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": { 84 | "collapsed": false 85 | }, 86 | "outputs": [], 87 | "source": [ 88 | "dir(d)" 89 | ] 90 | } 91 | ], 92 | "metadata": { 93 | "kernelspec": { 94 | "display_name": "Python 2", 95 | "language": "python", 96 | "name": "python2" 97 | }, 98 | "language_info": { 99 | "codemirror_mode": { 100 | "name": "ipython", 101 | "version": 2 102 | }, 103 | "file_extension": ".py", 104 | "mimetype": "text/x-python", 105 | "name": "python", 106 | "nbconvert_exporter": "python", 107 | "pygments_lexer": "ipython2", 108 | "version": "2.7.11" 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 0 113 | } 114 | -------------------------------------------------------------------------------- /notebooks/big-acl.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import ipaddress\n", 12 | "import random\n", 13 | "import jinja2\n", 14 | "\n", 15 | "net1 = ipaddress.ip_network(u'192.168.0.0/16')\n", 16 | "net2 = ipaddress.ip_network(u'172.16.0.0/16')\n", 17 | "\n", 18 | "alist1 = list(net1)\n", 19 | "alist2 = list(net2)\n", 20 | "\n", 21 | "random.shuffle(alist1)\n", 22 | "random.shuffle(alist2)" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": { 29 | "collapsed": false 30 | }, 31 | "outputs": [], 32 | "source": [ 33 | "#interface = ipaddress.IPv4Interface(u'10.55.106.5/28')\n", 34 | "#print(interface.network)\n", 35 | "#net3 = ipaddress.ip_network(u'10.55.106.0/28')\n", 36 | "\n", 37 | "#for addr in net3:\n", 38 | "# print(\"sudo ping -c 5 {}\".format(addr))\n", 39 | " " 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": { 46 | "collapsed": false 47 | }, 48 | "outputs": [], 49 | "source": [ 50 | "acl_raw = []\n", 51 | "for n, (src, dst) in enumerate(zip(alist1, alist2)):\n", 52 | " acl_raw.append((n, src, dst))" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": { 59 | "collapsed": true 60 | }, 61 | "outputs": [], 62 | "source": [ 63 | "HOST = '127.0.0.1'\n", 64 | "PORT = 8305\n", 65 | "USER = 'cisco'\n", 66 | "PASS = 'cisco'" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": { 73 | "collapsed": false 74 | }, 75 | "outputs": [], 76 | "source": [ 77 | "from ncclient import manager\n", 78 | "from lxml import etree\n", 79 | "\n", 80 | "def pretty_print(nc_retval):\n", 81 | " print(etree.tostring(nc_retval.data_ele, pretty_print=True))\n", 82 | " \n", 83 | "def my_unknown_host_cb(host, fingerprint):\n", 84 | " return True\n", 85 | " \n", 86 | "m = manager.connect(host=HOST, port=PORT, username=USER, password=PASS,\n", 87 | " timeout=86400,\n", 88 | " allow_agent=False,\n", 89 | " look_for_keys=False,\n", 90 | " hostkey_verify=False,\n", 91 | " unknown_host_cb=my_unknown_host_cb)" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": { 98 | "collapsed": false 99 | }, 100 | "outputs": [], 101 | "source": [ 102 | "ACL_TEMPLATE = jinja2.Template('''\n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " {{ACL_NAME}}\n", 107 | " \n", 108 | " {% for N, A, B in LIST %}\n", 109 | " {{N}}\n", 110 | " permit\n", 111 | " \n", 112 | " {{A}}\n", 113 | " \n", 114 | " \n", 115 | " {{B}}\n", 116 | " \n", 117 | " 10{% endfor %}\n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " ''')" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": { 130 | "collapsed": false 131 | }, 132 | "outputs": [], 133 | "source": [ 134 | "big_acl = ACL_TEMPLATE.render(ACL_NAME='BIG', LIST=acl_raw)" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": { 141 | "collapsed": false 142 | }, 143 | "outputs": [], 144 | "source": [ 145 | "print(len(big_acl))" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": null, 151 | "metadata": { 152 | "collapsed": false 153 | }, 154 | "outputs": [], 155 | "source": [ 156 | "try:\n", 157 | " m.edit_config(big_acl, target='candidate', format='xml')\n", 158 | " m.commit()\n", 159 | " c = m.get_config(source='running', filter=('subtree', filter))\n", 160 | " pretty_print(c)\n", 161 | "except TimeoutExpiredError as e:\n", 162 | " print(\"Operation timeout!\")\n", 163 | "except Exception as e:\n", 164 | " print(\"severity={}, tag={}\".format(e.severity, e.tag))\n", 165 | " print(e)" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": null, 171 | "metadata": { 172 | "collapsed": false 173 | }, 174 | "outputs": [], 175 | "source": [ 176 | "filter = ''''''\n", 177 | "\n", 178 | "c = m.get_config(source='running', filter=('subtree', filter))\n", 179 | "pretty_print(c)" 180 | ] 181 | } 182 | ], 183 | "metadata": { 184 | "kernelspec": { 185 | "display_name": "Python 2", 186 | "language": "python", 187 | "name": "python2" 188 | }, 189 | "language_info": { 190 | "codemirror_mode": { 191 | "name": "ipython", 192 | "version": 2 193 | }, 194 | "file_extension": ".py", 195 | "mimetype": "text/x-python", 196 | "name": "python", 197 | "nbconvert_exporter": "python", 198 | "pygments_lexer": "ipython2", 199 | "version": "2.7.12" 200 | } 201 | }, 202 | "nbformat": 4, 203 | "nbformat_minor": 0 204 | } 205 | -------------------------------------------------------------------------------- /notebooks/jxmlease-sample.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "#\n", 12 | "# Get running config from an IOS-XR device and print out some\n", 13 | "# interface information. Shows how to use the jxmlease library\n", 14 | "# for when you'd rather have JSON but have to deal with XML!\n", 15 | "#\n", 16 | "from ncclient import manager\n", 17 | "import jxmlease\n", 18 | "import json\n", 19 | "\n", 20 | "HOST = '127.0.0.1'\n", 21 | "PORT = 8304\n", 22 | "USER = 'cisco'\n", 23 | "PASS = 'cisco'\n", 24 | "\n", 25 | "def my_unknown_host_cb(host, fingerprint):\n", 26 | " return True\n", 27 | "\n", 28 | "m = manager.connect(host=HOST, port=PORT, username=USER, password=PASS,\n", 29 | " timeout=600,\n", 30 | " allow_agent=False,\n", 31 | " look_for_keys=False,\n", 32 | " hostkey_verify=False,\n", 33 | " unknown_host_cb=my_unknown_host_cb)\n", 34 | "\n", 35 | "c = m.get_config(source='running')\n", 36 | "r = jxmlease.parse(c.data_xml)\n", 37 | "\n", 38 | "#for intf in r[u'data'][u'interface-configurations'][u'interface-configuration']:\n", 39 | "# if 'ipv4-network' in intf.keys():\n", 40 | "# print(\"{} has IPv4 address {}\".format(\n", 41 | "# intf[u'interface-name'],\n", 42 | "# intf[u'ipv4-network'][u'addresses'][u'primary'][u'address']))\n", 43 | "# else:\n", 44 | "# print(\"{} has no IPv4 network config\".format(intf[u'interface-name']))\n", 45 | "\n", 46 | "print(r.emit_xml())\n", 47 | "# print(json.dumps(r, indent=2))\n", 48 | "\n", 49 | "#c = m.get('''\n", 50 | "# \n", 51 | "# \n", 52 | "# \n", 53 | "#''')\n", 54 | "#r = jxmlease.parse(c.data_xml)\n", 55 | "\n", 56 | "#for s in sorted(r[u'data'][u'netconf-state'][u'schemas'][u'schema']):\n", 57 | "# ident = s[u'identifier']\n", 58 | "# if 'openconfig' in ident:\n", 59 | "# print(ident)" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": null, 65 | "metadata": { 66 | "collapsed": false 67 | }, 68 | "outputs": [], 69 | "source": [ 70 | "import jxmlease\n", 71 | "from jxmlease import XMLDictNode\n", 72 | "from jxmlease import XMLCDATANode\n", 73 | "\n", 74 | "\n", 75 | "# \n", 76 | "r1 = XMLDictNode()\n", 77 | "top = r1.add_node('interface-configurations', xml_attrs={'xmlns': 'http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg'})\n", 78 | "print r1.emit_xml()\n", 79 | "\n", 80 | "r2 = XMLDictNode() # '')\n", 81 | "r2['interface-configurations'] = ''\n", 82 | "r2['interface-configurations'].xml_attrs = {'xmlns': 'http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg'}\n", 83 | "print r2.emit_xml()" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": { 90 | "collapsed": false 91 | }, 92 | "outputs": [], 93 | "source": [ 94 | "top.xml_attrs" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": { 101 | "collapsed": false 102 | }, 103 | "outputs": [], 104 | "source": [ 105 | "import jxmlease\n", 106 | "\n", 107 | "r = jxmlease.parse('')\n", 108 | "r" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "# DictToXML" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": { 122 | "collapsed": false 123 | }, 124 | "outputs": [], 125 | "source": [ 126 | "import dicttoxml\n", 127 | "\n", 128 | "obj = { u'interface-configurations': u''}\n", 129 | "\n", 130 | "xml = dicttoxml.dicttoxml(obj, attr_type=False, root=False)\n", 131 | "\n", 132 | "print(xml)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "# Using lxml" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": { 146 | "collapsed": false 147 | }, 148 | "outputs": [], 149 | "source": [ 150 | "from lxml import etree\n", 151 | "\n", 152 | "IFMGR = 'http://cisco.com/ns/yang/Cisco-IOS-XR-ifmgr-cfg'\n", 153 | "\n", 154 | "NC_NAMESPACE = 'urn:ietf:params:xml:ns:netconf:base:1.0'\n", 155 | "\n", 156 | "NC = '{%s}' % NC_NAMESPACE\n", 157 | "\n", 158 | "NSMAP = {\n", 159 | " 'nc': NC_NAMESPACE\n", 160 | "}\n", 161 | "\n", 162 | "def serialize(d, xmlns=IFMGR):\n", 163 | " \"\"\"Serialize a dictionary to XML\"\"\"\n", 164 | " assert len(d.keys()) == 1, 'Cannot encode more than one root element'\n", 165 | " name = d.keys()[0]\n", 166 | " root = etree.Element(name, xmlns=xmlns, nsmap=NSMAP)\n", 167 | " populate_element(root, d[name])\n", 168 | "\n", 169 | " return etree.tostring(root, pretty_print=True)\n", 170 | "\n", 171 | "\n", 172 | "def populate_element(element, e):\n", 173 | " \"\"\"Populates an etree with the given dictionary\"\"\"\n", 174 | " if type(e) is dict:\n", 175 | " # serialize child dictionary\n", 176 | " for k, v in e.iteritems():\n", 177 | " if type(v) is dict:\n", 178 | " child = etree.element(k)\n", 179 | " populate_element(child, v)\n", 180 | " else:\n", 181 | " if k[0] == '_':\n", 182 | " attr = k[1:]\n", 183 | " element.set(NC+attr, v)\n", 184 | " else:\n", 185 | " leaf = etree.Element(k, nsmap=NSMAP)\n", 186 | " leaf.text = unicode(v)\n", 187 | " element.append(leaf)\n", 188 | " elif type(e) is list:\n", 189 | " k = element.tag\n", 190 | " if k[-1] == 's':\n", 191 | " name = k[:-1]\n", 192 | " else:\n", 193 | " name = k\n", 194 | " for item in e:\n", 195 | " child = etree.Element(name, nsmap=NSMAP)\n", 196 | " populate_element(child, item)\n", 197 | " element.append(child)\n", 198 | " \n", 199 | "d1 = {\n", 200 | " u'interface-configurations': [\n", 201 | " {\n", 202 | " u'interface-name': 'GigabitEthernet0/0/0/0'\n", 203 | " }\n", 204 | " ]\n", 205 | "}\n", 206 | "d2 = {\n", 207 | " u'config': {\n", 208 | " u'interface-configurations': [\n", 209 | " {\n", 210 | " u'_operation': 'delete',\n", 211 | " u'interface-name': 'GigabitEthernet0/0/0/0'\n", 212 | " }\n", 213 | " ]\n", 214 | " }\n", 215 | "}\n", 216 | "\n", 217 | "\n", 218 | "print serialize(d1)\n", 219 | "print serialize(d2)" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": null, 225 | "metadata": { 226 | "collapsed": true 227 | }, 228 | "outputs": [], 229 | "source": [ 230 | "" 231 | ] 232 | } 233 | ], 234 | "metadata": { 235 | "kernelspec": { 236 | "display_name": "Python 2", 237 | "language": "python", 238 | "name": "python2" 239 | }, 240 | "language_info": { 241 | "codemirror_mode": { 242 | "name": "ipython", 243 | "version": 2.0 244 | }, 245 | "file_extension": ".py", 246 | "mimetype": "text/x-python", 247 | "name": "python", 248 | "nbconvert_exporter": "python", 249 | "pygments_lexer": "ipython2", 250 | "version": "2.7.12" 251 | } 252 | }, 253 | "nbformat": 4, 254 | "nbformat_minor": 0 255 | } -------------------------------------------------------------------------------- /notebooks/more-ydk-play.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "#\n", 12 | "# Only run this code if you want to see lots of debug!!\n", 13 | "#\n", 14 | "#import logging\n", 15 | "\n", 16 | "#handler = logging.StreamHandler()\n", 17 | "#for l in ['ncclient.transport.session', 'ncclient.operations.rpc']:\n", 18 | "# logger = logging.getLogger(l)\n", 19 | "# logger.addHandler(handler)\n", 20 | "# logger.setLevel(logging.DEBUG)" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "Put in your own details below...this IP address is a test machine for the DMI team in SJC." 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": { 34 | "collapsed": true 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "# ASR1K\n", 39 | "HOST = '172.27.255.40'\n", 40 | "PORT = 830\n", 41 | "USER = 'admin'\n", 42 | "PASS = 'admin'" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": { 49 | "collapsed": true 50 | }, 51 | "outputs": [], 52 | "source": [ 53 | "# 3850\n", 54 | "HOST = '10.85.70.86'\n", 55 | "PORT = 830\n", 56 | "USER = 'admin'\n", 57 | "PASS = 'admin'" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "### Basic YDK initialization" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": { 71 | "collapsed": false 72 | }, 73 | "outputs": [], 74 | "source": [ 75 | "from ydk.types import Empty\n", 76 | "from ydk.errors import YPYError\n", 77 | "from ydk.services import CRUDService\n", 78 | "from ydk.providers import NetconfServiceProvider\n", 79 | "\n", 80 | "session = NetconfServiceProvider(\n", 81 | " address=HOST,\n", 82 | " port=PORT,\n", 83 | " username=USER,\n", 84 | " password=PASS,\n", 85 | " protocol='ssh')\n", 86 | "\n", 87 | "# Initialize a CRUD service\n", 88 | "c = CRUDService()" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "### Some helpers to print, create and delete Loopbacks" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": { 102 | "collapsed": false 103 | }, 104 | "outputs": [], 105 | "source": [ 106 | "import ydk.models.ned as ned\n", 107 | "\n", 108 | "# create a Loopback\n", 109 | "def create_loopback(index):\n", 110 | " new_loopback = ned.Native.Interface.Loopback()\n", 111 | " new_loopback.name = index\n", 112 | " c.create(session, new_loopback)\n", 113 | "\n", 114 | "# create a list of Loopbacks\n", 115 | "def create_loopback_list(index_list):\n", 116 | " intf_container = ned.Native.Interface()\n", 117 | " for index in index_list:\n", 118 | " new_loopback = ned.Native.Interface.Loopback()\n", 119 | " new_loopback.name = index\n", 120 | " new_loopback.description = \"Created Interface {}\".format(index)\n", 121 | " intf_container.loopback.append(new_loopback)\n", 122 | " c.create(session, intf_container)\n", 123 | "\n", 124 | "# delete a Loopback\n", 125 | "def delete_loopback(index):\n", 126 | " new_loopback = ned.Native.Interface.Loopback()\n", 127 | " new_loopback.name = index\n", 128 | " c.delete(session, new_loopback)\n", 129 | "\n", 130 | "def print_loopbacks():\n", 131 | " q_loopbacks = ned.Native.Interface.Loopback()\n", 132 | " loopbacks = c.read(session, q_loopbacks)\n", 133 | " print \"Loopbacks:\"\n", 134 | " for l in loopbacks:\n", 135 | " print \" {} {}\".format(l.name, l.description)" 136 | ] 137 | }, 138 | { 139 | "cell_type": "raw", 140 | "metadata": {}, 141 | "source": [ 142 | "print_loopback()" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": { 149 | "collapsed": false 150 | }, 151 | "outputs": [], 152 | "source": [ 153 | "create_loopback(123)\n", 154 | "print_loopbacks()\n", 155 | "delete_loopback(123)\n", 156 | "print_loopbacks()" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": { 163 | "collapsed": false 164 | }, 165 | "outputs": [], 166 | "source": [ 167 | "create_loopback_list([5,6,7])\n", 168 | "print_loopbacks()" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": { 175 | "collapsed": false 176 | }, 177 | "outputs": [], 178 | "source": [ 179 | "delete_loopback(5)\n", 180 | "delete_loopback(6)\n", 181 | "delete_loopback(7)\n", 182 | "print_loopbacks()" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "### Some helpers to print, create and delete Loopbacks" 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": null, 195 | "metadata": { 196 | "collapsed": true 197 | }, 198 | "outputs": [], 199 | "source": [ 200 | "import ydk.models.ned as ned\n", 201 | "\n", 202 | "def print_vrfs():\n", 203 | " q_vrf = ned.Native.Vrf()\n", 204 | " vrfs = c.read(session, q_vrf)\n", 205 | " print(\"VRFs:\")\n", 206 | " for v in vrfs.definition:\n", 207 | " print(\" {}\".format(v.name))\n", 208 | "\n", 209 | "# add a new VRF\n", 210 | "def add_vrf(name, rd):\n", 211 | " vrfs = ned.Native.Vrf()\n", 212 | " new_vrf = ned.Native.Vrf.Definition()\n", 213 | " new_vrf.name = name\n", 214 | " new_vrf.rd = rd\n", 215 | " vrfs.definition.append(new_vrf)\n", 216 | " c.create(session, vrfs)\n", 217 | "\n", 218 | "# delete a VRF\n", 219 | "def delete_vrf(name):\n", 220 | " to_delete = ned.Native.Vrf.Definition()\n", 221 | " to_delete.name = name\n", 222 | " c.delete(session, to_delete)" 223 | ] 224 | }, 225 | { 226 | "cell_type": "code", 227 | "execution_count": null, 228 | "metadata": { 229 | "collapsed": false 230 | }, 231 | "outputs": [], 232 | "source": [ 233 | "print_vrfs()" 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": null, 239 | "metadata": { 240 | "collapsed": false 241 | }, 242 | "outputs": [], 243 | "source": [ 244 | "add_vrf('foo', '1:1')\n", 245 | "add_vrf('bar', '1:1')\n", 246 | "\n", 247 | "print_vrfs()" 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": { 254 | "collapsed": false 255 | }, 256 | "outputs": [], 257 | "source": [ 258 | "delete_vrf('foo')\n", 259 | "delete_vrf('bar')\n", 260 | "\n", 261 | "print_vrfs()" 262 | ] 263 | } 264 | ], 265 | "metadata": { 266 | "kernelspec": { 267 | "display_name": "Python 2", 268 | "language": "python", 269 | "name": "python2" 270 | }, 271 | "language_info": { 272 | "codemirror_mode": { 273 | "name": "ipython", 274 | "version": 2 275 | }, 276 | "file_extension": ".py", 277 | "mimetype": "text/x-python", 278 | "name": "python", 279 | "nbconvert_exporter": "python", 280 | "pygments_lexer": "ipython2", 281 | "version": "2.7.12" 282 | } 283 | }, 284 | "nbformat": 4, 285 | "nbformat_minor": 0 286 | } 287 | -------------------------------------------------------------------------------- /notebooks/paramiko-xe.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# Local CSR 1000v (running under vagrant)\n", 10 | "HOST = '127.0.0.1'\n", 11 | "PORT_NC = 2223\n", 12 | "PORT_SSH = 2222\n", 13 | "USER = 'vagrant'\n", 14 | "PASS = 'vagrant'" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 3, 20 | "metadata": { 21 | "scrolled": false 22 | }, 23 | "outputs": [ 24 | { 25 | "name": "stdout", 26 | "output_type": "stream", 27 | "text": [ 28 | "\r\n", 29 | "\r\n", 30 | "\r\n", 31 | "csr#\n", 32 | "show ip int brief\r\n", 33 | "Interface IP-Address OK? Method Status Protocol\r\n", 34 | "GigabitEthernet1 10.0.2.15 YES DHCP up up \r\n", 35 | "GigabitEthernet2 unassigned YES NVRAM administratively down down \r\n", 36 | "GigabitEthernet3 unassigned YES NVRAM administratively down down \r\n", 37 | "GigabitEthernet4 unassigned YES NVRAM administratively down down \r\n", 38 | "Loopback101 172.16.0.1 YES manual up up \r\n", 39 | "csr#\n", 40 | "conf t\r\n", 41 | "Enter configuration commands, one per line. End with CNTL/Z.\r\n", 42 | "csr(config)#\n", 43 | "interface lo101\r\n", 44 | "csr(config-if)#\n", 45 | "ip address 172.16.0.1 255.255.255.255\r\n", 46 | "csr(config-if)#\n", 47 | "end\r\n", 48 | "csr#\n" 49 | ] 50 | } 51 | ], 52 | "source": [ 53 | "import paramiko\n", 54 | "\n", 55 | "#\n", 56 | "# prompts are hostname-dependent\n", 57 | "#\n", 58 | "PROMPT1 = \"csr#\"\n", 59 | "PROMPT2 = \"csr(config)#\"\n", 60 | "PROMPT3 = \"csr(config-if)#\"\n", 61 | "\n", 62 | "def get_reply(chan, eom):\n", 63 | " bytes = u''\n", 64 | " while bytes.find(eom)==-1:\n", 65 | " bytes += chan.recv(65535).decode('utf-8')\n", 66 | " return bytes\n", 67 | "\n", 68 | "try:\n", 69 | " client = paramiko.SSHClient()\n", 70 | " client.set_missing_host_key_policy(paramiko.AutoAddPolicy)\n", 71 | " \n", 72 | " client.connect(HOST,\n", 73 | " port=PORT_SSH,\n", 74 | " username=USER,\n", 75 | " password=PASS,\n", 76 | " look_for_keys=False, allow_agent=False)\n", 77 | "\n", 78 | " conn = client.invoke_shell()\n", 79 | " print(get_reply(conn, PROMPT1))\n", 80 | " conn.send(\"show ip int brief\\n\")\n", 81 | " print(get_reply(conn, PROMPT1))\n", 82 | " conn.send(\"conf t\\n\")\n", 83 | " print(get_reply(conn, PROMPT2))\n", 84 | " conn.send(\"interface lo101\\n\")\n", 85 | " print(get_reply(conn, PROMPT3))\n", 86 | " conn.send(\"ip address 172.16.0.1 255.255.255.255\\n\")\n", 87 | " print(get_reply(conn, PROMPT3))\n", 88 | " conn.send(\"end\\n\")\n", 89 | " print(get_reply(conn, PROMPT1))\n", 90 | "\n", 91 | "finally:\n", 92 | " client.close()" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [] 101 | } 102 | ], 103 | "metadata": { 104 | "kernelspec": { 105 | "display_name": "Python 3", 106 | "language": "python", 107 | "name": "python3" 108 | }, 109 | "language_info": { 110 | "codemirror_mode": { 111 | "name": "ipython", 112 | "version": 3 113 | }, 114 | "file_extension": ".py", 115 | "mimetype": "text/x-python", 116 | "name": "python", 117 | "nbconvert_exporter": "python", 118 | "pygments_lexer": "ipython3", 119 | "version": "3.6.4" 120 | } 121 | }, 122 | "nbformat": 4, 123 | "nbformat_minor": 2 124 | } 125 | -------------------------------------------------------------------------------- /notebooks/xe-candidate-locking-and-syncing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# XE Candidate Datastore Demo\n", 8 | "\n", 9 | "This example uses **lock** and **unlock** on both the candidate and running datastores." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": null, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "HOST = '127.0.0.1'\n", 19 | "PORT_NC = 2223\n", 20 | "USER = 'vagrant'\n", 21 | "PASS = 'vagrant'" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Connect ncclient" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "from ncclient import manager\n", 38 | "from lxml import etree\n", 39 | "\n", 40 | "\n", 41 | "def pretty_print(retval):\n", 42 | " print(etree.tostring(retval.data, pretty_print=True))\n", 43 | "\n", 44 | "def my_unknown_host_cb(host, fingerprint):\n", 45 | " return True\n", 46 | "\n", 47 | "m = manager.connect(host=HOST, port=PORT_NC, username=USER, password=PASS,\n", 48 | " allow_agent=False,\n", 49 | " look_for_keys=False,\n", 50 | " hostkey_verify=False,\n", 51 | " unknown_host_cb=my_unknown_host_cb)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "## BDI Addition Sample Edit Config" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": null, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "config = '''\n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " {}\n", 72 | " hello\n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | "\n", 77 | "'''" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "m.lock(target='running')" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "m.lock(target='candidate')" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": null, 101 | "metadata": {}, 102 | "outputs": [], 103 | "source": [ 104 | "m.edit_config(config.format(666), format='xml', target='candidate', default_operation='merge')" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "m.commit()\n", 114 | "# m.discard_changes()" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": {}, 121 | "outputs": [], 122 | "source": [ 123 | "m.edit_config(config.format(777), format='xml', target='candidate', default_operation='merge')" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "m.commit()\n", 133 | "# m.discard_changes()" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "**Now go check logs and output in separate windows, BEFORE any datastore is unlocked!**" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "### Works" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": null, 153 | "metadata": {}, 154 | "outputs": [], 155 | "source": [ 156 | "m.unlock(target='running')\n", 157 | "m.unlock(target='candidate')" 158 | ] 159 | }, 160 | { 161 | "cell_type": "markdown", 162 | "metadata": {}, 163 | "source": [ 164 | "### Broken :(" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": null, 170 | "metadata": {}, 171 | "outputs": [], 172 | "source": [ 173 | "import time\n", 174 | "\n", 175 | "m.unlock(target='candidate')\n", 176 | "time.sleep(0.75)\n", 177 | "m.unlock(target='running')" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": null, 183 | "metadata": {}, 184 | "outputs": [], 185 | "source": [ 186 | "m.close_session()" 187 | ] 188 | }, 189 | { 190 | "cell_type": "markdown", 191 | "metadata": {}, 192 | "source": [ 193 | "### Display An XML Diff In Text Form" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "from difflib import context_diff\n", 203 | "\n", 204 | "running_before_xml = etree.tostring(running_before, pretty_print=True)\n", 205 | "running_after_xml = etree.tostring(running_after, pretty_print=True)\n", 206 | "candidate_after_xml = etree.tostring(candidate_after, pretty_print=True)\n", 207 | "\n", 208 | "#\n", 209 | "# remember to skip the first few lines that have timestamps & stuff that may differ\n", 210 | "#\n", 211 | "print('\\n'.join(context_diff(running_after_xml.decode().splitlines(),\n", 212 | " candidate_after_xml.decode().splitlines())))" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": {}, 218 | "source": [ 219 | "## Tidyup Sessions" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": null, 225 | "metadata": {}, 226 | "outputs": [], 227 | "source": [] 228 | } 229 | ], 230 | "metadata": { 231 | "kernelspec": { 232 | "display_name": "Python 3", 233 | "language": "python", 234 | "name": "python3" 235 | }, 236 | "language_info": { 237 | "codemirror_mode": { 238 | "name": "ipython", 239 | "version": 3 240 | }, 241 | "file_extension": ".py", 242 | "mimetype": "text/x-python", 243 | "name": "python", 244 | "nbconvert_exporter": "python", 245 | "pygments_lexer": "ipython3", 246 | "version": "3.7.0" 247 | } 248 | }, 249 | "nbformat": 4, 250 | "nbformat_minor": 2 251 | } 252 | -------------------------------------------------------------------------------- /notebooks/xe-datastore-locking.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# XE Datastore Locking\n", 8 | "\n", 9 | "This example uses **lock** and **unlock** on the running datastore to postpone syncing until several operations are done." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "# siddharth's cat9k\n", 19 | "HOST = '10.104.55.60'\n", 20 | "PORT_NC = 830\n", 21 | "USER = 'admin'\n", 22 | "PASS = 'c9k123!'" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "## Connect ncclient" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 2, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "from ncclient import manager\n", 39 | "from lxml import etree\n", 40 | "\n", 41 | "\n", 42 | "def pretty_print(retval):\n", 43 | " print(etree.tostring(retval.data, pretty_print=True))\n", 44 | "\n", 45 | "def my_unknown_host_cb(host, fingerprint):\n", 46 | " return True\n", 47 | "\n", 48 | "m = manager.connect(host=HOST, port=PORT_NC, username=USER, password=PASS,\n", 49 | " allow_agent=False,\n", 50 | " look_for_keys=False,\n", 51 | " hostkey_verify=False,\n", 52 | " unknown_host_cb=my_unknown_host_cb)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "## Switch GigabitEthernet Sample Edit Config" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 3, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "config = '''\n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " {}\n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " {}\n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | "\n", 86 | "'''" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 4, 92 | "metadata": {}, 93 | "outputs": [ 94 | { 95 | "data": { 96 | "text/plain": [ 97 | "\n", 98 | "" 99 | ] 100 | }, 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "output_type": "execute_result" 104 | } 105 | ], 106 | "source": [ 107 | "m.lock(target='running')" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": 5, 113 | "metadata": {}, 114 | "outputs": [ 115 | { 116 | "name": "stdout", 117 | "output_type": "stream", 118 | "text": [ 119 | "\n", 120 | "\n", 121 | "\n", 122 | "\n", 123 | "\n", 124 | "\n", 125 | "\n", 126 | "\n" 127 | ] 128 | } 129 | ], 130 | "source": [ 131 | "print(m.edit_config(config.format('1/1/1', '2,3'), format='xml', target='running'))\n", 132 | "print(m.edit_config(config.format('1/1/2', '3,4'), format='xml', target='running'))\n", 133 | "print(m.edit_config(config.format('1/1/3', '4,5'), format='xml', target='running'))\n", 134 | "print(m.edit_config(config.format('1/1/4', '5,6'), format='xml', target='running'))" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": 6, 140 | "metadata": {}, 141 | "outputs": [ 142 | { 143 | "data": { 144 | "text/plain": [ 145 | "\n", 146 | "" 147 | ] 148 | }, 149 | "execution_count": 6, 150 | "metadata": {}, 151 | "output_type": "execute_result" 152 | } 153 | ], 154 | "source": [ 155 | "m.unlock(target='running')" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 7, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "data": { 165 | "text/plain": [ 166 | "\n", 167 | "" 168 | ] 169 | }, 170 | "execution_count": 7, 171 | "metadata": {}, 172 | "output_type": "execute_result" 173 | } 174 | ], 175 | "source": [ 176 | "m.close_session()" 177 | ] 178 | } 179 | ], 180 | "metadata": { 181 | "kernelspec": { 182 | "display_name": "Python 3", 183 | "language": "python", 184 | "name": "python3" 185 | }, 186 | "language_info": { 187 | "codemirror_mode": { 188 | "name": "ipython", 189 | "version": 3 190 | }, 191 | "file_extension": ".py", 192 | "mimetype": "text/x-python", 193 | "name": "python", 194 | "nbconvert_exporter": "python", 195 | "pygments_lexer": "ipython3", 196 | "version": "3.7.0" 197 | } 198 | }, 199 | "nbformat": 4, 200 | "nbformat_minor": 2 201 | } 202 | -------------------------------------------------------------------------------- /notebooks/ydk-play.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "HOST = '172.27.255.29'\n", 12 | "PORT = 830\n", 13 | "USER = 'admin'\n", 14 | "PASS = 'admin'" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": { 21 | "collapsed": true 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "HOST = '127.0.0.1'\n", 26 | "PORT = 8304\n", 27 | "USER = 'cisco'\n", 28 | "PASS = 'cisco'" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": { 35 | "collapsed": false 36 | }, 37 | "outputs": [], 38 | "source": [ 39 | "import json\n", 40 | "import logging\n", 41 | "from argparse import ArgumentParser\n", 42 | "\n", 43 | "from ydk.types import Empty\n", 44 | "from ydk.errors import YPYError\n", 45 | "from ydk.services import CRUDService\n", 46 | "from ydk.providers import NetconfServiceProvider\n", 47 | "\n", 48 | "session = NetconfServiceProvider(\n", 49 | " address=HOST,\n", 50 | " port=PORT,\n", 51 | " username=USER,\n", 52 | " password=PASS,\n", 53 | " protocol='ssh')\n", 54 | "\n", 55 | "# Initialize a CRUD service\n", 56 | "c = CRUDService()\n" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": { 63 | "collapsed": false 64 | }, 65 | "outputs": [], 66 | "source": [ 67 | "from ydk.models.ifmgr import Cisco_IOS_XR_ifmgr_oper as xr_ifmgr_oper\n", 68 | "\n", 69 | "q_intf_props = xr_ifmgr_oper.InterfaceProperties()\n", 70 | "intf_props = c.read(session, q_intf_props)\n", 71 | "\n", 72 | "for dn in intf_props.data_nodes.data_node:\n", 73 | " print(dn.data_node_name)" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": null, 79 | "metadata": { 80 | "collapsed": false 81 | }, 82 | "outputs": [], 83 | "source": [ 84 | "from ydk.models.pfi import Cisco_IOS_XR_pfi_im_cmd_oper as pfi_oper\n", 85 | "\n", 86 | "q_pfi = pfi_oper.Interfaces()\n", 87 | "pfi = c.read(session, q_pfi)\n", 88 | "\n", 89 | "for intf in pfi.interface_briefs.interface_brief:\n", 90 | " print(intf.interface_name)" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": { 97 | "collapsed": true 98 | }, 99 | "outputs": [], 100 | "source": [] 101 | } 102 | ], 103 | "metadata": { 104 | "kernelspec": { 105 | "display_name": "Python 2", 106 | "language": "python", 107 | "name": "python2" 108 | }, 109 | "language_info": { 110 | "codemirror_mode": { 111 | "name": "ipython", 112 | "version": 2 113 | }, 114 | "file_extension": ".py", 115 | "mimetype": "text/x-python", 116 | "name": "python", 117 | "nbconvert_exporter": "python", 118 | "pygments_lexer": "ipython2", 119 | "version": "2.7.11" 120 | } 121 | }, 122 | "nbformat": 4, 123 | "nbformat_minor": 0 124 | } 125 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "ncc" 3 | description = "Simple NETCONF client app using ncclient and netmiko" 4 | authors = [ 5 | { name = "Einar Nilsen-Nygaard " } 6 | ] 7 | license = "Apache License, Version 2.0" 8 | dynamic = ["version"] 9 | 10 | [tool.poetry] 11 | packages = [ 12 | { include = "scripts", from = "src" }, 13 | { include = "nccutil", from = "src" }, 14 | { include = "ncc", from = "src" }, 15 | ] 16 | version = "0.0.0" 17 | 18 | [tool.poetry-dynamic-versioning] 19 | enable = true 20 | pattern = "^v(?P\\d+\\.\\d+\\.\\d+)$" 21 | 22 | [project.scripts] 23 | ncc = "scripts.ncc:main" 24 | ncc-capture-schema = "scripts.ncc_capture_schema:main" 25 | ncc-get-all-schema = "scripts.ncc_get_all_schema:main" 26 | ncc-get-schema = "scripts.ncc_get_schema:main" 27 | ncc-yang-push = "scripts.ncc_yang_push:main" 28 | 29 | [tool.poetry.requires-plugins] 30 | poetry-dynamic-versioning = { version = ">=1.0.0,<2.0.0", extras = ["plugin"] } 31 | 32 | [build-system] 33 | requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"] 34 | build-backend = "poetry_dynamic_versioning.backend" 35 | 36 | [tool.poetry.dependencies] 37 | python = ">= 3.11,<4.0" 38 | beautifulsoup4 = "^4.13.3,<5.0" 39 | gitpython = "^3.1.44,<4.0" 40 | jinja2 = "^3.1.6" 41 | markupsafe = "^3.0.2,<4.0" 42 | ncclient = ">= 0.7.0, <0.8.0" 43 | netmiko = "^4.5.0,<5.0" 44 | pyang = "^2.6.1,<3.0" 45 | requests = "^2.32.3,<3.0" 46 | urllib3 = "^2.3.0,<3.0" 47 | ssh-python = ">= 1.1.1, <2.0.0" 48 | -------------------------------------------------------------------------------- /sample-ns.json: -------------------------------------------------------------------------------- 1 | { 2 | "if": "urn:ietf:params:xml:ns:yang:ietf-interfaces", 3 | "oc-if": "http://openconfig.net/yang/interfaces" 4 | } 5 | -------------------------------------------------------------------------------- /sample-subscriptions.md: -------------------------------------------------------------------------------- 1 | # Sample Subscriptions 2 | 3 | Here are some sample subscriptions that can be used: 4 | 5 | ## Named Interface `in-octets` 6 | 7 | ``` 8 | python ncc-establish-subscription.py --host=127.0.0.1 --port=2223 -u vagrant -p vagrant \ 9 | --period=1000 \ 10 | --xpath '/interfaces/interface[name="GigabitEthernet1"]/statistics/in-octets' 11 | ``` 12 | 13 | ## Two Subscriptions On Named Interface, `in-octets` and `out-octets` 14 | 15 | ``` 16 | python ncc-establish-subscription.py --host=127.0.0.1 --port=2223 -u vagrant -p vagrant \ 17 | --period=1000 \ 18 | --xpath \ 19 | '/interfaces/interface[name="GigabitEthernet1"]/statistics/in-octets' \ 20 | '/interfaces/interface[name="GigabitEthernet1"]/statistics/out-octets' 21 | ``` 22 | 23 | ## Memory Statistics 24 | 25 | ``` 26 | python ncc-establish-subscription.py --host=127.0.0.1 --port=2223 -u vagrant -p vagrant \ 27 | --period=1000 \ 28 | --xpath '/memory-statistics' 29 | ``` 30 | 31 | ## Memeory Statistics, Named Component 32 | 33 | ``` 34 | python ncc-establish-subscription.py --host=127.0.0.1 --port=2223 -u vagrant -p vagrant \ 35 | --period=1000 \ 36 | --xpath '/memory-statistics/memory-statistic[name="Processor"]' 37 | ``` 38 | 39 | ## CPU Usage Statistics, Named IOSd Component 40 | 41 | ``` 42 | python ncc-establish-subscription.py --host=127.0.0.1 --port=2223 -u vagrant -p vagrant \ 43 | --period=1000 \ 44 | --xpath '/process-cpu-ios-xe-oper:cpu-usage/cpu-utilization/cpu-usage-processes/cpu-usage-process[pid=1][name="Chunk Manager"]' 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-bgp-basic.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 6 | 7 | 8 | 9 | 10 | 2.2.2.3 11 | 200 12 | 13 | 14 | 15 | 16 | unicast 17 | 18 | 2.2.2.3 19 | 20 | 21 | 22 | 10.1.1.1 23 | 255.255.255.255 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-bgp-del.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-bgp-nbr-create.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 6 | 7 | {{NBR_ID}} 8 | {{REMOTE_AS}} 9 | 10 | 11 | 12 | 13 | unicast 14 | 15 | {{NBR_ID}} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-bgp-nbr-delete.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 6 | 7 | {{NBR_ID}} 8 | 9 | 10 | 11 | 12 | unicast 13 | 14 | {{NBR_ID}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-bgp-nbr-merge.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 6 | 7 | {{NBR_ID}} 8 | {{REMOTE_AS}} 9 | 10 | 11 | 12 | 13 | unicast 14 | 15 | {{NBR_ID}} 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-bgp-nbr-remove.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 6 | 7 | {{NBR_ID}} 8 | 9 | 10 | 11 | 12 | unicast 13 | 14 | {{NBR_ID}} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-intf-named-set-mtu.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <{{IF_TYPE}}> 5 | {{IF_NUM}} 6 | 7 |
8 | 9 |
10 | {{IP_MTU}} 11 |
12 | 13 |
14 |
15 |
-------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-loop-merge.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NUMBER}} 6 | CLEU Demo 7 | 8 |
9 | 10 |
{{IP_ADDR}}
11 | {{IP_MASK}} 12 |
13 |
14 |
15 |
16 |
17 |
18 |
-------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-loop-remove.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NUMBER}} 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-oc-bgp-nbr-merge.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NBR_ID}} 6 | 7 | {{NBR_ID}} 8 | {{REMOTE_AS}} 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /snippets-cl/editconfigs/cl-oc-intf-named-set-mtu.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | 6 | 7 | {{IP_SUBIF_IDX}} 8 | 9 | 10 | {{IP_MTU}} 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-fib-oper.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-ietf-intf-oper-stats.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-ietf-intf-oper.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-intf-oper-in-out-octets.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-intf-oper-named-in-out-octets.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-intf-oper-named-stats.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-intf-oper-named.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-intf-oper-stats.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-intf-oper.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets-cl/filters/cl-oc-intf-named.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/00-oper-data-enable-16.4.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 30000 6 | false 7 | 8 | ACL 9 | 120000 10 | poll 11 | 12 | 13 | Archive 14 | 120000 15 | poll 16 | 17 | 18 | Environment 19 | 120000 20 | poll 21 | 22 | 23 | FlowMonitor 24 | 120000 25 | poll 26 | 27 | 28 | Interfaces 29 | 120000 30 | poll 31 | 32 | 33 | PlatformSoftware 34 | 120000 35 | poll 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/00-oper-data-enable.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 30000 6 | false 7 | 8 | parse.showACL 9 | 120000 10 | poll 11 | 12 | 13 | parse.showArchive 14 | 120000 15 | poll 16 | 17 | 18 | parse.showEnvironment 19 | 120000 20 | poll 21 | 22 | 23 | parse.showFlowMonitor 24 | 120000 25 | poll 26 | 27 | 28 | parse.showInterfaces 29 | 120000 30 | poll 31 | 32 | 33 | parse.showIpRoute 34 | 120000 35 | poll 36 | 37 | 38 | parse.showMemoryStatistics 39 | 120000 40 | poll 41 | 42 | 43 | parse.showPlatformSoftware 44 | 120000 45 | poll 46 | 47 | 48 | parse.showProcessesCPU 49 | 120000 50 | poll 51 | 52 | 53 | parse.showProcessesMemory 54 | 120000 55 | poll 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/00-snmp-config.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 1.3.6.1.4.1.9.9.41.2.0.1 8 | 9 | 10 | 1.3.6.1.6.3.1.1.5.3 11 | 12 | 13 | 1.3.6.1.6.3.1.1.5.4 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/01-oper-data-disable.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/01-snmp-config-disable: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-acl-00-create.tmpl: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 8 | TESTTEST 9 | 10 | 11 11 | 12 | deny 13 | ip 14 | 15 | 2.2.2.2 16 | 0.0.0.0 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-acl-00-merge.tmpl: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 8 | TESTTEST 9 | 10 | 13 11 | 12 | deny 13 | ip 14 | 15 | 4.4.4.4 16 | 0.0.0.0 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-acl-01-replace.tmpl: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 8 | TESTTEST 9 | 10 | 12 11 | 12 | deny 13 | ip 14 | 15 | 3.3.3.3 16 | 0.0.0.0 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-acl-02-remove.tmpl: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 8 | TESTTEST 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-create-acl.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ACL_NAME}} 7 | 8 | 11 9 | 10 | permit 11 | ip 12 | 13 | 2.2.2.2 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-create-class-map.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{C_NAME}} 6 | match-any 7 | 8 | cs5 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-create-policy-map.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{P_NAME}} 6 | 7 | {{C_NAME}} 8 | 9 | police 10 | 11 | 12 | 13 | 14 | 10 15 | 16 | 17 | 18 | 19 | 20 | 21 | priority 22 | 23 | 1 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-create-vlan.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{VLAN}} 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-delete-acl.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ACL_NAME}} 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-delete-class-map.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{C_NAME}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-delete-policy-map.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{P_NAME}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-delete-vlan.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{VLAN}} 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-add-acl.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 9 | 10 | 11 | {{ACL}} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-add-qos.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | {{P_NAME}} 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-delete-acl.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 9 | 10 | {{ACL}} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-delete-qos.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{INTF_NAME}} 7 | 8 | 9 | {{P_NAME}} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-no-shut.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-no-switchport.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | false 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-shutdown.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-switchport.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | false 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-intf-vlan-change.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 9 | {{VLAN}} 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-router-ospf-add-network.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ROUTER_ID}} 6 | 7 | {{NETWORK}} 8 | {{MASK}} 9 | 0 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/native-router-ospf-delete-network.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ROUTER_ID}} 6 | 7 | {{NETWORK}} 8 | {{MASK}} 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /snippets-xe/editconfigs/openconfig-intf-ip-address.tmpl: -------------------------------------------------------------------------------- 1 | {# with XE on switches, you will need to make sure no switchport happens first#} 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 0 9 | 10 | 11 |
12 | {{IP_ADDR}} 13 | 14 | {{IP_ADDR}} 15 | 16 | {# probably should make this a variable too#} 17 | 24 18 | 19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
-------------------------------------------------------------------------------- /snippets-xe/filters/MIB-filter.tmpl: -------------------------------------------------------------------------------- 1 | <{{MIB}}:{{MIB}} xmlns:{{MIB}}="urn:ietf:params:xml:ns:yang:smiv2:{{MIB}}"/> -------------------------------------------------------------------------------- /snippets-xe/filters/confd-state.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets-xe/filters/ietf-intf-named-description.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets-xe/filters/ietf-intf-named.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | -------------------------------------------------------------------------------- /snippets-xe/filters/ietf-intf.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets-xe/filters/native-gig-interface-vlan.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets-xe/filters/native-intf-named.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | 6 | 7 | -------------------------------------------------------------------------------- /snippets-xe/filters/netconf-state.tmpl: -------------------------------------------------------------------------------- 1 | 5 | {# Jinja2 comments #} 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets-xe/filters/openconfig-intf.tmpl: -------------------------------------------------------------------------------- 1 | {# comment: This is an example of the openconfig interfaces filter. Need to explicitly gert config vs oper-data #} 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/00-loop-remove.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 111 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/00-loop.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 111 6 | test 7 | 8 |
9 | 10 |
1.2.3.4
11 | 255.255.255.255 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /snippets/editconfigs/add-loop.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | Loop-back100 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/add_neighbor.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NEIGHBOR_ADDR}} 6 | 7 | {{NEIGHBOR_ADDR}} 8 | {{REMOTE_AS}} 9 | {{DESCRIPTION}} 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /snippets/editconfigs/add_static_route_default.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10.1.1.0 10 | 24 11 | 12 | 13 | 14 | Loopback0 15 | 10.10.10.1 16 | 17 | 18 | 19 | 20 | 21 | 10.1.2.0 22 | 24 23 | 24 | 25 | 26 | Loopback0 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /snippets/editconfigs/bdi-01-create-noshutdown.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NAME}} 6 | {{DESCR}} 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/bdi-01-create.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NAME}} 6 | {{DESCR}} 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/bdi-02-remove.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NAME}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/bdi-03-noshut.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NAME}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/bgp-01.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2 6 | 7 | 8 | 9 | unicast 10 | 11 | 12 | 4 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /snippets/editconfigs/bgp-02.2.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2 6 | 7 | 192.168.1.1 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /snippets/editconfigs/bgp-02.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2 6 | 7 | 192.168.1.1 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /snippets/editconfigs/bgp-03.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 2 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/class_dscp31_cr.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | dscp-31 7 | 8 | 9 | 31 10 | 11 | 12 | 13 | 14 | 2 | 3 | 4 | 5 | qos 6 | dscp-31 7 | 8 | 9 | 10 | 2 | 3 | 4 | 5 | qos 6 | FOO 7 | 8 | 9 | 1 10 | 2 11 | 3 12 | 4 13 | 5 14 | 6 15 | 7 16 | 8 17 | 9 18 | 10 19 | 11 20 | 12 21 | 13 22 | 14 23 | 15 24 | 16 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /snippets/editconfigs/classmap_delete_einarnn_all.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | EINARNN_3 7 | 8 | 9 | qos 10 | EINARNN_4 11 | 12 | 13 | qos 14 | EINARNN_5 15 | 16 | 17 | qos 18 | EINARNN_6 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /snippets/editconfigs/classmap_einarnn_3.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | EINARNN_3 7 | 8 | 9 | 42-45 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /snippets/editconfigs/classmap_einarnn_4.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | EINARNN_4 7 | 8 | 9 | 42 10 | 43 11 | 44 12 | 45 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /snippets/editconfigs/classmap_einarnn_5.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | EINARNN_5 7 | 8 | 9 | af21 10 | af22 11 | cs2 12 | cs6 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /snippets/editconfigs/classmap_einarnn_6.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | EINARNN_6 7 | 8 | 9 | 42 10 | 44 11 | 45 12 | 46 13 | 42 14 | 44 15 | 45 16 | 46 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /snippets/editconfigs/create-arp-entry.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | net1 6 | 7 | {{IP}} 8 | fa16.3ec5.64f4 9 | ARPA 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /snippets/editconfigs/del-ipv6-acl-binding.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | {{INTF}} 6 | 7 | 8 | {{INBOUND_ACL}} 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /snippets/editconfigs/del_neighbor.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{NEIGHBOR_ADDR}} 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/del_static_route_default.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10.1.1.0 10 | 24 11 | 12 | 13 | 14 | Loopback0 15 | 10.10.10.1 16 | 17 | 18 | 19 | 20 | 21 | 10.1.2.0 22 | 24 23 | 24 | 25 | 26 | Loopback0 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /snippets/editconfigs/delete-loopback1.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 1 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets/editconfigs/delete-update-source.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 100 6 | 7 | 2.2.2.2 8 | 9 | 10 | 11 | 14.14.14.2 12 | 13 | 77 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /snippets/editconfigs/delete_autoneg.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | GigabitEthernet0/0/0/0 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /snippets/editconfigs/delete_ebgp_multihop_enabled.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 192.168.1.222 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /snippets/editconfigs/delete_l2vpn.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /snippets/editconfigs/empty_l2vpn.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets/editconfigs/foo1_add_static_route_default.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10.1.3.0 10 | 24 11 | 12 | 13 | 14 | Loopback0 15 | 192.168.1.1 16 | foo 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /snippets/editconfigs/foo2_add_static_route_default.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10.1.4.0 10 | 24 11 | 12 | 13 | 14 | Loopback0 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /snippets/editconfigs/gs.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 0.0.0.0 7 | 0.0.0.0 8 | 9 | GigabitEthernet1 10 | 11 | 12 | 13 | 14 | 15 | 16 | {{VPG_IFNUM}} 17 | IOx External Interface 18 | 19 |
20 | 21 |
{{VPG_IP}}
22 | {{VPG_NETMASK}} 23 |
24 |
25 |
26 |
27 |
28 | 29 |
30 | 31 | 32 | 33 | guestshell 34 | 35 | 0 36 | 0 37 | {{GUEST_IP}} 38 | {{GUEST_NETMASK}} 39 | {{VPG_IP}} 40 | {{NS0}} 41 | 0 42 | {{NS1}} 43 | 44 | 45 | 46 | 47 |
48 | -------------------------------------------------------------------------------- /snippets/editconfigs/ietf-cr-loopback.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | ianaift:softwareLoopback 6 | true 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/ietf-intf-add-ipv4.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | 6 |
7 | 172.16.1.1 8 | 255.255.255.0 9 |
10 |
11 |
12 |
14 | -------------------------------------------------------------------------------- /snippets/editconfigs/l2vpn_bdgroups_cr.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SERVICE 7 | 8 | 9 | ESP-vPE1 10 | 11 | 12 | Bundle-Ether46001.1 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /snippets/editconfigs/l2vpn_bdgroups_del.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets/editconfigs/legacy-01.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | interface Loopback101 4 | description test 5 | 6 | -------------------------------------------------------------------------------- /snippets/editconfigs/lldp-basic-and-del.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /snippets/editconfigs/lldp-basic.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets/editconfigs/lldp-del.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /snippets/editconfigs/nacm-01-cr-other.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | other 5 | PRIV14 6 | 7 | permit-all 8 | * 9 | * 10 | permit 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /snippets/editconfigs/nacm-02-del-other.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | other 5 | 6 | 7 | -------------------------------------------------------------------------------- /snippets/editconfigs/nacm-03-add-group.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | admin 5 | PRIV14 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets/editconfigs/nacm-04-rm-group.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | admin 5 | PRIV14 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets/editconfigs/new-ip.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | {{INTF}} 6 | 7 | 8 | 9 |
{{NEWIP}}
10 |
11 |
12 |
13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /snippets/editconfigs/no_shut.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | GigabitEthernet0/0/0/2 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/oc-set-descr-broken.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | GigabitEthernet0/0/0/1 5 | 6 | Configured by Widget 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets/editconfigs/oc-set-descr.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | 6 | {{DESCR}} 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets/editconfigs/oc_basic.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 123 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/policy_test_cr.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | testtest 7 | 8 | 9 | 10 | 2 | 3 | 4 | 5 | qos 6 | test 7 | 8 | 9 |
2 | 3 | 4 | 5 | 100 6 | 7 | 8 | 9 | unicast 10 | 11 | Red 12 | 13 | 14 | 15 | 4294967295 16 | red 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /snippets/editconfigs/replace-lo.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{LO1}} 6 | foo 7 | 8 | 9 |
false
10 |
11 |
12 |
13 | {{LO2}} 14 | bar 15 | 16 | 17 |
false
18 |
19 |
20 | 21 | {{LO2}} 22 | baz 23 | 24 | 25 |
false
26 |
27 |
28 | 29 |
30 |
31 |
32 | 33 | -------------------------------------------------------------------------------- /snippets/editconfigs/restconf-enable.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | default 8 | 9 | 10 | 11 | 35 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | act 23 | Loopback2 24 | 25 | 26 | 27 | 28 |
128.0.0.1
29 | 255.0.0.0 30 |
31 |
32 |
33 | 34 |
35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | {{RC_HTTP_PORT}} 47 | {{RC_HTTPS_PORT}} 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 0.0.0.0 61 | 0 62 | 63 | 64 | 65 | MgmtEth0/RP0/CPU0/0 66 | {{BRIDGE_IP}} 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 | -------------------------------------------------------------------------------- /snippets/editconfigs/set_autoneg_override.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | GigabitEthernet0/0/0/0 6 | 7 | override 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /snippets/editconfigs/set_autoneg_true.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | GigabitEthernet0/0/0/0 6 | 7 | true 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /snippets/editconfigs/set_ebgp_multihop_enabled_false.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 192.168.1.222 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /snippets/editconfigs/set_ebgp_multihop_enabled_true.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 192.168.1.222 6 | 7 | 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /snippets/editconfigs/shut.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | act 5 | GigabitEthernet0/0/0/2 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /snippets/editconfigs/simple_ospf.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | apphost 6 | 7 | 8 | 9 | 0 10 | 11 | 12 | GigabitEthernet0/0/0/0 13 | 30 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /snippets/editconfigs/telem-cr.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DGroup1 7 | 8 | 9 | ipv6 10 | 11 | 2001:db8:0:100::15 12 | 5432 13 | self-describing-gpb 14 | 15 | tcp 16 | 17 | 0 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /snippets/editconfigs/telem-del-ipv6-fails.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DGroup1 7 | 8 | 9 | ipv6 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /snippets/editconfigs/telem-del-ipv6-works.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DGroup1 7 | 8 | 9 | ipv6 10 | 11 | 2001:db8:0:100::15 12 | 5432 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /snippets/editconfigs/two-roots.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 66 6 | none 7 | 8 | 9 | 10 | 11 | 12 | 13 | Loopback501 14 | foo 15 | ianaift:softwareLoopback 16 | true 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /snippets/editconfigs/vrf-01-replace.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | beae927f77b04f6e9c00265d999e9c04 6 | beae927f-77b0-4f6e-9c00-265d999e9c04 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /snippets/editconfigs/xe-delete-ace.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 101 7 | 8 | 15 9 | 10 | permit 11 | ip 12 | 1000.1000.1000.1000 13 | 14 | 15 | 16 | 17 | 18 | 19 | true 20 | true 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /snippets/editconfigs/xe-enable-polling.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets/editconfigs/xe-merge-ace.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 101 7 | 8 | 15 9 | 10 | permit 11 | ip 12 | 100.100.100.100 13 | 14 | 15 | 16 | 17 | 18 | 19 | true 20 | true 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /snippets/editconfigs/xxx.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | XXX 7 | 8 | 5 9 | 42 10 | 44 11 | 46 12 | 45 13 | 1 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /snippets/editconfigs/xxx_del.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | qos 6 | XXX 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets/filters/acl-666.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RUBBLE1 5 | 6 | 7 | 666 8 | 9 | 10 | 777 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /snippets/filters/acls-all.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets/filters/fivesecondcpu.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets/filters/ietf-intf.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets/filters/ietf-intfs-state.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets/filters/installmgr-admin-oper.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets/filters/intf-brief-all.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /snippets/filters/intf-brief.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets/filters/intf-stats-limited.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /snippets/filters/intf-stats.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{INTF_NAME}} 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /snippets/filters/lldp-all.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /snippets/filters/mdtoper.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/filters/oc-bgp-neighbors.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{NEIGHBOR}} 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /snippets/filters/oc-bgp.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets/filters/oc-intf-named.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | 6 | -------------------------------------------------------------------------------- /snippets/filters/oc-intf.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets/filters/oc-subintf-named-and-indexed.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | 6 | {{SUBINTF_INDEX}} 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets/filters/oc-subintf-named.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{INTF_NAME}} 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /snippets/filters/platform.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /snippets/filters/qos-oper-all.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets/filters/qos-oper-intf.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{INTF_NAME}} 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /snippets/filters/telem-all.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets/filters/vrrp-ipv4-all.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /snippets/filters/xe-cpu-usage.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/filters/xe-memory-statistics.tmpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/filters/xe-native-intf.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /snippets/filters/xe-native-ipv4-acl.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /snippets/filters/xe-native-ipv6-acl.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /snippets/filters/xe-native.tmpl: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /snippets/filters/xr-value-detailed-specific.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 0 5 | 6 | 7 | RP0 8 | 9 | 10 | host 11 | 12 | 13 | temp 14 | 15 | 16 | host__die_CPU 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /snippets/filters/xr-value-detailed-temp.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | temp 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /snippets/filters/xr-value-detailed.tmpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/ncc/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CiscoDevNet/ncc/72fb19553d1ab27f99ce4a1212a7a1d047c51220/src/ncc/__init__.py -------------------------------------------------------------------------------- /src/nccutil/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from ._version import get_versions 3 | __version__ = get_versions()['version'] 4 | del get_versions 5 | -------------------------------------------------------------------------------- /src/nccutil/repoutil.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2018 Cisco and/or its affiliates 3 | # 4 | import tempfile 5 | import shutil 6 | import os 7 | from git import Repo 8 | from git.exc import GitCommandError 9 | 10 | '''Notes: 11 | 12 | repo.index.add(repo.untracked_files) 13 | 14 | Add all new files to the index 15 | 16 | repo.index.add([i.a_path for i in repo.index.diff(None)]) 17 | 18 | Add all modified files to the index. Also works for new directories. 19 | 20 | repo.index.commit('commit for delete file') 21 | 22 | Commit any changes 23 | 24 | repo.git.push() 25 | 26 | Push changes to origin. 27 | 28 | repo.git.rm([f1, f2, ...]) 29 | 30 | Remove files safely and add removal to index (note that files are 31 | left in lace, and then look like untracked files). 32 | 33 | ''' 34 | 35 | class RepoUtil(object): 36 | '''Simple class for rolling up some git operations as part of file 37 | manipulation. The user should create the object with the URL to 38 | the repository and an appropriate set of credentials. At this 39 | ''' 40 | 41 | def __init__(self, repourl): 42 | self.repourl = repourl 43 | self.localdir = None 44 | self.repo = None 45 | 46 | def get_repo_dir(self): 47 | '''Return the repository directory name from the URL''' 48 | return os.path.basename(self.repourl) 49 | 50 | def get_repo_owner(self): 51 | '''Return the root directory name of the repo. In GitHub 52 | parlance, this would be the owner of the repository.''' 53 | owner = os.path.basename(os.path.dirname(self.repourl)) 54 | if ':' in owner: 55 | return owner[owner.index(':') + 1:] 56 | 57 | return owner 58 | 59 | def clone(self): 60 | '''Clone the specified repository to a local temp directory. This 61 | method may generate a git.exec.GitCommandError if the 62 | repository does not exist 63 | ''' 64 | self.localdir = tempfile.mkdtemp() 65 | self.repo = Repo.clone_from(self.repourl, self.localdir) 66 | 67 | def add_all_untracked(self): 68 | '''Commit all untracked and modified files. This method shouldn't 69 | generate any exceptions as we don't allow unexpected 70 | operations to be invoked. 71 | ''' 72 | self.repo.index.add(self.repo.untracked_files) 73 | modified = [] 74 | deleted = [] 75 | for i in self.repo.index.diff(None): 76 | if os.path.exists(self.localdir+'/'+i.a_path): 77 | modified.append(i.a_path) 78 | else: 79 | deleted.append(i.a_path) 80 | if len(modified)>0: 81 | self.repo.index.add(modified) 82 | if len(deleted)>0: 83 | self.repo.index.remove(deleted) 84 | 85 | def commit_all(self, message='RepoUtil Commit'): 86 | '''Equivalent of git commit -a -m MESSAGE.''' 87 | self.repo.git.commit(a=True, m=message) 88 | 89 | def push(self): 90 | '''Push repo to origin. Credential errors may happen here.''' 91 | self.repo.git.push("origin") 92 | 93 | def remove(self): 94 | '''Remove the temporary storage.''' 95 | shutil.rmtree(self.localdir) 96 | self.localdir = None 97 | self.repo = None 98 | 99 | 100 | if __name__=='__main__': 101 | 102 | # 103 | # local imports 104 | # 105 | from argparse import ArgumentParser 106 | 107 | # 108 | # test arguments 109 | # 110 | parser = ArgumentParser(description='RepoUtil test params:') 111 | parser.add_argument('userpass', nargs=1, type=str, 112 | help='Provide username:password for github https access') 113 | args = parser.parse_args() 114 | if not args.userpass: 115 | print("username:password required") 116 | sys.exit(1) 117 | 118 | # 119 | # This repo exists 120 | # 121 | TEST_REPO = 'https://%s@github.com/einarnn/test.git' 122 | 123 | # 124 | # This repo does not exist 125 | # 126 | BOGUS_REPO = 'https://%s@github.com/einarnn/testtest.git' 127 | 128 | # 129 | # Create, clone and remove repo that exists. 130 | # 131 | print('\nTest 1\n------') 132 | try: 133 | r = RepoUtil(TEST_REPO % args.userpass[0]) 134 | r.clone() 135 | print('Temp directory: '+r.localdir) 136 | r.remove() 137 | except GitCommandError as e: 138 | print('Git Exception: ' + e.status) 139 | 140 | # 141 | # Create, clone and modify a repo with good credentials. Will Then 142 | # try to modify, commit and push. If the file 'ok.txt' is present, 143 | # we will try to delete it. If it's not, we will create it! 144 | # 145 | print('\nTest 2\n------') 146 | try: 147 | r = RepoUtil(TEST_REPO % args.userpass[0]) 148 | r.clone() 149 | print('Temp directory: '+r.localdir) 150 | ok_path = r.localdir + '/ok.txt' 151 | if os.path.exists(ok_path): 152 | print('Removing test file!') 153 | r.repo.git.rm(ok_path) 154 | # os.remove(ok_path) 155 | else: 156 | print('Creating test file!') 157 | with open(ok_path, 'w') as f: 158 | f.write('hello!\n') 159 | f.close() 160 | try: 161 | r.add_all_untracked() 162 | r.commit_all(message='push should succeed') 163 | r.push() 164 | except GitCommandError as e: 165 | print('Git Exception: ' + e.stderr) 166 | r.remove() 167 | except GitCommandError as e: 168 | print('Git Exception: ' + e.stderr) 169 | 170 | # 171 | # Create, clone and modify a repo with bogus credentials. Will Then try 172 | # to modify, commit and push, but still with bogus credentials. 173 | # 174 | print('\nTest 3\n------') 175 | try: 176 | r = RepoUtil(TEST_REPO % (args.userpass[0]+'bogus')) 177 | r.clone() 178 | print('Temp directory: '+r.localdir) 179 | with open(r.localdir+'/bogus.txt', 'w') as f: 180 | f.write('hello!\n') 181 | f.close() 182 | try: 183 | r.add_all_untracked() 184 | r.commit_all(message='push should fail') 185 | r.push() 186 | except GitCommandError as e: 187 | print('Git Exception as expected: ' + e.stderr) 188 | r.remove() 189 | except GitCommandError as e: 190 | print('Git Exception: ' + e.stderr) 191 | 192 | # 193 | # Try to create, clone and remove repo that does not exist. If 194 | # this is the caser, no dangling directory is left, so no need to 195 | # try and remove it. 196 | # 197 | print('\nTest 4\n------') 198 | try: 199 | r = RepoUtil(BOGUS_REPO % args.userpass[0]) 200 | r.clone() 201 | print('Temp directory: ' + r.localdir) 202 | r.remove() 203 | except GitCommandError as e: 204 | print('Git Exception as expected: ' + e.stderr) 205 | -------------------------------------------------------------------------------- /src/redis-cb/__init__.py: -------------------------------------------------------------------------------- 1 | from .cb import init 2 | from .cb import callback 3 | from .cb import errback 4 | -------------------------------------------------------------------------------- /src/redis-cb/cb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple sample module showing a way to register a callback 3 | # dynamically. This is the same as in ncc-establish-subscription.py. 4 | # 5 | from lxml import etree 6 | import json 7 | import jxmlease 8 | import redis 9 | import time 10 | 11 | 12 | # 13 | # the redis connection 14 | # 15 | conn = redis.Redis() 16 | 17 | 18 | # 19 | # log an "event" 20 | # 21 | def log_items(rx_time, events): 22 | pipe = conn.pipeline(True) 23 | for event in events: 24 | id = conn.incr('cpu_usage:id') 25 | event['id'] = id 26 | event['timestamp'] = rx_time 27 | event_key = 'cpu_usage:{id}'.format(id=id) 28 | pipe.hmset(event_key, event) 29 | pipe.zadd('cpu_usage', str(id), rx_time) 30 | pipe.execute() 31 | 32 | 33 | # 34 | # If we need to do any pre-analysis based on xpaths that will be 35 | # subscribed to. 36 | # 37 | def init(xpaths): 38 | pass 39 | 40 | # 41 | # the callback for subscription events 42 | # 43 | def callback(notif): 44 | rx_time = time.time() 45 | print('-->>') 46 | print('Event time : %s' % notif.event_time) 47 | print('Subscription Id : %d' % notif.subscription_id) 48 | print('Type : %d' % notif.type) 49 | j = jxmlease.parse(notif.datastore_xml) 50 | try: 51 | cpu_usage_process = j["datastore-contents-xml"]["cpu-usage"]["cpu-utilization"]["cpu-usage-processes"]["cpu-usage-process"] 52 | if isinstance(cpu_usage_process, dict): 53 | log_items(rx_time, [cpu_usage_process]) 54 | elif isinstance(cpu_usage_process, list): 55 | log_items(rx_time, cpu_usage_process) 56 | else: 57 | print('Event is unknown!') 58 | except e: 59 | print(e) 60 | print('<<--') 61 | 62 | 63 | # 64 | # the (currently unused) error callback 65 | # 66 | def errback(notif): 67 | pass 68 | 69 | 70 | 71 | """ 72 | Sample Event: 73 | 74 | { 75 | "datastore-contents-xml": { 76 | "cpu-usage": { 77 | "cpu-utilization": { 78 | "cpu-usage-processes": { 79 | "cpu-usage-process": { 80 | "avg-run-time": "118", 81 | "five-minutes": "0", 82 | "five-seconds": "0", 83 | "invocation-count": "77552", 84 | "name": "PuntInject Keepalive Process", 85 | "one-minute": "0", 86 | "pid": "89", 87 | "total-run-time": "9212", 88 | "tty": "0" 89 | } 90 | }, 91 | "five-minutes": "0", 92 | "five-seconds": "0", 93 | "five-seconds-intr": "0", 94 | "one-minute": "0" 95 | } 96 | } 97 | } 98 | } 99 | """ 100 | -------------------------------------------------------------------------------- /src/redis-pub/__init__.py: -------------------------------------------------------------------------------- 1 | from .cb import init 2 | from .cb import callback 3 | from .cb import errback 4 | -------------------------------------------------------------------------------- /src/redis-pub/cb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple sample module showing a way to register a callback 3 | # dynamically. This is the same as in ncc-establish-subscription.py. 4 | # 5 | import json 6 | import jxmlease 7 | import redis 8 | import time 9 | import re 10 | 11 | 12 | # 13 | # the redis connection 14 | # 15 | conn = redis.Redis() 16 | 17 | # 18 | # Match only digits 19 | # 20 | d = re.compile('^\d+$') 21 | 22 | # 23 | # Publish a stats event in JSON on a Redis channel called 'yangpush'. 24 | # 25 | def log_items(rx_time, events): 26 | for event in events: 27 | id = conn.incr('cpu_usage:id') 28 | for k, v in event.items(): 29 | if isinstance(v, str) and d.match(v): 30 | event[k] = int(v) 31 | event['id'] = id 32 | event['timestamp'] = rx_time 33 | event_json = json.dumps(event) 34 | # print(event_json) 35 | conn.publish('yangpush', event_json) 36 | 37 | 38 | # 39 | # If we need to do any pre-analysis based on xpaths that will be 40 | # subscribed to. 41 | # 42 | def init(xpaths): 43 | pass 44 | 45 | 46 | # 47 | # the callback for subscription events 48 | # 49 | def callback(notif): 50 | rx_time = time.time() 51 | print('-->>') 52 | print('Event time : %s' % notif.event_time) 53 | print('Subscription Id : %d' % notif.subscription_id) 54 | print('Type : %d' % notif.type) 55 | j = jxmlease.parse(notif.datastore_xml) 56 | try: 57 | #cpu_usage_process = j["datastore-contents-xml"]["cpu-usage"]["cpu-utilization"]["cpu-usage-processes"]["cpu-usage-process"] 58 | cpu_usage_process = j.get( 59 | "datastore-contents-xml").get( 60 | "cpu-usage").get( 61 | "cpu-utilization").get( 62 | "cpu-usage-processes").get( 63 | "cpu-usage-process") 64 | if isinstance(cpu_usage_process, dict): 65 | log_items(rx_time, [cpu_usage_process]) 66 | elif isinstance(cpu_usage_process, list): 67 | log_items(rx_time, cpu_usage_process) 68 | else: 69 | print('Event is unknown!') 70 | except e: 71 | print(e) 72 | print('<<--') 73 | 74 | 75 | # 76 | # the (currently unused) error callback 77 | # 78 | def errback(notif): 79 | pass 80 | -------------------------------------------------------------------------------- /src/sample/__init__.py: -------------------------------------------------------------------------------- 1 | from .cb import init 2 | from .cb import callback 3 | from .cb import errback 4 | -------------------------------------------------------------------------------- /src/sample/cb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Simple sample module showing a way to register a callback 3 | # dynamically. This is the same as in ncc-establish-subscription.py. 4 | # 5 | from lxml import etree 6 | import json 7 | import jxmlease 8 | 9 | # 10 | # If we need to do any pre-analysis based on xpaths that will be 11 | # subscribed to. 12 | # 13 | def init(xpaths): 14 | pass 15 | 16 | 17 | def callback(notif): 18 | print('-->>') 19 | print('Event time : %s' % notif.event_time) 20 | print('Subscription Id : %d' % notif.subscription_id) 21 | print('Type : %d' % notif.type) 22 | print('Data :') 23 | j = jxmlease.parse(notif.datastore_xml) 24 | print(json.dumps(j, indent=2, sort_keys=True)) 25 | print('<<--') 26 | 27 | 28 | def errback(notif): 29 | pass 30 | 31 | -------------------------------------------------------------------------------- /src/scripts/ncc-establish-subscription.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | import datetime 6 | import logging 7 | import os 8 | import signal 9 | import sys 10 | import time 11 | 12 | from argparse import ArgumentParser 13 | from lxml import etree 14 | from ncclient import manager 15 | from ncclient.transport.session import SessionListener 16 | 17 | 18 | if __name__ == '__main__': 19 | 20 | parser = ArgumentParser(description='Select your telemetry parameters:') 21 | 22 | # Input parameters 23 | parser.add_argument('--host', type=str, 24 | default=os.environ.get('NCC_HOST','127.0.0.1'), 25 | help="The IP address for the device to connect to " 26 | "(default localhost)") 27 | parser.add_argument('-u', '--username', type=str, 28 | default=os.environ.get('NCC_USERNAME', 'cisco'), 29 | help="Username to use for SSH authentication " 30 | "(default 'cisco')") 31 | parser.add_argument('-p', '--password', type=str, 32 | default=os.environ.get('NCC_PASSWORD', 'cisco'), 33 | help="Password to use for SSH authentication " 34 | "(default 'cisco')") 35 | parser.add_argument('--port', type=int, 36 | default=os.environ.get('NCC_PORT',830), 37 | help="Specify this if you want a non-default port " 38 | "(default 830)") 39 | parser.add_argument('-v', '--verbose', action='store_true', 40 | help="Exceedingly verbose logging to the console") 41 | parser.add_argument('--delete-after', type=int, 42 | help="Delete the established subscription after N seconds") 43 | parser.add_argument('-x', '--xpaths', type=str, nargs='+', required=True, 44 | help="List of xpaths to subscribe to, one or more") 45 | parser.add_argument('--streamns', type=str, 46 | help="Namespace for a custom stream identity, " 47 | "e.g. urn:cisco:params:xml:ns:yang:cisco-xe-ietf-yang-push-ext") 48 | parser.add_argument('--callback', type=str, 49 | help="Module that a callback is defined in") 50 | 51 | g = parser.add_mutually_exclusive_group(required=True) 52 | g.add_argument('--period', type=int, 53 | help="Period in centiseconds for periodic subscription") 54 | g.add_argument('--dampening-period', type=int, 55 | help="Dampening period in centiseconds for on-change subscription") 56 | g.add_argument('--streamident', type=str, 57 | help="Custom stream identifier (e.g. yang-notif-native)") 58 | 59 | 60 | args = parser.parse_args() 61 | 62 | if args.verbose: 63 | handler = logging.StreamHandler() 64 | # for l in ['ncclient.transport.session', 'ncclient.operations.rpc']: 65 | for l in ['ncclient.transport.ssh', 'ncclient.transport.session', 'ncclient.operations.rpc']: 66 | logger = logging.getLogger(l) 67 | logger.addHandler(handler) 68 | logger.setLevel(logging.DEBUG) 69 | 70 | # 71 | # Connect 72 | # 73 | def unknown_host_cb(host, fingerprint): 74 | return True 75 | m = manager.connect(host=args.host, 76 | port=args.port, 77 | username=args.username, 78 | password=args.password, 79 | allow_agent=False, 80 | look_for_keys=False, 81 | hostkey_verify=False, 82 | device_params={'name':'iosxe'}, 83 | unknown_host_cb=unknown_host_cb) 84 | 85 | # 86 | # set up a ctrl+c handler to tear down the netconf session 87 | # 88 | def sigint_handler(signal, frame): 89 | m.close_session() 90 | sys.exit(0) 91 | signal.signal(signal.SIGINT, sigint_handler) 92 | 93 | # 94 | # A really simple callback, just spit out a header with some key 95 | # details plus the XML payload pretty-printed. 96 | # 97 | def callback(notif): 98 | print('-->>') 99 | print('(Default Callback)') 100 | print('Event time : %s' % notif.event_time) 101 | print('Subscription Id : %d' % notif.subscription_id) 102 | print('Type : %d' % notif.type) 103 | print('Data :') 104 | print(etree.tostring(notif.datastore_ele, pretty_print=True).decode('utf-8')) 105 | print('<<--') 106 | 107 | def errback(notif): 108 | pass 109 | 110 | # 111 | # Select the callback to use 112 | # 113 | selected_init = None 114 | selected_callback = callback 115 | selected_errback = errback 116 | if args.callback: 117 | import importlib 118 | module = importlib.import_module(args.callback) 119 | selected_init = getattr(module, 'init') 120 | selected_callback = getattr(module, 'callback') 121 | selected_errback = getattr(module, 'errback') 122 | 123 | # 124 | # If we have a callback "module" specified, call its init function 125 | # with the list of xpaths we are dealing with. 126 | # 127 | if selected_init: 128 | selected_init(args.xpaths) 129 | 130 | # 131 | # iterate over the list of xpaths and create subscriptions 132 | # 133 | subs = [] 134 | for xpath in args.xpaths: 135 | s = m.establish_subscription( 136 | selected_callback, 137 | selected_errback, 138 | xpath=xpath, 139 | period=args.period, 140 | dampening_period=args.dampening_period, 141 | streamident=args.streamident, 142 | streamns=args.streamns) 143 | print('Subscription Result : %s' % s.subscription_result) 144 | if s.subscription_result.endswith('ok'): 145 | print('Subscription Id : %d' % s.subscription_id) 146 | subs.append(s.subscription_id) 147 | if not len(subs): 148 | print('No active subscriptions, exiting.') 149 | sys.exit(1) 150 | 151 | # 152 | # simple forever loop 153 | # 154 | if args.delete_after: 155 | time.sleep(args.delete_after) 156 | for s in subs: 157 | r = m.delete_subscription(s) 158 | print('delete subscription result = %s' % r.subscription_result) 159 | else: 160 | while True: 161 | time.sleep(5) 162 | -------------------------------------------------------------------------------- /src/scripts/ncc-event-listener-demo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | # This sample works with NETCONF ebents of the format: 6 | # 7 | # 8 | # 2018-10-27T18:33:54+00:00 9 | # 10 | # 11 | # 4 12 | # down 13 | # 14 | # 15 | # 4 16 | # down 17 | # 18 | # 19 | # 20 | # 21 | import sys 22 | from argparse import ArgumentParser 23 | from functools import partial 24 | from ncclient import manager 25 | from lxml import etree 26 | import logging 27 | import time 28 | import datetime 29 | import threading 30 | import re 31 | 32 | 33 | # 34 | # Get the if-index for an interface from the IOS XE 35 | # Cisco-IOS-XE-interfaces-oper model. The {} are for substitution 36 | # using .format(...). 37 | # 38 | intf_query = ''' 39 | 40 | 41 | {} 42 | 43 | 44 | 45 | ''' 46 | 47 | 48 | # 49 | # Use the IOS XE native model Cisco-IOS-XE-native to bring up an 50 | # iterface (CLI equivalent of "no shutdown"). The {} are for 51 | # substitution using .format(...). 52 | # 53 | intf_no_shut = ''' 54 | 55 | 56 | 57 | <{}> 58 | {} 59 | 60 | 61 | 62 | 63 | 64 | ''' 65 | 66 | 67 | # 68 | # Simple example listener to run on a standalone thread. 69 | # 70 | def listener(mgr=None, stream_name=None, if_name=None, if_index=None): 71 | assert mgr is not None 72 | assert stream_name is not None 73 | assert if_name is not None 74 | assert if_index is not None 75 | 76 | # 77 | # assume if_name is a simple IOS XE-style interface name like 78 | # 'GigabitEthernet4'; this woukd clearly be inappropriate for 79 | # production code!! 80 | # 81 | p = re.compile(r'([a-zA-Z]+)([0-9]+)') 82 | m = p.match(if_name) 83 | if not m: 84 | print('cannot find if type and index') 85 | return 86 | if_type = m.group(1) 87 | if_ind = m.group(2) 88 | intf_no_shut_resolved = intf_no_shut.format(if_type, if_ind, if_type) 89 | print('Monitoring interface {} with SNMP if-index {}'.format( 90 | if_name, if_index)) 91 | 92 | # 93 | # Create a subscription and loop waiting for notifications form 94 | # the device mgr is connected to. Note that other threads can 95 | # still use the connection. 96 | # 97 | mgr.create_subscription(stream_name=stream_name) 98 | while True: 99 | # blocking call, but will see ALL notifications 100 | notif = mgr.take_notification() 101 | if notif: 102 | root = notif.notification_ele 103 | linkDown = root.xpath( 104 | '//ns1:linkDown/*[ns1:ifIndex={}]/ns1:ifAdminStatus'.format(if_index), 105 | namespaces={ 106 | 'ns1': 'urn:ietf:params:xml:ns:yang:smiv2:IF-MIB', 107 | }) 108 | if len(linkDown) > 0: 109 | print('linkDown event -> ifAdminStatus = {}'.format(linkDown[0].text)) 110 | print('Bringing interface back up...') 111 | mgr.edit_config( 112 | intf_no_shut_resolved, 113 | target='running', 114 | format='xml') 115 | print('Done') 116 | else: 117 | pass 118 | 119 | 120 | if __name__ == '__main__': 121 | 122 | parser = ArgumentParser(description='Select your simple poller parameters:') 123 | 124 | # Input parameters 125 | parser.add_argument('--host', type=str, required=True, 126 | help="The device IP or DN") 127 | parser.add_argument('-u', '--username', type=str, default='cisco', 128 | help="Go on, guess!") 129 | parser.add_argument('-p', '--password', type=str, default='cisco', 130 | help="Yep, this one too! ;-)") 131 | parser.add_argument('--port', type=int, default=830, 132 | help="Specify this if you want a non-default port") 133 | parser.add_argument('-v', '--verbose', action='store_true', 134 | help="Do I really need to explain?") 135 | 136 | # other options 137 | parser.add_argument('--stream', type=str, required=True, 138 | help="Event stream to register on") 139 | parser.add_argument('--if-name', type=str, required=True, 140 | help="Interface name to watch for link state events on") 141 | 142 | args = parser.parse_args() 143 | 144 | if args.verbose: 145 | handler = logging.StreamHandler() 146 | for l in ['ncclient.transport.ssh', 'ncclient.transport.session', 'ncclient.operations.rpc']: 147 | logger = logging.getLogger(l) 148 | logger.addHandler(handler) 149 | logger.setLevel(logging.DEBUG) 150 | 151 | # 152 | # Connect 153 | # 154 | def unknown_host_cb(host, fingerprint): 155 | return True 156 | m = manager.connect(host=args.host, 157 | port=args.port, 158 | username=args.username, 159 | password=args.password, 160 | allow_agent=False, 161 | look_for_keys=False, 162 | hostkey_verify=False, 163 | unknown_host_cb=unknown_host_cb) 164 | 165 | # 166 | # find the interface if-index for the provided name 167 | # 168 | r = m.get(filter=('subtree', intf_query.format(args.if_name))) 169 | if_index = r.data_ele.xpath( 170 | '//ns1:if-index', 171 | namespaces={ 172 | 'ns1': 'http://cisco.com/ns/yang/Cisco-IOS-XE-interfaces-oper', 173 | }) 174 | if len(if_index) == 0: 175 | print('No ifIndex found got {}'.format(args.if_name)) 176 | sys.exit(1) 177 | 178 | # 179 | # run the listener 180 | # 181 | thr = threading.Thread( 182 | target=partial( 183 | listener, 184 | mgr=m, 185 | stream_name=args.stream, 186 | if_name=args.if_name, 187 | if_index=int(if_index[0].text))) 188 | thr.start() 189 | thr.join() 190 | -------------------------------------------------------------------------------- /src/scripts/ncc-event-listener.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | import sys 6 | from argparse import ArgumentParser 7 | from ncclient import manager 8 | from lxml import etree 9 | import logging 10 | import time 11 | import datetime 12 | from ncclient.transport.session import SessionListener 13 | 14 | if __name__ == '__main__': 15 | 16 | parser = ArgumentParser(description='Select your simple poller parameters:') 17 | 18 | # Input parameters 19 | parser.add_argument('--host', type=str, required=True, 20 | help="The device IP or DN") 21 | parser.add_argument('-u', '--username', type=str, default='cisco', 22 | help="Go on, guess!") 23 | parser.add_argument('-p', '--password', type=str, default='cisco', 24 | help="Yep, this one too! ;-)") 25 | parser.add_argument('--port', type=int, default=830, 26 | help="Specify this if you want a non-default port") 27 | parser.add_argument('-v', '--verbose', action='store_true', 28 | help="Do I really need to explain?") 29 | 30 | # other options 31 | parser.add_argument('--stream', type=str, required=True, 32 | help="Event stream to register on") 33 | 34 | args = parser.parse_args() 35 | 36 | if args.verbose: 37 | handler = logging.StreamHandler() 38 | for l in ['ncclient.transport.ssh', 'ncclient.transport.session', 'ncclient.operations.rpc']: 39 | logger = logging.getLogger(l) 40 | logger.addHandler(handler) 41 | logger.setLevel(logging.DEBUG) 42 | 43 | # 44 | # Connect 45 | # 46 | def unknown_host_cb(host, fingerprint): 47 | return True 48 | m = manager.connect(host=args.host, 49 | port=args.port, 50 | username=args.username, 51 | password=args.password, 52 | allow_agent=False, 53 | look_for_keys=False, 54 | hostkey_verify=False, 55 | unknown_host_cb=unknown_host_cb) 56 | 57 | # 58 | # create the subscription 59 | # 60 | s = m.create_subscription(stream_name=args.stream) 61 | while True: 62 | n = m.take_notification() 63 | if n: 64 | print('----') 65 | print(etree.tostring(n.notification_ele, pretty_print=True).decode()) 66 | 67 | -------------------------------------------------------------------------------- /src/scripts/ncc-filtered-get.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | import sys 6 | from argparse import ArgumentParser 7 | from ncclient import manager 8 | from lxml import etree 9 | 10 | if __name__ == '__main__': 11 | 12 | parser = ArgumentParser(description='Select options.') 13 | 14 | # Input parameters 15 | parser.add_argument('--host', type=str, required=True, 16 | help="The device IP or DN") 17 | parser.add_argument('-u', '--username', type=str, default='cisco', 18 | help="Go on, guess!") 19 | parser.add_argument('-p', '--password', type=str, default='cisco', 20 | help="Yep, this one too! ;-)") 21 | parser.add_argument('--port', type=int, default=830, 22 | help="Specify this if you want a non-default port") 23 | parser.add_argument('--filter', type=str, required=True, 24 | help="The filter to use for the get operation") 25 | 26 | args = parser.parse_args() 27 | 28 | m = manager.connect(host=args.host, 29 | port=args.port, 30 | username=args.username, 31 | password=args.password, 32 | device_params={'name':"csr"}) 33 | data = m.get(''+args.filter+'') 34 | print etree.tostring(etree.fromstring(data.xml), pretty_print=True) 35 | -------------------------------------------------------------------------------- /src/scripts/ncc-locker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | import sys 6 | from argparse import ArgumentParser 7 | from functools import partial 8 | from ncclient import manager 9 | from lxml import etree 10 | import logging 11 | import time 12 | import os 13 | 14 | 15 | if __name__ == '__main__': 16 | 17 | parser = ArgumentParser(description='Select your simple poller parameters:') 18 | 19 | # Input parameters 20 | parser.add_argument('--host', type=str, 21 | default=os.environ.get('NCC_HOST', '127.0.0.1'), 22 | help="The IP address for the device to connect to " 23 | "(default localhost)") 24 | parser.add_argument('-u', '--username', type=str, 25 | default=os.environ.get('NCC_USERNAME', 'cisco'), 26 | help="Username to use for SSH authentication " 27 | "(default 'cisco')") 28 | parser.add_argument('-p', '--password', type=str, 29 | default=os.environ.get('NCC_PASSWORD', 'cisco'), 30 | help="Password to use for SSH authentication " 31 | "(default 'cisco')") 32 | parser.add_argument('--port', type=int, 33 | default=os.environ.get('NCC_PORT', 830), 34 | help="Specify this if you want a non-default port " 35 | "(default 830)") 36 | parser.add_argument('-v', '--verbose', action='store_true', 37 | help="Do I really need to explain?") 38 | 39 | # 40 | # alternate operations 41 | # 42 | parser.add_argument('--unlock', action='store_true', 43 | help="Instead of locking, unlock the target datastore") 44 | 45 | # other options 46 | parser.add_argument('--target', type=str, default='running', 47 | help="Datastore to lock") 48 | parser.add_argument('--blocking', action='store_true', 49 | help="Do a blocking lock") 50 | parser.add_argument('--time', type=int, default=10, 51 | help="Time to lock for") 52 | parser.add_argument('--retries', type=int, default=0, 53 | help="Number of retries, 0 is infinite") 54 | parser.add_argument('--interval', type=float, default=1.0, 55 | help="Time between retries in seconds (float)") 56 | parser.add_argument('--context', action='store_true', default=False, 57 | help="Use context-style locking") 58 | 59 | args = parser.parse_args() 60 | 61 | if args.verbose: 62 | handler = logging.StreamHandler() 63 | for l in ['ncclient.transport.ssh', 'ncclient.transport.session', 'ncclient.operations.rpc']: 64 | logger = logging.getLogger(l) 65 | logger.addHandler(handler) 66 | logger.setLevel(logging.DEBUG) 67 | 68 | # 69 | # Connect 70 | # 71 | def unknown_host_cb(host, fingerprint): 72 | return True 73 | m = manager.connect(host=args.host, 74 | port=args.port, 75 | username=args.username, 76 | password=args.password, 77 | allow_agent=False, 78 | look_for_keys=False, 79 | hostkey_verify=False, 80 | unknown_host_cb=unknown_host_cb) 81 | 82 | # 83 | # for testing, just try and unlock the target 84 | # 85 | if args.unlock: 86 | m.unlock(target=args.target) 87 | print('Unlocked {}'.format(args.target)) 88 | m.close_session() 89 | sys.exit(0) 90 | 91 | # 92 | # lock and unlock 93 | # 94 | if not args.context: 95 | m.lock(target=args.target, blocking=args.blocking, retries=args.retries, interval=1.0) 96 | print('Locked {}'.format(args.target)) 97 | print('Sleeping with lock for {} seconds...'.format(args.time)) 98 | time.sleep(args.time) 99 | m.unlock(target=args.target) 100 | print('Unlocked {}'.format(args.target)) 101 | else: 102 | with m.locked(args.target, blocking=args.blocking, retries=args.retries, interval=args.interval): 103 | print('Locked {}'.format(args.target)) 104 | time.sleep(args.time) 105 | print('Unlocked {}'.format(args.target)) 106 | 107 | # 108 | # graceful shutdown 109 | # 110 | m.close_session() 111 | -------------------------------------------------------------------------------- /src/scripts/ncc-simple-locker.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | import sys 6 | from argparse import ArgumentParser 7 | from functools import partial 8 | from ncclient import manager 9 | from lxml import etree 10 | import logging 11 | import time 12 | import os 13 | 14 | 15 | if __name__ == '__main__': 16 | 17 | parser = ArgumentParser(description='Select your simple poller parameters:') 18 | 19 | # Input parameters 20 | parser.add_argument('--host', type=str, 21 | default=os.environ.get('NCC_HOST', '127.0.0.1'), 22 | help="The IP address for the device to connect to " 23 | "(default localhost)") 24 | parser.add_argument('-u', '--username', type=str, 25 | default=os.environ.get('NCC_USERNAME', 'cisco'), 26 | help="Username to use for SSH authentication " 27 | "(default 'cisco')") 28 | parser.add_argument('-p', '--password', type=str, 29 | default=os.environ.get('NCC_PASSWORD', 'cisco'), 30 | help="Password to use for SSH authentication " 31 | "(default 'cisco')") 32 | parser.add_argument('--port', type=int, 33 | default=os.environ.get('NCC_PORT', 830), 34 | help="Specify this if you want a non-default port " 35 | "(default 830)") 36 | parser.add_argument('-v', '--verbose', action='store_true', 37 | help="Do I really need to explain?") 38 | 39 | # 40 | # alternate operations 41 | # 42 | parser.add_argument('--unlock', action='store_true', 43 | help="Instead of locking, unlock the target datastore") 44 | 45 | # other options 46 | parser.add_argument('--target', type=str, default='running', 47 | help="Datastore to lock") 48 | parser.add_argument('--time', type=int, default=10, 49 | help="Time to lock for") 50 | parser.add_argument('--context', action='store_true', default=False, 51 | help="Use context-style locking") 52 | 53 | args = parser.parse_args() 54 | 55 | if args.verbose: 56 | handler = logging.StreamHandler() 57 | for l in ['ncclient.transport.ssh', 'ncclient.transport.session', 'ncclient.operations.rpc']: 58 | logger = logging.getLogger(l) 59 | logger.addHandler(handler) 60 | logger.setLevel(logging.DEBUG) 61 | 62 | # 63 | # Connect 64 | # 65 | def unknown_host_cb(host, fingerprint): 66 | return True 67 | m = manager.connect(host=args.host, 68 | port=args.port, 69 | username=args.username, 70 | password=args.password, 71 | allow_agent=False, 72 | look_for_keys=False, 73 | hostkey_verify=False, 74 | unknown_host_cb=unknown_host_cb) 75 | 76 | # 77 | # for testing, just try and unlock the target 78 | # 79 | if args.unlock: 80 | m.unlock(target=args.target) 81 | print('Unlocked {}'.format(args.target)) 82 | m.close_session() 83 | sys.exit(0) 84 | 85 | # 86 | # lock and unlock 87 | # 88 | if not args.context: 89 | m.lock(target=args.target) 90 | print('Locked {}'.format(args.target)) 91 | print('Sleeping with lock for {} seconds...'.format(args.time)) 92 | time.sleep(args.time) 93 | m.unlock(target=args.target) 94 | print('Unlocked {}'.format(args.target)) 95 | else: 96 | with m.locked(args.target): 97 | print('Locked {}'.format(args.target)) 98 | time.sleep(args.time) 99 | print('Unlocked {}'.format(args.target)) 100 | 101 | # 102 | # graceful shutdown 103 | # 104 | m.close_session() 105 | -------------------------------------------------------------------------------- /src/scripts/ncc-simple-poller.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | import sys 6 | from argparse import ArgumentParser 7 | from ncclient import manager 8 | from lxml import etree 9 | from bs4 import BeautifulSoup 10 | import logging 11 | import time 12 | import datetime 13 | 14 | soup = None 15 | 16 | def get(m, filter=None, xpath=None): 17 | if filter and len(filter) > 0: 18 | return m.get(filter=('subtree', filter)) 19 | elif xpath and len(xpath)>0: 20 | return m.get(filter=('xpath', xpath)) 21 | else: 22 | print ("Need a filter for oper get!") 23 | return None 24 | 25 | 26 | if __name__ == '__main__': 27 | 28 | parser = ArgumentParser(description='Select your simple poller parameters:') 29 | 30 | # Input parameters 31 | parser.add_argument('--host', type=str, required=True, 32 | help="The device IP or DN") 33 | parser.add_argument('-u', '--username', type=str, default='cisco', 34 | help="Go on, guess!") 35 | parser.add_argument('-p', '--password', type=str, default='cisco', 36 | help="Yep, this one too! ;-)") 37 | parser.add_argument('--port', type=int, default=830, 38 | help="Specify this if you want a non-default port") 39 | parser.add_argument('-v', '--verbose', action='store_true', 40 | help="Do I really need to explain?") 41 | 42 | # other options 43 | parser.add_argument('--cadence', type=int, default=5, 44 | help="Cadence of gets") 45 | parser.add_argument('--display-tags', type=str, nargs='+', 46 | help="A list of display XML tags; first value matching displayed") 47 | 48 | # Only one type of filter 49 | g = parser.add_mutually_exclusive_group() 50 | g.add_argument('-s', '--subtree', type=str, 51 | help="XML-formatted netconf subtree filter") 52 | g.add_argument('-x', '--xpath', type=str, 53 | help="XPath-formatted filter") 54 | 55 | # Basic operations 56 | g = parser.add_mutually_exclusive_group() 57 | g.add_argument('--get-oper', action='store_true', 58 | help="Get oper data") 59 | 60 | args = parser.parse_args() 61 | 62 | if args.verbose: 63 | handler = logging.StreamHandler() 64 | for l in ['ncclient.transport.ssh', 'ncclient.transport.session', 'ncclient.operations.rpc']: 65 | logger = logging.getLogger(l) 66 | logger.addHandler(handler) 67 | logger.setLevel(logging.DEBUG) 68 | 69 | # 70 | # Could use this extra param instead of the last four arguments 71 | # specified below: 72 | # 73 | def unknown_host_cb(host, fingerprint): 74 | return True 75 | m = manager.connect(host=args.host, 76 | port=args.port, 77 | username=args.username, 78 | password=args.password, 79 | allow_agent=False, 80 | look_for_keys=False, 81 | hostkey_verify=False, 82 | unknown_host_cb=unknown_host_cb) 83 | 84 | kw = {} 85 | if args.xpath: 86 | kw['xpath'] = args.xpath 87 | elif args.subtree: 88 | kw['filter'] = args.subtree 89 | while True: 90 | st = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S') 91 | result = get(m, **kw) 92 | if not args.display_tags: 93 | print(st) 94 | print(etree.tostring(result.data, pretty_print=True)) 95 | else: 96 | values = [] 97 | for p in args.display_tags: 98 | try: 99 | soup = BeautifulSoup(result.data_xml) 100 | for n in soup.find_all(p): 101 | values.append(p + " = " + n.getText()) 102 | except AttributeError as e: 103 | values.append(p + " = ") 104 | print("{}: {}".format(st, ", ".join(values))) 105 | time.sleep(args.cadence) 106 | -------------------------------------------------------------------------------- /src/scripts/ncc_get_all_schema.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | from __future__ import print_function 6 | import logging 7 | import re 8 | from os import listdir 9 | from os.path import isfile, join, basename 10 | from argparse import ArgumentParser 11 | from ncclient import manager 12 | from ncclient.operations.rpc import RPCError 13 | import pyang 14 | import pyang.repository 15 | import pyang.context 16 | 17 | 18 | # 19 | # local logger 20 | # 21 | logger = logging.getLogger(__name__) 22 | 23 | 24 | # 25 | # The get filter we need to retrieve the schemas a device claims to have 26 | # 27 | schemas_filter = ''' 28 | 29 | 30 | 31 | 32 | 33 | ''' 34 | 35 | 36 | def get(m, filter=None): 37 | logger.debug('Getting %s', str(filter)) 38 | if filter and len(filter) > 0: 39 | c = m.get(filter=('subtree', filter)).data 40 | else: 41 | c = m.get().data 42 | return c 43 | 44 | 45 | def get_schema(m, schema_list, output_dir, start_after=None): 46 | failed_download = [] 47 | getting_yet = True 48 | if start_after: 49 | getting_yet = False 50 | for s in schema_list: 51 | if getting_yet is False: 52 | if s == start_after: 53 | getting_yet = True 54 | else: 55 | continue 56 | try: 57 | logger.debug('Retrieving %s', s) 58 | c = m.get_schema(s) 59 | with open(output_dir + '/' + s + '.yang', 'wb') as yang: 60 | yang.write(c.data.encode('UTF-8')) 61 | except RPCError as e: 62 | logger.debug('Failed to get %s', s) 63 | failed_download.append(s) 64 | return failed_download 65 | 66 | 67 | def main(): 68 | 69 | parser = ArgumentParser(description='Provide device and output parameters:') 70 | parser.add_argument('-a', '--host', type=str, required=True, 71 | help="The device IP or DN") 72 | parser.add_argument('-u', '--username', type=str, default='cisco', 73 | help="Go on, guess!") 74 | parser.add_argument('-p', '--password', type=str, default='cisco', 75 | help="Yep, this one too! ;-)") 76 | parser.add_argument('--port', type=int, default=830, 77 | help="Specify this if you want a non-default port") 78 | parser.add_argument('-o', '--output-dir', type=str, required=False, 79 | help="Where to write schema files") 80 | parser.add_argument('-t', '--timeout', type=int, required=False, default=30, 81 | help="Where to write schema files") 82 | parser.add_argument('-v', '--verbose', action='store_true', 83 | help="Do some verbose logging") 84 | 85 | g = parser.add_mutually_exclusive_group() 86 | g.add_argument('--start-after', type=str, required=False, 87 | help="Don't get schemas until after this one") 88 | g.add_argument('--skip-download', action='store_true', default=False, 89 | help="Skip downloading schema and just consider those downloaded already") 90 | 91 | args = parser.parse_args() 92 | 93 | # 94 | # if you enable verbose logging, it is INCREDIBLY verbose...you 95 | # have been warned!! 96 | # 97 | if args.verbose: 98 | handler = logging.StreamHandler() 99 | handler.setFormatter( 100 | logging.Formatter('%(asctime)s:%(name)s:%(levelname)s:%(message)s')) 101 | logger.addHandler(handler) 102 | logger.setLevel(logging.DEBUG) 103 | 104 | if not args.output_dir: 105 | # default the output to got to cwd 106 | args.output_dir = '.' 107 | 108 | def unknown_host_cb(host, fingerprint): 109 | return True 110 | def get_manager(): 111 | logger.debug('Connecting to netconf server') 112 | return manager.connect(host=args.host, 113 | port=args.port, 114 | username=args.username, 115 | password=args.password, 116 | timeout=args.timeout, 117 | allow_agent=False, 118 | look_for_keys=False, 119 | hostkey_verify=False, 120 | unknown_host_cb=unknown_host_cb) 121 | mgr = get_manager() 122 | 123 | # 124 | # retrieve the schemas datatree and extract all the schema 125 | # identifiers 126 | # 127 | schema_tree = get(mgr, schemas_filter) 128 | schema_list = [ 129 | n.text 130 | for n in schema_tree.xpath('//*[local-name()="identifier"]') 131 | ] 132 | 133 | # 134 | # check the schema list against server capabilities 135 | # 136 | not_in_schemas = set() 137 | for c in mgr.server_capabilities: 138 | model = re.search('module=([^&]*)', c) 139 | if model is not None: 140 | m = model.group(1) 141 | if m not in schema_list: 142 | not_in_schemas.add(m) 143 | deviations = re.search('deviations=([^&<]*)', c) 144 | if deviations is not None: 145 | d = deviations.group(1) 146 | for dfn in d.split(','): 147 | if dfn not in schema_list: 148 | logger.debug('Deviation %s not in schema list', dfn) 149 | not_in_schemas.add(dfn) 150 | if len(not_in_schemas) > 0: 151 | print('The following models are advertised in capabilities but are not in schemas tree:') 152 | for m in sorted(not_in_schemas): 153 | print(' {}'.format(m)) 154 | 155 | # 156 | # this dict is for keeping track of the schemas that failed to 157 | # download 158 | # 159 | failed_download = set() 160 | 161 | # 162 | # Now download all the schema, which also returns a list of any 163 | # that failed to be downloaded. If we downloaded, list the failed 164 | # downloads (if any). 165 | # 166 | if not args.skip_download: 167 | failed = get_schema(mgr, schema_list, args.output_dir, args.start_after) 168 | for f in failed: 169 | failed_download.add(str(f)) 170 | 171 | # 172 | # end of main download phase, so close the session for now 173 | # 174 | mgr.close_session() 175 | 176 | # 177 | # Now let's check all the schema that we downloaded (from this run 178 | # and any other) and parse them with pyang to extract any imports 179 | # or includes and verify that they were on the advertised schema 180 | # list and didn't fail download. 181 | # 182 | # TODO: cater for explicitly revisioned imports & includes 183 | # 184 | imports_and_includes = set() 185 | repos = pyang.repository.FileRepository(args.output_dir, use_env=False) 186 | ctx = pyang.context.Context(repos) 187 | yangfiles = [f for f in listdir(args.output_dir) if isfile(join(args.output_dir, f))] 188 | for fname in sorted(yangfiles): 189 | logger.debug('Parsing %s', fname) 190 | fd = open(args.output_dir + '/' + fname, 'rb') 191 | text = fd.read().decode('UTF-8') 192 | ctx.add_module(fname, text) 193 | this_module = basename(fname).split(".")[0] 194 | for ((m, r), module) in ctx.modules.items(): 195 | if m == this_module: 196 | for s in module.substmts: 197 | if (s.keyword == 'import') or (s.keyword == 'include'): 198 | imports_and_includes.add(s.arg) 199 | 200 | # 201 | # Verify that all imports and includes appeared in the advertised 202 | # schema 203 | # 204 | not_advertised = [str(i) for i in imports_and_includes if i not in schema_list] 205 | if len(not_advertised) > 0: 206 | 207 | # 208 | # list the not-advertised schemas 209 | # 210 | print('The following schema are imported or included, but not listed in schemas tree:') 211 | for m in sorted(not_advertised, key=str.lower): 212 | print(' {}'.format(m)) 213 | 214 | # 215 | # try to download the not-advertised schemas 216 | # 217 | mgr = get_manager() 218 | for m in not_advertised: 219 | logger.debug('Trying to get module %s, which is included or import, bit not advertised', m) 220 | try: 221 | c = mgr.get_schema(m) 222 | with open(args.output_dir + '/' + m + '.yang', 'wb') as yang: 223 | yang.write(c.data.encode('UTF-8')) 224 | except RPCError as e: 225 | failed_download.add(str(m)) 226 | mgr.close_session() 227 | 228 | # 229 | # List out the schema that are imported or included and NOT 230 | # downloaded successfully. 231 | # 232 | if len(failed_download) > 0: 233 | print('The following schema are imported, included or advertised, but not downloadable:') 234 | for m in sorted(failed_download, key=str.lower): 235 | print(' {}'.format(m)) 236 | -------------------------------------------------------------------------------- /src/scripts/ncc_get_schema.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | from __future__ import print_function 6 | 7 | import logging 8 | import os 9 | import os.path 10 | import pyang 11 | import pyang.repository 12 | import pyang.context 13 | import sys 14 | 15 | from argparse import ArgumentParser 16 | from ncclient import manager 17 | from ncclient.operations.rpc import RPCError 18 | 19 | 20 | # 21 | # local logger 22 | # 23 | logger = logging.getLogger(__name__) 24 | 25 | 26 | # 27 | # default bytes to display when UnicodeDecodeError exceptions are caught 28 | # 29 | UNICODE_ERRB = 30 30 | 31 | 32 | def report_unicode_decode_error(u): 33 | assert isinstance(u, UnicodeDecodeError) 34 | start = u.start - UNICODE_ERRB 35 | if start < 0: start = 0 36 | end = u.start + UNICODE_ERRB 37 | if end > len(u.object): end = len(u.object) 38 | print('Unicode Encode/Decode Error exception:', file=sys.stderr) 39 | print(' {}'.format(u), file=sys.stderr) 40 | print('Surrounding data (+/- up to {} bytes):'.format(UNICODE_ERRB), file=sys.stderr) 41 | print(' {}'.format(u.object[start:end]), file=sys.stderr) 42 | 43 | 44 | def report_unicode_encode_error(u): 45 | assert isinstance(u, UnicodeEncodeError) 46 | start = u.start - UNICODE_ERRB 47 | if start < 0: start = 0 48 | end = u.start + UNICODE_ERRB 49 | if end > len(u.object): end = len(u.object) 50 | print('Unicode Encode/Decode Error exception:', file=sys.stderr) 51 | print(' {}'.format(u), file=sys.stderr) 52 | print('Surrounding data (+/- up to {} bytes):'.format(UNICODE_ERRB), file=sys.stderr) 53 | print(' {}'.format(u.object[start:end].encode('UTF-8')), file=sys.stderr) 54 | 55 | 56 | def get_schema(m, schema, version): 57 | ''' 58 | Simple schema download to stdout. 59 | ''' 60 | try: 61 | logger.debug('Retrieving %s', schema) 62 | c = m.get_schema(schema, version=version) 63 | print(c.data) 64 | except RPCError as e: 65 | print( 66 | 'Failed to get schema {} || RPCError: severity={}, tag={}, message={}'.format( 67 | schema, e.severity, e.tag, e.message), 68 | file=sys.stderr) 69 | 70 | 71 | def get_schema_with_depends(mgr, schema, version, dest_dir="."): 72 | ''' 73 | Get a names schema, with optional version, and download it. If the 74 | downloaded revision doesn't exist in the destination directory, 75 | recursively resolve all dependencies the module has. If any of 76 | those dependencies already exist, they will not be downloaded. 77 | 78 | Any downloaded schema are saved to files with version-extended file 79 | names. 80 | 81 | If the module give to this routine is a sub-module, the 82 | 'belongs-to' statement is not resolved. 83 | ''' 84 | to_resolve = set([(schema, version)]) 85 | try: 86 | repo = pyang.repository.FileRepository(dest_dir) 87 | while to_resolve: 88 | s, v = to_resolve.pop() 89 | c = mgr.get_schema(s, version=v) 90 | ctx = pyang.context.Context(repo) 91 | ctx.add_module(s, c.data) 92 | for ((m, r), module) in ctx.modules.items(): 93 | if m == s: 94 | dest_file = '%s/%s@%s.yang' % (dest_dir, m, r) 95 | if not os.path.isfile(dest_file): 96 | for sub in module.substmts: 97 | if (sub.keyword == 'import') or (sub.keyword == 'include'): 98 | to_resolve.add((sub.arg, None)) 99 | with open(dest_file, 'wb') as f: 100 | f.write(c.data.encode('UTF-8')) 101 | except RPCError as e: 102 | print( 103 | 'Failed to get schema {} || RPCError: severity={}, tag={}, message={}'.format( 104 | schema, e.severity, e.tag, e.message), 105 | file=sys.stderr) 106 | 107 | 108 | def main(): 109 | 110 | parser = ArgumentParser(description='Select schema download options:') 111 | parser.add_argument('-a', '--host', type=str, required=True, 112 | help="The device IP or DN") 113 | parser.add_argument('-u', '--username', type=str, default='cisco', 114 | help="Go on, guess!") 115 | parser.add_argument('-p', '--password', type=str, default='cisco', 116 | help="Yep, this one too! ;-)") 117 | parser.add_argument('--port', type=int, default=830, 118 | help="Specify this if you want a non-default port") 119 | parser.add_argument('--schema', type=str, required=True, 120 | help="Get just this schema") 121 | parser.add_argument('--get-depends', action='store_true', 122 | help="Also get dependencies for named schema; " 123 | "use of this option will trigger writing " 124 | "downloaded schema to files") 125 | parser.add_argument('-o', '--output-dir', type=str, default=os.getcwd(), 126 | help="Where to write schema files, and if models or " 127 | " their dependencies already exist in this location, " 128 | "their download will be skipped") 129 | parser.add_argument('--version', type=str, default=None, 130 | help="Schema to retrieve") 131 | parser.add_argument('-v', '--verbose', action='store_true', 132 | help="Do some verbose logging") 133 | args = parser.parse_args() 134 | 135 | # 136 | # if you enable verbose logging, it is INCREDIBLY verbose...you 137 | # have been warned!! so verbose with .ssh that I have currently 138 | # commented that out ;-) 139 | # 140 | if args.verbose: 141 | handler = logging.StreamHandler() 142 | handler.setFormatter( 143 | logging.Formatter('%(asctime)s:%(name)s:%(levelname)s:%(message)s')) 144 | logger.addHandler(handler) 145 | logger.setLevel(logging.DEBUG) 146 | for l in ['ncclient.transport.session', 147 | # 'ncclient.transport.ssh', 148 | 'ncclient.operations.rpc']: 149 | ll = logging.getLogger(l) 150 | ll.addHandler(handler) 151 | ll.setLevel(logging.DEBUG) 152 | 153 | # 154 | # connect to the device and either get schema with dependencies, 155 | # or do a simple get schema. 156 | # 157 | with manager.connect( 158 | timeout=600, 159 | host=args.host, 160 | port=args.port, 161 | username=args.username, 162 | password=args.password, 163 | allow_agent=False, 164 | look_for_keys=False, 165 | hostkey_verify=False) as m: 166 | try: 167 | if args.get_depends: 168 | get_schema_with_depends(m, args.schema, args.version, dest_dir=args.output_dir) 169 | else: 170 | get_schema(m, args.schema, args.version) 171 | except UnicodeDecodeError as u: 172 | report_unicode_decode_error(u) 173 | except UnicodeEncodeError as u: 174 | report_unicode_encode_error(u) 175 | -------------------------------------------------------------------------------- /src/scripts/rc-xr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2018 Cisco and/or its affiliates 4 | # 5 | import sys 6 | import requests 7 | from argparse import ArgumentParser 8 | from requests.auth import HTTPBasicAuth 9 | 10 | 11 | def send_request(protocol, host, port, username, password): 12 | '''Generate a simple RESTCONF request. 13 | ''' 14 | # url = "{}://{}:{}/restconf/data/Cisco-IOS-XR-ifmgr-cfg:interface-configurations/interface-configuration=act,GigabitEthernet0%2f0%2f0%2f0/description".format( 15 | url = "{}://{}:{}/restconf/data/Cisco-IOS-XR-ifmgr-cfg:interface-configurations".format( 16 | protocol, host, port) 17 | try: 18 | response = requests.get( 19 | auth=HTTPBasicAuth(username, password), 20 | url=url, 21 | params={ 22 | "content": "config", 23 | }, 24 | headers={ 25 | "Accept": "application/yang.data+json, application/yang.errors+json", 26 | }, 27 | ) 28 | print('Response HTTP Status Code: {status_code}'.format( 29 | status_code=response.status_code)) 30 | print('Response HTTP Response Body: {content}'.format( 31 | content=response.content)) 32 | except requests.exceptions.RequestException: 33 | print('HTTP Request failed') 34 | 35 | 36 | if __name__ == '__main__': 37 | 38 | parser = ArgumentParser(description='Do a RESTCONF operation:') 39 | 40 | # Input parameters 41 | parser.add_argument('--host', type=str, required=True, 42 | help="The device IP or DN") 43 | parser.add_argument('-u', '--username', type=str, default='cisco', 44 | help="Go on, guess!") 45 | parser.add_argument('-p', '--password', type=str, default='cisco', 46 | help="Yep, this one too! ;-)") 47 | parser.add_argument('--port', type=int, default=830, 48 | help="Specify this if you want a non-default port") 49 | 50 | args = parser.parse_args() 51 | 52 | send_request( "http", args.host, args.port, args.username, args.password) 53 | --------------------------------------------------------------------------------