forked from mirrors/thatmattlove-hyperglass
massive overhaul
This commit is contained in:
parent
4bc56895a9
commit
3f7988910d
31 changed files with 860 additions and 2817 deletions
|
|
@ -198,7 +198,7 @@ class Execute:
|
|||
def __init__(self, lg_data):
|
||||
self.input_data = lg_data
|
||||
self.input_location = self.input_data["location"]
|
||||
self.input_type = self.input_data["type"]
|
||||
self.input_type = self.input_data["query_type"]
|
||||
self.input_target = self.input_data["target"]
|
||||
|
||||
def parse(self, raw_output, nos):
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ try:
|
|||
devices = models.Routers.import_params(user_devices["router"])
|
||||
credentials = models.Credentials.import_params(user_devices["credential"])
|
||||
proxies = models.Proxies.import_params(user_devices["proxy"])
|
||||
networks = models.Networks.import_params(user_devices["network"])
|
||||
_networks = models.Networks.import_params(user_devices["network"])
|
||||
except ValidationError as validation_errors:
|
||||
errors = validation_errors.errors()
|
||||
for error in errors:
|
||||
|
|
@ -86,3 +86,105 @@ logzero_formatter = logzero.LogFormatter(fmt=log_format, datefmt=date_format)
|
|||
logzero_config = logzero.setup_default_logger(
|
||||
formatter=logzero_formatter, level=log_level
|
||||
)
|
||||
|
||||
|
||||
class Networks:
|
||||
def __init__(self):
|
||||
self.routers = devices.routers
|
||||
self.networks = _networks.networks
|
||||
|
||||
def networks_verbose(self):
|
||||
locations_dict = {}
|
||||
for (router, router_params) in self.routers.items():
|
||||
for (netname, net_params) in self.networks.items():
|
||||
if router_params["network"] == netname:
|
||||
net_display = net_params["display_name"]
|
||||
if net_display in locations_dict:
|
||||
locations_dict[net_display].append(
|
||||
{
|
||||
"location": router_params["location"],
|
||||
"hostname": router,
|
||||
"display_name": router_params["display_name"],
|
||||
}
|
||||
)
|
||||
elif net_display not in locations_dict:
|
||||
locations_dict[net_display] = [
|
||||
{
|
||||
"location": router_params["location"],
|
||||
"hostname": router,
|
||||
"display_name": router_params["display_name"],
|
||||
}
|
||||
]
|
||||
if not locations_dict:
|
||||
raise ConfigError("Unable to build network to device mapping")
|
||||
return locations_dict
|
||||
|
||||
def networks_display(self):
|
||||
locations_dict = {}
|
||||
for (router, router_params) in devices.routers.items():
|
||||
for (netname, net_params) in _networks.networks.items():
|
||||
if router_params["network"] == netname:
|
||||
net_display = net_params["display_name"]
|
||||
if net_display in locations_dict:
|
||||
locations_dict[net_display].append(
|
||||
router_params["display_name"]
|
||||
)
|
||||
elif net_display not in locations_dict:
|
||||
locations_dict[net_display] = [router_params["display_name"]]
|
||||
if not locations_dict:
|
||||
raise ConfigError("Unable to build network to device mapping")
|
||||
return [
|
||||
{"network_name": netname, "location_names": display_name}
|
||||
for (netname, display_name) in locations_dict.items()
|
||||
]
|
||||
|
||||
|
||||
net = Networks()
|
||||
networks = net.networks_verbose()
|
||||
logger.debug(networks)
|
||||
display_networks = net.networks_display()
|
||||
|
||||
# def networks():
|
||||
# locations_dict = {}
|
||||
# for (router, router_params) in devices.routers.items():
|
||||
# for (netname, net_params) in _networks.networks.items():
|
||||
# if router_params["network"] == netname:
|
||||
# net_display = net_params["display_name"]
|
||||
# if net_display in locations_dict:
|
||||
# locations_dict[net_display].append(
|
||||
# {
|
||||
# "location": router_params["location"],
|
||||
# "hostname": router,
|
||||
# "display_name": router_params["display_name"],
|
||||
# }
|
||||
# )
|
||||
# elif net_display not in locations_dict:
|
||||
# locations_dict[net_display] = [
|
||||
# {
|
||||
# "location": router_params["location"],
|
||||
# "hostname": router,
|
||||
# "display_name": router_params["display_name"],
|
||||
# }
|
||||
# ]
|
||||
# if not locations_dict:
|
||||
# raise ConfigError("Unable to build network to device mapping")
|
||||
# return locations_dict
|
||||
|
||||
|
||||
# def display_networks():
|
||||
# locations_dict = {}
|
||||
# for (router, router_params) in devices.routers.items():
|
||||
# for (netname, net_params) in _networks.networks.items():
|
||||
# if router_params["network"] == netname:
|
||||
# net_display = net_params["display_name"]
|
||||
# if net_display in locations_dict:
|
||||
# locations_dict[net_display].append(router_params["display_name"])
|
||||
# elif net_display not in locations_dict:
|
||||
# locations_dict[net_display] = [router_params["display_name"]]
|
||||
# if not locations_dict:
|
||||
# raise ConfigError("Unable to build network to device mapping")
|
||||
# return locations_dict
|
||||
|
||||
|
||||
# networks = networks()
|
||||
# display_networks = display_networks()
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ class Router(BaseSettings):
|
|||
"""Model for per-router config in devices.yaml."""
|
||||
|
||||
address: Union[IPvAnyAddress, str]
|
||||
asn: int
|
||||
# asn: int
|
||||
network: str
|
||||
src_addr_ipv4: IPv4Address
|
||||
src_addr_ipv6: IPv6Address
|
||||
credential: str
|
||||
|
|
@ -70,6 +71,42 @@ class Router(BaseSettings):
|
|||
class Routers(BaseSettings):
|
||||
"""Base model for devices class."""
|
||||
|
||||
# @staticmethod
|
||||
# def build_network_lists(valid_devices):
|
||||
# """
|
||||
# Builds locations dict, which is converted to JSON and passed to
|
||||
# JavaScript to associate locations with the selected network/ASN.
|
||||
|
||||
# Builds networks dict, which is used to render the network/ASN
|
||||
# select element contents.
|
||||
# """
|
||||
# locations_dict = {}
|
||||
# networks_dict = {}
|
||||
# for (dev, params) in valid_devices.items():
|
||||
# asn = str(params["asn"])
|
||||
# if asn in locations_dict:
|
||||
# locations_dict[asn].append(
|
||||
# {
|
||||
# "location": params["location"],
|
||||
# "hostname": dev,
|
||||
# "display_name": params["display_name"],
|
||||
# }
|
||||
# )
|
||||
# networks_dict[asn].append(params["location"])
|
||||
# elif asn not in locations_dict:
|
||||
# locations_dict[asn] = [
|
||||
# {
|
||||
# "location": params["location"],
|
||||
# "hostname": dev,
|
||||
# "display_name": params["display_name"],
|
||||
# }
|
||||
# ]
|
||||
# networks_dict[asn] = [params["location"]]
|
||||
# if not locations_dict:
|
||||
# raise ConfigError('Unable to build locations list from "devices.yaml"')
|
||||
# if not networks_dict:
|
||||
# raise ConfigError('Unable to build networks list from "devices.yaml"')
|
||||
# return (locations_dict, networks_dict)
|
||||
@staticmethod
|
||||
def build_network_lists(valid_devices):
|
||||
"""
|
||||
|
|
@ -79,33 +116,6 @@ class Routers(BaseSettings):
|
|||
Builds networks dict, which is used to render the network/ASN
|
||||
select element contents.
|
||||
"""
|
||||
locations_dict = {}
|
||||
networks_dict = {}
|
||||
for (dev, params) in valid_devices.items():
|
||||
asn = str(params["asn"])
|
||||
if asn in locations_dict:
|
||||
locations_dict[asn].append(
|
||||
{
|
||||
"location": params["location"],
|
||||
"hostname": dev,
|
||||
"display_name": params["display_name"],
|
||||
}
|
||||
)
|
||||
networks_dict[asn].append(params["location"])
|
||||
elif asn not in locations_dict:
|
||||
locations_dict[asn] = [
|
||||
{
|
||||
"location": params["location"],
|
||||
"hostname": dev,
|
||||
"display_name": params["display_name"],
|
||||
}
|
||||
]
|
||||
networks_dict[asn] = [params["location"]]
|
||||
if not locations_dict:
|
||||
raise ConfigError('Unable to build locations list from "devices.yaml"')
|
||||
if not networks_dict:
|
||||
raise ConfigError('Unable to build networks list from "devices.yaml"')
|
||||
return (locations_dict, networks_dict)
|
||||
|
||||
@classmethod
|
||||
def import_params(cls, input_params):
|
||||
|
|
@ -122,11 +132,11 @@ class Routers(BaseSettings):
|
|||
setattr(Routers, dev, router_params)
|
||||
routers.update({dev: router_params.dict()})
|
||||
hostnames.append(dev)
|
||||
locations_dict, networks_dict = Routers.build_network_lists(routers)
|
||||
# locations_dict, networks_dict = Routers.build_network_lists(routers)
|
||||
Routers.routers = routers
|
||||
Routers.hostnames = hostnames
|
||||
Routers.locations = locations_dict
|
||||
Routers.networks = networks_dict
|
||||
# Routers.locations = locations_dict
|
||||
# Routers.networks = networks_dict
|
||||
return Routers()
|
||||
|
||||
class Config:
|
||||
|
|
@ -139,7 +149,6 @@ class Routers(BaseSettings):
|
|||
class Network(BaseSettings):
|
||||
"""Model for per-network/asn config in devices.yaml"""
|
||||
|
||||
asn: int
|
||||
display_name: str
|
||||
|
||||
|
||||
|
|
@ -154,9 +163,12 @@ class Networks(BaseSettings):
|
|||
the credentials class.
|
||||
"""
|
||||
obj = Networks()
|
||||
networks = {}
|
||||
for (netname, params) in input_params.items():
|
||||
netname = clean_name(netname)
|
||||
setattr(Networks, netname, Network(**params))
|
||||
networks.update({netname: Network(**params).dict()})
|
||||
Networks.networks = networks
|
||||
return obj
|
||||
|
||||
class Config:
|
||||
|
|
@ -339,7 +351,8 @@ class Branding(BaseSettings):
|
|||
"""Class model for 404 Error Page"""
|
||||
|
||||
title: str = "Error"
|
||||
subtitle: str = "Page Not Found"
|
||||
subtitle: str = "{uri} isn't a thing"
|
||||
button: str = "Home"
|
||||
|
||||
class Error500(BaseSettings):
|
||||
"""Class model for 500 Error Page"""
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""Hyperglass Front End"""
|
||||
|
||||
# Standard Library Imports
|
||||
import os
|
||||
import time
|
||||
from ast import literal_eval
|
||||
from pathlib import Path
|
||||
|
|
@ -12,6 +13,7 @@ from prometheus_client import CollectorRegistry
|
|||
from prometheus_client import Counter
|
||||
from prometheus_client import generate_latest
|
||||
from prometheus_client import multiprocess
|
||||
from prometheus_client import CONTENT_TYPE_LATEST
|
||||
from sanic import Sanic
|
||||
from sanic import response
|
||||
from sanic.exceptions import NotFound
|
||||
|
|
@ -26,6 +28,7 @@ from hyperglass.command.execute import Execute
|
|||
from hyperglass.configuration import devices
|
||||
from hyperglass.configuration import logzero_config # noqa: F401
|
||||
from hyperglass.configuration import params
|
||||
from hyperglass.configuration import display_networks
|
||||
from hyperglass.constants import Supported
|
||||
from hyperglass.constants import code
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
|
|
@ -76,13 +79,13 @@ limiter = Limiter(app, key_func=get_remote_address, global_limits=[rate_limit_si
|
|||
|
||||
# Prometheus Config
|
||||
count_data = Counter(
|
||||
"count_data", "Query Counter", ["source", "type", "loc_id", "target"]
|
||||
"count_data", "Query Counter", ["source", "query_type", "loc_id", "target"]
|
||||
)
|
||||
|
||||
count_errors = Counter(
|
||||
"count_errors",
|
||||
"Error Counter",
|
||||
["code", "reason", "source", "type", "loc_id", "target"],
|
||||
["code", "reason", "source", "query_type", "loc_id", "target"],
|
||||
)
|
||||
|
||||
count_ratelimit = Counter(
|
||||
|
|
@ -101,14 +104,20 @@ async def metrics(request):
|
|||
registry = CollectorRegistry()
|
||||
multiprocess.MultiProcessCollector(registry)
|
||||
latest = generate_latest(registry)
|
||||
return response.text(latest)
|
||||
return response.text(
|
||||
latest,
|
||||
headers={
|
||||
"Content-Type": CONTENT_TYPE_LATEST,
|
||||
"Content-Length": str(len(latest)),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@app.exception(NotFound)
|
||||
async def handle_404(request, exception):
|
||||
"""Renders full error page for invalid URI"""
|
||||
html = render.html("404")
|
||||
path = request.path
|
||||
html = render.html("404", uri=path)
|
||||
client_addr = get_remote_address(request)
|
||||
count_notfound.labels(exception, path, client_addr).inc()
|
||||
logger.error(f"Error: {exception}, Path: {path}, Source: {client_addr}")
|
||||
|
|
@ -118,7 +127,7 @@ async def handle_404(request, exception):
|
|||
@app.exception(RateLimitExceeded)
|
||||
async def handle_429(request, exception):
|
||||
"""Renders full error page for too many site queries"""
|
||||
html = render.html("429")
|
||||
html = render.html("ratelimit-site")
|
||||
client_addr = get_remote_address(request)
|
||||
count_ratelimit.labels(exception, client_addr).inc()
|
||||
logger.error(f"Error: {exception}, Source: {client_addr}")
|
||||
|
|
@ -148,14 +157,14 @@ async def clear_cache():
|
|||
@limiter.limit(rate_limit_site, error_message="Site")
|
||||
async def site(request):
|
||||
"""Main front-end web application"""
|
||||
return response.html(render.html("index"))
|
||||
return response.html(render.html("index", primary_asn=params.general.primary_asn))
|
||||
|
||||
|
||||
@app.route("/test", methods=["GET"])
|
||||
async def test_route(request):
|
||||
"""Test route for various tests"""
|
||||
html = render.html("500")
|
||||
return response.html(html, status=500), 500
|
||||
return response.html(html, status=500)
|
||||
|
||||
|
||||
@app.route("/locations/<asn>", methods=["GET"])
|
||||
|
|
@ -164,7 +173,17 @@ async def get_locations(request, asn):
|
|||
GET route provides a JSON list of all locations for the selected
|
||||
network/ASN.
|
||||
"""
|
||||
return response.json(devices.locations[asn])
|
||||
# return response.json(devices.locations[asn])
|
||||
return response.json([])
|
||||
|
||||
|
||||
@app.route("/networks", methods=["GET"])
|
||||
async def get_networks(request):
|
||||
"""
|
||||
GET route provides a JSON list of all locations for the selected
|
||||
network/ASN.
|
||||
"""
|
||||
return response.json(display_networks)
|
||||
|
||||
|
||||
@app.route("/lg", methods=["POST"])
|
||||
|
|
@ -187,14 +206,14 @@ async def hyperglass_main(request):
|
|||
logger.debug("No selection specified")
|
||||
return response.html(params.messages.no_location, status=code.invalid)
|
||||
# Return error if no query type is selected
|
||||
if not Supported.is_supported_query(lg_data["type"]):
|
||||
if not Supported.is_supported_query(lg_data["query_type"]):
|
||||
logger.debug("No query specified")
|
||||
return response.html(params.messages.no_query_type, status=code.invalid)
|
||||
# Get client IP address for Prometheus logging & rate limiting
|
||||
client_addr = get_remote_address(request)
|
||||
# Increment Prometheus counter
|
||||
count_data.labels(
|
||||
client_addr, lg_data["type"], lg_data["location"], lg_data["target"]
|
||||
client_addr, lg_data["query_type"], lg_data["location"], lg_data["target"]
|
||||
).inc()
|
||||
|
||||
logger.debug(f"Client Address: {client_addr}")
|
||||
|
|
@ -237,7 +256,7 @@ async def hyperglass_main(request):
|
|||
response_status,
|
||||
code.get_reason(response_status),
|
||||
client_addr,
|
||||
lg_data["type"],
|
||||
lg_data["query_type"],
|
||||
lg_data["location"],
|
||||
lg_data["target"],
|
||||
).inc()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ from markdown2 import Markdown
|
|||
# Project Imports
|
||||
from hyperglass.configuration import devices
|
||||
from hyperglass.configuration import logzero_config # noqa: F401
|
||||
from hyperglass.configuration import params
|
||||
from hyperglass.configuration import params, networks
|
||||
from hyperglass.exceptions import HyperglassError
|
||||
|
||||
# Module Directories
|
||||
|
|
@ -78,10 +78,11 @@ Performs BGP table lookup based on IPv4/IPv6 prefix.
|
|||
template: bgp_community
|
||||
link: <a href="#" id="helplink_bgpc">{{ general.org_name }} BGP Communities</a>
|
||||
---
|
||||
Performs BGP table lookup based on [Extended](https://tools.ietf.org/html/rfc4360) \
|
||||
or [Large](https://tools.ietf.org/html/rfc8195) community value.
|
||||
Performs BGP table lookup based on <a href="https://tools.ietf.org/html/rfc4360" target\
|
||||
="_blank">Extended</a> or <a href="https://tools.ietf.org/html/rfc8195" target=\
|
||||
"_blank">Large</a> community value.
|
||||
|
||||
{{ info["link"] | safe }}
|
||||
<!-- {{ info["link"] | safe }} -->
|
||||
""",
|
||||
"bgp_aspath": """
|
||||
---
|
||||
|
|
@ -90,7 +91,7 @@ link: <a href="#" id="helplink_bgpa">Supported BGP AS Path Expressions</a>
|
|||
---
|
||||
Performs BGP table lookup based on `AS_PATH` regular expression.
|
||||
|
||||
{{ info["link"] | safe }}
|
||||
<!-- {{ info["link"] | safe }} -->
|
||||
""",
|
||||
"ping": """
|
||||
---
|
||||
|
|
@ -103,8 +104,8 @@ Sends 5 ICMP echo requests to the target.
|
|||
template: traceroute
|
||||
---
|
||||
Performs UDP Based traceroute to the target.<br>For information about how to \
|
||||
interpret traceroute results, [click here]\
|
||||
(https://hyperglass.readthedocs.io/en/latest/assets/traceroute_nanog.pdf).
|
||||
interpret traceroute results, <a href="https://hyperglass.readthedocs.io/en/latest/ass\
|
||||
ets/traceroute_nanog.pdf" target="_blank">click here</a>.
|
||||
""",
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +129,7 @@ def generate_markdown(section, file_name):
|
|||
else:
|
||||
yaml_raw = defaults[file_name]
|
||||
_, frontmatter, content = yaml_raw.split("---", 2)
|
||||
html_classes = {"table": "table"}
|
||||
html_classes = {"table": "ui compact table"}
|
||||
markdown = Markdown(
|
||||
extras={
|
||||
"break-on-newline": True,
|
||||
|
|
@ -165,7 +166,7 @@ def generate_markdown(section, file_name):
|
|||
return help_dict
|
||||
|
||||
|
||||
def html(template_name):
|
||||
def html(template_name, **kwargs):
|
||||
"""Renders Jinja2 HTML templates"""
|
||||
details_name_list = ["footer", "bgp_aspath", "bgp_community"]
|
||||
details_dict = {}
|
||||
|
|
@ -181,7 +182,7 @@ def html(template_name):
|
|||
template_file = f"templates/{template_name}.html.j2"
|
||||
template = env.get_template(template_file)
|
||||
return template.render(
|
||||
params, info=info_dict, details=details_dict, networks=devices.networks
|
||||
params, info=info_dict, details=details_dict, networks=networks, **kwargs
|
||||
)
|
||||
except jinja2.TemplateNotFound as template_error:
|
||||
logger.error(
|
||||
|
|
|
|||
2
hyperglass/render/templates/.gitignore
vendored
Normal file
2
hyperglass/render/templates/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.DS_Store
|
||||
old/
|
||||
|
|
@ -1,42 +1,18 @@
|
|||
{% extends "templates/base.html.j2" %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
{% block head %}
|
||||
{% include "templates/inlinestyle.html.j2" %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
{% block content %}
|
||||
|
||||
<body class="has-background-danger">
|
||||
<section class="section">
|
||||
<nav class="navbar has-background-danger">
|
||||
<div class="navbar-brand has-background-danger">
|
||||
</div>
|
||||
</nav>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</section>
|
||||
<section>
|
||||
<div class="container has-text-centered">
|
||||
<h1 class="title is-size-1">
|
||||
{{ branding.text.error404.title }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-size-3">
|
||||
{{ branding.text.error404.subtitle }}
|
||||
</h2>
|
||||
<br>
|
||||
</div>
|
||||
</section>
|
||||
{% if branding.footer.enable == true %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endif %}
|
||||
{% if branding.credit.enable == true %}
|
||||
{% include "templates/credit.html.j2" %}
|
||||
{% endif %}
|
||||
<div class="ui vertical center aligned segment" id="lg-maincontainer">
|
||||
{% import "templates/errortext.html.j2" as errortext %}
|
||||
{{ errortext.errortext(branding.text.error404.title, branding.text.error404.subtitle.format(uri=uri), branding.text.error404.button, "h1", "h3") }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
{% block footer %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endblock %}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
{% extends "templates/base.html.j2" %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
</head>
|
||||
|
||||
{% block content %}
|
||||
|
||||
<body class="has-background-danger">
|
||||
<section class="section">
|
||||
<nav class="navbar has-background-danger">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</section>
|
||||
<section>
|
||||
<div class="container has-text-centered">
|
||||
<h1 class="title is-size-1">
|
||||
{{ features.rate_limit.site.title }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-size-3">
|
||||
{{ features.rate_limit.site.subtitle }}
|
||||
</h2>
|
||||
<br>
|
||||
<a href="/" class="button is-medium is-rounded is-inverted is-danger is-outlined">{{ features.rate_limit.site.button }}</a>
|
||||
</div>
|
||||
</section>
|
||||
{% if branding.footer.enable == true %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endif %}
|
||||
{% if branding.credit.enable == true %}
|
||||
{% include "templates/credit.html.j2" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,45 +1,18 @@
|
|||
{% extends "templates/base.html.j2" %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
{% block head %}
|
||||
{% include "templates/inlinestyle.html.j2" %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
{% block content %}
|
||||
|
||||
<body class="has-background-danger">
|
||||
<section class="section">
|
||||
<nav class="navbar has-background-danger">
|
||||
<div class="container">
|
||||
<div class="navbar-brand">
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</section>
|
||||
<section>
|
||||
<div class="container has-text-centered">
|
||||
<h1 class="title is-size-1">
|
||||
{{ branding.text.error500.title }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-size-3">
|
||||
{{ branding.text.error500.subtitle }}
|
||||
</h2>
|
||||
<br>
|
||||
<a href="/" class="button is-medium is-rounded is-inverted is-danger is-outlined">{{ branding.text.error500.button }}</a>
|
||||
</div>
|
||||
</section>
|
||||
{% if branding.footer.enable == true %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endif %}
|
||||
{% if branding.credit.enable == true %}
|
||||
{% include "templates/credit.html.j2" %}
|
||||
{% endif %}
|
||||
<div class="ui vertical center aligned segment" id="lg-maincontainer">
|
||||
{% import "templates/errortext.html.j2" as errortext %}
|
||||
{{ errortext.errortext(branding.text.error500.title, branding.text.error500.subtitle, branding.text.error500.button, "h1", "h3") }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
{% block footer %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endblock %}
|
||||
|
|
@ -1,44 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
{% block head %}
|
||||
<title>{{ branding.site_name }}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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="{{ branding.logo.favicons }}apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ branding.logo.favicons }}favicon-16x16.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ branding.logo.favicons }}favicon-32x32.png">
|
||||
<link rel="manifest" href="{{ branding.logo.favicons }}site.webmanifest">
|
||||
<link rel="mask-icon" href="{{ branding.logo.favicons }}safari-pinned-tab.svg" color="{{ branding.colors.tag.command }}">
|
||||
<link rel="shortcut icon" href="{{ branding.logo.favicons }}favicon.ico">
|
||||
<meta name="msapplication-TileColor" content="{{ branding.colors.tag.location_title }}">
|
||||
<meta name="msapplication-config" content="{{ branding.logo.favicons }}browserconfig.xml">
|
||||
<meta name="theme-color" content="{{ branding.colors.button_submit }}">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ branding.logo.favicons }}apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ branding.logo.favicons }}favicon-16x16.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ branding.logo.favicons }}favicon-32x32.png" />
|
||||
<link rel="manifest" href="{{ branding.logo.favicons }}site.webmanifest" />
|
||||
<link rel="mask-icon" href="{{ branding.logo.favicons }}safari-pinned-tab.svg"
|
||||
color="{{ branding.colors.tag.command }}" />
|
||||
<link rel="shortcut icon" href="{{ branding.logo.favicons }}favicon.ico" />
|
||||
<meta name="msapplication-TileColor" content="{{ branding.colors.tag.location_title }}" />
|
||||
<meta name="msapplication-config" content="{{ branding.logo.favicons }}browserconfig.xml" />
|
||||
<meta name="theme-color" content="{{ branding.colors.button_submit }}" />
|
||||
<link href="static/css/icofont/icofont.min.css" rel="stylesheet" />
|
||||
<link href="static/css/hyperglass.css" rel="stylesheet" />
|
||||
{% endblock %}
|
||||
<link href="static/semantic/dist/semantic.min.css" rel="stylesheet" type="text/css" />
|
||||
<link href="static/css/animsition.min.css" rel="stylesheet" />
|
||||
<!-- <link href="static/css/hyperglass.css" rel="stylesheet" /> -->
|
||||
{% block head %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
<body id="root">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
{% block footer %}
|
||||
{% endblock %}
|
||||
<script src="static/js/jquery-3.4.0.min.js"></script>
|
||||
<script src="static/semantic/dist/semantic.min.js"></script>
|
||||
<script src="static/js/clipboard.min.js"></script>
|
||||
<script src="static/js/animsition.min.js"></script>
|
||||
<script src="static/js/hyperglass.js"></script>
|
||||
{% if general.google_analytics %}
|
||||
<!--Google Analytics-->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{general.google_analytics}}">
|
||||
</script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag("js", new Date());
|
||||
gtag("config", "{{ general.google_analytics }}");
|
||||
</script>
|
||||
{% endif %}
|
||||
{% block scripts %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
{% block scripts %}
|
||||
<script src="static/js/jquery-3.4.0.min.js"></script>
|
||||
<script src="static/js/clipboard.min.js"></script>
|
||||
<script src="static/js/hyperglass.js"></script>
|
||||
{% if general.google_analytics %}
|
||||
<!--Google Analytics-->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{ general.google_analytics }}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '{{ general.google_analytics }}');
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</html>
|
||||
</html>
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
<div class="content is-small has-text-centered" id="credit">
|
||||
<p>Powered by <a href="https://github.com/checktheroads/hyperglass">hyperglass</a>. Source code licensed <a href="https://github.com/checktheroads/hyperglass/blob/master/LICENSE">BSD 3-Clause Clear.</a></p>
|
||||
</div>
|
||||
<p class="ui ">Powered by <a href="https://github.com/checktheroads/hyperglass" target="_blank">hyperglass</a>.
|
||||
Source code
|
||||
licensed <a href="https://github.com/checktheroads/hyperglass/blob/master/LICENSE" target="_blank">BSD
|
||||
3-Clause
|
||||
Clear.</a></p>
|
||||
12
hyperglass/render/templates/errortext.html.j2
Normal file
12
hyperglass/render/templates/errortext.html.j2
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{% macro errortext(title, subtitle, button, size_title="h1", size_subtitle="h3") -%}
|
||||
<div class="ui content container">
|
||||
<{{ size_title }} class="ui header">{{ title }}
|
||||
</{{ size_title }}>
|
||||
<{{ size_subtitle }} class="ui header">{{ subtitle }}</{{ size_subtitle }}>
|
||||
<br>
|
||||
<a href="/"><button class="ui basic small button">
|
||||
<i class="angle left icon"></i>
|
||||
{{ button }}
|
||||
</button></a>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
|
@ -1,7 +1,39 @@
|
|||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="content is-small has-text-centered">
|
||||
{{ details["footer"]["content"] | safe }}
|
||||
{% if branding.footer.enable and branding.credit.enable %}
|
||||
<div class="ui vertical footer segment">
|
||||
<div class="ui center aligned fluid container">
|
||||
<div class="ui vertical basic segments">
|
||||
<div class="ui padded segment" id="lg-footer-text">
|
||||
{{ details.footer.content | safe }}
|
||||
</div>
|
||||
<div class="ui padded segment" id="lg-credit-text">
|
||||
{% include "templates/credit.html.j2" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
{% elif branding.footer.enable and not branding.credit.enable %}
|
||||
<div class="ui vertical footer segment">
|
||||
<div class="ui center aligned fluid container">
|
||||
<div class="ui vertical basic segments">
|
||||
<div class="ui padded segment" id="lg-footer-text">
|
||||
{{ details.footer.content | safe }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% elif branding.credit.enable and not branding.footer.enable %}
|
||||
<div class="ui vertical footer segment">
|
||||
<div class="ui center aligned fluid container">
|
||||
<div class="ui vertical basic segments">
|
||||
<div class="ui padded segment" id="lg-credit-text">
|
||||
{% include "templates/credit.html.j2" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% elif not branding.footer.enable and not branding.footer.enable %}
|
||||
<div class="ui vertical footer segment">
|
||||
<div class="ui center aligned fluid container">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
@ -1,264 +1,106 @@
|
|||
{% extends "templates/base.html.j2" %}
|
||||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
{% block head %}
|
||||
{% include "templates/inlinestyle.html.j2" %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block content %}
|
||||
<div class="modal" id="ratelimit">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-content">
|
||||
<article class="message is-danger">
|
||||
<div class="message-header">
|
||||
<p>{{ features.rate_limit.query.title }}</p>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
<p>{{ features.rate_limit.query.message }}</p>
|
||||
<br>
|
||||
<div class="buttons is-right">
|
||||
<a href="/" class="button is-danger is-rounded is-outlined">{{ features.rate_limit.query.button }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
{% block content %}
|
||||
{% include "templates/ratelimit-query.html.j2" %}
|
||||
{% if branding.peering_db.enable %}
|
||||
<div class="ui secondary menu">
|
||||
<div class="right menu">
|
||||
<a href="https://as{{ general.primary_asn }}.peeringdb.com/" target="_blank" class="item">
|
||||
PeeringDB
|
||||
<i class="sign out alternate icon"></i>
|
||||
</a>
|
||||
</div>
|
||||
{% if features.bgp_aspath.enable == true %}
|
||||
<div class="modal" id="help_bgp_aspath">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-content is-clipped">
|
||||
<div class="box">
|
||||
<p class="title">{{ details["bgp_aspath"]["title"] | safe }}</p>
|
||||
{{ details["bgp_aspath"]["content"] | safe }}
|
||||
</div>
|
||||
</div>
|
||||
<button class="modal-close is-large" aria-label="close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.bgp_community.enable == true %}
|
||||
<div class="modal" id="help_bgp_community">
|
||||
<div class="modal-background"></div>
|
||||
<div class="modal-content">
|
||||
<div class="box">
|
||||
<p class="title">{{ details["bgp_community"]["title"] | safe }}</p>
|
||||
{{ details["bgp_community"]["content"] | safe }}
|
||||
</div>
|
||||
</div>
|
||||
<button class="modal-close is-large" aria-label="close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<nav class="navbar">
|
||||
<div class="container is-fluid">
|
||||
<div class="navbar-brand">
|
||||
</div>
|
||||
{% if branding.peering_db.enable == true %}
|
||||
<div class="navbar-menu">
|
||||
<div class="navbar-end">
|
||||
<a class="navbar-item" href="https://as{{ general.primary_asn }}.peeringdb.com" target="_blank">
|
||||
<span>PeeringDB</span>
|
||||
<span class="icon">
|
||||
<i class="icofont-external"></i>
|
||||
</span>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</nav>
|
||||
<section class="section">
|
||||
<div class="container has-text-centered is-fluid">
|
||||
{% if branding.text.title_mode == 'all' %}
|
||||
<img src="{{ branding.logo.path }}" style="width: {{ branding.logo.width }}px;">
|
||||
<h1 class="title is-3" id="lg-title">
|
||||
{{ branding.text.title }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-5" id="lg-subtitle">
|
||||
{{ branding.text.subtitle }}
|
||||
</h2>
|
||||
<br>
|
||||
{% elif branding.text.title_mode == 'text_only' %}
|
||||
<h1 class="title is-1" id="lg-title">
|
||||
{{ branding.text.title }}
|
||||
</h1>
|
||||
<h2 class="subtitle is-3" id="lg-subtitle">
|
||||
{{ branding.text.subtitle }}
|
||||
</h2>
|
||||
<br>
|
||||
{% elif branding.text.title_mode == 'logo_title' %}
|
||||
<img src="{{ branding.logo.path }}" style="width: {{ branding.logo.width }}px;">
|
||||
<h1 class="title is-3" id="lg-title">
|
||||
{{ branding.text.title }}
|
||||
</h1>
|
||||
{% elif branding.text.title_mode == 'logo_only' %}
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<img src="{{ branding.logo.path }}" style="width: {{ branding.logo.width }}px;">
|
||||
<br>
|
||||
<br>
|
||||
{% endif %}
|
||||
<br>
|
||||
<form onsubmit="return false" name="queryform" id="lgForm" action="?" method="POST">
|
||||
<div class="container is-fluid">
|
||||
<div class="field has-addons has-addons-centered">
|
||||
<div class="control has-icons-left is-expanded">
|
||||
<input type="text" class="input is-medium is-rounded is-family-monospace" id="target" placeholder="{{ branding.text.query_placeholder }}">
|
||||
<span class="icon is-small is-left"><i class="icofont-at"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="field has-addons has-addons-centered" id="lg-netlocdropdown">
|
||||
<div class="control has-icons-left" id="network-control">
|
||||
<div class="select is-medium is-rounded">
|
||||
<select id="network" name="network" style="width: 256px">
|
||||
{% for net in networks %}
|
||||
<option value="{{ net }}">AS{{ net }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="ui vertical center aligned segment" id="lg-maincontainer">
|
||||
<div class="ui content container animsition" data-animsition-out-class="fade-out-right"
|
||||
data-animsition-in-class="fade-in-left" id="lg-form">
|
||||
{% import "templates/title.html.j2" as title %}
|
||||
{{ title.title(branding, primary_asn, size_title="h1", size_subtitle="h3") }}
|
||||
<form class="ui huge form" onsubmit="return false" name="queryform" id="lgForm" action="?" method="POST">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<div class="ui fluid search selection dropdown" id="location">
|
||||
<input type="hidden" name="location">
|
||||
<div class="default text">{{ branding.text.location }}</div>
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
{% for (netname, loc_params) in networks.items() %}
|
||||
<div class="divider"></div>
|
||||
<div class="header">
|
||||
<i class="globe icon"></i>
|
||||
{{ netname }}
|
||||
</div>
|
||||
<span class="icon is-left"><i class="icofont-cloudapp"></i></span>
|
||||
</div>
|
||||
<div class="control has-icons-left" id="location-control">
|
||||
<div class="select is-medium is-rounded">
|
||||
<select id="location" style="width: 256px">
|
||||
<option id="text_location" selected disabled>{{ branding.text.location }}</option>
|
||||
</select>
|
||||
{% for param in loc_params %}
|
||||
<div class="item" data-value='{{param["hostname"]}}'>
|
||||
{{param["display_name"]}}
|
||||
</div>
|
||||
<span class="icon is-left"><i class="icofont-location-arrow"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
</div>
|
||||
<div class="container is-fluid">
|
||||
<div class="field has-addons has-addons-centered is-grouped-centered">
|
||||
<div class="control">
|
||||
<div class="dropdown is-right" id="help-dropdown">
|
||||
<div class="dropdown-trigger">
|
||||
<button type="button" class="button is-rounded is-medium" aria-haspopup="true" aria-controls="dropdown-menu2" id="help-dropdown-button">
|
||||
<span class="icon is-size-6 lg-icon-help">
|
||||
<i class="icofont-info-circle" aria-hidden="true"></i>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="dropdown-menu is-expanded" id="dropdown-menu2" role="menu">
|
||||
<div class="dropdown-content lg-help">
|
||||
{% if features.bgp_route.enable == true %}
|
||||
<div class="dropdown-item">
|
||||
<strong>{{ branding.text.bgp_route | safe }}</strong>
|
||||
<p>{{ info["bgp_route"]["content"] | safe }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.bgp_community.enable == true %}
|
||||
<div class="dropdown-item">
|
||||
<strong>{{ branding.text.bgp_community | safe }}</strong>
|
||||
<p>{{ info["bgp_community"]["content"] | safe }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.bgp_aspath.enable == true %}
|
||||
<div class="dropdown-item">
|
||||
<strong>{{ branding.text.bgp_aspath | safe }}</strong>
|
||||
<p>{{ info["bgp_aspath"]["content"] | safe }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.ping.enable == true %}
|
||||
<div class="dropdown-item">
|
||||
<strong>{{ branding.text.ping | safe }}</strong>
|
||||
<p>{{ info["ping"]["content"] | safe }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.traceroute.enable == true %}
|
||||
<div class="dropdown-item">
|
||||
<strong>{{ branding.text.traceroute | safe }}</strong>
|
||||
<p>{{ info["traceroute"]["content"] | safe }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<div class="select is-medium is-rounded">
|
||||
<select id="type">
|
||||
<option selected disabled>
|
||||
{{ branding.text.query_type }}
|
||||
</option>
|
||||
{% if features.bgp_route.enable == true %}
|
||||
<option name="type" id="type_bgp_route" value="bgp_route">
|
||||
{{ branding.text.bgp_route }}
|
||||
</option>
|
||||
{% endif %}
|
||||
{% if features.bgp_community.enable == true %}
|
||||
<option name="type" id="type_bgp_community" value="bgp_community">
|
||||
{{ branding.text.bgp_community }}
|
||||
</option>
|
||||
{% endif %}
|
||||
{% if features.bgp_aspath.enable == true %}
|
||||
<option name="type" id="type_bgp_aspath" value="bgp_aspath">
|
||||
{{ branding.text.bgp_aspath }}
|
||||
</option>
|
||||
{% endif %}
|
||||
{% if features.ping.enable == true %}
|
||||
<option name="type" id="type_ping" value="ping">
|
||||
{{ branding.text.ping }}
|
||||
</option>
|
||||
{% endif %}
|
||||
{% if features.traceroute.enable == true %}
|
||||
<option name="type" id="type_traceroute" value="traceroute">
|
||||
{{ branding.text.traceroute }}
|
||||
</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button class="button lg-btn-submit is-medium is-rounded" type="submit" name="type">
|
||||
<span class="icon">
|
||||
<i class="icofont-search-1"></i>
|
||||
</span>
|
||||
</button>
|
||||
<input type="hidden" id='{{param["hostname"]}}' name='{{param["display_name"]}}' value="{{ netname }}">
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-one-third" id="target_error">
|
||||
<div class="field">
|
||||
<div class="ui selection dropdown left icon" id="query_type">
|
||||
<input type="hidden" name="query_type">
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="default text">{{ branding.text.query_type }}</div>
|
||||
<div class="ui menu">
|
||||
{% if features.bgp_route.enable %}
|
||||
<div class="item feature-selection" id="type_bgp_route" data-value="bgp_route">
|
||||
{{ branding.text.bgp_route }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.bgp_community.enable == true %}
|
||||
<div class="item feature-selection" id="type_bgp_community" data-value="bgp_community">
|
||||
{{ branding.text.bgp_community }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.bgp_aspath.enable == true %}
|
||||
<div class="item feature-selection" id="type_bgp_aspath" data-value="bgp_aspath">
|
||||
{{ branding.text.bgp_aspath }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.ping.enable == true %}
|
||||
<div class="item feature-selection" id="type_ping" data-value="ping">
|
||||
{{ branding.text.ping }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if features.traceroute.enable == true %}
|
||||
<div class="item feature-selection" id="type_traceroute" data-value="traceroute">
|
||||
{{ branding.text.traceroute }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field" id="field-target">
|
||||
<div class="ui fluid icon input">
|
||||
<input type="text" placeholder="{{ branding.text.query_placeholder }}" id="target">
|
||||
<i class="search link icon" id="submit_button"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui hidden message"></div>
|
||||
</form>
|
||||
</section>
|
||||
<section class="section">
|
||||
<div class="container is-fluid">
|
||||
<div class="box" id="resultsbox">
|
||||
<a class="button is-rounded is-pulled-right" id="btn-copy" data-clipboard-target="#output">
|
||||
<span class="icon is-small">
|
||||
<i id="copy-icon" class="icofont-ui-copy"></i>
|
||||
</span>
|
||||
</a>
|
||||
<p class="title" id="results">{{ branding.text.results }}</p>
|
||||
<p id="queryInfo">
|
||||
</p>
|
||||
<p id="progress">
|
||||
<br>
|
||||
<progress class="progress is-medium lg-progressbar" max="100">50%</progress>
|
||||
</p>
|
||||
<br>
|
||||
<p class="query-output" id="output">
|
||||
</p>
|
||||
{% if features.cache.show_text == true %}
|
||||
<hr>
|
||||
<p class="is-size-7">{{ features.cache.text }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% if branding.footer.enable == true %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endif %}
|
||||
{% if branding.credit.enable == true %}
|
||||
{% include "templates/credit.html.j2" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<div class="ui popup" id="bgpr_help_content">{{ info["bgp_route"]["content"] | safe }}</div>
|
||||
<div class="ui popup" id="bgpc_help_content">{{ info["bgp_community"]["content"] | safe }}<div class="ui divider">
|
||||
</div>{{ details["bgp_community"]["content"] | safe }}</div>
|
||||
<div class="ui popup" id="bgpa_help_content">{{ info["bgp_aspath"]["content"] | safe }}<div class="ui divider">
|
||||
</div>{{ details["bgp_aspath"]["content"] | safe }}</div>
|
||||
<div class="ui popup" id="ping_help_content">{{ info["ping"]["content"] | safe }}</div>
|
||||
<div class="ui popup" id="traceroute_help_content">{{ info["traceroute"]["content"] | safe }}</div>
|
||||
</div>
|
||||
{% include "templates/results.html.j2" %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block footer %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endblock %}
|
||||
74
hyperglass/render/templates/inlinestyle.html.j2
Normal file
74
hyperglass/render/templates/inlinestyle.html.j2
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<style type="text/css">
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 768px) {
|
||||
.ui.container {
|
||||
width: 700px;
|
||||
max-width: 700px;
|
||||
}
|
||||
}
|
||||
|
||||
#lg-results a {
|
||||
color: rgba(0, 0, 0, .87);
|
||||
}
|
||||
|
||||
#lg-maincontainer {
|
||||
padding-top: 36px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#lg-results-output {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.ui.content.container {
|
||||
height: 300px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.ui.vertical.segment footer.ui.segment {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
padding-left: 2em;
|
||||
padding-right: 2em;
|
||||
}
|
||||
|
||||
.ui.huge.header {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.ui.fluid.container {
|
||||
height: 75%;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
#lg-footer-text,
|
||||
#lg-credit-text {
|
||||
font-size: 75%;
|
||||
margin-left: 12.5%;
|
||||
margin-right: 12.5%;
|
||||
}
|
||||
|
||||
#lg-credit-text a,
|
||||
#lg-footer-text a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#clip-button {
|
||||
float: right;
|
||||
-webkit-transition: all 0.5s ease;
|
||||
-moz-transition: all 0.5s ease;
|
||||
-o-transition: all 0.5s ease;
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
</style>
|
||||
15
hyperglass/render/templates/ratelimit-query.html.j2
Normal file
15
hyperglass/render/templates/ratelimit-query.html.j2
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<div class="ui modal" id="ratelimit">
|
||||
<div class="header">
|
||||
{{ features.rate_limit.query.title }}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{ features.rate_limit.query.message }}</p>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="/">
|
||||
<div class="ui button">
|
||||
{{ features.rate_limit.query.button }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
18
hyperglass/render/templates/ratelimit-site.html.j2
Normal file
18
hyperglass/render/templates/ratelimit-site.html.j2
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{% extends "templates/base.html.j2" %}
|
||||
|
||||
<head>
|
||||
{% block head %}
|
||||
{% include "templates/inlinestyle.html.j2" %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
|
||||
{% block content %}
|
||||
<div class="ui vertical center aligned segment" id="lg-maincontainer">
|
||||
{% import "templates/errortext.html.j2" as errortext %}
|
||||
{{ errortext.errortext(features.rate_limit.site.title, features.rate_limit.site.subtitle, features.rate_limit.site.button, "h1", "h3") }}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}
|
||||
{% include "templates/footer.html.j2" %}
|
||||
{% endblock %}
|
||||
29
hyperglass/render/templates/results.html.j2
Normal file
29
hyperglass/render/templates/results.html.j2
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<div class="ui content fluid left aligned container animsition" data-animsition-out-class="fade-out-left"
|
||||
data-animsition-in-class="fade-in-right" id="lg-results">
|
||||
{% import "templates/title.html.j2" as title %}
|
||||
{{ title.title(branding, primary_asn, size_title="h1", size_subtitle="h3") }}
|
||||
<div class="ui segments">
|
||||
<div class="ui padded fluid segment">
|
||||
<h2 class="ui header">
|
||||
<a href="#" id="results_back"><i class="icon angle left"></i></a>
|
||||
<div class="content">
|
||||
{{ branding.text.results }}
|
||||
</div>
|
||||
</h2>
|
||||
<div id="results_detail">
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui padded fluid segment">
|
||||
<!-- <button class="ui basic right floated icon button" id="clip-button" data-clipboard-target="#lg-results-segment"><i
|
||||
class="copy outline icon" id="clip-icon"></i></button> -->
|
||||
<i id="clip-button" data-clipboard-target="#lg-results-segment" data-content="Copy Output"
|
||||
class="copy link icon"></i>
|
||||
<div id="lg-results-segment"></div>
|
||||
</div>
|
||||
{% if features.cache.show_text %}
|
||||
<div class="ui padded fluid segment">
|
||||
<span class="ui small text">{{ features.cache.text }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
19
hyperglass/render/templates/title.html.j2
Normal file
19
hyperglass/render/templates/title.html.j2
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{% macro title(branding, primary_asn, size_title="h1", size_subtitle="h3") -%}
|
||||
{% if branding.text.title_mode == 'text_only' %}
|
||||
<{{ size_title }} class="ui header">{{ branding.text.title }}</{{ size_title }}>
|
||||
<{{ size_subtitle }} class="ui header">{{ branding.text.subtitle.format(primary_asn=primary_asn) }}</{{ size_subtitle }}>
|
||||
<br>
|
||||
{% elif branding.text.title_mode == 'all' %}
|
||||
<img src="{{ branding.logo.path }}" style="width: {{ branding.logo.width }}px;">
|
||||
<{{ size_title }} class="ui header">{{ branding.text.title }}</{{ size_title }}>
|
||||
<{{ size_subtitle }} class="ui header">{{ branding.text.subtitle.format(primary_asn=primary_asn) }}</{{ size_subtitle }}>
|
||||
<br>
|
||||
{% elif branding.text.title_mode == 'logo_title' %}
|
||||
<img src="{{ branding.logo.path }}" style="width: {{ branding.logo.width }}px;">
|
||||
<{{ size_title }} class="ui header">{{ branding.text.title }}</{{ size_title }}>
|
||||
<br>
|
||||
{% elif branding.text.title_mode == 'logo_only' %}
|
||||
<img src="{{ branding.logo.path }}" style="width: {{ branding.logo.width }}px;">
|
||||
<br>
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
7
hyperglass/static/css/animsition.min.css
vendored
Executable file
7
hyperglass/static/css/animsition.min.css
vendored
Executable file
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
8
hyperglass/static/js/animsition.min.js
vendored
Executable file
8
hyperglass/static/js/animsition.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
|
|
@ -1,259 +1,219 @@
|
|||
// Get the list of locations for the selected Network
|
||||
|
||||
var progress = ($('#progress'));
|
||||
var resultsbox = ($('#resultsbox'));
|
||||
var target_error = ($('#target_error'));
|
||||
var target_input = ($('#target'));
|
||||
adjustDropdowns();
|
||||
var progress = $("#progress");
|
||||
var resultsbox = $("#resultsbox");
|
||||
var target_error = $("#target_error");
|
||||
var target_input = $("#target");
|
||||
// adjustDropdowns();
|
||||
clearPage();
|
||||
|
||||
// Bulma Toggable Dropdown - help text
|
||||
$('#help-dropdown').click(
|
||||
function (event) {
|
||||
event.stopPropagation();
|
||||
$(this).toggleClass('is-active');
|
||||
}
|
||||
);
|
||||
$(".selection.dropdown").dropdown({
|
||||
fullTextSearch: true,
|
||||
match: "both",
|
||||
allowCategorySelection: true,
|
||||
ignoreCare: true
|
||||
});
|
||||
|
||||
$("#type_bgp_route").popup({
|
||||
hoverable: true,
|
||||
variation: "wide",
|
||||
position: "right center",
|
||||
html: $("#bgpr_help_content").html()
|
||||
});
|
||||
|
||||
$("#type_bgp_community").popup({
|
||||
hoverable: true,
|
||||
variation: "wide",
|
||||
position: "right center",
|
||||
html: $("#bgpc_help_content").html()
|
||||
});
|
||||
|
||||
$("#type_bgp_aspath").popup({
|
||||
hoverable: true,
|
||||
variation: "wide",
|
||||
position: "right center",
|
||||
html: $("#bgpa_help_content").html()
|
||||
});
|
||||
|
||||
$("#type_ping").popup({
|
||||
hoverable: true,
|
||||
variation: "wide",
|
||||
position: "right center",
|
||||
html: $("#ping_help_content").html()
|
||||
});
|
||||
|
||||
$("#type_traceroute").popup({
|
||||
hoverable: true,
|
||||
variation: "wide",
|
||||
position: "right center",
|
||||
html: $("#traceroute_help_content").html()
|
||||
});
|
||||
|
||||
// ClipboardJS Elements
|
||||
var btn_copy = document.getElementById('btn-copy');
|
||||
var clipboard = new ClipboardJS(btn_copy);
|
||||
clipboard.on('success', function (e) {
|
||||
console.log(e);
|
||||
$('#btn-copy').addClass('is-success').addClass('is-outlined');
|
||||
$('#copy-icon').removeClass('icofont-ui-copy').addClass('icofont-check');
|
||||
setTimeout(function () {
|
||||
$('#btn-copy').removeClass('is-success').removeClass('is-outlined');
|
||||
$('#copy-icon').removeClass('icofont-check').addClass('icofont-ui-copy');
|
||||
}, 1000);
|
||||
var clip_button = document.getElementById("clip-button");
|
||||
var clipboard = new ClipboardJS(clip_button);
|
||||
clipboard.on("success", function (e) {
|
||||
$("#clip-button")
|
||||
.removeClass("copy link icon")
|
||||
.addClass("green check icon");
|
||||
e.clearSelection();
|
||||
setTimeout(function () {
|
||||
$("#clip-button")
|
||||
.removeClass("green check icon")
|
||||
.addClass("copy link icon");
|
||||
}, 800);
|
||||
});
|
||||
clipboard.on('error', function (e) {
|
||||
console.log(e);
|
||||
clipboard.on("error", function (e) {
|
||||
console.log(e);
|
||||
});
|
||||
|
||||
$('.modal-background, .modal-close').click(
|
||||
function (event) {
|
||||
event.stopPropagation();
|
||||
$('.modal').removeClass("is-active");
|
||||
}
|
||||
);
|
||||
|
||||
// Adjust behavior of help text dropdown based on device screen size
|
||||
$('#help-dropdown-button').click(
|
||||
function (event) {
|
||||
if (window.innerWidth < 1024) {
|
||||
$('#help-dropdown').removeClass('is-right');
|
||||
$('.lg-help').addClass('lg-help-mobile').removeClass('lg-help');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
function adjustDropdowns() {
|
||||
var actual_width = window.innerWidth;
|
||||
if (actual_width < 1024) {
|
||||
$('#lg-netlocdropdown').removeClass('has-addons').removeClass('has-addons-centered').addClass('is-grouped').addClass('is-grouped-centered').addClass('is-grouped-multiline');
|
||||
$('#network').css('width', actual_width * 0.85);
|
||||
$('#location').css('width', actual_width * 0.85);
|
||||
}
|
||||
}
|
||||
|
||||
function clearErrors() {
|
||||
progress.hide();
|
||||
target_error.hide();
|
||||
if (target_input.hasClass("is-warning")) {
|
||||
target_input.removeClass("is-warning");
|
||||
}
|
||||
if (target_input.hasClass("is-danger")) {
|
||||
target_input.removeClass("is-danger");
|
||||
}
|
||||
$("#lgForm").removeClass("error");
|
||||
$("#lgForm").removeClass("warning");
|
||||
$("#lgForm > div.ui.message").html("").removeClass("error").addClass("hidden");
|
||||
$("#field-target").removeClass("error");
|
||||
$(".ui.fluid.icon.input").removeClass("loading");
|
||||
}
|
||||
|
||||
function clearPage() {
|
||||
progress.hide();
|
||||
resultsbox.hide();
|
||||
target_error.hide();
|
||||
if (target_input.hasClass("is-warning")) {
|
||||
target_input.removeClass("is-warning");
|
||||
}
|
||||
if (target_input.hasClass("is-danger")) {
|
||||
target_input.removeClass("is-danger");
|
||||
}
|
||||
}
|
||||
|
||||
function prepResults() {
|
||||
progress.show();
|
||||
resultsbox.show();
|
||||
$(".ui.fluid.icon.input").removeClass("loading");
|
||||
progress.hide();
|
||||
resultsbox.hide();
|
||||
target_error.hide();
|
||||
if (target_input.hasClass("is-warning")) {
|
||||
target_input.removeClass("is-warning");
|
||||
}
|
||||
if (target_input.hasClass("is-danger")) {
|
||||
target_input.removeClass("is-danger");
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var defaultasn = $("#network").val();
|
||||
$.ajax({
|
||||
url: '/locations/' + defaultasn,
|
||||
context: document.body,
|
||||
type: 'get',
|
||||
success: function (data) {
|
||||
selectedRouters = data;
|
||||
console.log(selectedRouters);
|
||||
updateRouters(selectedRouters);
|
||||
},
|
||||
error: function (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
$('#lg-results').hide();
|
||||
$(".animsition").animsition({
|
||||
inClass: 'fade-in',
|
||||
outClass: 'fade-out',
|
||||
inDuration: 800,
|
||||
outDuration: 800,
|
||||
transition: function (url) { window.location.href = url; }
|
||||
});
|
||||
|
||||
$('#lg-form').animsition('in');
|
||||
});
|
||||
|
||||
$('#network').on('change', (function (event) {
|
||||
var asn = $("select[id=network").val();
|
||||
$('#location').children(":not(#text_location)").remove();
|
||||
$.ajax({
|
||||
url: '/locations/' + asn,
|
||||
type: 'get',
|
||||
success: function (data) {
|
||||
clearPage();
|
||||
updateRouters(JSON.parse(data));
|
||||
},
|
||||
error: function (err) {
|
||||
console.log(err);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
function updateRouters(locations) {
|
||||
locations.forEach(function (r) {
|
||||
$('#location').append($("<option>").attr('value', r.hostname).text(r.display_name));
|
||||
});
|
||||
}
|
||||
|
||||
$('#helplink_bgpc').click(function (event) {
|
||||
$('#help_bgp_community').addClass("is-active");
|
||||
});
|
||||
|
||||
$('#helplink_bgpa').click(function (event) {
|
||||
$('#help_bgp_aspath').addClass("is-active");
|
||||
});
|
||||
$("#results_back").on("click", function () {
|
||||
$('#lg-results').animsition('out', $('#lg-form'), '#');
|
||||
$('#lg-results').hide();
|
||||
$('#lg-form').show();
|
||||
$('#lg-form').animsition('in');
|
||||
})
|
||||
|
||||
// Submit Form Action
|
||||
$('#lgForm').on('submit', function () {
|
||||
submitForm();
|
||||
$("#lgForm").form().submit(function (event) {
|
||||
event.preventDefault();
|
||||
clearErrors();
|
||||
submitForm();
|
||||
});
|
||||
|
||||
function submitForm() {
|
||||
clearErrors();
|
||||
var type = $('#type option:selected').val();
|
||||
var type_title = $('#type option:selected').text();
|
||||
var network = $('#network option:selected').val();
|
||||
var location = $('#location option:selected').val();
|
||||
var location_name = $('#location option:selected').text();
|
||||
var target = $('#target').val();
|
||||
$("#submit_button").on("click", function () {
|
||||
clearErrors();
|
||||
submitForm();
|
||||
})
|
||||
|
||||
var tags = [
|
||||
'<div class="field is-grouped is-grouped-multiline">',
|
||||
'<div class="control">',
|
||||
'<div class="tags has-addons">',
|
||||
'<span class="tag lg-tag-loc-title">AS',
|
||||
network,
|
||||
'</span>',
|
||||
'<span class="tag lg-tag-loc">',
|
||||
location_name,
|
||||
'</span>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="control">',
|
||||
'<div class="tags has-addons">',
|
||||
'<span class="tag lg-tag-type-title">',
|
||||
type_title,
|
||||
'</span>',
|
||||
'<span class="tag lg-tag-type">',
|
||||
target,
|
||||
'</span>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'</div>'
|
||||
].join('');
|
||||
|
||||
$('#output').text("");
|
||||
$('#queryInfo').text("");
|
||||
$('#queryInfo').html(tags);
|
||||
|
||||
$.ajax(
|
||||
{
|
||||
url: '/lg',
|
||||
type: 'POST',
|
||||
data: JSON.stringify(
|
||||
{
|
||||
location: location,
|
||||
type: type,
|
||||
target: target
|
||||
}
|
||||
),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
context: document.body,
|
||||
readyState: prepResults(),
|
||||
statusCode: {
|
||||
200: function (response, code) {
|
||||
response_html = [
|
||||
'<br>',
|
||||
'<div class="content">',
|
||||
'<p class="query-output" id="output">',
|
||||
response,
|
||||
'</p>',
|
||||
'</div>',
|
||||
];
|
||||
progress.hide();
|
||||
$('#output').html(response_html);
|
||||
},
|
||||
401: function (response, code) {
|
||||
response_html = [
|
||||
'<br>',
|
||||
'<div class="notification is-danger">',
|
||||
response.responseText,
|
||||
'</div>',
|
||||
].join('');
|
||||
clearPage();
|
||||
target_error.show();
|
||||
target_input.addClass('is-danger');
|
||||
target_error.html(response_html);
|
||||
},
|
||||
405: function (response, code) {
|
||||
response_html = [
|
||||
'<br>',
|
||||
'<div class="notification is-warning">',
|
||||
response.responseText,
|
||||
'</div>',
|
||||
].join('');
|
||||
clearPage();
|
||||
target_error.show();
|
||||
target_input.addClass('is-warning');
|
||||
target_error.html(response_html);
|
||||
},
|
||||
415: function (response, code) {
|
||||
response_html = [
|
||||
'<br>',
|
||||
'<div class="notification is-danger">',
|
||||
response.responseText,
|
||||
'</div>',
|
||||
].join('');
|
||||
clearPage();
|
||||
target_error.show();
|
||||
target_input.addClass('is-danger');
|
||||
target_error.html(response_html);
|
||||
},
|
||||
429: function (response, code) {
|
||||
clearPage();
|
||||
$("#ratelimit").addClass("is-active");
|
||||
},
|
||||
504: function (response, code) {
|
||||
response_html = [
|
||||
'<br>',
|
||||
'<div class="notification is-danger">',
|
||||
response.responseText,
|
||||
'</div>',
|
||||
].join('');
|
||||
clearPage();
|
||||
target_error.show();
|
||||
target_error.html(response_html);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
function buildError(msgClass, msg) {
|
||||
var msgHtml = [
|
||||
'<div class="ui ',
|
||||
msgClass,
|
||||
' message transition hidden>',
|
||||
'<i class="close icon"></i>',
|
||||
'<p>',
|
||||
msg,
|
||||
'</p>',
|
||||
'</div>'
|
||||
].join("");
|
||||
return msgHtml;
|
||||
}
|
||||
|
||||
function submitForm() {
|
||||
clearErrors();
|
||||
var query_type = $("#query_type").dropdown("get value");
|
||||
var query_type_title = $("#query_type").dropdown("get text");
|
||||
var location = $("#location").dropdown("get value");
|
||||
var location_name = $("#location").dropdown("get text");
|
||||
var target = $("#target").val();
|
||||
console.log(query_type);
|
||||
console.log(location);
|
||||
console.log(target);
|
||||
|
||||
network = $("#" + location).val();
|
||||
|
||||
var tags = [
|
||||
'<div class="ui label">',
|
||||
network,
|
||||
'<div class="detail">',
|
||||
location_name,
|
||||
"</div>",
|
||||
"</div>",
|
||||
'<div class="ui label">',
|
||||
query_type_title,
|
||||
'<div class="detail">',
|
||||
target,
|
||||
"</div>",
|
||||
"</div>"
|
||||
].join("");
|
||||
|
||||
$("#results_detail").html(tags);
|
||||
$(".ui.fluid.icon.input").addClass("loading");
|
||||
|
||||
$.ajax({
|
||||
url: "/lg",
|
||||
type: "POST",
|
||||
data: JSON.stringify({
|
||||
location: location,
|
||||
query_type: query_type,
|
||||
target: target
|
||||
}),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
context: document.body,
|
||||
statusCode: {
|
||||
200: function (response, code) {
|
||||
$('#lg-form').animsition('out', $('#lg-results'), '#');
|
||||
$('#lg-results').show();
|
||||
$('#lg-results').animsition('in');
|
||||
response_html = [
|
||||
'<pre>',
|
||||
response,
|
||||
"</pre>"
|
||||
].join("");
|
||||
$(".ui.fluid.icon.input").removeClass("loading");
|
||||
$("#lg-results-segment").html(response_html);
|
||||
},
|
||||
401: function (response, code) {
|
||||
$("#lgForm").addClass("error");
|
||||
$("#lgForm > div.ui.hidden.message").html(response.responseText).addClass("error").removeClass("hidden");
|
||||
$("#field-target").addClass("error");
|
||||
$(".ui.fluid.icon.input").removeClass("loading");
|
||||
},
|
||||
405: function (response, code) {
|
||||
$("#lgForm").addClass("error");
|
||||
$("#lgForm > div.ui.hidden.message").html(response.responseText).addClass("error").removeClass("hidden");
|
||||
$("#field-target").addClass("error");
|
||||
$(".ui.fluid.icon.input").removeClass("loading");
|
||||
},
|
||||
415: function (response, code) {
|
||||
$("#lgForm").addClass("warning");
|
||||
$("#lgForm > div.ui.hidden.message").html(response.responseText).addClass("warning").removeClass("hidden");
|
||||
$(".ui.fluid.icon.input").removeClass("loading");
|
||||
},
|
||||
429: function (response, code) {
|
||||
$("#ratelimit").modal("show");
|
||||
},
|
||||
504: function (response, code) {
|
||||
$("#lgForm").addClass("error");
|
||||
$("#lgForm > div.ui.hidden.message").html(response.responseText).addClass("error").removeClass("hidden");
|
||||
$("#field-target").addClass("error");
|
||||
$(".ui.fluid.icon.input").removeClass("loading");
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
22
hyperglass/static/semantic.json
Normal file
22
hyperglass/static/semantic.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"base": "semantic/",
|
||||
"paths": {
|
||||
"source": {
|
||||
"config": "src/theme.config",
|
||||
"definitions": "src/definitions/",
|
||||
"site": "src/site/",
|
||||
"themes": "src/themes/"
|
||||
},
|
||||
"output": {
|
||||
"packaged": "dist/",
|
||||
"uncompressed": "dist/components/",
|
||||
"compressed": "dist/components/",
|
||||
"themes": "dist/themes/"
|
||||
},
|
||||
"clean": "dist/"
|
||||
},
|
||||
"permission": false,
|
||||
"autoInstall": false,
|
||||
"rtl": false,
|
||||
"version": "2.7.7"
|
||||
}
|
||||
|
|
@ -9,18 +9,20 @@ port = 8001
|
|||
|
||||
try:
|
||||
import multiprocessing
|
||||
import os
|
||||
import tempfile
|
||||
from hyperglass import render
|
||||
from hyperglass import hyperglass
|
||||
from hyperglass.configuration import params
|
||||
except ImportError as import_error:
|
||||
raise RuntimeError(import_error)
|
||||
|
||||
debug = False
|
||||
access_log = True
|
||||
|
||||
if params.general.debug:
|
||||
debug = True
|
||||
access_log = False
|
||||
elif not params.general.debug:
|
||||
debug = False
|
||||
access_log = True
|
||||
|
||||
# Override the number of web server workers if necessary:
|
||||
workers = multiprocessing.cpu_count()
|
||||
|
|
@ -35,6 +37,10 @@ def start():
|
|||
render.css()
|
||||
except Exception as render_error:
|
||||
raise RuntimeError(render_error)
|
||||
|
||||
tempdir = tempfile.TemporaryDirectory(prefix="hyperglass_")
|
||||
os.environ["prometheus_multiproc_dir"] = tempdir.name
|
||||
|
||||
try:
|
||||
hyperglass.app.run(
|
||||
host=host,
|
||||
|
|
|
|||
58
setup.py
Normal file
58
setup.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
from distutils.core import setup
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 6):
|
||||
sys.exit("Python 3.6+ is required.")
|
||||
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
with open("README.md", "r") as ld:
|
||||
long_description = ld.read()
|
||||
|
||||
package_json = {
|
||||
"dependencies": {
|
||||
"animsition": "^4.0.2",
|
||||
"clipboard": "^2.0.4",
|
||||
"fomantic-ui": "^2.7.7",
|
||||
"jquery": "^3.4.1",
|
||||
}
|
||||
}
|
||||
|
||||
setup(
|
||||
name="hyperglass",
|
||||
version="1.0.0",
|
||||
author="Matt Love",
|
||||
author_email="matt@allroads.io",
|
||||
description="hyperglass is a modern, customizable network looking glass written in Python 3.",
|
||||
url="https://github.com/checktheroads/hyperglass",
|
||||
python_requires=">=3.6",
|
||||
packages=["hyperglass"],
|
||||
install_requires=[
|
||||
"aredis==1.1.5",
|
||||
"click==6.7",
|
||||
"hiredis==1.0.0",
|
||||
"http3==0.6.7",
|
||||
"jinja2==2.10.1",
|
||||
"libsass==0.18.0",
|
||||
"logzero==1.5.0",
|
||||
"markdown2==2.3.7",
|
||||
"netmiko==2.3.3",
|
||||
"passlib==1.7.1",
|
||||
"prometheus_client==0.7.0",
|
||||
"pydantic==0.29",
|
||||
"pyyaml==5.1.1",
|
||||
"redis==3.2.1",
|
||||
"sanic_limiter==0.1.3",
|
||||
"sanic==19.6.2",
|
||||
"sshtunnel==0.1.5",
|
||||
],
|
||||
setup_requires=[
|
||||
"calmjs==3.4.1",
|
||||
]
|
||||
package_json=package_json,
|
||||
license="BSD 3-Clause Clear License",
|
||||
long_description=long_description,
|
||||
long_description_content_type="text/markdown",
|
||||
)
|
||||
Loading…
Add table
Reference in a new issue