├── .travis.yml
├── BackEndModeules
├── GetRibData.py
├── api_routes.py
├── device_call_backup.py
├── devicecalls.py
├── requirements.txt
└── wsgi.py
├── LICENSE
├── Python
├── README.rst
├── arps.py
├── dp_neighbors.py
├── get_cpu.py
├── get_environment.py
├── get_interfaces.py
├── get_l2_ports.py
├── get_ospf.py
├── get_vlans.py
├── mac_address_table.py
└── requirements.txt
├── README.rst
├── build
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── robots.txt
└── static
│ ├── css
│ ├── 2.f7c5f18f.chunk.css
│ ├── 2.f7c5f18f.chunk.css.map
│ ├── main.f05ca24e.chunk.css
│ └── main.f05ca24e.chunk.css.map
│ ├── js
│ ├── 2.fa43104b.chunk.js
│ ├── 2.fa43104b.chunk.js.LICENSE.txt
│ ├── 2.fa43104b.chunk.js.map
│ ├── main.07de7263.chunk.js
│ ├── main.07de7263.chunk.js.map
│ ├── main.b227f7a6.chunk.js
│ ├── main.b227f7a6.chunk.js.map
│ ├── runtime-main.32e9b272.js
│ └── runtime-main.32e9b272.js.map
│ └── media
│ └── router.cd099654.png
├── images
├── Layer2.png
├── iosxeops-int.PNG
├── mem-cpu.PNG
├── xeoprestprod.PNG
├── xeopslaprod.PNG
├── xeopsloading.PNG
├── xeopsprod-env.PNG
└── xeopsprodinterfaces.PNG
├── init_app_api.sh
├── install_dependencies.sh
├── package.json
├── public
├── favicon.ico
├── index.html
├── manifest.json
└── robots.txt
├── server.js
├── src
├── App.css
├── App.js
├── App.test.js
├── Components
│ ├── Config
│ │ └── config.js
│ ├── DMVPN
│ │ ├── Dmvpn-Parent.js
│ │ ├── dmvpnData.js
│ │ └── topology.js
│ ├── Environment
│ │ ├── Env-Parent.js
│ │ ├── cpuUsages.js
│ │ ├── env.js
│ │ ├── poe.js
│ │ ├── sensors.js
│ │ ├── transceivers.js
│ │ └── transieverInventory.js
│ ├── Forms
│ │ ├── bgpNeighborForm.js
│ │ ├── interfaceForm.js
│ │ └── ospfNeighborForm.js
│ ├── IPSlas
│ │ ├── Sla-Parent.js
│ │ ├── ipslastats.js
│ │ ├── slatopologies.js
│ │ └── topology.js
│ ├── Images
│ │ └── router.png
│ ├── Index
│ │ ├── Index-Parent.js
│ │ ├── InterfacesTable.js
│ │ ├── arps.js
│ │ ├── hsrp.js
│ │ ├── interfaceCard.js
│ │ ├── qos.js
│ │ ├── qosCharts.js
│ │ └── topology.js
│ ├── InterfaceGraphs
│ │ └── liveInterface.js
│ ├── LayerThree
│ │ ├── Routing-Parent.js
│ │ ├── bgp.js
│ │ ├── ospf.js
│ │ ├── ospfFormOverlay.js
│ │ ├── routing.js
│ │ └── topology.js
│ ├── LayerTwo
│ │ ├── accessPorts.js
│ │ ├── layerTwo-Parent.js
│ │ ├── layerTwo.js
│ │ ├── macAddress.js
│ │ ├── spanTree.js
│ │ ├── trunks.js
│ │ └── vlans.js
│ ├── Modals
│ │ ├── bgpFormModal.js
│ │ ├── configQueryModal.js
│ │ ├── configSendModal.js
│ │ ├── interfaceModal.js
│ │ └── loadingModal.js
│ ├── Other
│ │ ├── axiosRequests.js
│ │ ├── bandwidthFunctions.js
│ │ ├── chartConfigs.js
│ │ ├── configNavbar.js
│ │ ├── data.js
│ │ ├── dp_neighbors.js
│ │ ├── errorBoundry.js
│ │ ├── errorComponent.js
│ │ ├── errorData.js
│ │ ├── interfaceOverlay.js
│ │ ├── jsxCard.js
│ │ ├── login.js
│ │ ├── navbar.js
│ │ ├── navbarError.js
│ │ ├── pageLoader.js
│ │ ├── promises.js
│ │ └── tables.js
│ └── RibStatus
│ │ ├── RIB-Parent.js
│ │ ├── RibMain.js
│ │ ├── getRibs.js
│ │ ├── promises.js
│ │ ├── protocols.js
│ │ └── ribDiff.js
├── holder.rst
├── index.css
├── index.js
├── reportWebVitals.js
└── setupTests.js
└── test
├── GetRibData.py
├── ansible.cfg
├── ansible_config.py
├── ansible_config_new.py
├── api_routes.py
├── bgp_config.j2
├── bgp_config.yml
├── bgp_config_script.py
├── device_call_backup.py
├── devicecalls.py
├── intf_config.j2
├── intf_config.j2.bak
├── intf_config_vars.yml
├── intf_playbook.yml
├── inventory.yml
├── my_file.out
├── ospf_config.j2
├── ospf_config.py
├── ospf_config.yml
├── requirements.txt
├── show_version.yml
├── test.rst
├── wsgi.py
└── yang_conversions.py
/.travis.yml:
--------------------------------------------------------------------------------
1 | jobs:
2 | include:
3 | before_script:
4 | -cd BackEndModeules
5 | - language: python
6 | python: 3.8
7 | install:
8 | - pip install -r requirements.txt
9 | "script": [
10 | "echo \"skipping tests\""
11 | ]
12 |
13 | - language: node_js
14 | node_js:
15 | - "stable"
16 | script:
17 | - npm test
18 |
--------------------------------------------------------------------------------
/BackEndModeules/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 | flask
3 | flask_jwt_extended
4 | netmiko
5 | ipapi
6 | SQLAlchemy
7 | gunicorn
8 |
9 |
--------------------------------------------------------------------------------
/BackEndModeules/wsgi.py:
--------------------------------------------------------------------------------
1 | from api_routes import app
2 | import os
3 | import ssl
4 |
5 | ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
6 | ctx.load_cert_chain(f'{os.getcwd()}/domainame.crt', f'{os.getcwd()}/domainame.key')
7 |
8 | if __name__ == "__main__":
9 | app.run(ssl_context=ctx)
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 cober2019
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Python/README.rst:
--------------------------------------------------------------------------------
1 | IOS-XE Rest Functions
2 | ---------------------
3 |
4 | These are a collection of functions which I'm currently using with the IOS-XE React App. I've converted these to print the data along with return for use elsewhere.
5 |
6 | Enjoy!
7 |
--------------------------------------------------------------------------------
/Python/arps.py:
--------------------------------------------------------------------------------
1 | """Set of functions that gets and prints arp entries"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import warnings
7 |
8 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
9 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
10 |
11 | def _check_api_error(response) -> bool:
12 | """Check for API Errors"""
13 |
14 | is_error = False
15 |
16 | if list(response.keys())[0] == 'errors':
17 | is_error = True
18 |
19 | return is_error
20 |
21 | def _print_arps(table_detail, entry) -> None:
22 | """Print Arp entries"""
23 |
24 | try:
25 | print(f"{entry.get('address', {}):<25}{entry.get('enctype', {}):<30} {entry.get('hardware', {}):<30}{entry.get('mode'):<30}{entry.get('time', {}):<40}{entry.get('type'):<30}{table_detail.get('vrf'):<20}")
26 | except TypeError:
27 | pass
28 |
29 | def get_arps(ip, port, username, password) -> list:
30 | """Collects arp for the matching"""
31 |
32 | entries = []
33 |
34 | try:
35 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-arp-oper:arp-data/arp-vrf"
36 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
37 | arp_entries = json.loads(response.text, strict=False)
38 |
39 | check_error = _check_api_error(arp_entries)
40 |
41 | if check_error:
42 | raise AttributeError
43 |
44 | try:
45 | print(f"{'Address':<30} {'Encap':<30} {'Mac':<30}{'Mode':<40}{'Time':<25} {'Type':<30}{'VRF':<20}")
46 | print("-" * 200)
47 | for i in arp_entries.get('Cisco-IOS-XE-arp-oper:arp-vrf'):
48 | [ _print_arps(i, entry) for entry in i.get('arp-oper')]
49 | except (TypeError, AttributeError):
50 | pass
51 |
52 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL, AttributeError):
53 | pass
54 |
55 | return entries
56 |
57 |
58 | if __name__ == '__main__':
59 |
60 | try:
61 | get_arps()
62 | except TypeError:
63 | input('Input credentials')
64 |
--------------------------------------------------------------------------------
/Python/dp_neighbors.py:
--------------------------------------------------------------------------------
1 | """ Set of fuctions which collects CDP and LLDP neighbor info"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import time
7 | import os
8 | import warnings
9 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
10 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
11 |
12 | def get_dp_neighbors(ip, port, username, password) -> list:
13 | """Gets device components restconf/data/Cisco-IOS-XE-cdp-oper:cdp-neighbor-details"""
14 |
15 | data = []
16 |
17 | try:
18 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-cdp-oper:cdp-neighbor-details"
19 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
20 | converted_json = json.loads(response.text)
21 | data.append(converted_json)
22 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError):
23 | data.append({})
24 |
25 | try:
26 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-lldp-oper:lldp-entries"
27 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
28 | converted_json = json.loads(response.text)
29 | data.append(converted_json)
30 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError):
31 | data.append({})
32 |
33 | _print_dp_neighbors(data)
34 |
35 | return data
36 |
37 | def _print_dp_neighbors(data):
38 |
39 | print(f"CDP {'Device':<50} {'Local Int':<25} {'Remote-Port':<20}{'Capability':<25}{'Duplex':<30}{'Platform':<25}{'Mgmt IP':<20}{'IP':<20}")
40 | print("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------")
41 | if data[0].get('Cisco-IOS-XE-cdp-oper:cdp-neighbor-details', {}).get('cdp-neighbor-detail', {}):
42 | for i in data:
43 | if isinstance(i.get('Cisco-IOS-XE-cdp-oper:cdp-neighbor-details', {}).get('cdp-neighbor-detail', {}), list):
44 | for a in i['Cisco-IOS-XE-cdp-oper:cdp-neighbor-details']['cdp-neighbor-detail']:
45 | print(f"{a['device-name']:<45}{a['local-intf-name']:<25}{a['port-id']:<25}{a['capability']:<25}{a['duplex']:<30}{a['platform-name']:<25}{a['mgmt-address']:<18}{a['ip-address']}")
46 | else:
47 | print('No CDP Neighbors or CDP isnt Enabled\n')
48 |
49 | print(f"\nLLDP {'Device':<38} {'Local Int':<30} {'Remote-Port':<33}{'Capability':<25}")
50 | print("-------------------------------------------------------------------------------------------------------------------------------------------------------------------")
51 | if data[1].get('Cisco-IOS-XE-lldp-oper:lldp-entries', {}).get('lldp-entry'):
52 | for i in data:
53 | if isinstance(i.get('Cisco-IOS-XE-lldp-oper:lldp-entries', {}).get('lldp-entry'), list):
54 | for a in i['Cisco-IOS-XE-lldp-oper:lldp-entries']['lldp-entry']:
55 | print(f"{a['device-id']:<40}{a.get('local-interface'):<30}{a.get('connecting-interface'):<33}{', '.join(list(dict.fromkeys(a.get('capabilities', {})))):<25}")
56 | else:
57 | print('No LLDP Neighbors or LLDP isnt Enabled\n')
58 |
59 | if __name__ == '__main__':
60 |
61 | try:
62 | get_dp_neighbors()
63 | except TypeError:
64 | input('Input credentials')
65 |
--------------------------------------------------------------------------------
/Python/get_cpu.py:
--------------------------------------------------------------------------------
1 | """Function for getting CPU data from a device"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import time
7 | import os
8 | import warnings
9 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
10 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
11 |
12 |
13 | def get_cpu_usages(ip, port, username, password, show_proccess=False) -> tuple:
14 | """Gets real time CPU statistics using restconf/data/Cisco-IOS-XE-process-cpu-oper:cpu-usage"""
15 |
16 | cpu_stats = {}
17 | memory_stats = {}
18 |
19 | try:
20 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-process-cpu-oper:cpu-usage/cpu-utilization"
21 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
22 | cpu_stats = json.loads(response.text)
23 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError):
24 | pass
25 |
26 | try:
27 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-platform-software-oper:cisco-platform-software/control-processes/control-process"
28 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
29 | converted_json = json.loads(response.text)
30 | get_keys = dict.fromkeys(converted_json)
31 | parent_key = list(get_keys.keys())[0]
32 | memory_stats = converted_json[parent_key]
33 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError):
34 | pass
35 |
36 | if cpu_stats:
37 | print("{0:<15}{1:<15}\n{2:<15}{3:<16}\n{4:<15}{5:<5}".format('Five Seconds:', cpu_stats['Cisco-IOS-XE-process-cpu-oper:cpu-utilization']['five-seconds'],
38 | 'One Minute:',cpu_stats['Cisco-IOS-XE-process-cpu-oper:cpu-utilization']['one-minute'],
39 | 'Five Minutes:', cpu_stats['Cisco-IOS-XE-process-cpu-oper:cpu-utilization']['five-minutes']))
40 | if show_proccess:
41 | print("{0:<5}{1:<55}{2:<20}{3:<10}{4:<10}{5:<10}{6:<10}".format('PID', 'Name', 'TTY', 'Avg-Run', 'Five Sec.', 'One Min.', 'Five Min.'))
42 | print('-' * 130)
43 | for i in cpu_stats['Cisco-IOS-XE-process-cpu-oper:cpu-utilization']['cpu-usage-processes']['cpu-usage-process']:
44 | print("{0:<5}{1:<55}{2:<20}{3:<10}{4:<10}{5:<10}{6:<10}".format(i.get('pid'), i.get('name'), i.get('tty'), i.get('avg-run-time'),
45 | i.get('five-seconds'), i.get('one-minute'), i.get('five-minutes')))
46 | return cpu_stats, memory_stats
47 |
48 | if __name__ == '__main__':
49 |
50 | try:
51 | get_dp_neighbors()
52 | except TypeError:
53 | input('Input credentials')
54 |
--------------------------------------------------------------------------------
/Python/get_environment.py:
--------------------------------------------------------------------------------
1 | """Function that gets device enviromental stats"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import time
7 | import os
8 | import warnings
9 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
10 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
11 |
12 |
13 | def get_envirmoment(ip, port, username, password) -> dict:
14 | """Gets real time enviroment statistics using restconf/data/Cisco-IOS-XE-environment-oper:environment-sensors"""
15 |
16 | data = {}
17 |
18 | try:
19 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-environment-oper:environment-sensors"
20 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
21 | data = json.loads(response.text)
22 |
23 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError):
24 | pass
25 |
26 | if data:
27 | print("{0:<17}{1:<13}{2:<18}{3:<10}{4:<5}".format('Name', 'Location', 'State', 'Current', 'Measurement'))
28 | print("-" * 70 )
29 | for i in test['Cisco-IOS-XE-environment-oper:environment-sensors']['environment-sensor']:
30 | print("{0:<20}{1:<10}{2:<20}{3:<10}{4:<5}".format(i.get('name'), i.get('location'), i.get('state'), i.get('current-reading'), i.get('sensor-units')))
31 |
32 | return data
33 |
34 | if __name__ == '__main__':
35 |
36 | try:
37 | get_envirmoment()
38 | except TypeError:
39 | input('Input credentials')
40 |
--------------------------------------------------------------------------------
/Python/get_interfaces.py:
--------------------------------------------------------------------------------
1 | """Set of functions to collect interface stats"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import time
7 | import os
8 | import warnings
9 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
10 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
11 |
12 | def get_interfaces(ip, port, username, password, ex_down=None):
13 | """Gets real time interface statistics using IOS-XE\n
14 | Cisco-IOS-XE-interfaces-oper:interfaces and live arp data via Cisco-IOS-XE-arp-oper:arp-data/arp-vrf"""
15 |
16 | data = {}
17 | interface_data = {}
18 |
19 | try:
20 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-interfaces-oper:interfaces"
21 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
22 | converted_json = json.loads(response.text)
23 | interface_data = converted_json.get('Cisco-IOS-XE-interfaces-oper:interfaces').get('interface')
24 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError):
25 | pass
26 |
27 | if interface_data:
28 | try:
29 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-arp-oper:arp-data/arp-vrf"
30 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
31 |
32 | converted_json = json.loads(response.text, strict=False)
33 | get_keys = dict.fromkeys(converted_json)
34 | parent_key = list(get_keys.keys())[0]
35 |
36 | for interface in interface_data:
37 | convert_bandwidth = _convert_to_mbps(interface)
38 | entries = [_get_arps(interface, i) for i in converted_json[parent_key]][0]
39 | data[interface.get('name')] = {'interface': interface.get('name'), 'data': convert_bandwidth, 'arps': entries}
40 |
41 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError):
42 | for interface in interface_data:
43 | convert_bandwidth = _convert_to_mbps(interface)
44 | data[interface.get('name')] = {'interface': interface.get('name'), 'data': convert_bandwidth, 'arps': []}
45 |
46 | for v in data.values():
47 | [_print_interfaces_extended(data, ex_down) for data in v.values() if isinstance(data, dict)]
48 |
49 | return data
50 |
51 | def _print_interfaces_extended(data, ex_down) -> dict:
52 | """Prints interface data"""
53 |
54 | if ex_down == True:
55 | if data.get('oper-status', {}) == 'up':
56 | print(f"{data.get('name', {}):<35}{data.get('oper-status', {}):<15} {int(data.get('statistics', {}).get('rx-kbps')) / 1000:<10}{int(data.get('statistics', {}).get('tx-kbps')) / 1000:<10}{data.get('statistics', {}).get('rx-pps'):<10} {data.get('statistics', {}).get('tx-pps'):<10}{data.get('mtu'):<10}{data.get('ipv4', ''):<20} {data.get('ipv4-subnet-mask', ''):<1}")
57 | else:
58 | print(f"{data.get('name', {}):<35}{data.get('oper-status', {}):<15} {int(data.get('statistics', {}).get('rx-kbps')) / 1000:<10}{int(data.get('statistics', {}).get('tx-kbps')) / 1000:<10}{data.get('statistics', {}).get('rx-pps'):<10} {data.get('statistics', {}).get('tx-pps'):<10}{data.get('mtu'):<10}{data.get('ipv4', ''):<20} {data.get('ipv4-subnet-mask', ''):<1}")
59 |
60 | def _convert_to_mbps(interface):
61 | """Convert Kbps to Mbps"""
62 |
63 | interface['statistics']['tx-kbps'] = int(interface.get('statistics').get('tx-kbps')) / 1000
64 | interface['statistics']['rx-kbps'] = int(interface.get('statistics').get('tx-kbps')) / 1000
65 | if interface['oper-status'] == 'if-oper-state-ready':
66 | interface['oper-status'] = 'up'
67 | else:
68 | interface['oper-status'] = 'down'
69 |
70 | return interface
71 |
72 | def _get_arps(interface, i):
73 | """Collects arp for the matching interface"""
74 |
75 | entries = []
76 |
77 | try:
78 | for entry in i.get('arp-oper'):
79 | if entry.get('interface') == interface.get('name'):
80 | entry.pop('interface')
81 | entry['time'] = entry.get('time').split('.')[0].strip('T00')
82 | entries.append(entry)
83 | except TypeError:
84 | pass
85 |
86 | return entries
87 |
88 | if __name__ == '__main__':
89 |
90 | try:
91 | get_interfaces()
92 | except TypeError:
93 | input('Input credentials')
94 |
--------------------------------------------------------------------------------
/Python/get_l2_ports.py:
--------------------------------------------------------------------------------
1 | """Collection of fuction to get layer 2 ports"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import time
7 | import os
8 | import warnings
9 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
10 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
11 |
12 | def get_switch(ip, port, username, password) -> tuple:
13 | """Gets device components /restconf/data/openconfig-platform:components"""
14 |
15 | data = {}
16 | trunk =[]
17 | access = []
18 |
19 | try:
20 | interfaces_configs = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-native:native/interface"
21 | interface_status = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-interfaces-oper:interfaces"
22 | config_response = requests.get(interfaces_configs, headers=headers, verify=False, auth=(username, password))
23 | stats_response = requests.get(interface_status, headers=headers, verify=False, auth=(username, password))
24 | config_json = json.loads(config_response.text)
25 | stats_json = json.loads(stats_response.text)
26 |
27 | for interface, v in config_json['Cisco-IOS-XE-native:interface'].items():
28 | if isinstance(v, list):
29 | mapped = [map_switchports(config, interface, stats_json) for config in v]
30 | data[interface] = list(mapped)
31 |
32 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL):
33 | pass
34 |
35 | for v in data.values():
36 | for i in v:
37 | if i[0].get('mode') == 'trunk':
38 | trunk.append(i[0])
39 | elif i[0].get('mode') == 'access':
40 | access.append(i[0])
41 |
42 | if trunk:
43 | print(f"{'Interface':<30} {'Mode':<15} {'Status':<28}{'Mbps In':<20}{'Mbps Out':<17}{'Allow Vlans':<13}")
44 | print("-------------------------------------------------------------------------------------------------------------------------------------------")
45 | [print(f"{i.get('interface', {}):<30}{i.get('mode', {}):<10} {i.get('status', {}):<35}{i.get('mbpsOut'):<20}{i.get('mbpsIn'):<20}{i.get('vlans'):<20}") for i in trunk]
46 | print('\n')
47 | if access:
48 | print(f"{'Interface':<35} {'Status':<28} {'Mbps Out':<19}{'Mbps In':<20}{'Vlans'}")
49 | print("-------------------------------------------------------------------------------------------------------------------------------------------")
50 | [print(f"{i.get('interface', {}):<30}{i.get('status', {}):<35}{i.get('mbpsOut'):<20}{i.get('mbpsIn'):<20}{i.get('vlan'):<20}") for i in access]
51 |
52 | return trunk, access
53 |
54 | def map_switchports(config, interface, interfaces_statuses) -> list:
55 |
56 | complete_interface = f"{interface}{config.get('name')}"
57 | interface_mode = False
58 | data = []
59 | statistics = next((interface for interface in interfaces_statuses['Cisco-IOS-XE-interfaces-oper:interfaces']['interface'] if interface['name'] == complete_interface), None)
60 |
61 | if config.get('switchport', {}).get('Cisco-IOS-XE-switch:mode', {}):
62 | interface_mode = list(config.get('switchport', {}).get('Cisco-IOS-XE-switch:mode', {}).keys())[0]
63 |
64 | if interface_mode == 'access':
65 | access_vlan = config.get('switchport').get('Cisco-IOS-XE-switch:access').get('vlan').get('vlan')
66 | data.append({'mode': 'access','interface': complete_interface, 'vlan': access_vlan, 'status': statistics['oper-status'],
67 | 'mbpsOut': int(statistics['statistics']['tx-kbps'])/1000, 'mbpsIn': int(statistics['statistics']['rx-kbps'])/1000})
68 |
69 | elif interface_mode == 'trunk':
70 | if config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("allowed", {}).get("vlan", {}).get("vlans", {}):
71 | trunked_vlans = config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("allowed", {}).get("vlan", {}).get("vlans", {})
72 | native = config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("native", {}).get("vlan", {})
73 | elif config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("allowed", {}).get("vlan", {}).get("add", {}):
74 | trunked_vlans = config.get('switchport').get('Cisco-IOS-XE-switch:trunk').get('allowed').get('vlan').get('add').get('vlans')
75 | native = config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("native", {}).get("vlan", {})
76 | elif config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("allowed", {}).get("vlan", {}).get('vlans', {}):
77 | trunked_vlans = config.get('switchport').get('Cisco-IOS-XE-switch:trunk').get('allowed').get('vlan').get('vlans')
78 | native = config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("native", {}).get("vlan", {})
79 | else:
80 | trunked_vlans = 'all'
81 | native = config.get("switchport").get("Cisco-IOS-XE-switch:trunk", {}).get("native", {}).get("vlan", {})
82 |
83 | data.append({'mode': 'trunk', 'interface': complete_interface, 'vlans': trunked_vlans, 'native': native, 'status': statistics['oper-status'],
84 | 'mbpsOut': int(statistics['statistics']['tx-kbps'])/1000, 'mbpsIn': int(statistics['statistics']['rx-kbps'])/1000})
85 | else:
86 | data.append({'mode': None, 'interface': complete_interface, 'status': statistics['oper-status'],
87 | 'mbpsOut': int(statistics['statistics']['tx-kbps'])/1000, 'mbpsIn': int(statistics['statistics']['rx-kbps'])/1000})
88 |
89 | return data
90 |
91 | if __name__ == '__main__':
92 |
93 | try:
94 | get_switch()
95 | except TypeError:
96 | input('Input credentials')
97 |
--------------------------------------------------------------------------------
/Python/get_ospf.py:
--------------------------------------------------------------------------------
1 | """Set of functions that gets and prints arp entries"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import warnings
7 |
8 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
9 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
10 |
11 | def _check_api_error(response) -> bool:
12 | """Check for API Errors"""
13 |
14 | is_error = False
15 |
16 | if list(response.keys())[0] == 'errors':
17 | is_error = True
18 |
19 | return is_error
20 |
21 | def _print_ospf_neigh(ospf_neighbors=None, ospf_interfaces=None) -> None:
22 | """Print Arp entries"""
23 |
24 | print(f"{'Neighbor':<25} {'Address':<30} {'DR':<30}{'BDR':<27}{'State':<25}")
25 | print('-' * 125)
26 | try:
27 | if ospf_neighbors:
28 | for neighbor in ospf_neighbors:
29 | print(f"{neighbor.get('neighbor-id', {}):<25}{neighbor.get('address', {}):<30} {neighbor.get('dr', {}):<30}{neighbor.get('bdr', {}):<25}{neighbor.get('state', {}):<30}")
30 | else:
31 | print('No Neighbors')
32 | except TypeError:
33 | pass
34 |
35 | def _print_ospf_ints(ospf_interfaces) -> None:
36 | """Print Arp entries"""
37 |
38 |
39 | print(f"\n{'Neighbor':<25} {'Network Type':<30} {'Area':<10}{'BDR':<10}{'DR':<10}{'Cost':<15} {'Dead Interval':<15} {'Hello Interval':<15}{'Hello Time':<15}{'Priority':<25}")
40 | try:
41 | print('-' * 200)
42 | for interface in ospf_interfaces:
43 | print(f"{interface.get('name', {}):<25}{interface.get('network-type', {}):<30} {interface.get('area', {}):<10}{interface.get('bdr', {}):<10}{interface.get('dr', {}):<15}{interface.get('cost', {}):<15}{interface.get('dead-interval', {}):<15} {interface.get('hello-interval', {}):<15}{interface.get('hello-timer', {}):<15}{interface.get('priority', {}):<30}")
44 |
45 | except TypeError:
46 | pass
47 |
48 | def get_ospf(ip, port, username, password):
49 | """Gets device ospf operational data"""
50 |
51 | ospf_neighbors = []
52 | ospf_interfaces = []
53 |
54 | try:
55 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-ospf-oper:ospf-oper-data/ospf-state/ospf-instance?fields=ospf-area/ospf-interface/ospf-neighbor"
56 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
57 | ospf = json.loads(response.text)
58 |
59 | check_error = _check_api_error(ospf)
60 |
61 | if check_error:
62 | raise AttributeError
63 |
64 | for i in ospf.get('Cisco-IOS-XE-ospf-oper:ospf-instance')[0].get('ospf-area'):
65 | [list((ospf_neighbors.append(neighbor) for neighbor in interface.get('ospf-neighbor'))) for interface in i.get('ospf-interface')]
66 |
67 | _print_ospf_neigh(ospf_neighbors)
68 |
69 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError, TypeError):
70 | pass
71 |
72 | try:
73 |
74 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-ospf-oper:ospf-oper-data/ospf-state/ospf-instance"
75 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
76 | ospf = json.loads(response.text)
77 |
78 | check_error = _check_api_error(ospf)
79 | if check_error:
80 | raise AttributeError
81 |
82 | for instance in ospf.get('Cisco-IOS-XE-ospf-oper:ospf-instance', {}):
83 | for area in instance.get('ospf-area', {}):
84 | if isinstance(area.get('ospf-interface', {}), list):
85 | for interface in area.get('ospf-interface', {}):
86 | interface['area'] = area.get('area-id', {})
87 | for i in interface.get('ospf-neighbor', {}):
88 | ospf_interfaces.append(interface)
89 |
90 | _print_ospf_ints(ospf_interfaces)
91 |
92 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError, TypeError) as e:
93 | pass
94 |
95 |
96 | return ospf_neighbors, ospf_interfaces
97 |
98 | if __name__ == '__main__':
99 |
100 | try:
101 | get_ospf()
102 | except TypeError:
103 | input('Input credentials')
104 |
--------------------------------------------------------------------------------
/Python/get_vlans.py:
--------------------------------------------------------------------------------
1 | """Set of fuctions which collects vlan data"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import time
7 | import os
8 | import warnings
9 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
10 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
11 |
12 | def get_vlans(ip, port, username, password) -> list:
13 | """Gets device components /restconf/data/openconfig-platform:components"""
14 |
15 | data = []
16 |
17 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-vlan-oper:vlans"
18 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
19 | vlans = json.loads(response.text)
20 |
21 | for i in vlans.get('Cisco-IOS-XE-vlan-oper:vlans', {}).get('vlan', {}):
22 | try:
23 | if i.get('vlan-interfaces'):
24 | data.append({"id": i.get('id'), "name": i.get('name'), "status": i.get('status'), "interfaces": ", ".join([interface.get('interface') for interface in i.get('vlan-interfaces')])})
25 | else:
26 | data.append({"id": i.get('id'), "name": i.get('name'), "status": i.get('status'), "interfaces": ''})
27 | except TypeError:
28 | pass
29 |
30 | if data:
31 | print(f"\n{'Vlans':<30} {'Name':<39} {'Status':<50}{'Interfaces':<25}")
32 | print(f"--------------------------------------------------------------------------------------")
33 | for vlan_data in data:
34 | print(f"{vlan_data.get('id', {}):<30}{vlan_data.get('name', {}):<40} {vlan_data.get('status', {}):<30}{', '.join(vlan_data.get('interfaces', '').split(',')[0:4]):<20}")
35 | [_print_vlans_extended(index, vlan, vlan_data) for index, vlan in enumerate(vlan_data.get('interfaces').split(',')) if index != 0 and index % 4 == 0]
36 | else:
37 | print('No Vlans')
38 |
39 | return data
40 |
41 | def _print_vlans_extended(index, vlan, vlan_data):
42 | """Prints vlans sideXside"""
43 |
44 | try:
45 | print(" " * 100 + vlan, vlan_data.get('interfaces', '').split(',')[index + 1], vlan_data.get('interfaces', '').split(',')[index + 2], vlan_data.get('interfaces', '').split(',')[index + 4])
46 | except IndexError:
47 | pass
48 |
49 | if __name__ == '__main__':
50 |
51 | try:
52 | get_vlans()
53 | except TypeError:
54 | input('Input credentials')
55 |
--------------------------------------------------------------------------------
/Python/mac_address_table.py:
--------------------------------------------------------------------------------
1 | """Set of functions that get and print mac address table"""
2 |
3 | from json.decoder import JSONDecodeError
4 | import requests
5 | import json
6 | import warnings
7 |
8 | warnings.filterwarnings('ignore', message='Unverified HTTPS request')
9 | headers = {"Content-Type": 'application/yang-data+json', 'Accept': 'application/yang-data+json'}
10 |
11 | def _print_macs(entry) -> None:
12 | """Print mac address entries"""
13 |
14 | try:
15 | print(f"{entry.get('vlan-id-number', {}):<20}{entry.get('mac', {}):<20} {entry.get('mat-addr-type', {}):<15}{entry.get('port'):<20}")
16 | except TypeError:
17 | pass
18 |
19 | def get_bridge(ip, port, username, password) -> list:
20 | """Gets device mac-address-table"""
21 |
22 | mac_table = []
23 |
24 | try:
25 | uri = f"https://{ip}:{port}/restconf/data/Cisco-IOS-XE-matm-oper:matm-oper-data"
26 | response = requests.get(uri, headers=headers, verify=False, auth=(username, password))
27 | data = json.loads(response.text)
28 |
29 | print(f"{'Vlan':<25} {'Mac':<15} {'Type':<15}{'Port':<20}")
30 | print("--------------------------------------------------------------------")
31 |
32 | for i in data['Cisco-IOS-XE-matm-oper:matm-oper-data']['matm-table']:
33 | if i.get('matm-mac-entry', {}):
34 | [_print_macs(i) for i in i.get('matm-mac-entry', {})]
35 |
36 | except (JSONDecodeError, requests.exceptions.ConnectionError, requests.exceptions.InvalidURL,UnboundLocalError, AttributeError, KeyError):
37 | print('No macs found. Please check device compatability with this model')
38 |
39 | return mac_table
40 |
41 | if __name__ == '__main__':
42 |
43 | try:
44 | get_bridge()
45 | except TypeError:
46 | input('Input credentials')
47 |
--------------------------------------------------------------------------------
/Python/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | .. image:: https://app.travis-ci.com/cober2019/react-ios-xe-ops.svg?branch=main
2 | :target: -
3 | .. image:: https://img.shields.io/badge/npm-16.14.12-blue
4 | :target: -
5 | .. image:: https://img.shields.io/badge/Node-stable-blue
6 | :target: -
7 |
8 | XE-Ops
9 | ============
10 |
11 | View operational and config data from devices running Cisco IOS-XE software.
12 |
13 | NoteS
14 | ============
15 |
16 | The build folder is the latest build. All other files are for developement and are updated frequently. They've not been tested for prod build yet.
17 |
18 | **Tested Models**
19 |
20 | | -ASR 1000 Series
21 | | -ISR 4000 Series
22 | | -CSR 1000v
23 | | -CAT 3000 Series
24 |
25 | Available Views:
26 | -----------------
27 |
28 | **Interfaces:**
29 |
30 | | -Layer Two and Layer Three
31 | | -Arps
32 | | -QoS
33 | **Neighbors:**
34 |
35 | | -DP Neighbors
36 | | -OSPF Neighbors
37 | | -BGP Neighbors
38 |
39 | **Routing:**
40 |
41 | | -OSPF
42 | | -BGP
43 | | -Routing Table (Flapping Route Checker)
44 |
45 | **IP SLAs:**
46 |
47 | | -Check current IP SLA statuses
48 |
49 | **Environment:**
50 |
51 | | -CPU/Memory statuse
52 | | -Sensor statuses
53 | | -SFP statuses
54 | | -POE port statuses
55 |
56 | **DMVPN:**
57 |
58 | | -Tunnel statuses
59 | | -Peer statuses
60 | | -Public IP resolution
61 | | -DMVPN topology visualization
62 |
63 | **LayerTwo:**
64 |
65 | | -Vlans
66 | | -Trunks
67 | | -Spanning-tree
68 |
69 | **Rest Viewer:**
70 |
71 | | -View all device data in JSON format
72 |
73 |
74 | **Snapshots:**
75 | ----------------
76 | |
77 |
78 | .. image:: https://github.com/cober2019/react-ios-xe-ops/blob/main/images/xeopsprodinterfaces.PNG
79 | .. image:: https://github.com/cober2019/react-ios-xe-ops/blob/main/images/xeopsprod-env.PNG
80 | .. image:: https://github.com/cober2019/react-ios-xe-ops/blob/main/images/xeoprestprod.PNG
81 | .. image:: https://github.com/cober2019/react-ios-xe-ops/blob/main/images/xeopslaprod.PNG
82 | .. image:: https://github.com/cober2019/react-ios-xe-ops/blob/main/images/xeopsloading.PNG
83 |
84 |
85 | **Notes:**
86 | | -Switches are slower to poll than routers
87 | | -Some YANG models may not be compatible with your device. If so, data is collected via Netmiko
88 | | -Views are conditionally rendered which means so some views wont display.
89 | | -Sometimes CPU data for CSRs will error. If so, it will be represented with 'Err'
90 | | -Page data will be cached for 5 minutes per device. This means if you switch pages or log into another device, the page will load what was polled last for that device/page. Beats a loading page!
91 | | -Login timeout set to 30 seconds
92 | | -Collecting RIB tables can take some time. Be patient
93 | |
94 |
95 | Requirements:
96 | --------------
97 |
98 | Check to see if your device is compatible to use this program. Use the following instructions - https://developer.cisco.com/docs/ios-xe/#!enabling-restconf-on-ios-xe
99 |
100 | Install:Linux
101 | --------------
102 | The following dependencies are required. If you don't have the following dependencies installed, execute: "sudo bash install_dependencies.sh"
103 | |
104 | | -NPM && Node.js https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
105 | | -Python: https://docs.python-guide.org/starting/install3/linux/
106 | | -Open SSL
107 |
108 | **Once Dependecies Are Installed:**
109 | |
110 | | **Note: If you're using windows 10, you can use built-in Ubuntu**
111 | |
112 | | 1. Clone this repo to you server and navigate to the /react-ios-xe-ops (root) directory.
113 | | 2. Execute command "sudo bash init_app_routes" which will take care of everything below. When running the script, SSL certs will be created for app to api security. TLSv1.3 for transport.
114 | |
115 | | **If you want to manualy install then continue with these steps:**
116 | |
117 | | 2. Located package.json and execute code "npm install package.json"
118 | | 3. Once packages are installed, execute code "node server.js&"
119 | | 4. Navigate to 127.0.0.1:3000
120 | | 5. Create a virtual environment by executing "python3.8 -m venv ios-xe-ops-env" and activate the env using "source ios-xe-ops-env/bin/activate"
121 | | 6. Install python modules using pip "pip install -r requirements.txt"
122 | | 7. Start the API using "Python3 api_routes.py"
123 | | 8. Go back to the web app and login to your device
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
--------------------------------------------------------------------------------
/build/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.css": "/static/css/main.f05ca24e.chunk.css",
4 | "main.js": "/static/js/main.07de7263.chunk.js",
5 | "main.js.map": "/static/js/main.07de7263.chunk.js.map",
6 | "runtime-main.js": "/static/js/runtime-main.32e9b272.js",
7 | "runtime-main.js.map": "/static/js/runtime-main.32e9b272.js.map",
8 | "static/css/2.f7c5f18f.chunk.css": "/static/css/2.f7c5f18f.chunk.css",
9 | "static/js/2.fa43104b.chunk.js": "/static/js/2.fa43104b.chunk.js",
10 | "static/js/2.fa43104b.chunk.js.map": "/static/js/2.fa43104b.chunk.js.map",
11 | "index.html": "/index.html",
12 | "static/css/2.f7c5f18f.chunk.css.map": "/static/css/2.f7c5f18f.chunk.css.map",
13 | "static/css/main.f05ca24e.chunk.css.map": "/static/css/main.f05ca24e.chunk.css.map",
14 | "static/js/2.fa43104b.chunk.js.LICENSE.txt": "/static/js/2.fa43104b.chunk.js.LICENSE.txt",
15 | "static/media/router.cd099654.png": "/static/media/router.cd099654.png"
16 | },
17 | "entrypoints": [
18 | "static/js/runtime-main.32e9b272.js",
19 | "static/css/2.f7c5f18f.chunk.css",
20 | "static/js/2.fa43104b.chunk.js",
21 | "static/css/main.f05ca24e.chunk.css",
22 | "static/js/main.07de7263.chunk.js"
23 | ]
24 | }
--------------------------------------------------------------------------------
/build/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cober2019/react-ios-xe-ops/37476df9ebdcca1cef4e16e68fbf1a5ee6b0456c/build/favicon.ico
--------------------------------------------------------------------------------
/build/index.html:
--------------------------------------------------------------------------------
1 |
IOS-XE-Ops You need to enable JavaScript to run this app.
--------------------------------------------------------------------------------
/build/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/build/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/build/static/css/main.f05ca24e.chunk.css:
--------------------------------------------------------------------------------
1 | body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}.App{text-align:center}.App-logo{height:40vmin;pointer-events:none}@media (prefers-reduced-motion:no-preference){.App-logo{-webkit-animation:App-logo-spin 20s linear infinite;animation:App-logo-spin 20s linear infinite}}body>iframe{display:none}.App-header{background-color:#282c34;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:calc(10px + 2vmin);color:#fff}.App-link{color:#61dafb}#dpneighbors-tab-cdp,#dpneighbors-tab-lldp,#interfaces-tab-arp,#interfaces-tab-Interfacetable,#spanningtre-tab-globalvlan,#spanningtre-tab-pervlan,#uncontrolled-tab-example-tab-ipv4,card #uncontrolled-tab-example-tab-ipv6{color:#fff;background-color:inherit;font-weight:700}.text-white{color:#adff2f;text-align:left}.text-yellow{background-color:#ff0!important}.bg-green{background-color:#98fb98}.bg-orange{background-color:orange}.green{background-color:#98fb98!important}th,tr{text-align:center}.disabledCursor{cursor:default}.row-text{font-size:5;text-align:left}.row-text,div[class~=dataTables_filter],div[class~=dataTables_info],div[class~=dataTables_length],label{color:#fff}div[class~=card]{border-radius:15px}input[type~=search],td{color:#fff}a:link,div[role=status]{color:#fff!important}option,select{color:#fff;background-color:#000}.env-row-text{color:#adff2f;font-size:5;text-align:center}.env-row-text-warn{color:orange;font-size:5;text-align:center;font-weight:700}.box-text{color:#000;font-size:5}.up{background-color:#adff2f}.dow,.up{height:25px;width:25px;border-radius:50%;display:inline-block}.dow{background-color:red}body{background-color:grey}.fade-in{-webkit-animation:fadeInAnimation 3s ease;animation:fadeInAnimation 3s ease;-webkit-animation-iteration-count:1;animation-iteration-count:1;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes fadeInAnimation{0%{opacity:0}to{opacity:1}}@keyframes fadeInAnimation{0%{opacity:0}to{opacity:1}}.nav-tabs>li.active>a{color:#000;font-size:16px}.nav-tabs>li>a{color:#575757}.export-button{display:block;width:150px;margin-left:10px;color:#fff;background-color:#3498db;border-radius:8px}.h3{margin-bottom:15px}.background{background-color:#dddada}.card-text{margin-top:0;margin-bottom:0;text-align:left}.overlay{position:absolute;top:0;left:0;right:0;bottom:0;background-color:rgba(66,61,61,.9);z-index:2}.center-login{margin-top:200px;margin-left:600px;width:25%;padding:10px}.loading-table{width:100%;height:200px;padding:10px;opacity:.4;background-color:rgba(66,61,61,.5);border-radius:6px;margin:auto}.status{color:#000;text-align:right}.h3{color:#000;text-align:center}.status{float:right;font-size:10}.fadeTables{display:none}.input-text{text-align:center}.submitButton{display:block;max-width:300px;width:150px;margin:auto;color:#fff;background-color:#4c4ce7;border-radius:6px}.loader{border-width:6px 16px;width:80px;height:80px}.loader,.status-loader{border-bottom:16px solid #f3f3f3;border-top:16px solid #f3f3f3;border-color:#3498db #f3f3f3;border-style:solid;border-radius:50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;margin:auto}.status-loader{border-width:16px;width:10px;height:10px}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes App-logo-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes App-logo-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.blinking{-webkit-animation:blinkingText 1.5s infinite;animation:blinkingText 1.5s infinite}@-webkit-keyframes blinkingText{0%{color:orange}60%{color:#ff0}99%{color:#ff0}to{color:orange}}.blinking-status{-webkit-animation:blinkingStatusText infinite .5;animation:blinkingStatusText infinite .5}@-webkit-keyframes blinkingStatusText{0%{color:#000}49%{color:#000}60%{color:transparent}99%{color:transparent}to{color:#000}}@keyframes blinkingStatusText{0%{color:#000}49%{color:#000}60%{color:transparent}99%{color:transparent}to{color:#000}}.spinner{height:60px;width:60px;display:block;-webkit-animation:rotation .6s linear infinite;animation:rotation .6s linear infinite;border:6px solid rgba(0,174,239,.15);border-top-color:rgba(0,174,239,.8);border-radius:100%}@-webkit-keyframes rotation{0%{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(359deg)}}@keyframes rotation{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.spinner-status{height:20px;width:20px;display:flex;-webkit-animation:rotation .6s linear infinite;animation:rotation .6s linear infinite;border:4px solid rgba(0,174,239,.15);border-top-color:rgba(0,174,239,.8);border-radius:100%}.warning-loader{border-bottom:16px solid #f3f3f3;border-top:16px solid #f3f3f3;border-color:orange #f3f3f3;border-style:solid;border-width:16px;border-radius:50%;width:80px;height:80px;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;margin:auto}.blinking-loader{-webkit-animation:blinkingText 2s infinite;animation:blinkingText 2s infinite}@keyframes blinkingText{0%{color:#fff}60%{color:grey}99%{color:#fff}to{color:#fff}}
2 | /*# sourceMappingURL=main.f05ca24e.chunk.css.map */
--------------------------------------------------------------------------------
/build/static/js/runtime-main.32e9b272.js:
--------------------------------------------------------------------------------
1 | !function(e){function r(r){for(var n,i,l=r[0],p=r[1],f=r[2],c=0,s=[];c"
21 | exit 11
22 | fi
23 |
24 | fail_if_error() {
25 | [ $1 != 0 ] && {
26 | unset PASSPHRASE
27 | exit 10
28 | }
29 | }
30 |
31 | export PASSPHRASE=$(head -c 500 /dev/urandom | tr -dc a-z0-9A-Z | head -c 128; echo)
32 |
33 | subj="
34 | C=US
35 | ST=MD
36 | O=Blah
37 | localityName=Bal
38 | commonName=$DOMAIN
39 | organizationalUnitName=XEOps
40 | emailAddress=admin@x.com
41 | "
42 |
43 | openssl genrsa -des3 -out $DOMAIN.key -passout env:PASSPHRASE 2048
44 | fail_if_error $?
45 |
46 | openssl req \
47 | -new \
48 | -batch \
49 | -subj "$(echo -n "$subj" | tr "\n" "/")" \
50 | -key $DOMAIN.key \
51 | -out $DOMAIN.csr \
52 | -passin env:PASSPHRASE
53 | fail_if_error $?
54 | cp $DOMAIN.key $DOMAIN.key.org
55 | fail_if_error $?
56 |
57 | openssl rsa -in $DOMAIN.key.org -out $DOMAIN.key -passin env:PASSPHRASE
58 | fail_if_error $?
59 |
60 | openssl x509 -req -days 3650 -in $DOMAIN.csr -signkey $DOMAIN.key -out $DOMAIN.crt
61 | fail_if_error $?
62 |
63 | #CREATE PYTHON VIRTUAL ENVIRONMENT
64 | python3.8 -m venv ios-xe-ops-env
65 | #ACTIVATE ENVIRONMENT
66 | source ios-xe-ops-env/bin/activate
67 | #INSTALL REQUIREMENTS
68 | pip3 install -r requirements.txt
69 | #START API
70 | python3 wsgi.py
71 |
--------------------------------------------------------------------------------
/install_dependencies.sh:
--------------------------------------------------------------------------------
1 |
2 | #!/bin/bash
3 |
4 | #IF YOU DONT HAVE THE FOLLOWING DEPENDENCIES INSTALLED THEN RUN THIS SCRIPT, sudo bash install_dependencies
5 | sudo apt update
6 | INSTALL_PKGS="python3.10 nodejs npm openssl python3.8-venv pip"
7 | for i in $INSTALL_PKGS; do
8 | sudo apt-get install -y $i
9 | done
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ios-xe-ops",
3 | "version": "0.1.0",
4 | "private": true,
5 | "proxy": "http://127.0.0.1:5000/",
6 | "dependencies": {
7 | "@egjs/hammerjs": "^2.0.17",
8 | "@fortawesome/fontawesome-svg-core": "^1.2.36",
9 | "@material-ui/styles": "^4.11.4",
10 | "@testing-library/jest-dom": "^5.12.0",
11 | "@testing-library/react": "^11.2.7",
12 | "@testing-library/user-event": "^12.8.3",
13 | "axios": "^0.21.4",
14 | "bootstrap": "^5.1.3",
15 | "chart.js": "^3.5.0",
16 | "concurrently": "^6.2.0",
17 | "crypto-js": "^4.1.1",
18 | "datatables.net": "^1.11.3",
19 | "datatables.net-buttons": "^1.7.1",
20 | "datatables.net-buttons-dt": "^1.7.1",
21 | "datatables.net-dt": "^1.10.25",
22 | "electron-builder": "^22.10.5",
23 | "electron-is-dev": "^2.0.0",
24 | "http-proxy-middleware": "^2.0.1",
25 | "jquery": "^3.6.0",
26 | "keycharm": "^0.4.0",
27 | "package.json": "^2.0.1",
28 | "react": "^17.0.2",
29 | "react-bootstrap": "^2.0.1",
30 | "react-d3-speedometer": "^1.0.1",
31 | "react-dom": "^17.0.2",
32 | "react-error-boundary": "^3.1.3",
33 | "react-history": "^0.18.2",
34 | "react-new-window": "^0.1.3",
35 | "react-query": "^3.24.3",
36 | "react-router-bootstrap": "^0.25.0",
37 | "react-router-dom": "^5.2.0",
38 | "react-scripts": "4.0.3",
39 | "react-tabs": "^3.2.2",
40 | "react-web-tabs": "^1.0.1",
41 | "reactjs-popup": "^2.0.4",
42 | "recoil": "^0.4.1",
43 | "vis-data": "^7.1.2",
44 | "vis-network": "^9.1.0",
45 | "vis-util": "^5.0.2",
46 | "wait-on": "^5.3.0",
47 | "web-vitals": "^1.1.2"
48 | },
49 | "scripts": {
50 | "start": "react-scripts start",
51 | "build": "react-scripts build",
52 | "test": "react-scripts test",
53 | "eject": "react-scripts eject"
54 | },
55 | "eslintConfig": {
56 | "extends": [
57 | "react-app",
58 | "react-app/jest"
59 | ]
60 | },
61 | "browserslist": {
62 | "production": [
63 | ">0.2%",
64 | "not dead",
65 | "not op_mini all"
66 | ],
67 | "development": [
68 | "last 1 chrome version",
69 | "last 1 firefox version",
70 | "last 1 safari version"
71 | ]
72 | },
73 | "devDependencies": {
74 | "@types/datatables.net": "^1.10.20",
75 | "@types/jquery": "^3.5.6"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cober2019/react-ios-xe-ops/37476df9ebdcca1cef4e16e68fbf1a5ee6b0456c/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
17 | IOS-XE-Ops
18 |
19 |
20 | You need to enable JavaScript to run this app.
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "theme_color": "#000000",
7 | "background_color": "#ffffff"
8 | }
9 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const path = require("path");
3 | const { createProxyMiddleware } = require('http-proxy-middleware');
4 |
5 | const app = express();
6 |
7 | app.use(express.static(path.join(__dirname, 'build')));
8 |
9 | app.post('/login', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true, secure: false }));
10 | app.post('/pollIndexPage', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
11 | app.post('/pollEnv', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
12 | app.post('/pollL2Page', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
13 | app.post('/pollRouting', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
14 | app.post('/getDmvpn', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
15 | app.post('/getipsla', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
16 | app.post('/ribStatus', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
17 | app.post('/liveinterfaces', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
18 | app.post('/pollRouting', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
19 | app.post('/getDmvpn', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
20 | app.post('/getipsla', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
21 | app.post('/query', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
22 | app.post('/apistatus', createProxyMiddleware({ target: 'https://127.0.0.1:5000', changeOrigin: true , secure: false }));
23 |
24 | app.get('/*', function (req, res) {res.sendFile(path.join(__dirname, 'build', 'index.html'));});
25 |
26 | const PORT = process.env.PORT || 3000;
27 |
28 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`));
29 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import './App.css';
2 | import 'bootstrap/dist/css/bootstrap.min.css';
3 | import { Index } from './Components/Index/Index-Parent.js';
4 | import { LayerTwo } from './Components/LayerTwo/layerTwo-Parent.js';
5 | import { Environment } from './Components/Environment/Env-Parent.js';
6 | import { Routing } from './Components/LayerThree/Routing-Parent.js';
7 | import { Dmvpn } from './Components/DMVPN/Dmvpn-Parent.js';
8 | import { RestConfig } from './Components/Config/config.js';
9 | import { RibIndex } from './Components/RibStatus/RIB-Parent.js';
10 | import { DeviceAuth } from './Components/Other/login.js';
11 | import { IpSlas } from './Components/IPSlas/Sla-Parent.js';
12 | import { LiveInterfaces } from './Components/InterfaceGraphs/liveInterface.js';
13 | import { RecoilRoot, atom } from 'recoil';
14 | import {
15 | BrowserRouter as Router,
16 | Switch,
17 | Route,
18 | } from "react-router-dom";
19 | import { QueryClient, QueryClientProvider } from 'react-query';
20 | const queryClient = new QueryClient();
21 |
22 | export const encytpKey = atom({
23 | key: 'key',
24 | default: 'jdh%):Aap(3>S#',
25 | });
26 |
27 | export const client = atom({
28 | key: 'queryClient',
29 | default: CachedQueryClient,
30 | });
31 |
32 |
33 | function App() {
34 |
35 | return (
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | );
137 | }
138 |
139 | export default App;
140 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | it('xeops', () => {
5 | render( );
6 | });
7 |
--------------------------------------------------------------------------------
/src/Components/DMVPN/Dmvpn-Parent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Container from "react-bootstrap/Container";
3 | import Row from "react-bootstrap/Row";
4 | import Col from "react-bootstrap/Col";
5 | import {useRecoilState} from 'recoil';
6 | import { ErrorBoundary } from 'react-error-boundary'
7 | import { Ospf } from '../LayerThree/ospf';
8 | import { Navigation } from '../Other/navbar';
9 | import { DmvpnData } from './dmvpnData';
10 | import { useQuery, useQueryClient} from 'react-query';
11 | import {encytpKey, client} from '../../App'
12 | import { NavigationFallback } from "../Other/navbarError";
13 | import { IsErrorFallback } from "../Other/errorComponent";
14 | import { PageLoader } from '../Other/pageLoader';
15 | import { ApiRequest } from "../Other/axiosRequests";
16 |
17 | export function Dmvpn(){
18 | const [decryptKey] = useRecoilState(encytpKey);
19 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') + 'getDmvpn', async () => {
20 |
21 | const response = await ApiRequest(decryptKey, '/getDmvpn')
22 |
23 | return response.data
24 |
25 | },
26 | {
27 | refetchInterval: 20000
28 | }
29 | )
30 |
31 |
32 | if (error){
33 | return
34 |
35 |
36 |
37 |
Error Collecting Data. I'll Keep Trying
38 |
39 |
40 | }
41 | else if (data){
42 | return
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {data.dmvpn.length > 0 ? :
}
57 |
58 |
59 |
60 |
61 | }
62 | else if (isLoading){
63 | return
64 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
65 |
66 | }
67 |
68 |
69 | }
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/Components/DMVPN/topology.js:
--------------------------------------------------------------------------------
1 | import router from '../Images/router.png';
2 | import { Network } from "vis-network";
3 |
4 | var font = { size: 18, strokeWidth: 0, color: 'white'}
5 | var Hubfont = { size: 18, strokeWidth: 0, color: 'orange'}
6 | var nodeFont = { size: 16, color: "white"}
7 | var options = {
8 | nodes: {
9 | shape: 'image',
10 | image: router,
11 | size: 35,
12 | color: {
13 | border: 'black',
14 | background: '#166F20',
15 | highlight: {
16 | border: '#2B7CE9',
17 | background: '#D2E5FF'
18 | }
19 | }
20 | },
21 | layout: {
22 | randomSeed: undefined,
23 | improvedLayout:true,
24 | clusterThreshold: 200,
25 | hierarchical: {
26 | enabled:true,
27 | levelSeparation: 500,
28 | treeSpacing: 300,
29 | edgeMinimization: true,
30 | parentCentralization: true,
31 | direction: 'DU', // UD, DU, LR, RL
32 | sortMethod: 'hubsize', // hubsize, directed
33 | shakeTowards: 'roots' // roots, leaves
34 | }
35 | },
36 | physics:{
37 | enabled: true,
38 | hierarchicalRepulsion: {
39 | centralGravity: 0.0,
40 | springLength: 0,
41 | springConstant: 0.01,
42 | nodeDistance: 250,
43 | damping: 1,
44 | avoidOverlap: 1
45 | },
46 | },
47 |
48 | }
49 |
50 | export function UpdateDmvpnTopology(ref, peers, localIp){
51 |
52 | Object.entries(peers).forEach((details, i) => {
53 | if (details[1].state !== 'UP'){
54 | ref.body.data.edges.push({id: details[1].peerNbma,
55 | from: localIp,
56 | to: i,
57 | color: 'yellow',
58 | label: details[1].state + '\n' + details[1].peerTunnel + "\n" + details[1].attrb,
59 | font: font
60 | });
61 | }
62 | else{
63 | ref.body.data.edges.push({id: details[1].vlanInt,
64 | from: localIp,
65 | to: i,
66 | color: 'green',
67 | label: details[1].state + '\n' + details[1].peerTunnel + "\n" + details[1].attrb,
68 | font: font
69 | });
70 | }})
71 |
72 | return ref
73 |
74 | }
75 |
76 | export function DmvpnTopologyBuild(ref, peers, localIp, hubs){
77 |
78 | const nodes = []
79 | const edges = []
80 |
81 | nodes.push({id: localIp, label: 'Local\n' + localIp, font: nodeFont })
82 |
83 | Object.entries(peers).forEach((details, i) => {
84 |
85 | if (hubs.some(ip => ip.hubNbma === details[1].peerNbma)){
86 | const spookeOrHub = details[1].peerNbma + ': Hub'
87 | nodes.push({id: details[0], label: spookeOrHub, font: Hubfont});
88 | }
89 | else{
90 | const spookeOrHub = details[1].peerNbma + ': Spoke'
91 | nodes.push({id: details[0], label: spookeOrHub, font: font});
92 | }
93 |
94 |
95 | })
96 |
97 | Object.entries(peers).forEach((details, i) => {
98 |
99 |
100 | if (details[1].state !== 'UP'){
101 | edges.push({id: details[1].peerNbma,
102 | from: localIp,
103 | to: i,
104 | color: 'yellow',
105 | label: details[1].state + '\n' + details[1].peerTunnel + "\n" + details[1].attrb,
106 | font: font
107 | });
108 | }
109 | else{
110 | edges.push({id: details[1].peerNbma,
111 | from: localIp,
112 | to: i,
113 | color: 'green',
114 | label: details[1].state + '\n' + details[1].peerTunnel + "\n" + details[1].attrb,
115 | font: font
116 | });
117 | }})
118 |
119 | var network = new Network(ref, {nodes: nodes, edges: edges}, options);
120 |
121 | return network
122 |
123 | }
--------------------------------------------------------------------------------
/src/Components/Environment/Env-Parent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useQuery } from 'react-query';
3 | import Row from "react-bootstrap/Row";
4 | import Container from "react-bootstrap/Container";
5 | import Col from "react-bootstrap/Col";
6 | import {useRecoilState} from 'recoil';
7 | import { CpuUsage} from './cpuUsages'
8 | import { Sensors} from './sensors'
9 | import { ErrorBoundary } from 'react-error-boundary'
10 | import { CreateCard } from '../Other/jsxCard';
11 | import { Navigation } from '../Other/navbar';
12 | import { NavigationFallback } from "../Other/navbarError";
13 | import { ApiRequest } from "../Other/axiosRequests";
14 | import { IsErrorFallback } from "../Other/errorComponent";
15 | import { PoeConnections } from './poe'
16 | import { Transceivers } from './transceivers'
17 | import { TransceiversInv } from './transieverInventory'
18 | import { PageLoader } from '../Other/pageLoader';
19 | import {encytpKey} from '../../App'
20 |
21 |
22 | export function Environment(){
23 | const [decryptKey] = useRecoilState(encytpKey);
24 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') + 'pollEnv', async () => {
25 |
26 | const response = await ApiRequest(decryptKey, '/pollEnv')
27 |
28 | return response.data
29 |
30 | },
31 | {
32 | refetchInterval: 10000
33 | }
34 | )
35 |
36 |
37 | if (error){
38 | return <>
39 |
40 |
41 |
42 | Error Collecting Data. I'll Keep Trying
43 |
44 | >
45 | }
46 | else if (data){
47 | return
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | {CreateCard(, "SFP Statuses")}
57 |
58 |
59 | {CreateCard(, 'Environmental Stats')}
60 | {CreateCard(, 'Poe Interface')}
61 | {CreateCard(, "SFP Inventory")}
62 |
63 |
64 |
65 | }
66 | else if (isLoading){
67 | return <>
68 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
69 | >
70 | }
71 |
72 |
73 |
74 | }
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/Components/Environment/env.js:
--------------------------------------------------------------------------------
1 | import React, {useEffect } from 'react';
2 | import { useQuery } from 'react-query';
3 | import axios from 'axios';
4 | import { CpuUsage} from './cpuUsages'
5 | import { Sensors} from './sensors'
6 | import { ErrorBoundary } from '../Other/errorBoundry';
7 | import { EnvData} from '../Other/data';
8 | import { Navbar } from '../Other/navbar';
9 | import { Poe , Transiever } from '../Other/data';
10 | import { PoeConnections } from './poe'
11 | import { Transceivers } from './transceivers'
12 | import {AES, enc}from 'crypto-js';
13 |
14 |
15 |
16 | export function Environment(props){
17 | const passwordDecrypt = AES.decrypt(localStorage.getItem('password'), 'MYKEY4DEMO');
18 | const password = passwordDecrypt.toString(enc.Utf8);
19 | const { isLoading, error, data, isFetching } = useQuery('pollEnv', async () => {
20 |
21 | const response = await axios.post('/pollEnv', {'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
22 | 'password': password, 'port': localStorage.getItem('port')})
23 | return response.data
24 |
25 | },
26 | {
27 | refetchInterval: 10000, cacheTime: 0
28 | }
29 | )
30 |
31 |
32 | if (error){
33 | return
34 |
35 | Error Collecting Data. I'll Keep Trying
36 |
37 |
38 | }
39 | else if (data){
40 | return
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | }
63 | else if (isLoading){
64 | return
65 |
Collecting Data for {localStorage.getItem('ip')}
66 |
67 |
68 | }
69 |
70 |
71 |
72 | }
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/src/Components/Environment/poe.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { PoeTableHtml } from '../Other/chartConfigs';
3 | import { PoeData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function PoeConnections(props){
8 | const poeTableRef = React.createRef()
9 | const poeTable = PoeTableHtml(poeTableRef)
10 | $.fn.dataTable.ext.errMode = 'none';
11 |
12 | useEffect(() => {
13 | if(poeTableRef.current !== null){
14 | try{
15 | $(poeTableRef.current).DataTable().clear()
16 | $(poeTableRef.current).DataTable().rows.add(Object.values(props.poeprops.poe))
17 | $(poeTableRef.current).DataTable().rows.add(Object.values(props.poe))
18 | $(poeTableRef.current).DataTable().draw(false)
19 | }
20 | catch{}
21 | }
22 | }, [props.poe])
23 |
24 | useEffect(() => {
25 | $(poeTableRef.current).DataTable().destroy()
26 | PoeData(poeTableRef.current, props.poe)
27 | }, [])
28 |
29 | return poeTable
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/Components/Environment/sensors.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { EnvTableHtml } from '../Other/chartConfigs';
3 | import { SensorData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function Sensors(props){
8 | const envTableRef = React.createRef()
9 | const table = EnvTableHtml(envTableRef)
10 | $.fn.dataTable.ext.errMode = 'none';
11 |
12 |
13 | useEffect(() => {
14 | if(envTableRef.current !== null){
15 | try{
16 | $(envTableRef.current).DataTable().clear()
17 | $(envTableRef.current).DataTable().rows.add(Object.values(props.env))
18 | $(envTableRef.current).DataTable().draw(false)
19 | }
20 | catch{}
21 | }
22 | }, [props.env])
23 |
24 | useEffect(() => {
25 | $(envTableRef.current).DataTable().destroy()
26 | SensorData(envTableRef.current, props.env)
27 |
28 | }, [])
29 |
30 | return table
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/Components/Environment/transceivers.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { TransceiverTableHtml } from '../Other/chartConfigs';
3 | import { TransieverData } from '../Other/tables';
4 |
5 | const $ = require('jquery');
6 | $.DataTable = require('datatables.net');
7 |
8 | export function Transceivers(props){
9 | const transceiverTableRef = React.createRef()
10 | const transceiverOpertable = TransceiverTableHtml(transceiverTableRef)
11 | $.fn.dataTable.ext.errMode = 'none';
12 |
13 | useEffect(() => {
14 | if(transceiverTableRef.current !== null){
15 | try{
16 | $(transceiverTableRef.current).DataTable().clear()
17 | $(transceiverTableRef.current).DataTable().rows.add(props.transceivers)
18 | $(transceiverTableRef.current).DataTable().draw(false)
19 | }
20 | catch{}
21 | }
22 | }, [props.transceivers])
23 |
24 | useEffect(() => {
25 |
26 | $(transceiverTableRef.current).DataTable().destroy()
27 | TransieverData(transceiverTableRef.current, props.transceivers)
28 |
29 | }, [])
30 |
31 | return transceiverOpertable
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/Components/Environment/transieverInventory.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { InventoryTransceiverTableHtml } from '../Other/chartConfigs';
3 | import { InvTransieverData } from '../Other/tables';
4 |
5 | const $ = require('jquery');
6 | $.DataTable = require('datatables.net');
7 |
8 |
9 | export function TransceiversInv(props){
10 | const inventoryTransceiverTableRef = React.createRef()
11 | const inventorytable = InventoryTransceiverTableHtml(inventoryTransceiverTableRef)
12 | $.fn.dataTable.ext.errMode = 'none';
13 |
14 | useEffect(() => {
15 | if(inventoryTransceiverTableRef.current !== null){
16 | try{
17 | $(inventoryTransceiverTableRef.current).DataTable().clear()
18 | $(inventoryTransceiverTableRef.current).DataTable().rows.add(props.transceivers)
19 | $(inventoryTransceiverTableRef.current).DataTable().draw(false)
20 | }
21 | catch{}
22 | }
23 | }, [props.transceivers])
24 |
25 | useEffect(() => {
26 |
27 | $(inventoryTransceiverTableRef.current).DataTable().destroy()
28 | InvTransieverData(inventoryTransceiverTableRef.current, props.transceivers)
29 |
30 | }, [])
31 |
32 | return inventorytable
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/Components/Forms/ospfNeighborForm.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useRef, useEffect } from 'react';
2 | import axios from 'axios';
3 | import Form from 'react-bootstrap/Form'
4 | import { useQuery } from 'react-query'
5 | import {useRecoilState} from 'recoil';
6 | import Card from "react-bootstrap/Card";
7 | import Row from "react-bootstrap/Row";
8 | import Col from "react-bootstrap/Col";
9 | import { AES, enc }from 'crypto-js';
10 | import {encytpKey} from '../../App'
11 |
12 | export function ModifyOspfNeighbor(props){
13 | const bgpForm = useRef();
14 | const [network, setNetwork] = useState(undefined)
15 | const [wildcard, setWildcard] = useState(undefined)
16 | const [decrypt] = useRecoilState(encytpKey);
17 | const passwordDecrypt = AES.decrypt(localStorage.getItem('password'), decrypt);
18 | const { isLoading, error, data, isFetching, refetch } = useQuery(localStorage.getItem('ip') + 'modifyOspfNeighbor', async () => {
19 |
20 | const data = await axios.post('/modifyOspfNeighbor', {'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
21 | 'password': passwordDecrypt.toString(enc.Utf8), 'port': localStorage.getItem('port'),'data': {'type': 'ospf', 'network': network, 'wildcard': wildcard}})
22 |
23 | return data.data
24 |
25 | },
26 | {enabled: false} );
27 |
28 | const handleSubmit = (evt) => {
29 | evt.preventDefault();
30 | refetch()};
31 |
32 | return
33 |
34 | Add OSPF Network
35 |
48 |
49 |
50 |
51 |
52 | }
--------------------------------------------------------------------------------
/src/Components/IPSlas/Sla-Parent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Container from "react-bootstrap/Container";
3 | import Col from "react-bootstrap/Col";
4 | import Row from "react-bootstrap/Row";
5 | import {useRecoilState} from 'recoil';
6 | import { Navigation } from '../Other/navbar'
7 | import { SlaStats } from './ipslastats'
8 | import { BuildSlaTopologies } from './slatopologies'
9 | import { useQuery } from 'react-query';
10 | import { ErrorBoundary } from 'react-error-boundary'
11 | import { encytpKey, client} from '../../App'
12 | import { CreateCard } from '../Other/jsxCard';
13 | import { NavigationFallback } from "../Other/navbarError";
14 | import { PageLoader } from '../Other/pageLoader';
15 | import { ApiRequest } from "../Other/axiosRequests";
16 |
17 | export function IpSlas(){
18 | const [decryptKey] = useRecoilState(encytpKey);
19 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') + 'getipsla', async () => {
20 |
21 | const response = await ApiRequest(decryptKey, '/getipsla')
22 |
23 | return response.data
24 |
25 | },
26 | {
27 | refetchInterval: 5000
28 | }
29 | )
30 |
31 | if (error){
32 | return <>
33 |
34 |
35 |
36 | Error Collecting Data. I'll Keep Trying
37 |
38 | >
39 | }
40 | else if (data){
41 | return
42 |
43 |
44 |
45 |
46 | {CreateCard(, "IP SLAs")}
47 |
48 |
49 | { data.slas.map(sla => (
50 |
51 |
52 | {CreateCard(, "SLA ID: " + sla['oper-id'])}
53 |
54 |
55 | ))}
56 |
57 |
58 | }
59 | else if (isLoading){
60 | return <>
61 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
62 | >
63 | }
64 |
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/src/Components/IPSlas/ipslastats.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { SlaTableHtml } from '../Other/chartConfigs';
3 | import { IpSlaData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function SlaStats(props){
8 | const slaTableRef = React.createRef()
9 | const slaTable = SlaTableHtml(slaTableRef)
10 | $.fn.dataTable.ext.errMode = 'none';
11 |
12 |
13 | useEffect(() => {
14 | if(slaTableRef.current !== null){
15 | try{
16 | $(slaTableRef.current).DataTable().clear()
17 | $(slaTableRef.current).DataTable().rows.add(props.slas)
18 | $(slaTableRef.current).DataTable().draw(false)
19 | }
20 | catch{}
21 | }
22 |
23 | }, [props.slas])
24 |
25 |
26 | useEffect(() => {
27 |
28 | $(slaTableRef.current).DataTable().destroy()
29 | IpSlaData(slaTableRef.current, props.slas)
30 |
31 | }, [])
32 |
33 | return slaTable
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/Components/IPSlas/slatopologies.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 | import { IpSlaTopologyBuild, UpdateIpSlaTopology } from './topology';
3 | const $ = require('jquery');
4 | $.DataTable = require('datatables.net');
5 |
6 | export function BuildSlaTopologies(props){
7 | const slaTopologyRef = React.createRef()
8 | const slaTopology = useRef()
9 | $.fn.dataTable.ext.errMode = 'none';
10 |
11 | useEffect(() => {
12 | try{
13 | slaTopology.current = UpdateIpSlaTopology(slaTopology.current, props.sla, props.localIp)
14 | slaTopologyRef.current = slaTopology.current
15 | }
16 | catch(e){console.log(e)}
17 |
18 | }, [props.sla])
19 |
20 | useEffect(() => {
21 |
22 | try{
23 | slaTopology.current = IpSlaTopologyBuild(slaTopologyRef.current, props.sla, props.localIp)
24 | slaTopologyRef.current = slaTopology.current
25 | }
26 | catch{}
27 | }, [])
28 |
29 | return
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/Components/IPSlas/topology.js:
--------------------------------------------------------------------------------
1 |
2 | import router from '../Images/router.png';
3 | import { Network } from "vis-network";
4 |
5 | var font = { size: 15, strokeWidth: 0, color: 'white'}
6 | var arrowEnabled = {enabled: true}
7 | var nodeFont = { size: 16, color: "white"}
8 | var options = {
9 | nodes: {
10 | shape: 'image',
11 | image: router,
12 | size: 35,
13 | color: {
14 | border: 'black',
15 | background: '#166F20',
16 | highlight: {
17 | border: '#2B7CE9',
18 | background: '#D2E5FF'
19 | }
20 | }
21 | },
22 | layout: {
23 | randomSeed: undefined,
24 | improvedLayout:true,
25 | clusterThreshold: 150,
26 | hierarchical: {
27 | enabled:true,
28 | levelSeparation: 500,
29 | treeSpacing: 150,
30 | edgeMinimization: true,
31 | parentCentralization: true,
32 | direction: 'RL', // UD, DU, LR, RL
33 | sortMethod: 'hubsize', // hubsize, directed
34 | shakeTowards: 'roots' // roots, leaves
35 | }
36 | },
37 | physics:{
38 | enabled: true,
39 | hierarchicalRepulsion: {
40 | centralGravity: 0.0,
41 | springLength: 0,
42 | springConstant: 0.01,
43 | nodeDistance: 200,
44 | damping: 1,
45 | avoidOverlap: 1
46 | },
47 | },
48 |
49 | }
50 |
51 | export function UpdateIpSlaTopology(ref, sla, localIp){
52 |
53 |
54 | if(sla['latest-return-code'] !== 'ret-code-ok'){
55 | ref.body.data.edges.update({id: 2000,
56 | from: 1,
57 | to: localIp,
58 | color: 'yellow',
59 | label: 'Latest: ' + sla['latest-return-code'] + '\nSuccess: ' +sla['success-count'] + '\nFailures: ' + sla['failure-count'],
60 | })
61 | }
62 | else{
63 | ref.body.data.edges.update({id: 2000,
64 | from: 1,
65 | to: localIp,
66 | color: 'green',
67 | label: 'Latest: ' + sla['latest-return-code'] + '\nSuccess: ' +sla['success-count'] + '\nFailures: ' + sla['failure-count'],
68 | })
69 | }
70 |
71 | return ref
72 |
73 | }
74 |
75 |
76 |
77 | export function IpSlaTopologyBuild(ref, sla, localIp){
78 |
79 | const nodes = []
80 | const edges = []
81 |
82 | nodes.push({id: 1, label: 'Responder', font: nodeFont})
83 | nodes.push({id: localIp, label: localIp, font: nodeFont})
84 |
85 |
86 | if(sla['latest-return-code'] !== 'ret-code-ok'){
87 | edges.push({id: 2000,
88 | from: 1,
89 | to: localIp,
90 | color: 'yellow',
91 | label: 'Latest: ' + sla['latest-return-code'] + '\nSuccess: ' +sla['success-count'] + '\nFailures: ' + sla['failure-count'],
92 | font: font,
93 | arrows:{from: arrowEnabled}
94 | })
95 | }
96 | else{
97 | edges.push({id: 2000,
98 | from: 1,
99 | to: localIp,
100 | color: 'green',
101 | label: 'Latest: ' + sla['latest-return-code'] + '\nSuccess: ' +sla['success-count'] + '\nFailures: ' + sla['failure-count'],
102 | font: font,
103 | arrows:{from: arrowEnabled}
104 | })
105 | }
106 |
107 |
108 | var data = {
109 | nodes: nodes,
110 | edges: edges,
111 | };
112 |
113 | var network = new Network(ref, data, options);
114 |
115 | return network
116 |
117 | }
118 |
119 |
--------------------------------------------------------------------------------
/src/Components/Images/router.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cober2019/react-ios-xe-ops/37476df9ebdcca1cef4e16e68fbf1a5ee6b0456c/src/Components/Images/router.png
--------------------------------------------------------------------------------
/src/Components/Index/Index-Parent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useQuery, useQueryClient } from 'react-query'
3 | import Tabs from "react-bootstrap/Tabs";
4 | import Tab from "react-bootstrap/Tab";
5 | import Container from "react-bootstrap/Container";
6 | import Card from "react-bootstrap/Card";
7 | import {useRecoilState} from 'recoil';
8 | import { ErrorBoundary } from 'react-error-boundary'
9 | import { Arps} from './arps'
10 | import { InterfaceTable} from './InterfacesTable'
11 | import { Qos} from './qos'
12 | import { Hsrp} from './hsrp'
13 | import { DpNeighbors} from '../Other/dp_neighbors'
14 | import { CreateCard } from '../Other/jsxCard';
15 | import { Navigation } from '../Other/navbar';
16 | import { PageLoader } from '../Other/pageLoader';
17 | import { NavigationFallback } from "../Other/navbarError";
18 | import { IsErrorFallback } from "../Other/errorComponent";
19 | import { ModifyInterface } from '../Forms/interfaceForm';
20 | import { BandwidthDiff } from '../Other/bandwidthFunctions';
21 | import { ApiRequest } from '../Other/axiosRequests';
22 | import {encytpKey, client} from '../../App'
23 |
24 | export function Index(){
25 | const [decryptKey] = useRecoilState(encytpKey);
26 | const cache = React.useRef(useQueryClient())
27 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') + 'indexData', async () => {
28 |
29 | const response = await ApiRequest(decryptKey, '/pollIndexPage')
30 | const calulatedBandwdithDiff = BandwidthDiff(cache, response.data)
31 |
32 | return calulatedBandwdithDiff
33 |
34 | },
35 | {
36 | refetchInterval: 2000
37 | }
38 | )
39 |
40 | if (error){
41 | return
42 |
43 |
44 |
45 |
Error Collecting Data. I'll Keep Trying
46 |
47 |
48 | }
49 | else if (data){
50 |
51 | return
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | {CreateCard()}
63 |
64 |
65 |
66 |
67 |
68 |
69 | { Object.values(data.interfaces).map(interfaceDetail => (
70 |
71 | {interfaceDetail.qos.length !== 0 ? : <>>}
72 |
73 | ))}
74 |
75 |
76 | {CreateCard(, "ARPs")}
77 | {CreateCard()}
78 | {data.hsrp.length > 0 ? CreateCard(, "HSRP Topology") :
}
79 |
80 | }
81 | else if (isLoading){
82 |
83 | return <>
84 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
85 | >
86 | }
87 |
88 |
89 | }
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/src/Components/Index/InterfacesTable.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { InterfacesTableHtml } from '../Other/chartConfigs';
3 | import { InterfaceData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function InterfaceTable(props){
8 | const interfacesTableRef = React.createRef()
9 | const interfacestable = InterfacesTableHtml(interfacesTableRef)
10 | $.fn.dataTable.ext.errMode = 'none';
11 |
12 | useEffect(() => {
13 | if(interfacesTableRef.current !== null){
14 | try{
15 | $(interfacesTableRef.current).DataTable().clear()
16 | $(interfacesTableRef.current).DataTable().rows.add(Object.values(props.interfaces))
17 | $(interfacesTableRef.current).DataTable().draw(false)
18 | }
19 | catch{}
20 | }
21 |
22 | }, [props.interfaces])
23 |
24 |
25 | useEffect(() => {
26 | $(interfacesTableRef.current).DataTable().destroy()
27 | InterfaceData(interfacesTableRef.current, props.interfaces)
28 | }, [])
29 |
30 | return interfacestable
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/Components/Index/arps.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { ArpTableHtml } from '../Other/chartConfigs';
3 | import { ArpData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 |
8 | export function Arps(props){
9 | const arpTableRef = React.createRef()
10 | const table = ArpTableHtml(arpTableRef)
11 | $.fn.dataTable.ext.errMode = 'none';
12 |
13 | useEffect(() => {
14 | if(arpTableRef.current !== null){
15 | try{
16 | $(arpTableRef.current).DataTable().clear()
17 | $(arpTableRef.current).DataTable().rows.add(props.arps)
18 | $(arpTableRef.current).DataTable().draw(false)
19 | }
20 | catch{}
21 | }
22 |
23 | }, [props.arps])
24 |
25 | useEffect(() => {
26 | $(arpTableRef.current).DataTable().destroy()
27 | ArpData(arpTableRef.current, props.arps)
28 |
29 | }, [])
30 |
31 | return table
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/Components/Index/hsrp.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 | import { HsrpTableHtml } from '../Other/chartConfigs';
3 | import { HsrpData } from '../Other/tables';
4 | import { HsrpTopologyBuild, UpdateHsrpTopology } from './topology';
5 | const $ = require('jquery');
6 | $.DataTable = require('datatables.net');
7 |
8 |
9 | export function Hsrp(props){
10 | const hsrpTableRef = React.createRef()
11 | const table = HsrpTableHtml(hsrpTableRef)
12 | const hsrpTopologyRef = React.createRef()
13 | const hsrpTopology = useRef(null)
14 | $.fn.dataTable.ext.errMode = 'none';
15 |
16 | useEffect(() => {
17 | if(hsrpTableRef.current !== null){
18 | try{
19 | $(hsrpTableRef.current).DataTable().clear()
20 | $(hsrpTableRef.current).DataTable().rows.add(props.hsrp)
21 | $(hsrpTableRef.current).DataTable().draw(false)
22 | }
23 | catch{}
24 | try{
25 | hsrpTopology.current = UpdateHsrpTopology(hsrpTopology.current, props.hsrp, props.localIp)
26 | hsrpTopologyRef.current = hsrpTopology.current
27 | }
28 | catch{}
29 | }
30 |
31 | }, [props.hsrp])
32 |
33 | useEffect(() => {
34 |
35 | $(hsrpTableRef.current).DataTable().destroy()
36 | HsrpData(hsrpTableRef.current, props.hsrp)
37 |
38 | try{
39 | if(props.hsrp.length >= 1){
40 | hsrpTopology.current = HsrpTopologyBuild(hsrpTopologyRef.current, props.hsrp, props.localIp)
41 | hsrpTopologyRef.current = hsrpTopology.current
42 | }
43 | }
44 | catch{}
45 |
46 | }, [])
47 |
48 | return
49 |
52 |
53 | {table}
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/Components/Index/interfaceCard.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 | import Col from "react-bootstrap/Col";
3 | import Row from "react-bootstrap/Row";
4 | import { InitialChartBuild, UpdateChart } from '../Other/chartConfigs';
5 | const $ = require('jquery');
6 | $.DataTable = require('datatables.net');
7 |
8 |
9 | export function InterfaceCard(props){
10 | const interfacesChart = useRef(null)
11 | const interfacesRef = React.createRef()
12 | const interfaceNameRef = React.createRef(props.value.name)
13 | $.fn.dataTable.ext.errMode = 'none';
14 |
15 | useEffect(() => {
16 | if(interfacesChart.current !== null){
17 | try{
18 | let updatedChart = UpdateChart(interfacesChart.current, parseInt(props.value['statistics']['tx-kbps']),parseInt(props.value['statistics']['rx-kbps']));
19 | updatedChart.update()
20 | interfacesChart.current = updatedChart
21 | }
22 | catch{}
23 | }
24 |
25 | }, [props.value])
26 |
27 |
28 | useEffect(() => {
29 | try{
30 | let chart = InitialChartBuild(interfacesRef.current.getContext('2d'), parseInt(props.value['statistics']['tx-kbps']), parseInt(props.value['statistics']['rx-kbps']));
31 | interfacesChart.current = chart
32 | }
33 | catch{}
34 | }, [])
35 |
36 |
37 | return
38 |
39 |
40 |
41 |
42 |
43 |
44 | Speed:
45 | Status:
46 | IP:
47 | MTU:
48 | Mbps Out:
49 | Mbps In:
50 | Mbps Out Diff:
51 | Mbps In Diff:
52 |
53 |
54 | {Math.round(parseInt(props.value.speed) / 1000000000) * 1000 } (Mbps)
55 | {props.value['oper-status']}
56 | {props.value.ipv4 ? {props.value.ipv4}
: n/a
}
57 | {props.value.mtu}
58 | {props.value['statistics']['tx-kbps']}
59 | {props.value['statistics']['rx-kbps']}
60 | {props.value.outbandwidthDiff}
61 | {props.value.inbandwidthDiff}
62 |
63 |
64 | PPs Out:
65 | PPs In:
66 | InDis:
67 | OutDis:
68 | InErr:
69 | InDis:
70 | CRC:
71 | InDis:
72 |
73 |
74 |
75 | {props.value['statistics']['rx-pps']}
76 | {props.value['statistics']['tx-pps']}
77 | {props.value['statistics']['in-discards']}
78 | {props.value['statistics']['out-discards']}
79 | {props.value['statistics']['in-errors']}
80 | {props.value['statistics']['out-errors']}
81 | {props.value['statistics']['in-crc-errors']}
82 | {props.value['statistics']['num-flaps']}
83 |
84 |
85 |
86 |
87 |
88 | Description:
89 | LastChange:
90 |
91 |
92 | {props.value.description ? {props.value.description}
: n/a
}
93 | {props.value['statistics']['discontinuity-time'].split('.')[0]}
94 |
95 |
96 |
97 |
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/Components/Index/qos.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useRef } from 'react';
2 | import Row from "react-bootstrap/Row";
3 | import Col from "react-bootstrap/Col";
4 | import { ErrorBoundary } from 'react-error-boundary'
5 | import { QosChart } from './qosCharts';
6 | import { IsErrorFallback } from "../Other/errorComponent";
7 | import { QosTopologyBuild, UpdateQosTopology } from './topology';
8 | const $ = require('jquery');
9 | $.DataTable = require('datatables.net');
10 |
11 | export function Qos(props){
12 | const qosTopologyRef = React.createRef()
13 | const qosTopology = useRef(null)
14 | $.fn.dataTable.ext.errMode = 'none';
15 |
16 | useEffect(() => {
17 | try{
18 | props.qos.map(queue => {
19 | qosTopology.current = UpdateQosTopology(qosTopology.current, queue, props.interface.data.name)
20 | qosTopologyRef.current = qosTopology.current
21 | })
22 | }
23 | catch{}
24 | }, [props.qos])
25 |
26 | useEffect(() => {
27 |
28 | try{
29 | props.qos.map(queue => {
30 | qosTopology.current = QosTopologyBuild(qosTopologyRef.current, queue, props.interface.data.name)
31 | qosTopologyRef.current = qosTopology.current
32 | })
33 | }
34 | catch{}
35 |
36 | }, [])
37 |
38 | return
39 | { props.qos.map(queue => (
40 | <>
41 |
42 | {props.interface.data.name} - Allocation: {queue.allocation} - Policy: {queue.interface_policy} - Direction: {queue.direction}
43 |
44 |
45 |
46 | {
47 | queue.queues.map(queueDetails =>
48 |
49 |
50 |
51 |
52 |
53 | )}
54 |
55 | >
56 | ))}
57 |
58 |
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/Components/Index/qosCharts.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 | import { BarChart, BarChartUpdate } from '../Other/chartConfigs';
3 | import { CreateCard } from '../Other/jsxCard';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function QosChart(props){
8 | const qosChartRef = useRef(null)
9 | const chartCanvasRef = React.createRef()
10 | $.fn.dataTable.ext.errMode = 'none';
11 |
12 | useEffect(() => {
13 | try{
14 | let updatedChart = BarChartUpdate(qosChartRef.current, [parseInt(props.queue.rate)]);
15 | updatedChart.update()
16 | chartCanvasRef.current = updatedChart
17 | }
18 | catch{}
19 |
20 | }, [props.queue])
21 |
22 | useEffect(() => {
23 | let qosChart = BarChart(chartCanvasRef.current.getContext('2d'), parseInt(props.queue.rate));
24 | qosChartRef.current = qosChart
25 | }, [])
26 |
27 | return <>{CreateCard( , '',{props.queue['queue-name']} )}>
28 |
29 |
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/src/Components/InterfaceGraphs/liveInterface.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useQuery, useQueryClient } from 'react-query'
3 | import Container from "react-bootstrap/Container";
4 | import Col from "react-bootstrap/Col";
5 | import Row from "react-bootstrap/Row";
6 | import {useRecoilState} from 'recoil';
7 | import { InterfaceCard} from '../Index/interfaceCard'
8 | import { Navigation } from '../Other/navbar';
9 | import { NavigationFallback } from '../Other/navbarError';
10 | import { CreateCard } from '../Other/jsxCard';
11 | import { IsErrorFallback } from "../Other/errorComponent";
12 | import { ErrorBoundary } from 'react-error-boundary'
13 | import { PageLoader } from '../Other/pageLoader';
14 | import { BandwidthDiff } from '../Other/bandwidthFunctions';
15 | import { encytpKey, client} from '../../App'
16 | import { ShowInterface } from '../Modals/interfaceModal';
17 | import { ModifyInterface } from '../Forms/interfaceForm';
18 | import { ApiRequest } from "../Other/axiosRequests";
19 |
20 | export function LiveInterfaces(){
21 | const [decryptKey] = useRecoilState(encytpKey);
22 | const cache = React.useRef(useQueryClient())
23 | const [modalShow, setModalShow] = React.useState(false);
24 | const [interfaceShow, setInterfaceShow] = React.useState(false);
25 | const [selectInterface, setSelectInterface] = React.useState(undefined)
26 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') + 'liveinterfaces', async () => {
27 |
28 | const response = await ApiRequest(decryptKey, '/liveinterfaces')
29 | const calulatedBandwdithDiff = BandwidthDiff(cache, response.data)
30 |
31 | if(selectInterface !== undefined){
32 | Object.values(calulatedBandwdithDiff.interfaces).map(int => {
33 | if(int.data.name === selectInterface.interface && modalShow){
34 | setSelectInterface(int)
35 | }
36 | })
37 | }
38 |
39 | return calulatedBandwdithDiff
40 |
41 | },
42 | {
43 | refetchInterval: 5000
44 | }
45 | )
46 |
47 | const interfaceFocus = (interfaceDetails) => {
48 | setSelectInterface(interfaceDetails)
49 | setModalShow(true)
50 | }
51 |
52 | const closeInterface = () => {
53 | setSelectInterface(undefined)
54 | setInterfaceShow(false)
55 | setModalShow(false)
56 | }
57 |
58 | if (error){
59 | return <>
60 |
61 |
62 |
63 | Error Collecting Data. I'll Keep Trying
64 |
65 | >
66 | }
67 | else if (data){
68 | return
69 |
70 |
71 |
72 |
73 |
74 |
75 | setInterfaceShow(true)}>Add Interface
76 | { Object.values(data.interfaces).map((value) => (
77 | interfaceFocus(value)}>{value.interface}
78 | ))}
79 |
80 |
81 |
82 |
83 | { Object.values(data.interfaces).map((value) => (
84 |
85 | {CreateCard(, value.interface)}
86 |
87 | ))}
88 |
89 |
90 |
91 | {modalShow ? } show={modalShow} onHide={() => closeInterface()}/>
92 | :
93 | <>>}
94 |
95 | {interfaceShow ? } show={interfaceShow} onHide={() => closeInterface()}/>
96 | :
97 | <>>}
98 |
99 |
100 |
101 | }
102 | else if (isLoading){
103 |
104 | return <>
105 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
106 | >
107 | }
108 |
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/src/Components/LayerThree/Routing-Parent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Container from "react-bootstrap/Container";
3 | import Row from "react-bootstrap/Row";
4 | import Col from "react-bootstrap/Col";
5 | import {useRecoilState} from 'recoil';
6 | import { Ospf } from './ospf';
7 | import { Bgp } from './bgp';
8 | import { Navigation } from '../Other/navbar'
9 | import { useQuery } from 'react-query';
10 | import { ErrorBoundary } from 'react-error-boundary'
11 | import {encytpKey, client} from '../../App'
12 | import { NavigationFallback } from "../Other/navbarError";
13 | import { IsErrorFallback } from "../Other/errorComponent";
14 | import { ApiRequest } from "../Other/axiosRequests";
15 | import { PageLoader } from '../Other/pageLoader';
16 |
17 |
18 | export function Routing(){
19 | const [decryptKey] = useRecoilState(encytpKey);
20 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') + 'pollRouting', async () => {
21 |
22 | const response = await ApiRequest(decryptKey, '/pollRouting')
23 |
24 | return response.data
25 |
26 | },
27 | {
28 | refetchInterval: 5000,
29 | }
30 | )
31 |
32 | if (error){
33 | return <>
34 |
35 |
36 |
37 | Error Collecting Data. I'll Keep Trying
38 |
39 | >
40 | }
41 | else if (data){
42 | return
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | }
62 | else if (isLoading){
63 | return <>
64 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
65 | >
66 | }
67 |
68 | }
69 |
70 |
71 |
--------------------------------------------------------------------------------
/src/Components/LayerThree/bgp.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 | import Card from "react-bootstrap/Card";
3 | import Row from "react-bootstrap/Row";
4 | import Col from "react-bootstrap/Col";
5 | import { CreateCard } from '../Other/jsxCard';
6 | import { BgpTableHtml } from '../Other/chartConfigs';
7 | import { BgpData } from '../Other/tables';
8 | import { BgpTopologyBuild, UpdateBgpTopology } from './topology';
9 | import { ModifyBgpNeighbor } from '../Forms/bgpNeighborForm';
10 | import { BgpModal } from '../Modals/bgpFormModal';
11 | const $ = require('jquery');
12 | $.DataTable = require('datatables.net');
13 |
14 | export function Bgp(props){
15 | const [modalShow, setModalShow] = React.useState(false);
16 | const bgpTableRef = React.createRef()
17 | const bgpTopologyRef = React.createRef()
18 | const bgpTopology = useRef(null)
19 | const bgpTable = BgpTableHtml(bgpTableRef)
20 |
21 | useEffect(() => {
22 |
23 | try{
24 | if(props.neighbors.length <= 10){
25 | $(bgpTableRef.current).DataTable().destroy()
26 | BgpData(bgpTableRef.current, props.neighbors)
27 | bgpTopology.current = BgpTopologyBuild(bgpTopologyRef.current, props.neighbors, props.details[0], props.details[2], props.details[5], props.topology)
28 | bgpTopologyRef.current = bgpTopology.current
29 |
30 | }
31 | else if(props.neighbors.length > 10){
32 | $(bgpTableRef.current).DataTable().clear()
33 | $(bgpTableRef.current).DataTable().rows.add(props.neighbors)
34 | $(bgpTableRef.current).DataTable().draw(false)
35 | bgpTopology.current = UpdateBgpTopology(bgpTopology.current, props.neighbors, props.details[2])
36 | bgpTopologyRef.current = bgpTopology.current
37 | }
38 |
39 | }
40 | catch{}
41 |
42 | }, [props.neighbors])
43 |
44 |
45 | if(props.neighbors.length !== 0){
46 | return
47 |
48 |
49 |
50 | Local AS: {props.details[0]}
51 |
52 |
53 | Vrf-Name:
54 | Router-Id:
55 | BGP Table Ver.:
56 | Routing Table Ver.:
57 | Total Prefixes:
58 | Path Entries:
59 | AS Path Ent.
60 | Route-Map Ent.
61 | Filter-List Ent.:
62 | Total Memory:
63 |
64 |
65 | {props.details[1]}
66 | {props.details[2]}
67 | {props.details[3]}
68 | {props.details[4]}
69 | {props.details[5]}
70 | {props.details[7]}
71 | {props.details[9]}
72 | {props.details[11]}
73 | {props.details[13]}
74 | {props.details[19]}
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | {modalShow ? } show={modalShow} onHide={() => setModalShow(false)}/> :
}
83 |
84 |
85 | {CreateCard(bgpTable, "BGP Neighbors", setModalShow(true)}>Add Neighbor
)}
86 |
87 |
88 | {CreateCard(
, "BGP Topology")}
89 |
90 |
91 |
92 |
93 |
94 |
95 | }
96 | else{
97 | return
98 |
99 | BGP Neighbors
100 | setModalShow(true)}>Add Neighbor
101 | {bgpTable}
102 | {modalShow ? } show={modalShow} onHide={() => setModalShow(false)}/> :
}
103 |
104 |
105 | }
106 |
107 | }
108 |
109 |
--------------------------------------------------------------------------------
/src/Components/LayerThree/ospf.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 | import Card from "react-bootstrap/Card";
3 | import Row from "react-bootstrap/Row";
4 | import Col from "react-bootstrap/Col";
5 | import { OpsfIntsTableHtml } from '../Other/chartConfigs';
6 | import { OspfData} from '../Other/tables';
7 | import { OspfTopologyBuild, UpdateOspfTopology } from './topology';
8 | import { ModifyOspfNeighbor } from '../Forms/ospfNeighborForm';
9 | import { CreateCard } from '../Other/jsxCard';
10 | import { OspfForm } from './ospfFormOverlay';
11 | const $ = require('jquery');
12 | $.DataTable = require('datatables.net');
13 |
14 | export function Ospf(props){
15 | const [modalShow, setModalShow] = React.useState(false);
16 | const ospfTableRef = React.createRef()
17 | const ospfIntsTableRef = React.createRef()
18 | const ospfTopologyRef = React.createRef()
19 | const ospfTopology = useRef(null)
20 | const ospfIntTable = OpsfIntsTableHtml(ospfIntsTableRef)
21 | $.fn.dataTable.ext.errMode = 'none';
22 |
23 | useEffect(() => {
24 | if(ospfTableRef.current !== null){
25 |
26 | try{
27 | $(ospfIntsTableRef.current).DataTable().clear()
28 | $(ospfIntsTableRef.current).DataTable().rows.add(Object.values(props.interfaces))
29 | $(ospfIntsTableRef.current).DataTable().draw(false)
30 | }
31 | catch{}
32 |
33 | try{
34 | if(props.topology.length >= 1){
35 | ospfTopology.current = UpdateOspfTopology(ospfTopology.current, props.neighbors, props.topology)
36 | ospfTopologyRef.current = ospfTopology.current
37 | }
38 | }
39 | catch(e){}
40 | }
41 | }, [props.neighbors])
42 |
43 | useEffect(() => {
44 |
45 | OspfData(ospfIntsTableRef.current, props.interfaces)
46 |
47 | try{
48 | if(props.interfaces.length >= 1){
49 | ospfTopology.current = OspfTopologyBuild(ospfTopologyRef.current, props.neighbors, props.topology)
50 | ospfTopologyRef.current = ospfTopology.current
51 | }
52 | }
53 | catch{}
54 |
55 | }, [])
56 |
57 | return <>
58 | {
59 | OSPF Interfaces/Neighbors
60 |
61 | setModalShow(true)}>Add Network
62 |
63 |
64 | {ospfIntTable}
65 |
66 | }
67 |
68 | {modalShow ? } show={modalShow} onHide={() =>setModalShow(false)}/> :
}
69 |
70 |
71 | {props.interfaces.length >= 1 ?
72 | <>{ {CreateCard(
, "OSPF Topology")}
}>
73 | :
74 | <>>}
75 |
76 | >
77 |
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/Components/LayerThree/ospfFormOverlay.js:
--------------------------------------------------------------------------------
1 | import Modal from 'react-bootstrap/Modal'
2 | import Button from 'react-bootstrap/Button'
3 | import Container from "react-bootstrap/Container";
4 | import { CreateCard } from '../Other/jsxCard';
5 |
6 | export function OspfForm(props) {
7 | console.log(props)
8 | return (
9 |
17 |
18 |
19 |
20 | {CreateCard(props.component, props.interface)}
21 |
22 |
23 |
24 | );
25 | }
--------------------------------------------------------------------------------
/src/Components/LayerThree/routing.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import axios from 'axios';
3 | import { Ospf } from './ospf';
4 | import { Bgp } from './bgp';
5 | import { Navbar } from '../Other/navbar'
6 | import { useQuery, getQueriesData } from 'react-query';
7 | import { ErrorBoundary } from '../Other/errorBoundry';
8 | import {AES, enc}from 'crypto-js';
9 |
10 |
11 | export function Routing(props){
12 | const passwordDecrypt = AES.decrypt(localStorage.getItem('password'), 'MYKEY4DEMO');
13 | const password = passwordDecrypt.toString(enc.Utf8);
14 | const { isLoading, error, data, isFetching } = useQuery('pollRouting', async () => {
15 |
16 | const response = await axios.post('/pollRouting',{'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
17 | 'password': password, 'port': localStorage.getItem('port')})
18 |
19 | return response.data
20 |
21 | },
22 | {
23 | refetchInterval: 5000,
24 | }
25 | )
26 |
27 | if (error){
28 | return
29 |
30 | Error Collecting Data. I'll Keep Trying
31 |
32 |
33 | }
34 | else if (data){
35 | return
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | }
53 | else if (isLoading){
54 | return
55 |
Collecting routing data for {localStorage.getItem('ip')}
56 |
57 |
58 | }
59 |
60 | }
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/Components/LayerTwo/accessPorts.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { AccessTableHtml } from '../Other/chartConfigs';
3 | import { AccesPortData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function AccessPorts(props){
8 | const accesssTableRef = React.createRef()
9 | const accessstable = AccessTableHtml(accesssTableRef)
10 | $.fn.dataTable.ext.errMode = 'none';
11 |
12 |
13 | useEffect(() => {
14 | if(accesssTableRef.current !== null){
15 | try{
16 | $(accesssTableRef.current).DataTable().clear()
17 | $(accesssTableRef.current).DataTable().rows.add(Object.values(props.ports))
18 | $(accesssTableRef.current).DataTable().draw(false)
19 | }
20 | catch{}
21 | }
22 | }, [props.ports])
23 |
24 |
25 | useEffect(() => {
26 | $(accesssTableRef.current).DataTable().destroy()
27 | AccesPortData(accesssTableRef.current, props.ports)
28 | }, [])
29 |
30 | return accessstable
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/Components/LayerTwo/layerTwo-Parent.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { useQuery } from 'react-query';
3 | import Tabs from "react-bootstrap/Tabs";
4 | import Tab from "react-bootstrap/Tab";
5 | import Container from "react-bootstrap/Container";
6 | import Row from "react-bootstrap/Row";
7 | import Col from "react-bootstrap/Col";
8 | import {useRecoilState} from 'recoil';
9 | import { DpNeighbors} from '../Other/dp_neighbors'
10 | import { GlobalSpanTreeHtml} from '../Other/chartConfigs'
11 | import { MacTable} from './macAddress'
12 | import { SpanTable} from './spanTree'
13 | import { Trunks} from './trunks'
14 | import { AccessPorts} from './accessPorts'
15 | import { Vlans} from './vlans'
16 | import { Navigation } from '../Other/navbar';
17 | import { ErrorBoundary } from 'react-error-boundary'
18 | import {encytpKey, cache} from '../../App'
19 | import { CreateCard } from '../Other/jsxCard';
20 | import { Card } from 'react-bootstrap';
21 | import { NavigationFallback } from "../Other/navbarError";
22 | import { IsErrorFallback } from "../Other/errorComponent";
23 | import { PageLoader } from '../Other/pageLoader';
24 | import { ApiRequest } from "../Other/axiosRequests";
25 |
26 | export function LayerTwo(){
27 | const bridgeGlobalTble = useRef(false)
28 | const [decryptKey] = useRecoilState(encytpKey);
29 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') +'pollL2Page', async () => {
30 |
31 | const response = await ApiRequest(decryptKey, '/pollL2Page')
32 |
33 | try{
34 | bridgeGlobalTble.current = GlobalSpanTreeHtml(response.data.globalSpan)
35 | }
36 | catch{}
37 |
38 | return response.data
39 |
40 | },
41 | {
42 | refetchInterval: 5000
43 | }
44 | )
45 |
46 | if (error){
47 | return <>
48 |
49 |
50 |
51 | Error Collecting Data. I'll Keep Trying
52 |
53 | >
54 | }
55 | else if (data){
56 |
57 | return
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | {bridgeGlobalTble.current}
68 |
69 | {data.span.hasOwnProperty.key ?
70 | { data.span.map(instance => ( ))}
71 | :
}
72 |
73 |
74 |
75 |
76 |
77 | {CreateCard()}
78 |
79 |
80 |
81 |
82 | {data.vlans.length > 0 ? CreateCard(, "Vlans") :
}
83 |
84 |
85 |
86 | {data.trunks.length > 0 ? CreateCard(, "Trunks") :
}
87 |
88 |
89 | {data.access.length > 0 ? CreateCard(, "Access Ports"):
}
90 |
91 |
92 | {data.mac_addresses.length > 0 ? CreateCard(, "MAC-Addresses") :
}
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | }
101 | else if (isLoading){
102 | return <>
103 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
104 | >
105 | }
106 | }
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/Components/LayerTwo/layerTwo.js:
--------------------------------------------------------------------------------
1 | import React, { useRef } from 'react';
2 | import { useQuery } from 'react-query';
3 | import axios from 'axios';
4 | import { DpNeighbors} from '../Other/dp_neighbors'
5 | import { GlobalSpanTreeHtml} from '../Other/chartConfigs'
6 | import { MacTable} from './macAddress'
7 | import { SpanTable} from './spanTree'
8 | import { Trunks} from './trunks'
9 | import { AccessPorts} from './accessPorts'
10 | import { Vlans} from './vlans'
11 | import { Navbar } from '../Other/navbar';
12 | import { ErrorBoundary } from '../Other/errorBoundry';
13 | import { MacData, SpanData, VlansData, TrunkData, AccessData, DpData} from '../Other/data';
14 | import {AES, enc}from 'crypto-js';
15 |
16 |
17 |
18 | export function LayerTwo(props){
19 | const bridgeGlobalTble = useRef(false)
20 | const passwordDecrypt = AES.decrypt(localStorage.getItem('password'), 'MYKEY4DEMO');
21 | const password = passwordDecrypt.toString(enc.Utf8);
22 | const { isLoading, error, data, isFetching } = useQuery('pollL2Page', async () => {
23 |
24 | const response = await axios.post('/pollL2Page',{'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
25 | 'password': password, 'port': localStorage.getItem('port')})
26 | bridgeGlobalTble.current = GlobalSpanTreeHtml(SpanData[1]['Cisco-IOS-XE-spanning-tree-oper:stp-global'])
27 | return response.data
28 |
29 | },
30 | {
31 | refetchInterval: 5000,
32 | }
33 | )
34 |
35 | if (error){
36 | return
37 |
38 | Error Collecting Data. I'll Keep Trying
39 |
40 |
41 | }
42 | else if (data){
43 | return
44 |
45 |
46 |
47 |
48 |
56 |
57 |
58 | { data.span[0].map(instance => (
59 |
60 |
61 |
62 | ))}
63 |
64 |
65 | {bridgeGlobalTble.current}
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | }
100 | else if (isLoading){
101 | return
102 |
Collecting L2 data for {localStorage.getItem('ip')}
103 |
104 |
105 | }
106 |
107 | }
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/Components/LayerTwo/macAddress.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { MacTableHtml } from '../Other/chartConfigs';
3 | import { MacAddressData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function MacTable(props){
8 | const macTableRef = React.createRef()
9 | const macTable = MacTableHtml(macTableRef)
10 | $.fn.dataTable.ext.errMode = 'none';
11 | console.log(props.macs)
12 |
13 | useEffect(() => {
14 | if(macTableRef.current !== null){
15 | try{
16 | $(macTableRef.current).DataTable().clear()
17 | $(macTableRef.current).DataTable().rows.add(Object.values(props.macs))
18 | $(macTableRef.current).DataTable().draw(false)
19 | }
20 | catch{}
21 | }
22 |
23 | }, [props.macs])
24 |
25 |
26 | useEffect(() => {
27 | $(macTableRef.current).DataTable().destroy()
28 | MacAddressData(macTableRef.current, props.macs)
29 | }, [])
30 |
31 | return macTable
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/Components/LayerTwo/spanTree.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import Row from "react-bootstrap/Row";
3 | import Col from "react-bootstrap/Col";
4 | import Card from "react-bootstrap/Card";
5 | import { SpanTreeHtml } from '../Other/chartConfigs';
6 | import { SpanTableData } from '../Other/tables';
7 | import { CreateCard } from '../Other/jsxCard';
8 | const $ = require('jquery');
9 | $.DataTable = require('datatables.net');
10 |
11 |
12 | export function SpanTable(props){
13 | const spanTableRef = React.createRef()
14 | const spanTable = SpanTreeHtml(spanTableRef)
15 | $.fn.dataTable.ext.errMode = 'none';
16 |
17 | useEffect(() => {
18 | if(spanTableRef.current !== null){
19 | try{
20 | $(spanTableRef.current).DataTable().clear()
21 | $(spanTableRef.current).DataTable().rows.add(Object.values(props.span))
22 | $(spanTableRef.current).DataTable().draw(false)
23 | }
24 | catch{}
25 | }
26 |
27 | }, [props.span])
28 |
29 |
30 | useEffect(() => {
31 | $(spanTableRef.current).DataTable().destroy()
32 | SpanTableData(spanTableRef.current, props.span)
33 |
34 | }, [])
35 |
36 | return
37 |
38 |
39 |
40 | {props.span.instance}
41 |
42 |
43 |
44 |
45 | Hello:
46 | Fwd-Delay:
47 | Hold Count:
48 | Bridge Prio.:
49 | Bridge Add.:
50 | Des. Root Prio.:
51 | Des. Root Add.:
52 | Root Port:
53 | Root Cost:
54 | Hold Time:
55 | Topology Changes:
56 | Last Change:
57 |
58 |
59 | {props.span['hello-time']}
60 | {props.span['forwarding-delay']}
61 | {props.span['hold-count']}
62 | {props.span['bridge-priority']}
63 | {props.span['bridge-address']}
64 | {props.span['designated-root-priority']}
65 | {props.span['designated-root-address']}
66 | {props.span['root-port']}
67 | {props.span['root-cost']}
68 | {props.span['hold-time']}
69 | {props.span['topology-changes']}
70 | {props.span['time-of-last-topology-change']}
71 |
72 |
73 | {CreateCard(spanTable, "Ports")}
74 |
75 |
76 |
77 |
78 |
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/Components/LayerTwo/trunks.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { TrunkTableHtml } from '../Other/chartConfigs';
3 | import { TrunkData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function Trunks(props){
8 | const trunksTableRef = React.createRef()
9 | const trunkstable = TrunkTableHtml(trunksTableRef)
10 | console.log(props.ports, 'yes')
11 |
12 | useEffect(() => {
13 | if(trunksTableRef.current !== null){
14 | try{
15 | $(trunksTableRef.current).DataTable().clear()
16 | $(trunksTableRef.current).DataTable().rows.add(Object.values(props.ports))
17 | $(trunksTableRef.current).DataTable().draw(false)
18 | }
19 | catch{}
20 | }
21 | }, [props.ports])
22 |
23 | useEffect(() => {
24 | $(trunksTableRef.current).DataTable().destroy()
25 | TrunkData(trunksTableRef.current, props.ports)
26 | }, [])
27 |
28 | return trunkstable
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/Components/LayerTwo/vlans.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { VlanTableHtml } from '../Other/chartConfigs';
3 | import { VlanData } from '../Other/tables';
4 |
5 | const $ = require('jquery');
6 | $.DataTable = require('datatables.net');
7 |
8 | export function Vlans(props){
9 | const vlanTableRef = React.createRef()
10 | const vlantable = VlanTableHtml(vlanTableRef)
11 |
12 | useEffect(() => {
13 | $(vlanTableRef.current).DataTable().destroy()
14 | VlanData(vlanTableRef.current, props.vlans)
15 |
16 | }, [])
17 |
18 | return vlantable
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/Components/Modals/bgpFormModal.js:
--------------------------------------------------------------------------------
1 | import Modal from 'react-bootstrap/Modal'
2 | import { CreateCard } from '../Other/jsxCard';
3 |
4 | export function BgpModal(props) {
5 |
6 | return (
7 |
16 |
17 |
18 |
19 | {CreateCard(props.component)}
20 |
21 |
22 |
23 | );
24 | }
--------------------------------------------------------------------------------
/src/Components/Modals/configQueryModal.js:
--------------------------------------------------------------------------------
1 | import Modal from 'react-bootstrap/Modal'
2 | import Button from 'react-bootstrap/Button'
3 | import Col from 'react-bootstrap/Row'
4 |
5 | export function RestQueryModal(props) {
6 |
7 | if(props.msg === 'Request Timeout'){
8 |
9 | return (
10 |
11 |
12 | {props.msg}
13 | The App Did Not Receive A Response From The Device
14 |
15 |
16 | Resend
17 |
18 |
19 | );
20 | }
21 | else if(props.msg === 'Fetching'){
22 | return
23 |
24 | {props.msg}
25 |
26 |
27 |
28 | }
29 | else{
30 | return
31 |
32 | {props.msg}
33 |
34 |
35 | Exit
36 |
37 |
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Components/Modals/configSendModal.js:
--------------------------------------------------------------------------------
1 | import Modal from 'react-bootstrap/Modal'
2 | import Button from 'react-bootstrap/Button'
3 | import Col from 'react-bootstrap/Row'
4 |
5 | export function ConfigurationModal(props) {
6 |
7 | if(props.msg === 'Request Timeout'){
8 |
9 | return (
10 |
11 |
12 | {props.msg}
13 | The App Did Not Receive A Response From The Device
14 |
15 |
16 | Resend
17 |
18 |
19 | );
20 | }
21 | else if(props.msg === 'Sending Config'){
22 | return
23 |
24 | {props.msg}
25 |
26 |
27 |
28 | }
29 | else{
30 | return
31 |
32 | {props.msg}
33 | {props.msg !== 'Configuration Successful' ? <>> : }
34 |
35 |
36 | {props.msg === 'Configuration Successful' ? Exit
37 | :
38 | Exit }
39 |
40 |
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Components/Modals/interfaceModal.js:
--------------------------------------------------------------------------------
1 | import Modal from 'react-bootstrap/Modal'
2 | import { CreateCard } from '../Other/jsxCard';
3 |
4 | export function ShowInterface(props) {
5 | console.log(props)
6 | return (
7 |
15 |
16 |
17 |
18 | {CreateCard(props.component, props.interface)}
19 |
20 |
21 | );
22 | }
--------------------------------------------------------------------------------
/src/Components/Modals/loadingModal.js:
--------------------------------------------------------------------------------
1 | import Modal from 'react-bootstrap/Modal'
2 | import Button from 'react-bootstrap/Button'
3 | import Col from 'react-bootstrap/Row'
4 |
5 | export function LoginModal(props) {
6 |
7 | if(props.msg === 'Request Timeout'){
8 |
9 | return (
10 |
11 |
12 | {props.msg}
13 | The App Did Not Receive A Response From The Device
14 |
15 |
16 | ReAuth
17 |
18 |
19 | );
20 | }
21 | else{
22 | return (
23 |
24 |
25 | {props.msg}
26 | {props.msg !== 'Authentication Failed' ? : Verify RESTCONF Capabilities and Credentials
}
27 |
28 |
29 | {props.msg === 'Authentication Failed' ? ReAuth :
}
30 |
31 |
32 | );
33 | }
34 | }
--------------------------------------------------------------------------------
/src/Components/Other/axiosRequests.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import {AES, enc}from 'crypto-js';
3 |
4 | const credentials = (decryptKey, customUrl) => {
5 |
6 | const passwordDecrypt = AES.decrypt(localStorage.getItem('password'), decryptKey);
7 |
8 | if(customUrl === undefined){
9 |
10 | var credentialsObj = {'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
11 | 'password': passwordDecrypt.toString(enc.Utf8), 'port': localStorage.getItem('port')};
12 | }
13 | else{
14 | var credentialsObj = {'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
15 | 'password': passwordDecrypt.toString(enc.Utf8), 'port': localStorage.getItem('port'), 'url': customUrl};
16 | }
17 |
18 | return credentialsObj
19 |
20 | }
21 |
22 | export const ApiRequest = async (decryptKey, url, customUrl) => {
23 |
24 | const payload = credentials(decryptKey, customUrl)
25 | const response = await axios.post(url, payload).then(response => {
26 |
27 | return response
28 |
29 | }).catch(error => {
30 | console.log(error)
31 | })
32 |
33 | return response
34 | }
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/Components/Other/bandwidthFunctions.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | export const BandwidthDiff = (cachedQuery, data) => {
4 | try{
5 | const lastQuery = cachedQuery.getQueryCache(localStorage.getItem('ip') + 'indexData').queries[0].state.data.interfaces;
6 | Object.values(lastQuery).map(cacheValue => {
7 | Object.values(data.interfaces).map(newValue => {
8 | if(newValue.data.name === cacheValue.data.name){
9 |
10 | const diffIn = parseFloat(newValue.data['statistics']['rx-kbps'] - parseFloat(cacheValue.data['statistics']['rx-kbps']));
11 | const diffOut = parseFloat(newValue.data['statistics']['tx-kbps'] - parseFloat(cacheValue.data['statistics']['tx-kbps']));
12 |
13 | if(Math.sign(diffIn) === 1){
14 | newValue.data.inbandwidthDiff = '+' + diffIn.toFixed(2)
15 | }
16 | else if(Math.sign(diffIn) === -1){
17 | newValue.data.inbandwidthDiff = diffIn.toFixed(2)
18 | }
19 | else{
20 | newValue.data.inbandwidthDiff = diffIn
21 | };
22 |
23 | if(Math.sign(diffOut) === 1){
24 | newValue.data.outbandwidthDiff = '+' + diffOut.toFixed(2)
25 | }
26 | else if(Math.sign(diffOut) === -1){
27 | newValue.data.outbandwidthDiff = diffOut.toFixed(2)
28 | }
29 | else{
30 | newValue.data.outbandwidthDiff = diffOut
31 | };
32 | };
33 | });
34 | });
35 | }
36 | catch{}
37 |
38 | return data
39 |
40 | }
--------------------------------------------------------------------------------
/src/Components/Other/configNavbar.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { ApiCheck } from './promises'
3 | import Nav from "react-bootstrap/Nav";
4 | import Navbar from "react-bootstrap/Navbar";
5 | import Container from "react-bootstrap/Container";
6 | import Offcanvas from 'react-bootstrap/Offcanvas'
7 | import Row from "react-bootstrap/Row";
8 | import { Link } from "react-router-dom";
9 |
10 | export function RestConfigNavbar(props){
11 | const [apiStatus, setApiStatus] = useState(true)
12 |
13 | useEffect(() => {
14 | (async () => {
15 | try{
16 | let apiStatus = await ApiCheck()
17 | if(apiStatus.status === 200)
18 | setApiStatus(true)
19 | else{
20 | setApiStatus(false)
21 | }
22 | }
23 | catch{
24 | setApiStatus(false)
25 | }
26 |
27 | })()
28 | }, [props.update])
29 |
30 | return
31 |
32 |
33 |
34 |
38 |
39 | XE-Ops
40 |
41 |
42 |
43 |
44 | Home
45 | {localStorage.getItem('model') !== 'ASR' && localStorage.getItem('model') !== 'CSR' ? LayerTwo :
}
46 | Routing
47 | Env
48 | DMVPN
49 | IP Slas
50 | RibStatus
51 | Live-Interfaces
52 | Cfg/Oper
53 | Logout
54 |
55 | Connection: {props.ip}
56 | {apiStatus ? API Reachable:
57 | :
58 | API Unreachable
}
59 | Device Model/SN: {localStorage.getItem('model')} ({localStorage.getItem('serial')})
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/Components/Other/dp_neighbors.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import Tabs from "react-bootstrap/Tabs";
3 | import Tab from "react-bootstrap/Tab";
4 | import { CdpTableHtml, LldpTableHtml } from './chartConfigs';
5 | import { CdpTable, LldpTable } from './tables';
6 | const $ = require('jquery');
7 | $.DataTable = require('datatables.net');
8 |
9 |
10 | export function DpNeighbors(props){
11 | const cdpTableRef = React.createRef()
12 | const cdptable = CdpTableHtml(cdpTableRef)
13 | const lldpTableRef = React.createRef()
14 | const lldptable = LldpTableHtml(lldpTableRef)
15 | $.fn.dataTable.ext.errMode = 'none';
16 |
17 | useEffect(() => {
18 | if(cdpTableRef.current !== null){
19 | try{
20 | $(cdptable.current).DataTable().clear()
21 | $(cdptable.current).DataTable().rows.add(props.dpNeighbors[0])
22 | $(cdptable.current).DataTable().draw(false)
23 | }
24 | catch{}
25 | }
26 |
27 |
28 | if(lldpTableRef.current !== null){
29 | try{
30 | $(lldpTableRef.current).DataTable().clear()
31 | $(lldpTableRef.current).DataTable().rows.add(props.dpNeighbors[1])
32 | $(lldpTableRef.current).DataTable().draw(false)
33 | }
34 | catch{}
35 | }
36 | }, [props.dpNeighbors])
37 |
38 | useEffect(() => {
39 | $(lldpTableRef.current).DataTable().destroy()
40 | $(cdptable.current).DataTable().destroy()
41 | CdpTable(cdpTableRef.current, props.dpNeighbors[0])
42 | LldpTable(lldpTableRef.current, props.dpNeighbors[1])
43 | }, [])
44 |
45 | return
46 |
47 | {cdptable}
48 |
49 |
50 | {lldptable}
51 |
52 |
53 |
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/Components/Other/errorBoundry.js:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react';
3 |
4 |
5 | export classname ErrorBoundary extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = { hasError: false,
9 | error: undefined };
10 | }
11 |
12 | static getDerivedStateFromError(error) {
13 | console.log(error)
14 | // Update state so the next render will show the fallback UI.
15 | return { hasError: true, error: error };
16 | }
17 |
18 |
19 | render() {
20 | if (this.state.hasError) {
21 | // You can render any custom fallback UI
22 | return
23 | }
24 | else{
25 | // You can render any custom fallback UI
26 | return this.props.children;
27 | }
28 |
29 |
30 | }
31 | }
--------------------------------------------------------------------------------
/src/Components/Other/errorComponent.js:
--------------------------------------------------------------------------------
1 |
2 | import Card from "react-bootstrap/Card";
3 | import Col from "react-bootstrap/Col";
4 |
5 |
6 | export function IsErrorFallback({error}){
7 | const reportError = String(error.message)
8 | return
9 |
10 | !Something Went Wrong. Please Refresh! Please Report the Issue
11 |
12 | Click Here to Submit Issue
13 |
14 | Report your current page/location in the app. Also a brief explanation on your task that errored
15 | {reportError}
16 |
17 |
18 | }
--------------------------------------------------------------------------------
/src/Components/Other/interfaceOverlay.js:
--------------------------------------------------------------------------------
1 | import Modal from 'react-bootstrap/Modal'
2 |
3 | function InterfaceOverlay(props) {
4 | return (
5 |
11 |
12 |
13 | Modal heading
14 |
15 |
16 |
17 | Centered Modal
18 |
19 | Cras mattis consectetur purus sit amet fermentum. Cras justo odio,
20 | dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac
21 | consectetur ac, vestibulum at eros.
22 |
23 |
24 |
25 | Close
26 |
27 |
28 | );
29 | }
--------------------------------------------------------------------------------
/src/Components/Other/jsxCard.js:
--------------------------------------------------------------------------------
1 | import { ErrorBoundary } from 'react-error-boundary'
2 | import Card from "react-bootstrap/Card";
3 | import { IsErrorFallback } from "../Other/errorComponent";
4 |
5 | export function CreateCard(component, title, extra){
6 |
7 | const card =
8 |
9 | {title}
10 | {extra}
11 |
12 | {component}
13 |
14 |
15 |
16 |
17 | return card
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/Components/Other/login.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { Redirect } from "react-router-dom";
3 | import { useQuery } from 'react-query'
4 | import axios from 'axios';
5 | import Container from "react-bootstrap/Container";
6 | import Card from "react-bootstrap/Card";
7 | import Row from "react-bootstrap/Row";
8 | import Col from "react-bootstrap/Col";
9 | import Form from 'react-bootstrap/Form'
10 | import {useRecoilState} from 'recoil';
11 | import { LoginModal } from '../Modals/loadingModal'
12 | import { AES }from 'crypto-js';
13 | import {encytpKey} from '../../App'
14 |
15 | export function DeviceAuth(){
16 | const [encrypt] = useRecoilState(encytpKey);
17 | const [ip, setIp] = useState('')
18 | const [username, setUserNaMe] = useState('')
19 | const [password, setPassword] = useState('')
20 | const [port, setPort] = useState(443)
21 | const [isAuth, setAuth] = useState(false)
22 | const [modalShow, setModalShow] = React.useState(false);
23 | const [msg, setMsg] = useState('Autheniticating')
24 | const requestSession = axios.create();
25 | requestSession.defaults.timeout = 30000;
26 | const {refetch } = useQuery(ip + 'login', async () => {
27 |
28 | const response = await requestSession.post('/login', {'ip': ip, 'username': username, 'password': password, 'port': port}).then(response =>{
29 |
30 | if(response.data.status === 200){
31 | const encryptPassword = AES.encrypt(password, encrypt);
32 | localStorage.setItem('ip', ip);
33 | localStorage.setItem('port', 443);
34 | localStorage.setItem('username', username);
35 | localStorage.setItem('password', encryptPassword.toString());
36 | localStorage.setItem('model', response.data.model);
37 | localStorage.setItem('serial', response.data.serial);
38 | localStorage.setItem('uptime', response.data.uptime);
39 | localStorage.setItem('software', response.data.software)
40 | setModalShow(false)
41 | setAuth(true)
42 | return response.data
43 |
44 | }
45 | else{
46 | setMsg('Authentication Failed')
47 | }
48 | }).catch(() => {setMsg('Request Timeout')})
49 |
50 | return response
51 |
52 | },
53 | {
54 | enabled: false, cacheTime: Infinity
55 | })
56 |
57 |
58 | const handleSubmit = (evt) => {
59 | evt.preventDefault();
60 | refetch();
61 |
62 | }
63 |
64 | const resetPageStatus = () => {
65 | setMsg('Autheniticating')
66 | setModalShow(false)
67 | }
68 |
69 | useEffect(() => {
70 | localStorage.clear()
71 | }, [])
72 |
73 |
74 | if(!isAuth){
75 | return (
76 |
77 |
78 |
79 |
80 |
81 |
82 | IOS-XE Login
83 | setIp(e.target.value)} placeholder="IP Address" name="ipAddress" required/>
85 | setUserNaMe(e.target.value)} placeholder="Username" name="username" required/>
86 | setPassword(e.target.value)} placeholder="Password" name="password" required/>
87 | setPort(e.target.value)} placeholder="Default 443" name="restconfPort" required/>
88 | setModalShow(true)} type="submit" value="Login" className="btn btn-success"/>
89 |
90 | {modalShow ? resetPageStatus()}/> : <>>}
91 |
92 |
93 |
94 |
95 |
96 |
97 | );
98 | }
99 | else if(isAuth){
100 | return(
101 |
102 | )
103 | }
104 | }
--------------------------------------------------------------------------------
/src/Components/Other/navbar.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { ApiCheck } from './promises'
3 | import Nav from "react-bootstrap/Nav";
4 | import Navbar from "react-bootstrap/Navbar";
5 | import Container from "react-bootstrap/Container";
6 | import Offcanvas from 'react-bootstrap/Offcanvas'
7 | import Row from "react-bootstrap/Row";
8 | import { Link } from "react-router-dom";
9 |
10 | export function Navigation(props){
11 | const [apiStatus, setApiStatus] = useState(true)
12 |
13 | useEffect(() => {
14 | (async () => {
15 | try{
16 | let apiStatus = await ApiCheck()
17 | if(apiStatus.status === 200)
18 | setApiStatus(true)
19 | else{
20 | setApiStatus(false)
21 | }
22 | }
23 | catch{
24 | setApiStatus(false)
25 | }
26 |
27 | })()
28 | }, [props.update])
29 |
30 | return
31 |
32 |
33 |
34 |
35 |
39 |
40 | XE-Ops
41 |
42 |
43 |
44 |
45 | Home
46 | {localStorage.getItem('model') !== 'ASR' && localStorage.getItem('model') !== 'CSR' ? LayerTwo :
}
47 | Routing
48 | Env
49 | DMVPN
50 | IP Slas
51 | RibStatus
52 | Live-Interfaces
53 | Cfg/Oper
54 | Logout
55 |
56 | Connection: {props.ip}
57 | {apiStatus ? API Reachable:
58 | :
59 | API Unreachable
}
60 | {props.fetchingStatus ? Polling Status:
61 | :
62 | Polling Status:
63 | }
64 | CPU: {props.cpu['Cisco-IOS-XE-process-cpu-oper:cpu-utilization']['five-seconds']}%
65 | Memory: {props.mem['used-percent']}%
66 | Device Model/SN: {localStorage.getItem('model')} ({localStorage.getItem('serial')})
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/Components/Other/navbarError.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { ApiCheck } from './promises'
3 | import Nav from "react-bootstrap/Nav";
4 | import Navbar from "react-bootstrap/Navbar";
5 | import Container from "react-bootstrap/Container";
6 | import Offcanvas from 'react-bootstrap/Offcanvas'
7 | import Row from "react-bootstrap/Row";
8 | import { Link } from "react-router-dom";
9 |
10 | export function NavigationFallback(props){
11 | const [apiStatus, setApiStatus] = useState(true)
12 |
13 | useEffect(() => {
14 | (async () => {
15 | try{
16 | let apiStatus = await ApiCheck()
17 | if(apiStatus.status === 200)
18 | setApiStatus(true)
19 | else{
20 | setApiStatus(false)
21 | }
22 | }
23 | catch{
24 | setApiStatus(false)
25 | }
26 |
27 | })()
28 | }, [props.update])
29 |
30 | return
31 |
32 |
33 |
34 |
35 |
39 |
40 | XE-Ops
41 |
42 |
43 |
44 |
45 | Home
46 | {localStorage.getItem('model') !== 'ASR' && localStorage.getItem('model') !== 'CSR' ? LayerTwo :
}
47 | Routing
48 | Env
49 | DMVPN
50 | IP Slas
51 | RibStatus
52 | Live-Interfaces
53 | Cfg/Oper
54 | Logout
55 |
56 | Connection: {props.ip}
57 | {apiStatus ? API Reachable:
58 | :
59 | API Unreachable
}
60 | {props.fetchingStatus ? Polling Status:
61 | :
62 | Polling Status:
63 | }
64 | CPU: Err%
65 | Memory: Err%
66 | Device Model/SN: {localStorage.getItem('model')} ({localStorage.getItem('serial')})
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/Components/Other/pageLoader.js:
--------------------------------------------------------------------------------
1 | import Col from "react-bootstrap/Col";
2 | import Row from "react-bootstrap/Row";
3 | import Card from "react-bootstrap/Card";
4 | import Container from "react-bootstrap/Container";
5 |
6 | export const PageLoader = (ip, serial, model, uptime, software) => {
7 |
8 | const html =
9 |
10 |
11 |
12 |
13 |
14 | Collecting Data From {ip}
15 |
16 | Device Model/SN: {model} ({serial})
17 | Uptime: {uptime}
18 | Software: ({software})
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | return html
27 | }
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/Components/Other/promises.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | const instance = axios.create();
3 | instance.defaults.timeout = 3000;
4 |
5 | export function Login(ip, username, password) {
6 | return new Promise(resolve => {
7 | resolve(axios.post('/login', {'ip': ip, 'username': username, 'password': password, 'port': 443}, { timeout: 30000 }))}
8 | );
9 | }
10 |
11 | export function Token() {
12 | return new Promise(resolve => {
13 | resolve(axios.post('/token', {'username': 'test', 'password': 'password'}))}
14 | );
15 | }
16 |
17 |
18 | export function PollInterfaces(ip, username, password, port) {
19 | return new Promise(resolve => {
20 | setTimeout(() => {
21 | resolve(axios.post('/getinterfaces', {'ip': ip, 'username': username, 'password': password, 'port': port}));
22 | }, 2000);
23 | });
24 | }
25 |
26 | export function GetCpuStatus(ip, username, password, port) {
27 | return new Promise(resolve => {
28 | setTimeout(() => {
29 | resolve(axios.post('/cpustatus', {'ip': ip, 'username': username, 'password': password, 'port': port}));
30 | }, 2000);
31 | });
32 | }
33 |
34 | export function GetHwdStatus(ip, username, password, port) {
35 | return new Promise(resolve => {
36 | setTimeout(() => {
37 | resolve(axios.post('/hardwarestatus', {'ip': ip, 'username': username, 'password': password, 'port': port}));
38 | }, 5000);
39 | });
40 | }
41 |
42 | export function GetComponents(ip, username, password, port) {
43 | return new Promise(resolve => {
44 | setTimeout(() => {
45 | resolve(axios.post('/getcomponents', {'ip': ip, 'username': username, 'password': password, 'port': port}));
46 | }, 5000);
47 | });
48 | }
49 |
50 | export function GetDpNeighbors(ip, username, password, port) {
51 | return new Promise(resolve => {
52 | setTimeout(() => {
53 | resolve(axios.post('/neighbors', {'ip': ip, 'username': username, 'password': password, 'port': port}));
54 | }, 5000);
55 | });
56 | }
57 |
58 | export function GetVlans(ip, username, password, port) {
59 | return new Promise(resolve => {
60 | setTimeout(() => {
61 | resolve(axios.post('/vlans', {'ip': ip, 'username': username, 'password': password, 'port': port}));
62 | }, 5000);
63 | });
64 | }
65 |
66 | export function GetLayerTwoInterfaces(ip, username, password, port) {
67 | return new Promise(resolve => {
68 | setTimeout(() => {
69 | resolve(axios.post('/layertwointerfaces', {'ip': ip, 'username': username, 'password': password, 'port': port}));
70 | }, 5000);
71 | });
72 | }
73 |
74 | export function GetEnvStatus(ip, username, password, port) {
75 | return new Promise(resolve => {
76 | setTimeout(() => {
77 | resolve(axios.post('/getenvirmoment', {'ip': ip, 'username': username, 'password': password, 'port': port}));
78 | }, 5000);
79 | });
80 | }
81 |
82 | export function GetSfpStatus(ip, username, password, port) {
83 | return new Promise(resolve => {
84 | setTimeout(() => {
85 | resolve(axios.post('/sfpstatus', {'ip': ip, 'username': username, 'password': password, 'port': port}));
86 | }, 5000);
87 | });
88 | }
89 |
90 | export function GeBgpStatus(ip, username, password, port) {
91 | return new Promise(resolve => {
92 | setTimeout(() => {
93 | resolve(axios.post('/bgpstatus', {'ip': ip, 'username': username, 'password': password, 'port': port}));
94 | }, 5000);
95 | });
96 | }
97 |
98 | export function PollIndexPage(ip, username, password, port, source) {
99 | return new Promise(resolve => {
100 | setTimeout(() => {
101 | resolve(axios.post('/pollIndexPage', {'ip': ip, 'username': username, 'password': password, 'port': port}));
102 | }, 5000);
103 | });
104 | }
105 |
106 | export function PollL2Page(ip, username, password, port) {
107 | return new Promise(resolve => {
108 | setTimeout(() => {
109 | resolve(axios.post('/pollL2Page', {'ip': ip, 'username': username, 'password': password, 'port': port}));
110 | }, 5000);
111 | });
112 | }
113 |
114 | export function ApiCheck() {
115 | return new Promise(resolve => {
116 | setTimeout(() => {
117 | resolve(axios.post('/apistatus'));
118 | }, 5000);
119 | });
120 | }
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/src/Components/RibStatus/RIB-Parent.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { useQuery } from 'react-query';
3 | import Container from "react-bootstrap/Container";
4 | import Row from "react-bootstrap/Row";
5 | import Col from "react-bootstrap/Col";
6 | import {AES, enc} from 'crypto-js';
7 | import {useRecoilState} from 'recoil';
8 | import { Navigation } from '../Other/navbar';
9 | import { RibInfo} from './getRibs';
10 | import { RibDiff} from './ribDiff';
11 | import { RoutingProtocols} from './protocols';
12 | import {encytpKey} from '../../App'
13 | import { CreateCard } from '../Other/jsxCard';
14 | import { NavigationFallback } from "../Other/navbarError";
15 | import { ErrorBoundary } from 'react-error-boundary'
16 | import { PageLoader } from '../Other/pageLoader';
17 | const $ = require('jquery');
18 | $.DataTable = require('datatables.net');
19 |
20 |
21 | export function RibIndex(){
22 | const [decrypt] = useRecoilState(encytpKey);
23 | const passwordDecrypt = AES.decrypt(localStorage.getItem('password'), decrypt);
24 | const { isLoading, error, data, isFetching } = useQuery(localStorage.getItem('ip') + 'ribStatus', async () => {
25 |
26 | const response = await axios.post('/ribStatus',{'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
27 | 'password': passwordDecrypt.toString(enc.Utf8), 'port': localStorage.getItem('port')}, {'headers': { 'Authorization': 'Bearer ' + localStorage.getItem('token')}})
28 |
29 | return response.data
30 |
31 | },
32 | {
33 | refetchInterval: 10000,
34 | }
35 | )
36 |
37 | if (error){
38 | return
39 |
40 |
41 |
42 |
Error Collecting Data. I'll Keep Trying
43 |
44 |
45 | }
46 | else if (data){
47 | return
48 |
49 |
50 |
51 | {CreateCard()}
52 |
53 |
54 | {CreateCard(, "Protocols")}
55 |
56 |
57 | {CreateCard(, 'Flapping Routes')}
58 |
59 |
60 |
61 | }
62 | else if (isLoading){
63 | return
64 | {PageLoader(localStorage.getItem('ip'), localStorage.getItem('serial'), localStorage.getItem('model'), localStorage.getItem('uptime'), localStorage.getItem('software'))}
65 |
66 | }
67 |
68 | }
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/Components/RibStatus/RibMain.js:
--------------------------------------------------------------------------------
1 |
2 | import { Navbar } from '../Other/navbar'
3 | import { RibInfo} from './getRibs'
4 | import { RibDiff} from './ribDiff'
5 | import { RoutingProtocols} from './protocols'
6 | import axios from 'axios';
7 | import { useQuery } from 'react-query';
8 | import {AES, enc}from 'crypto-js';
9 | const $ = require('jquery');
10 | $.DataTable = require('datatables.net');
11 |
12 |
13 | export function RibIndex(){
14 | const passwordDecrypt = AES.decrypt(localStorage.getItem('password'), 'MYKEY4DEMO');
15 | const password = passwordDecrypt.toString(enc.Utf8);
16 | const { isLoading, error, data, isFetching } = useQuery('ribStatus', async () => {
17 |
18 | const response = await axios.post('/ribStatus',{'ip': localStorage.getItem('ip'), 'username': localStorage.getItem('username'),
19 | 'password': password, 'port': localStorage.getItem('port')}, {'headers': { 'Authorization': 'Bearer ' + localStorage.getItem('token')}})
20 |
21 | return response.data
22 |
23 | },
24 | {
25 | refetchInterval: 10000,
26 | }
27 | )
28 |
29 | if (error){
30 | return
31 |
32 | Error Collecting Data. I'll Keep Trying
33 |
34 |
35 | }
36 | else if (data){
37 | return
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | }
47 | else if (isLoading){
48 | return
49 |
Collecting RIB data from {localStorage.getItem('ip')}
50 |
51 |
52 | }
53 |
54 | }
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/Components/RibStatus/getRibs.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import Tabs from "react-bootstrap/Tabs";
3 | import Tab from "react-bootstrap/Tab";
4 | import { Ipv4RibTableHtml, Ipv6RibTableHtml } from '../Other/chartConfigs';
5 | import { Ipv4Ribs, Ipv6Ribs } from '../Other/tables';
6 | const $ = require('jquery');
7 | $.DataTable = require('datatables.net');
8 |
9 | export function RibInfo(props){
10 | const ipv4RibTableRef = React.createRef()
11 | const ipv6RibTableRef = React.createRef()
12 | const ipv4IntTable = Ipv4RibTableHtml(ipv4RibTableRef)
13 | const ipv6IntTable = Ipv6RibTableHtml(ipv6RibTableRef)
14 | $.fn.dataTable.ext.errMode = 'none';
15 |
16 | useEffect(() => {
17 |
18 | if(ipv4RibTableRef.current !== null){
19 | try{
20 | $(ipv4RibTableRef.current).DataTable().clear()
21 | $(ipv4RibTableRef.current).DataTable().rows.add(props.routes['ietf-routing:ipv4'])
22 | $(ipv4RibTableRef.current).DataTable().draw(false)
23 |
24 | $(ipv6RibTableRef.current).DataTable().clear()
25 | $(ipv6RibTableRef.current).DataTable().rows.add(props.routes['ietf-routing:ipv6'])
26 | $(ipv6RibTableRef.current).DataTable().draw(false)
27 | }
28 | catch{}
29 | }
30 |
31 | }, [props.routes])
32 |
33 |
34 | useEffect(() => {
35 | $(ipv4RibTableRef.current).DataTable().destroy()
36 | Ipv4Ribs(ipv4RibTableRef.current, props.routes['ietf-routing:ipv4'])
37 | $(ipv6RibTableRef.current).DataTable().destroy()
38 | Ipv6Ribs(ipv6RibTableRef.current, props.routes['ietf-routing:ipv6'])
39 |
40 | }, [])
41 |
42 | return
43 |
44 | {ipv4IntTable}
45 |
46 |
47 | {ipv6IntTable}
48 |
49 |
50 |
51 | };
52 |
--------------------------------------------------------------------------------
/src/Components/RibStatus/promises.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export function Login(ip, username, password, port) {
4 | return new Promise(resolve => {
5 | resolve(axios.post('/login', {'ip': ip, 'username': username, 'password': password, 'port': port}))}
6 | );
7 | }
8 |
9 | export function GetRibData(ip, username, password, port) {
10 | return new Promise(resolve => {
11 | resolve(axios.post('/index', {'ip': ip, 'username': username, 'password': password, 'port': port}));
12 | });
13 | }
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/Components/RibStatus/protocols.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { ProtocolsTableHtml } from '../Other/chartConfigs';
3 | import { RoutingProtocolData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function RoutingProtocols(props){
8 | const routingProtocolsRef = React.createRef()
9 | const routingProtocolsTable = ProtocolsTableHtml(routingProtocolsRef)
10 |
11 | useEffect(() => {
12 | $(routingProtocolsRef.current).DataTable().destroy()
13 | RoutingProtocolData(routingProtocolsRef.current, props.protocols)
14 |
15 | }, [])
16 |
17 | return routingProtocolsTable
18 |
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/src/Components/RibStatus/ribDiff.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { PlusRibEntriesTableHtml } from '../Other/chartConfigs';
3 | import { RibDiffData } from '../Other/tables';
4 | const $ = require('jquery');
5 | $.DataTable = require('datatables.net');
6 |
7 | export function RibDiff(props){
8 | const ribDiffEntries = React.createRef()
9 | const plusEntriesTable = PlusRibEntriesTableHtml(ribDiffEntries)
10 | console.log(props.ribs)
11 |
12 | useEffect(() => {
13 |
14 | if(ribDiffEntries.current !== null){
15 |
16 | try{
17 | $(ribDiffEntries.current).DataTable().clear()
18 | $(ribDiffEntries.current).DataTable().rows.add(props.ribs)
19 | $(ribDiffEntries.current).DataTable().draw(false)
20 | }
21 | catch{}
22 |
23 | }
24 |
25 | }, [props.ribs])
26 |
27 |
28 | useEffect(() => {
29 | $(ribDiffEntries.current).DataTable().destroy()
30 | RibDiffData(ribDiffEntries.current, props.ribs)
31 | }, [])
32 |
33 |
34 | return plusEntriesTable
35 |
36 | };
37 |
--------------------------------------------------------------------------------
/src/holder.rst:
--------------------------------------------------------------------------------
1 | l
2 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App.js';
5 | import { RecoilRoot, atom } from 'recoil';
6 |
7 | ReactDOM.render(
8 | ,
9 | document.getElementById('root')
10 | );
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/test/ansible.cfg:
--------------------------------------------------------------------------------
1 | [defaults]
2 |
3 | # some basic default values...
4 |
5 | inventory = inventory.yml
6 | forks=10
7 | retry_files_enabled = False
8 | callback_whitelist = profile_tasks
9 | host_key_checking = False
10 | #roles_path = ~/iosxe-ansible/roles/
11 | collections_paths = ~/.ansible/collections
12 | timeout = 60
13 | #log_path = ~/iosxe-ansible/ansible.log
14 | deprecation_warnings=False
15 | ansible_python_interpreter = /usr/bin/python3
16 |
17 |
18 |
--------------------------------------------------------------------------------
/test/ansible_config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 | from getpass import getpass
5 | from ansible import context
6 | from ansible.parsing.dataloader import DataLoader
7 | from ansible.vars.manager import VariableManager
8 | from ansible.inventory.manager import InventoryManager
9 | from ansible.executor.playbook_executor import PlaybookExecutor
10 | from ansible.module_utils.common.collections import ImmutableDict
11 |
12 | loader = DataLoader()
13 | inventory = InventoryManager(loader=loader, sources='/home/appdeveloper/react-xe-ops-testing/BackEndModeules/AnsiblePlaybooks/inventory.yml')
14 | variable_manager = VariableManager(loader=loader, inventory=inventory)
15 |
16 | def interface_configurations(config_data) -> str:
17 |
18 | variable_manager._extra_vars = {"ip_interfaces": [
19 | {
20 | "intf_name": config_data.get('name'),
21 | "intf_description": config_data.get('description'),
22 | "intf_ipv4": config_data.get('ip'),
23 | "intf_ipv4_mask": config_data.get('mask'),
24 | "intf_speed": config_data.get('speed'),
25 | "port_status": config_data.get('portStatus')
26 | }
27 | ]
28 | }
29 | playbook_path = '/home/appdeveloper/react-xe-ops-testing/BackEndModeules/AnsiblePlaybooks/intf_playbook.yml'
30 |
31 | if not os.path.exists(playbook_path):
32 | print('[ERROR] The playbook does not exist')
33 | sys.exit()
34 |
35 | context.CLIARGS = ImmutableDict(tags={},
36 | listtags=False,
37 | listtasks=False,
38 | listhosts=False,
39 | syntax=False,
40 | connection='smart',
41 | module_path=None,
42 | forks=100,
43 | #remote_user='developer',
44 | # remote_pass=password,
45 | private_key_file=None,
46 | ssh_common_args=None,
47 | ssh_extra_args=None,
48 | sftp_extra_args=None,
49 | scp_extra_args=None,
50 | become=False, # 'True'
51 | become_method=None, # 'sudo'
52 | become_user=None, # 'root'
53 | verbosity=True,
54 | check=False,
55 | start_at_task=None)
56 |
57 | results = execute_ansible_playbook(playbook_path, variable_manager)
58 |
59 | return results
60 |
61 | def execute_ansible_playbook(playbook_path, variable_manager) -> str:
62 | play_ex = PlaybookExecutor(playbooks=[playbook_path], inventory=inventory, variable_manager=variable_manager, loader=loader, passwords={})
63 | results = play_ex.run()
64 |
65 | return results
66 |
--------------------------------------------------------------------------------
/test/ansible_config_new.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import ansible_runner
4 | import json
5 |
6 | def playbook_runner(config_data) -> dict:
7 | """
8 | Run the playbook defined in the function,
9 | extravars will come via config_date dict
10 | variable.
11 | """
12 | runner = ansible_runner.run(
13 | private_data_dir='/home/appdeveloper/react-xe-ops-testing/BackEndModeules/AnsiblePlaybooks/',
14 | playbook='intf_playbook.yml',
15 | inventory='inventory.yml',
16 | envvars='',
17 | extravars= {"ip_interfaces": [
18 | {
19 | "intf_name": config_data.get('name'),
20 | "intf_description": config_data.get('description'),
21 | "intf_ipv4": config_data.get('ip'),
22 | "intf_ipv4_mask": config_data.get('mask'),
23 | "intf_speed": config_data.get('speed'),
24 | "port_status": config_data.get('portStatus')
25 | }
26 | ]
27 | }
28 | )
29 |
30 | stdout = runner.stdout.read()
31 | stdout_lines = runner.stdout.readlines()
32 | events = list(runner.events)
33 | stats = runner.stats
34 | job_status = runner.status
35 |
36 | # print(json.dumps(stats, indent=4))
37 | # print(job_status)
38 |
39 | for event in runner.events:
40 | event_data = event['event_data']
41 | if 'host' in event_data:
42 | host = event_data['host']
43 |
44 | for event in runner.events:
45 | event_data = event['event_data']
46 | if 'res' in event_data:
47 | resp = event_data['res']
48 | if 'intf_config.updates' in resp:
49 | updates = resp['intf_config.updates']
50 | msg_data = json.dumps(updates, indent=4) ## green
51 | if 'msg' in resp:
52 | updates = resp['msg']
53 | msg_data = json.dumps(updates, indent=4) ## red
54 |
55 | if job_status == 'successful':
56 | status = f"{host} has been configured successfully." # green
57 |
58 | if job_status == 'failed':
59 | status = f"[Error]: {host} changes are failed"
60 |
61 | return {"config_data": updates, "status": job_status}
62 |
63 |
--------------------------------------------------------------------------------
/test/bgp_config.j2:
--------------------------------------------------------------------------------
1 | router bgp {{ bgp.local_as }}
2 | bgp router-id {{ bgp.router_id }}
3 | neighbor {{ bgp.neighbor }} remote-as {{ bgp.remote_as }}
4 | address-family ipv4 unicast
5 | {% if bgp.route_map is not none and 'routeMap' in bgp.route_map_key %}
6 | neighbor {{ bgp.neighbor }} route-map {{ bgp.route_map }} {{ bgp.direction }}
7 | {% elif bgp.prefix_list is not none and 'prefixList' in bgp.prefix_list_key %}
8 | neighbor {{ bgp.neighbor }} prefix-list {{ bgp.prefix_list }} {{ bgp.direction }}
9 | {% endif %}
10 | exit-address-family
11 |
--------------------------------------------------------------------------------
/test/bgp_config.yml:
--------------------------------------------------------------------------------
1 | - name: IOSXE CONFIGURATION CONFIG VIA JINJA
2 | hosts: sandbox-iosxe-latest-1.cisco.com
3 | gather_facts: false
4 | connection: network_cli
5 |
6 | tasks:
7 | - name: Configure BGP on IOS-XE via jinja2 tempalte
8 | ios_config:
9 | backup: no
10 | src: bgp_config.j2
11 | when:
12 | - ansible_network_os == 'ios'
13 | register: bgp_config
14 |
15 | - name: Getting the interface configuration
16 | debug:
17 | var: bgp_config.updates
18 |
--------------------------------------------------------------------------------
/test/bgp_config_script.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import ansible_runner
4 | import json
5 |
6 | def playbook_runner(config_data) -> dict:
7 | """
8 | Run the playbook defined in the function,
9 | extravars will come via config_date dict
10 | variable.
11 | """
12 |
13 | runner = ansible_runner.interface.run(
14 | private_data_dir='/home/appdeveloper/react-xe-ops-testing/BackEndModeules/AnsiblePlaybooks/',
15 | playbook='bgp_config.yml',
16 | inventory='inventory.yml',
17 | extravars = {"bgp":
18 | {
19 | "local_as": config_data.get('localAs'),
20 | "router_id": config_data.get('routerId'),
21 | "neighbor": config_data.get('neighbor'),
22 | "remote_as": config_data.get('remoteAs'),
23 | "prefix_list": config_data.get('policyType').split(':')[0],
24 | "prefix_list_key": config_data.get('policyType').split(':')[1],
25 | "route_map": config_data.get('policyType').split(':')[0],
26 | "route_map_key": config_data.get('policyType').split(':')[1],
27 | "direction": config_data.get('policyDirection')
28 | }
29 | }
30 | )
31 |
32 |
33 | stdout = runner.stdout.read()
34 | stdout_lines = runner.stdout.readlines()
35 | events = list(runner.events)
36 | stats = runner.stats
37 | job_status = runner.status
38 |
39 | # print(json.dumps(stats, indent=4))
40 | # print(job_status)
41 |
42 | for event in runner.events:
43 | event_data = event['event_data']
44 | if 'host' in event_data:
45 | host = event_data['host']
46 |
47 | for event in runner.events:
48 | event_data = event['event_data']
49 | if 'res' in event_data:
50 | resp = event_data['res']
51 | if 'bgp_config.updates' in resp:
52 | updates = resp['bgp_config.updates']
53 | msg_data = json.dumps(updates, indent=4)
54 | if 'msg' in resp:
55 | updates = resp['msg']
56 | msg_data = json.dumps(updates, indent=4)
57 |
58 | if job_status == 'successful':
59 | status = f"{host} has been configured successfully."
60 |
61 | if job_status == 'failed':
62 | status = f"[Error]: {host} changes are failed"
63 |
64 | return {"config_data": updates, "status": job_status}
65 |
--------------------------------------------------------------------------------
/test/intf_config.j2:
--------------------------------------------------------------------------------
1 | {% for item in ip_interfaces %}
2 | interface {{ item.intf_name }}
3 | {% if item.intf_description is not none %}
4 | description {{ item.intf_description }}
5 | {% endif %}
6 | {% if item.intf_ipv4 is not none %}
7 | ip address {{ item.intf_ipv4 }} {{ item.intf_ipv4_mask }}
8 | {% else %}
9 | no ip address
10 | {% endif %}
11 | {% if item.intf_speed is not none %}
12 | no negotiation auto
13 | speed {{ item.intf_speed }}
14 | {% endif %}
15 | {% if item.port_status == "up" %}
16 | no shutdown
17 | {% elif item.port_status == "down" %}
18 | shutdown
19 | {% endif %}
20 | exit
21 | {% endfor %}
22 |
23 |
--------------------------------------------------------------------------------
/test/intf_config.j2.bak:
--------------------------------------------------------------------------------
1 | {% for item in ip_interfaces %}
2 | interface {{ item.intf_name }}
3 | {% if item.intf_description is not none %}
4 | description {{ item.intf_description }}
5 | {% endif %}
6 | {% if item.intf_ipv4 is not none %}
7 | ip address {{ item.intf_ipv4 }} {{ item.intf_ipv4_mask }}
8 | {% endif %}
9 | {% if item.intf_speed is not none %}
10 | speed {{ item.intf_speed }}
11 | {% endif %}
12 | {% if item.port_status == "up" %}
13 | no shutdown
14 | {% elif item.port_status == "down" %}
15 | shutdown
16 | {% endif %}
17 | exit
18 | {% endfor %}
19 |
--------------------------------------------------------------------------------
/test/intf_config_vars.yml:
--------------------------------------------------------------------------------
1 | ---
2 | ip_interfaces:
3 | - intf_name:
4 | intf_description:
5 | intf_ipv4:
6 | intf_ipv4_mask:
7 | intf_speed:
8 | port_status:
9 |
--------------------------------------------------------------------------------
/test/intf_playbook.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: IOSXE CONFIGURATION CONFIG VIA JINJA
3 | hosts: IOSXE
4 | connection: local
5 | gather_facts: no
6 | # vars_files:
7 | # - intf_config_vars.yml
8 |
9 | # ansible-playbook -i inventory.yml intf_playbook.yml
10 | #
11 | tasks:
12 | #- name: Generate IOS-XE Interfaces Config
13 | # template:
14 | # src: "{{ item.src }}"
15 | # dest: "{{ item.dest }}"
16 | # mode: 0777
17 | # with_items:
18 | # - {src: 'intf_config.j2', dest: 'intf_config_output.cfg'}
19 | # register: output
20 |
21 | - name: Configure IOS-XE device vi a Jinja2 template
22 | ios_config:
23 | # backup: yes
24 | # src: intf_config_output.cfg
25 | src: intf_config.j2
26 | when:
27 | - ansible_network_os == 'ios'
28 | register: intf_config
29 |
30 | - name: Getting the interface configuration
31 | debug:
32 | var: intf_config.updates
33 |
34 |
--------------------------------------------------------------------------------
/test/inventory.yml:
--------------------------------------------------------------------------------
1 | ---
2 | all:
3 | children:
4 | IOSXE:
5 | hosts:
6 | sandbox-iosxe-latest-1.cisco.com:
7 | ansible_host: 131.226.217.143
8 | ansible_network_os: ios
9 | ansible_password: C1sco12345
10 | ansible_user: developer
11 | ungrouped: {}
12 |
--------------------------------------------------------------------------------
/test/my_file.out:
--------------------------------------------------------------------------------
1 |
2 | Welcome to the DevNet Sandbox for CSR1000v and IOS XE
3 |
4 | The following programmability features are already enabled:
5 | - NETCONF
6 | - RESTCONF
7 |
8 | Thanks for stopping by.
9 |
10 |
11 | csr1000v-1#terminal width 511
12 | csr1000v-1#terminal length 0
13 | csr1000v-1#
14 | csr1000v-1#
15 | csr1000v-1#show standby brief | ex Interface
16 |
17 | csr1000v-1#
18 | csr1000v-1#exit
19 |
--------------------------------------------------------------------------------
/test/ospf_config.j2:
--------------------------------------------------------------------------------
1 | {% if ospf.vrf is not none %}
2 | router ospfv3 {{ ospf.process_id }}
3 | address-faimily ipv4 unicast vrf {ospf.vrf}
4 | {% if ospf.network is not none %}
5 | network {{ ospf.network }} {{ ospf.wildcard }} area {{ ospf.area }}
6 | {%endif%}
7 | {% if ospf.area_type is not none %}
8 | area {{ ospf.area }} {{ ospf.area_type }}
9 | {%endif%}
10 |
11 |
12 | {%else%}
13 | router ospf {{ ospf.process_id }}
14 | {%endif%}
15 | {% if ospf.network is not none %}
16 | network {{ ospf.network }} {{ ospf.wildcard }} area {{ ospf.area }}
17 | {%endif%}
18 | {% if ospf.area_type is not none %}
19 | area {{ ospf.area }} {{ ospf.area_type }}
20 | {%endif%}
21 |
22 |
--------------------------------------------------------------------------------
/test/ospf_config.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import ansible_runner
4 | import json
5 |
6 | def playbook_runner(config_data) -> dict:
7 | print(config_data)
8 | """
9 | Run the playbook defined in the function,
10 | extravars will come via config_date dict
11 | variable.
12 | """
13 |
14 | runner = ansible_runner.interface.run(
15 | private_data_dir='/home/appdeveloper/react-xe-ops-testing/BackEndModeules/AnsiblePlaybooks/',
16 | playbook='ospf_config.yml',
17 | inventory='inventory.yml',
18 | extravars = {"ospf":
19 | {
20 | "router_id": config_data.get('routerId'),
21 | "process_id": config_data.get('process'),
22 | "network": config_data.get('network'),
23 | "wildcard": config_data.get('wildcard'),
24 | "area": config_data.get('area'),
25 | "area_type": config_data.get('areaType'),
26 | "vrf": config_data.get('vrf'),
27 |
28 | }
29 | }
30 | )
31 |
32 |
33 | stdout = runner.stdout.read()
34 | stdout_lines = runner.stdout.readlines()
35 | events = list(runner.events)
36 | stats = runner.stats
37 | job_status = runner.status
38 |
39 | # print(json.dumps(stats, indent=4))
40 | # print(job_status)
41 |
42 | for event in runner.events:
43 | event_data = event['event_data']
44 | if 'host' in event_data:
45 | host = event_data['host']
46 |
47 | for event in runner.events:
48 | event_data = event['event_data']
49 | if 'res' in event_data:
50 | resp = event_data['res']
51 | if 'ospf_config.updates' in resp:
52 | updates = resp['ospf_config.updates']
53 | msg_data = json.dumps(updates, indent=4)
54 | if 'msg' in resp:
55 | updates = resp['msg']
56 | msg_data = json.dumps(updates, indent=4)
57 |
58 | if job_status == 'successful':
59 | status = f"{host} has been configured successfully."
60 |
61 | if job_status == 'failed':
62 | status = f"[Error]: {host} changes are failed"
63 |
64 | return {"config_data": updates, "status": job_status}
65 |
--------------------------------------------------------------------------------
/test/ospf_config.yml:
--------------------------------------------------------------------------------
1 | - name: IOSXE CONFIGURATION CONFIG VIA JINJA
2 | hosts: sandbox-iosxe-latest-1.cisco.com
3 | gather_facts: false
4 | connection: network_cli
5 |
6 | tasks:
7 | - name: Configure OSPF on IOS-XE via jinja2 tempalte
8 | ios_config:
9 | backup: no
10 | src: ospf_config.j2
11 | when:
12 | - ansible_network_os == 'ios'
13 | register: ospf_config
14 |
15 | - name: Getting the ospf configuration
16 | debug:
17 | var: ospf_config.updates
18 |
--------------------------------------------------------------------------------
/test/requirements.txt:
--------------------------------------------------------------------------------
1 | requests
2 | flask
3 | flask_jwt_extended
4 | netmiko
5 | ipapi
6 | SQLAlchemy
7 | gunicorn
8 | ansible==2.9.16
9 | ansible-runner
10 |
--------------------------------------------------------------------------------
/test/show_version.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - name: SHOW IOSXE VERSION
3 | hosts: "{{ target_hosts|default('localhost') }}"
4 | connection: local
5 | gather_facts: no
6 |
7 | # ansible-playbook -i inventory.yml -e target_hosts=sandbox-iosxe-latest-1.cisco.com show_version.yml
8 |
9 | tasks:
10 | - name: GET THE IOS-XE SOFTWARE VERSION
11 | ios_command:
12 | commands: show version
13 | wait_for: result[0] contains IOS
14 | register: ios_version
15 |
16 | - name: SHOW THE IOS-XE SOFTWARE VERSION
17 | debug:
18 | msg:
19 | - "{{ ios_version }}"
20 | # - "{{ ios_version.stdout_lines[0][0] }}"
21 |
--------------------------------------------------------------------------------
/test/test.rst:
--------------------------------------------------------------------------------
1 | ddd
2 |
--------------------------------------------------------------------------------
/test/wsgi.py:
--------------------------------------------------------------------------------
1 | from api_routes import app
2 | import os
3 | import ssl
4 |
5 | ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
6 | ctx.load_cert_chain(f'{os.getcwd()}/domainame.crt', f'{os.getcwd()}/domainame.key')
7 |
8 | if __name__ == "__main__":
9 | app.run(ssl_context=ctx)
10 |
--------------------------------------------------------------------------------
/test/yang_conversions.py:
--------------------------------------------------------------------------------
1 | import os, subprocess
2 | import time
3 |
4 | yang_dir = f"{os.getcwd()}/yangFiles"
5 |
6 | def get_yang():
7 |
8 | global yang_dir
9 |
10 | files = [yang_file for yang_file in os.listdir(yang_dir) if yang_file.endswith(".yang")]
11 |
12 | return files
13 |
14 |
15 | def get_standard_tree(model):
16 |
17 |
18 | get_model = subprocess.run(["pyang", "-f", "tree", f"{yang_dir}/{model}"], capture_output=True)
19 | model_stdout = str(get_model.stdout, 'utf-8')
20 |
21 | return model_stdout
22 |
23 |
24 | def get_dynamic_tree(model):
25 |
26 | process = subprocess.Popen(['pyang', '-f', 'jstree', '-o', f"{yang_dir}/jstree.html" , f'{model}'], shell=False)
27 |
28 | while process.poll() is None:
29 | time.sleep(1)
30 |
31 | return process.poll()
32 |
33 |
34 | def get_yin(model):
35 |
36 | process = subprocess.Popen(['pyang', '-f', 'yin', '-o', f"{yang_dir}/yin.xml" , f'{yang_dir}/{model}'], shell=False)
37 |
38 | while process.poll() is None:
39 | time.sleep(1)
40 |
41 | yin_file = open(f"{yang_dir}/yin.xml")
42 |
43 | return yin_file.read()
44 |
45 | def get_xpaths(model):
46 |
47 | get_model = subprocess.run(["pyang", "-f", "xpath", f"{yang_dir}/{model}"], capture_output=True)
48 | model_stdout = str(get_model.stdout, 'utf-8')
49 | print(model_stdout)
50 |
51 | return model_stdout
52 |
--------------------------------------------------------------------------------