diff --git a/.flask_cache/0cc005a225d064a6216a21c390e8fd8f b/.flask_cache/0cc005a225d064a6216a21c390e8fd8f new file mode 100644 index 0000000..788cb21 Binary files /dev/null and b/.flask_cache/0cc005a225d064a6216a21c390e8fd8f differ diff --git a/.flask_cache/1fc39e56a58c627ed59c0d0523e808e2 b/.flask_cache/1fc39e56a58c627ed59c0d0523e808e2 new file mode 100644 index 0000000..d7f3b14 Binary files /dev/null and b/.flask_cache/1fc39e56a58c627ed59c0d0523e808e2 differ diff --git a/.flask_cache/2029240f6d1128be89ddc32729463129 b/.flask_cache/2029240f6d1128be89ddc32729463129 index 19194ee..5815809 100644 Binary files a/.flask_cache/2029240f6d1128be89ddc32729463129 and b/.flask_cache/2029240f6d1128be89ddc32729463129 differ diff --git a/.flask_cache/379a23d6e49ea74418d51711a36df194 b/.flask_cache/379a23d6e49ea74418d51711a36df194 new file mode 100644 index 0000000..42123ed Binary files /dev/null and b/.flask_cache/379a23d6e49ea74418d51711a36df194 differ diff --git a/.flask_cache/5e8887a448534e50af390288650930ea b/.flask_cache/5e8887a448534e50af390288650930ea new file mode 100644 index 0000000..6d142c9 Binary files /dev/null and b/.flask_cache/5e8887a448534e50af390288650930ea differ diff --git a/.flask_cache/632595e1de107e8f891d3cf18b102ff1 b/.flask_cache/632595e1de107e8f891d3cf18b102ff1 new file mode 100644 index 0000000..3b22b1d Binary files /dev/null and b/.flask_cache/632595e1de107e8f891d3cf18b102ff1 differ diff --git a/.flask_cache/74bc75c0764cbc805c70645cef1f026b b/.flask_cache/74bc75c0764cbc805c70645cef1f026b index e7d10b7..180e4b3 100644 Binary files a/.flask_cache/74bc75c0764cbc805c70645cef1f026b and b/.flask_cache/74bc75c0764cbc805c70645cef1f026b differ diff --git a/.flask_cache/c10d865004bdf7e67dcf50a6039073dd b/.flask_cache/c10d865004bdf7e67dcf50a6039073dd new file mode 100644 index 0000000..09cd911 Binary files /dev/null and b/.flask_cache/c10d865004bdf7e67dcf50a6039073dd differ diff --git a/.flask_cache/c9a8ada7d4e04353536dc74ceb1b08e2 b/.flask_cache/c9a8ada7d4e04353536dc74ceb1b08e2 new file mode 100644 index 0000000..702cf88 Binary files /dev/null and b/.flask_cache/c9a8ada7d4e04353536dc74ceb1b08e2 differ diff --git a/.flask_cache/d277c4e120e0e4b7fa8f80455a32af2e b/.flask_cache/d277c4e120e0e4b7fa8f80455a32af2e new file mode 100644 index 0000000..35f7f75 Binary files /dev/null and b/.flask_cache/d277c4e120e0e4b7fa8f80455a32af2e differ diff --git a/.flask_cache/e6dad9c79446e7c35963c49fd05507d6 b/.flask_cache/e6dad9c79446e7c35963c49fd05507d6 new file mode 100644 index 0000000..44dfb58 Binary files /dev/null and b/.flask_cache/e6dad9c79446e7c35963c49fd05507d6 differ diff --git a/.flask_cache/e9ad28e2141cab0361d67aef3520c6f7 b/.flask_cache/e9ad28e2141cab0361d67aef3520c6f7 new file mode 100644 index 0000000..f68511c Binary files /dev/null and b/.flask_cache/e9ad28e2141cab0361d67aef3520c6f7 differ diff --git a/hyperglass/command/construct.py b/hyperglass/command/construct.py index 4836b2d..9c472b8 100644 --- a/hyperglass/command/construct.py +++ b/hyperglass/command/construct.py @@ -3,12 +3,11 @@ import sys import toml import logging from netaddr import * -from loguru import logger +from logzero import logger # Local imports from hyperglass import configuration -log = logging.getLogger(__name__) # Load TOML config file devices = configuration.devices() @@ -18,13 +17,10 @@ commands = configuration.commands() # Filter config to router list routers_list = devices["router"] -logger.add(sys.stderr) - # Receives JSON from Flask, constucts the command that will be passed to the router # Also handles input validation & error handling def construct(router, cmd, ipprefix): - input_params = (router, cmd, ipprefix) - logger.info(*input_params) + logger.info(f"Constructing {cmd} command for {router} to {ipprefix}...") try: # Loop through routers config file, match input router with configured routers, set variables for r in routers_list: @@ -47,8 +43,10 @@ def construct(router, cmd, ipprefix): if cmd == "Query Type": msg = "You must select a query type." code = 415 - logger.error(msg, code, *input_params) - return (msg, code) + logger.error( + f"{msg}, {code}, {router}, {cmd}, {ipprefix}" + ) + return (msg, code, router, cmd, ipprefix) # BGP Community Query elif cmd in ["bgp_community"]: # Extended Communities, new-format @@ -56,26 +54,18 @@ def construct(router, cmd, ipprefix): for a, c in dual_commands.items(): if a == cmd: command = c.format(target=ipprefix) - msg = "{i} matched new-format community.".format( - i=ipprefix - ) + msg = f"{ipprefix} matched new-format community." code = 200 - logger.warning( - msg, code, router, type, command - ) return (msg, code, router, type, command) # Extended Communities, 32 bit format elif re.match("^[0-9]{1,10}$", ipprefix): for a, c in dual_commands.items(): if a == cmd: command = c.format(target=ipprefix) - msg = "{i} matched 32 bit community.".format( - i=ipprefix + msg = ( + f"{ipprefix} matched 32 bit community." ) code = 200 - logger.warning( - msg, code, router, type, command - ) return (msg, code, router, type, command) # RFC 8092 Large Community Support elif re.match( @@ -85,42 +75,32 @@ def construct(router, cmd, ipprefix): for a, c in dual_commands.items(): if a == cmd: command = c.format(target=ipprefix) - msg = "{i} matched large community.".format( - i=ipprefix - ) + msg = f"{ipprefix} matched large community." code = 200 - logger.warning( - msg, code, router, type, command - ) return (msg, code, router, type, command) - else: - msg = "{i} is an invalid BGP Community Format.".format( - i=ipprefix - ) - code = 415 - logger.error(msg, code, *input_params) - return (msg, code) + else: + msg = f"{ipprefix} is an invalid BGP Community Format." + code = 415 + logger.error( + f"{msg}, {code}, {router}, {cmd}, {ipprefix}" + ) + return (msg, code, router, cmd, ipprefix) # BGP AS_PATH Query elif cmd in ["bgp_aspath"]: if re.match(".*", ipprefix): for a, c in dual_commands.items(): if a == cmd: command = c.format(target=ipprefix) - msg = "{i} matched AS_PATH regex.".format( - i=ipprefix - ) + msg = f"{ipprefix} matched AS_PATH regex." code = 200 - logger.warning( - msg, code, router, type, command - ) return (msg, code, router, type, command) else: - msg = "{i} is an invalid AS_PATH regex.".format( - i=ipprefix - ) + msg = f"{ipprefix} is an invalid AS_PATH regex." code = 415 - logger.error(msg, code, *input_params) - return (msg, code) + logger.error( + f"{msg}, {code}, {router}, {cmd}, {ipprefix}" + ) + return (msg, code, router, cmd, ipprefix) # BGP Route Query elif cmd in ["bgp_route"]: try: @@ -129,13 +109,8 @@ def construct(router, cmd, ipprefix): for a, c in ipv4_commands.items(): if a == cmd: command = c.format(target=ipprefix) - msg = "{i} is a valid IPv4 Adddress.".format( - i=ipprefix - ) + msg = f"{ipprefix} is a valid IPv4 Adddress." code = 200 - logger.warning( - msg, code, router, type, command - ) return ( msg, code, @@ -148,13 +123,8 @@ def construct(router, cmd, ipprefix): for a, c in ipv6_commands.items(): if a == cmd: command = c.format(target=ipprefix) - msg = "{i} is a valid IPv6 Adddress.".format( - i=ipprefix - ) + msg = f"{ipprefix} is a valid IPv6 Adddress." code = 200 - logger.warning( - msg, code, router, type, command - ) return ( msg, code, @@ -164,12 +134,12 @@ def construct(router, cmd, ipprefix): ) # Exception from netaddr library will return a user-facing error except: - msg = "{i} is an invalid IP Address.".format( - i=ipprefix - ) + msg = f"{ipprefix} is an invalid IP Address." code = 415 - logger.error(msg, code, *input_params) - return (msg, code) + logger.error( + f"{msg}, {code}, {router}, {cmd}, {ipprefix}" + ) + return (msg, code, router, cmd, ipprefix) # Ping/Traceroute elif cmd in ["ping", "traceroute"]: try: @@ -180,13 +150,8 @@ def construct(router, cmd, ipprefix): target=ipprefix, src_addr_ipv4=src_addr_ipv4, ) - msg = "{i} is a valid IPv4 Adddress.".format( - i=ipprefix - ) + msg = f"{ipprefix} is a valid IPv4 Adddress." code = 200 - logger.warning( - msg, code, router, type, command - ) return ( msg, code, @@ -201,13 +166,8 @@ def construct(router, cmd, ipprefix): target=ipprefix, src_addr_ipv6=src_addr_ipv6, ) - msg = "{i} is a valid IPv6 Adddress.".format( - i=ipprefix - ) + msg = f"{ipprefix} is a valid IPv6 Adddress." code = 200 - logger.warning( - msg, code, router, type, command - ) return ( msg, code, @@ -216,22 +176,23 @@ def construct(router, cmd, ipprefix): command, ) except: - msg = "{i} is an invalid IP Address.".format( - i=ipprefix - ) + msg = f"{ipprefix} is an invalid IP Address." code = 415 - logger.error(msg, code, *input_params) - return (msg, code) + logger.error( + f"{msg}, {code}, {router}, {cmd}, {ipprefix}" + ) + return (msg, code, router, cmd, ipprefix) else: - msg = "Command {i} not found.".format(i=cmd) + msg = f"Command {cmd} not found." code = 415 - logger.error(msg, code, *input_params) - return (msg, code) + logger.error( + f"{msg}, {code}, {router}, {cmd}, {ipprefix}" + ) + return (msg, code, router, cmd, ipprefix) except: + router_ip = r["address"] error_msg = logger.error( - "Input router IP {router} does not match the configured router IP of {ip}".format( - router=router, ip=r["address"] - ) + f"Input router IP {router} does not match the configured router IP of {router_ip}" ) raise ValueError(error_msg) except: diff --git a/hyperglass/command/execute.py b/hyperglass/command/execute.py index 6028152..523f756 100644 --- a/hyperglass/command/execute.py +++ b/hyperglass/command/execute.py @@ -1,7 +1,7 @@ import sys import time from netaddr import * -from loguru import logger +from logzero import logger from netmiko import redispatch from netmiko import ConnectHandler from hyperglass import configuration @@ -22,35 +22,36 @@ blacklist = IPSet(blacklist_config["blacklist"]) general_error = "Error connecting to device." -logger.add(sys.stderr) - def execute(lg_data): - logger.info(lg_data) + logger.info(f"Received lookup request for: {lg_data}") # Check POST data from JS, if location matches a configured router's # location, use the router's configured IP address to connect + router = lg_data["router"] + cmd = lg_data["cmd"] + ipprefix = lg_data["ipprefix"] + for r in routers_list: - if r["location"] == lg_data["router"]: + if r["location"] == router: lg_router_address = r["address"] # Check blacklist.toml array for prefixes/IPs and return an error upon a match - if lg_data["cmd"] in ["bgp_route", "ping", "traceroute"]: + if cmd in ["bgp_route", "ping", "traceroute"]: try: - if IPNetwork(lg_data["ipprefix"]).ip in blacklist: - msg = "{i} is not allowed.".format(i=lg_data["ipprefix"]) + if IPNetwork(ipprefix).ip in blacklist: + msg = f"{ipprefix} is not allowed." code = 405 - logger.error(msg, code, lg_data) + logger.error(f"{msg}, {code}, {lg_data}") return (msg, code, lg_data) # If netaddr library throws an exception, return a user-facing error. except: - msg = "{i} is not a valid IP Address.".format(i=lg_data["ipprefix"]) + msg = f"{ipprefix} is not a valid IP Address." code = 415 - logger.error(msg, code, lg_data) + logger.error(f"{msg}, {code}, {lg_data}") return (msg, code, lg_data) # Send "clean" request to constructor to build the command that will be sent to the router - print(lg_router_address) msg, status, router, type, command = construct.construct( - lg_router_address, lg_data["cmd"], lg_data["ipprefix"] + lg_router_address, cmd, ipprefix ) # Loop through proxy config, match configured proxy name for each router with a configured proxy # Return configured proxy parameters for netmiko @@ -71,7 +72,7 @@ def execute(lg_data): else: msg = "Router does not have a proxy configured." code = 415 - logger.error(msg, code, lg_data) + logger.error(f"{msg}, {code}, {lg_data}") return (msg, code, lg_data) # Matches router with configured credential @@ -88,9 +89,9 @@ def execute(lg_data): matched_password = credentials_list[configured_credential]["password"] return matched_username, matched_password else: - msg = "Credential {i} does not exist".format(i=configured_credential) + msg = f"Credential {configured_credential} does not exist" code = 415 - logger.error(msg, code, lg_data) + logger.error(f"{msg}, {code}, {lg_data}") return (general_error, code, lg_data) # Connect to the router via netmiko library, return the command output @@ -100,9 +101,9 @@ def execute(lg_data): nm_output_direct = nm_connect_direct.send_command(command) return nm_output_direct except: - msg = "Unable to reach target {l}".format(l=lg_data["router"]) + msg = f"Unable to reach target {router}" code = 415 - logger.error(msg, code, lg_data) + logger.error(f"{msg}, {code}, {lg_data}") return (general_error, code, lg_data) # Connect to the proxy server via netmiko library, then log into the router @@ -137,11 +138,9 @@ def execute(lg_data): if host_output: return host_output except: - msg = "Proxy server {p} unable to reach target {d}".format( - p=nm_proxy["host"], d=nm_host["host"] - ) + msg = f'Proxy server {nm_proxy["host"]} unable to reach target {nm_host["host"]}' code = 415 - logger.error(msg, code, lg_data) + logger.error(f"{msg}, {code}, {lg_data}") return (general_error, code, lg_data) nm_host = { @@ -160,14 +159,15 @@ def execute(lg_data): else: connection_proxied = True if status == 200: + logger.info(f"Executing {command} on {router}...") try: if connection_proxied is True: output_proxied = getOutputProxy(configured_proxy) - parsed_output = parse.parse(output_proxied, type, lg_data["cmd"]) + parsed_output = parse.parse(output_proxied, type, cmd) return parsed_output, status, router, type, command elif connection_proxied is False: output_direct = getOutputDirect() - parsed_output = parse.parse(output_direct, type, lg_data["cmd"]) + parsed_output = parse.parse(output_direct, type, cmd) return parsed_output, status, router, type, command except: raise diff --git a/hyperglass/configuration/__init__.py b/hyperglass/configuration/__init__.py index 0bab6fd..e94130e 100644 --- a/hyperglass/configuration/__init__.py +++ b/hyperglass/configuration/__init__.py @@ -32,7 +32,7 @@ def devices(): def requires_ipv6_cidr(): f = os.path.join(dir, "requires_ipv6_cidr.toml") t = toml.load(f) - return t + return t["requires_ipv6_cidr"] # Filter config to branding variables diff --git a/hyperglass/hyperglass.py b/hyperglass/hyperglass.py index 1881bb2..fbdac82 100644 --- a/hyperglass/hyperglass.py +++ b/hyperglass/hyperglass.py @@ -2,7 +2,7 @@ import sys import json import toml -from loguru import logger +from logzero import logger from flask import Flask, request, Response, jsonify, flash from flask_caching import Cache from flask_limiter import Limiter @@ -13,8 +13,6 @@ from hyperglass import render from hyperglass import configuration from hyperglass.command import execute -logger.add(sys.stderr) - # Load TOML config file devices = configuration.devices() # Filter config file to list of routers & subsequent configurations @@ -130,17 +128,14 @@ def lg(): # Check if cached entry exists if cache.get(cache_key) is None: cache_value = execute.execute(lg_data) - logger.info(cache_value[1:]) value_output = cache_value[0] value_code = cache_value[1] value_params = cache_value[2:] - logger.info("No cache match for: {cache_key}".format(cache_key=cache_key)) + logger.info(f"No cache match for: {cache_key}") # If it doesn't, create a cache entry try: cache.set(cache_key, value_output) - logger.info( - "Added cache entry: {value_params}".format(value_params=value_params) - ) + logger.info(f"Added cache entry: {value_params}") except: raise RuntimeError("Unable to add output to cache.", 415, *value_params) # If 200, return output @@ -151,11 +146,7 @@ def lg(): return Response(cache.get(cache_key), value_code) # If it does, return the cached entry else: - logger.info( - "Cache match for: {cache_key}, returning cached entry...".format( - cache_key=cache_key - ) - ) + logger.info(f"Cache match for: {cache_key}, returning cached entry...") try: return cache.get(cache_key) except: diff --git a/requirements.txt b/requirements.txt index 1ffd03f..698cc5d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,4 @@ netmiko netaddr markdown2 libsass -loguru +logzero