forked from mirrors/thatmattlove-hyperglass
all user facing errors now customizable
This commit is contained in:
parent
4c72ad0814
commit
0174e58692
6 changed files with 73 additions and 102 deletions
|
|
@ -11,6 +11,7 @@ from hyperglass import configuration
|
|||
|
||||
|
||||
code = configuration.codes()
|
||||
g = configuration.general()
|
||||
|
||||
|
||||
def frr(cmd, ipprefix, device):
|
||||
|
|
@ -39,7 +40,7 @@ def frr(cmd, ipprefix, device):
|
|||
msg = f"{ipprefix} matched large community."
|
||||
return (msg, code.success, d_address, query)
|
||||
else:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid BGP Community Format."
|
||||
msg = g.msg_error_invaliddual.format(i=ipprefix, qt="BGP Community")
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {query}")
|
||||
return (msg, code.danger, d_address, query)
|
||||
# BGP AS_PATH Query
|
||||
|
|
@ -49,7 +50,7 @@ def frr(cmd, ipprefix, device):
|
|||
msg = f"{ipprefix} matched AS_PATH regex."
|
||||
return (msg, code.success, d_address, query)
|
||||
else:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid AS_PATH regex."
|
||||
msg = g.msg_error_invaliddual.format(i=ipprefix, qt="AS Path")
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {cmd}, {ipprefix}")
|
||||
return (msg, code.danger, d_address, query)
|
||||
# BGP Route Query
|
||||
|
|
@ -67,7 +68,7 @@ def frr(cmd, ipprefix, device):
|
|||
return (msg, code.success, d_address, query)
|
||||
# Exception from netaddr library will return a user-facing error
|
||||
except:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid IP Address."
|
||||
msg = g.msg_error_invalidip.format(i=ipprefix)
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {query}")
|
||||
return (msg, code.danger, d_address, query)
|
||||
# Ping/Traceroute
|
||||
|
|
@ -93,10 +94,10 @@ def frr(cmd, ipprefix, device):
|
|||
"target": ipprefix,
|
||||
}
|
||||
)
|
||||
msg = f"<b>{ipprefix}</b> is a valid IPv6 Adddress."
|
||||
msg = f"{ipprefix} is a valid IPv6 Adddress."
|
||||
return (msg, code.success, d_address, query)
|
||||
except:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid IP Address."
|
||||
msg = g.msg_error_invalidip.format(i=ipprefix)
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {query}")
|
||||
return (msg, code.danger, d_name, query)
|
||||
else:
|
||||
|
|
@ -137,7 +138,7 @@ def ssh(cmd, ipprefix, device):
|
|||
msg = f"{ipprefix} matched large community."
|
||||
return (msg, code.success, d_address, d_type, command)
|
||||
else:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid BGP Community Format."
|
||||
msg = g.msg_error_invaliddual.format(i=ipprefix, qt="BGP Community")
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {cmd}, {ipprefix}")
|
||||
return (msg, code.danger, d_name, cmd, ipprefix)
|
||||
# BGP AS_PATH Query
|
||||
|
|
@ -148,7 +149,7 @@ def ssh(cmd, ipprefix, device):
|
|||
msg = f"{ipprefix} matched AS_PATH regex."
|
||||
return (msg, code.success, d_address, d_type, command)
|
||||
else:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid AS_PATH regex."
|
||||
msg = g.msg_error_invaliddual.format(i=ipprefix, qt="AS Path")
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {cmd}, {ipprefix}")
|
||||
return (msg, code.danger, d_name, cmd, ipprefix)
|
||||
# BGP Route Query
|
||||
|
|
@ -168,7 +169,7 @@ def ssh(cmd, ipprefix, device):
|
|||
return (msg, code.success, d_address, d_type, command)
|
||||
# Exception from netaddr library will return a user-facing error
|
||||
except:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid IP Address."
|
||||
msg = g.msg_error_invalidip.format(i=ipprefix)
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {cmd}, {ipprefix}")
|
||||
return (msg, code.danger, d_name, cmd, ipprefix)
|
||||
# Ping/Traceroute
|
||||
|
|
@ -185,7 +186,7 @@ def ssh(cmd, ipprefix, device):
|
|||
msg = f"{ipprefix} is a valid IPv6 Adddress."
|
||||
return (msg, code.success, d_address, d_type, command)
|
||||
except:
|
||||
msg = f"<b>{ipprefix}</b> is an invalid IP Address."
|
||||
msg = g.msg_error_invalidip.format(i=ipprefix)
|
||||
logger.error(f"{msg}, {code.danger}, {d_name}, {cmd}, {ipprefix}")
|
||||
return (msg, code.danger, d_name, cmd, ipprefix)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -166,39 +166,33 @@ def execute(lg_data):
|
|||
global code
|
||||
code = configuration.codes()
|
||||
|
||||
# Initialize general configuration parameters class, create global variable for reuse.
|
||||
global general
|
||||
general = configuration.general()
|
||||
|
||||
# Validate prefix input with netaddr library
|
||||
if lg_cmd in ["bgp_route", "ping", "traceroute"]:
|
||||
# Initialize prefix regex check class
|
||||
ipc = ipcheck().test(lg_ipprefix)
|
||||
msg = general.msg_error_invalidip.format(i=lg_ipprefix)
|
||||
try:
|
||||
# Initialize prefix regex check class
|
||||
ipc = ipcheck().test(lg_ipprefix)
|
||||
if IPNetwork(lg_ipprefix).ip.is_reserved():
|
||||
msg = f"<b>{lg_ipprefix}</b> is not a valid IP address."
|
||||
return (msg, code.danger, lg_data)
|
||||
elif IPNetwork(lg_ipprefix).ip.is_netmask():
|
||||
msg = f"<b>{lg_ipprefix}</b> is not a valid IP address."
|
||||
return (msg, code.danger, lg_data)
|
||||
elif IPNetwork(lg_ipprefix).ip.is_hostmask():
|
||||
msg = f"<b>{lg_ipprefix}</b> is not a valid IP address."
|
||||
return (msg, code.danger, lg_data)
|
||||
elif IPNetwork(lg_ipprefix).ip.is_loopback():
|
||||
msg = f"<b>{lg_ipprefix}</b> is not a valid IP address."
|
||||
return (msg, code.danger, lg_data)
|
||||
elif IPNetwork(lg_ipprefix).ip.is_unicast():
|
||||
pass
|
||||
else:
|
||||
msg = f"<b>{lg_ipprefix}</b> is not a valid unicast IP address."
|
||||
return (msg, code.danger, lg_data)
|
||||
except:
|
||||
msg = f"<b>{lg_ipprefix}</b> is not a valid IP Address."
|
||||
return (msg, code.danger, lg_data)
|
||||
|
||||
if lg_cmd == "Query Type":
|
||||
msg = "You must select a query type."
|
||||
return (msg, code.warning, lg_data)
|
||||
|
||||
# Initialize general configuration parameters class, create global variable for reuse.
|
||||
global general
|
||||
general = configuration.general()
|
||||
return (general.msg_error_querytype, code.warning, lg_data)
|
||||
|
||||
global d
|
||||
d = configuration.device(lg_router)
|
||||
|
|
@ -209,15 +203,14 @@ def execute(lg_data):
|
|||
# Check blacklist list for prefixes/IPs and return an error upon a match
|
||||
if lg_cmd in ["bgp_route", "ping", "traceroute"]:
|
||||
blacklist = IPSet(configuration.blacklist())
|
||||
msg = general.msg_error_notallowed.format(i=lg_ipprefix)
|
||||
if IPNetwork(lg_ipprefix).ip in blacklist:
|
||||
msg = f"<b>{lg_ipprefix}</b> is not allowed."
|
||||
return (msg, code.warning, lg_data)
|
||||
if lg_cmd == "bgp_route" and IPNetwork(lg_ipprefix).version == 6:
|
||||
if requires_ipv6_cidr == True and ipc["type"] == "host":
|
||||
msg = f"<b>{d.display_name}</b> requires IPv6 BGP lookups to be in CIDR notation."
|
||||
msg = general.msg_error_ipv6cidr.format(d=d.display_name)
|
||||
return (msg, code.warning, lg_data)
|
||||
if lg_cmd in ["ping", "traceroute"] and ipc["type"] == "cidr":
|
||||
msg = f"<code>{lg_cmd}</code> does not allow networks masks."
|
||||
return (msg, code.warning, lg_data)
|
||||
|
||||
# If enable_max_prefix feature enabled, require BGP Route queries be smaller than prefix size limit
|
||||
|
|
@ -226,13 +219,17 @@ def execute(lg_data):
|
|||
IPNetwork(lg_ipprefix).version == 4
|
||||
and IPNetwork(lg_ipprefix).prefixlen > general.max_prefix_length_ipv4
|
||||
):
|
||||
msg = f"Prefix length must be smaller than /{general.max_prefix_length_ipv4}. <b>{IPNetwork(lg_ipprefix)}</b> is too specific."
|
||||
msg = general.msg_max_prefix.format(
|
||||
m=general.max_prefix_length_ipv4, i=IPNetwork(lg_ipprefix)
|
||||
)
|
||||
return (msg, code.warning, lg_data)
|
||||
if (
|
||||
IPNetwork(lg_ipprefix).version == 6
|
||||
and IPNetwork(lg_ipprefix).prefixlen > general.max_prefix_length_ipv6
|
||||
):
|
||||
msg = f"Prefix length must be smaller than /{general.max_prefix_length_ipv4}. <b>{IPNetwork(lg_ipprefix)}</b> is too specific."
|
||||
msg = general.msg_max_prefix.format(
|
||||
m=general.max_prefix_length_ipv6, i=IPNetwork(lg_ipprefix)
|
||||
)
|
||||
return (msg, code.warning, lg_data)
|
||||
|
||||
if d.type == "frr":
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Module Imports
|
||||
import os
|
||||
import math
|
||||
|
|
@ -143,10 +141,26 @@ class general:
|
|||
self.org_name = g.get("org_name", "The Company")
|
||||
self.debug = g.get("debug", False)
|
||||
self.google_analytics = g.get("google_analytics", "")
|
||||
self.message_error = g.get("message_error", "{input} is invalid.")
|
||||
self.message_blacklist = g.get("message_blacklist", "{input} is not allowed.")
|
||||
self.message_general_error = g.get(
|
||||
"message_general_error", "Error connecting to device."
|
||||
self.msg_error_querytype = g.get(
|
||||
"msg_error_querytype", "You must select a query type."
|
||||
)
|
||||
self.msg_error_notallowed = g.get(
|
||||
"msg_error_notallowed", "<b>{i}</b> is not allowed."
|
||||
)
|
||||
self.msg_error_ipv6cidr = g.get(
|
||||
"msg_error_ipv6cidr",
|
||||
"<b>{d}</b> requires IPv6 BGP lookups to be in CIDR notation.",
|
||||
)
|
||||
self.msg_error_invalidip = g.get(
|
||||
"msg_error_invalidip", "<b>{i}</b> is not a valid IP address."
|
||||
)
|
||||
self.msg_error_invaliddual = g.get(
|
||||
"msg_error_invaliddual", "<b>{i}</b> is an invalid {qt}."
|
||||
)
|
||||
self.msg_error_general = g.get("msg_error_general", "A general error occurred.")
|
||||
self.msg_max_prefix = g.get(
|
||||
"msg_max_prefix",
|
||||
"Prefix length must be smaller than /{m}. <b>{i}</b> is too specific.",
|
||||
)
|
||||
self.rate_limit_query = g.get("rate_limit_query", "5")
|
||||
self.message_rate_limit_query = g.get(
|
||||
|
|
@ -192,13 +206,8 @@ class branding:
|
|||
"logo_path",
|
||||
os.path.join(hyperglass_root, "static/images/hyperglass-dark.png"),
|
||||
)
|
||||
self.favicon16_path = b.get(
|
||||
"favicon16_path", "static/images/favicon/favicon-16x16.png"
|
||||
)
|
||||
self.favicon32_path = b.get(
|
||||
"favicon32_path", "static/images/favicon/favicon-32x32.png"
|
||||
)
|
||||
self.logo_width = b.get("logo_width", "384")
|
||||
self.favicon_dir = b.get("favicon_path", "static/images/favicon/")
|
||||
self.placeholder_prefix = b.get(
|
||||
"placeholder_prefix", "IP, Prefix, Community, or AS_PATH"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,58 +1,23 @@
|
|||
# General site-wide parameters
|
||||
[[general]]
|
||||
primary_asn = ""
|
||||
org_name = ""
|
||||
debug = false
|
||||
google_analytics = ""
|
||||
message_error = ""
|
||||
message_blacklist = ""
|
||||
message_rate_limit_query = ""
|
||||
enable_bgp_route = true
|
||||
enable_bgp_community = true
|
||||
enable_bgp_aspath = true
|
||||
enable_ping = true
|
||||
enable_traceroute = true
|
||||
rate_limit_query = ""
|
||||
rate_limit_site = ""
|
||||
cache_timeout = 120
|
||||
cache_directory = ""
|
||||
# primary_asn = ""
|
||||
# org_name = ""
|
||||
# google_analytics = ""
|
||||
# enable_bgp_route = ""
|
||||
# enable_bgp_community = ""
|
||||
# enable_bgp_aspath = ""
|
||||
# enable_ping = ""
|
||||
# enable_traceroute = ""
|
||||
# enable_max_prefix = ""
|
||||
# max_prefix_length_ipv4 = ""
|
||||
# max_prefix_length_ipv6 = ""
|
||||
|
||||
# Branding/Site Customization Parameters
|
||||
[[branding]]
|
||||
site_title = ""
|
||||
title_mode = ""
|
||||
title = ""
|
||||
subtitle = ""
|
||||
enable_footer = true
|
||||
enable_credit = true
|
||||
color_bg = ""
|
||||
color_danger = ""
|
||||
color_btn_submit = ""
|
||||
color_tag_loctitle = ""
|
||||
color_tag_cmdtitle = ""
|
||||
color_tag_cmd = ""
|
||||
color_tag_loc = ""
|
||||
color_progressbar = ""
|
||||
logo_path = ""
|
||||
logo_width = ""
|
||||
favicon16_path = ""
|
||||
favicon32_path = ""
|
||||
placeholder_prefix = ""
|
||||
show_peeringdb = true
|
||||
text_results = ""
|
||||
text_location = ""
|
||||
text_cache = ""
|
||||
text_limiter_title = ""
|
||||
text_limiter_subtitle = ""
|
||||
text_500_title = ""
|
||||
text_500_subtitle = ""
|
||||
text_500_button = ""
|
||||
text_help_bgp_route = ""
|
||||
text_help_bgp_community = ""
|
||||
text_help_bgp_aspath = ""
|
||||
text_help_ping = ""
|
||||
text_help_traceroute = ""
|
||||
primary_font_url = ""
|
||||
primary_font_name = ""
|
||||
mono_font_url = ""
|
||||
mono_font_name = ""
|
||||
# site_title = ""
|
||||
# title = ""
|
||||
# subtitle = ""
|
||||
# title_mode = ""
|
||||
# logo_path = ""
|
||||
# logo_width = ""
|
||||
# favicon_dir = ""
|
||||
|
|
|
|||
|
|
@ -68,8 +68,7 @@ class html:
|
|||
footer_content=md.convert(footer_jinja),
|
||||
logo_path=branding.logo_path,
|
||||
logo_width=branding.logo_width,
|
||||
favicon16_path=branding.favicon16_path,
|
||||
favicon32_path=branding.favicon32_path,
|
||||
favicon_dir=branding.favicon_dir,
|
||||
placeholder_prefix=branding.placeholder_prefix,
|
||||
show_peeringdb=branding.show_peeringdb,
|
||||
text_results=branding.text_results,
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="static/images/favicon/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ favicon32_path }}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ favicon16_path }}">
|
||||
<link rel="manifest" href="static/images/favicon/site.webmanifest">
|
||||
<link rel="mask-icon" href="static/images/favicon/safari-pinned-tab.svg" color="{{ color_tag_cmd }}">
|
||||
<link rel="shortcut icon" href="static/images/favicon/favicon.ico">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ favicon_dir }}apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ favicon_dir }}favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ favicon_dir }}favicon-32x32.png">
|
||||
<link rel="manifest" href="{{ favicon_dir }}site.webmanifest">
|
||||
<link rel="mask-icon" href="{{ favicon_dir }}safari-pinned-tab.svg" color="{{ color_tag_cmd }}">
|
||||
<link rel="shortcut icon" href="{{ favicon_dir }}favicon.ico">
|
||||
<meta name="msapplication-TileColor" content="{{ color_tag_loctitle }}">
|
||||
<meta name="msapplication-config" content="static/images/favicon/browserconfig.xml">
|
||||
<meta name="msapplication-config" content="{{ favicon_dir }}browserconfig.xml">
|
||||
<meta name="theme-color" content="{{ color_btn_submit }}">
|
||||
<link href="static/css/icofont/icofont.min.css" rel="stylesheet" />
|
||||
<link href="static/css/hyperglass.css" rel="stylesheet" />
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue