1
0
mirror of https://github.com/checktheroads/hyperglass synced 2024-05-11 05:55:08 +00:00

refactor logzero → loguru; docstrings

This commit is contained in:
checktheroads
2019-12-29 23:57:39 -07:00
parent 1049bb3a4f
commit ea3a08b28a
24 changed files with 299 additions and 279 deletions

View File

@@ -1,4 +1,5 @@
"""
"""Validate, construct, execute queries.
Constructs SSH commands or API call parameters based on front end
input, executes the commands/calls, returns the output to front end.
"""

View File

@@ -1,29 +1,25 @@
"""
"""Construct SSH command/API parameters from validated query data.
Accepts filtered & validated input from execute.py, constructs SSH
command for Netmiko library or API call parameters for supported
hyperglass API modules.
"""
# Standard Library Imports
import ipaddress
import json
import operator
import re
# Third Party Imports
from logzero import logger as log
# Project Imports
from hyperglass.configuration import commands
from hyperglass.configuration import logzero_config # NOQA: F401
from hyperglass.constants import target_format_space
from hyperglass.exceptions import HyperglassError
from hyperglass.util import log
class Construct:
"""
Constructs SSH commands or REST API queries based on validated
input parameters.
"""
"""Construct SSH commands/REST API parameters from validated query data."""
def get_device_vrf(self):
_device_vrf = None

View File

@@ -1,3 +1,5 @@
"""Handle JSON Web Token Encoding & Decoding."""
# Standard Library Imports
import datetime
@@ -9,7 +11,7 @@ from hyperglass.exceptions import RestError
async def jwt_decode(payload, secret):
"""Decode & validate an encoded JSON Web Token (JWT)"""
"""Decode & validate an encoded JSON Web Token (JWT)."""
try:
decoded = jwt.decode(payload, secret, algorithm="HS256")
decoded = decoded["payload"]
@@ -19,7 +21,7 @@ async def jwt_decode(payload, secret):
async def jwt_encode(payload, secret, duration):
"""Encode a query to a JSON Web Token (JWT)"""
"""Encode a query to a JSON Web Token (JWT)."""
token = {
"payload": payload,
"nbf": datetime.datetime.utcnow(),

View File

@@ -1,4 +1,5 @@
"""
"""Execute validated & constructed query on device.
Accepts input from front end application, validates the input and
returns errors if input is invalid. Passes validated parameters to
construct.py, which is used to build & run the Netmiko connectoins or
@@ -11,7 +12,6 @@ import re
# Third Party Imports
import httpx
import sshtunnel
from logzero import logger as log
from netmiko import ConnectHandler
from netmiko import NetMikoAuthenticationException
from netmiko import NetmikoAuthError
@@ -20,10 +20,10 @@ from netmiko import NetMikoTimeoutException
# Project Imports
from hyperglass.command.construct import Construct
from hyperglass.command.encode import jwt_decode
from hyperglass.command.encode import jwt_encode
from hyperglass.command.validate import Validate
from hyperglass.command.encode import jwt_decode, jwt_encode
from hyperglass.configuration import devices
from hyperglass.configuration import logzero_config # noqa: F401
from hyperglass.configuration import params
from hyperglass.constants import Supported
from hyperglass.constants import protocol_map
@@ -32,6 +32,7 @@ from hyperglass.exceptions import DeviceTimeout
from hyperglass.exceptions import ResponseEmpty
from hyperglass.exceptions import RestError
from hyperglass.exceptions import ScrapeError
from hyperglass.util import log
class Connect:
@@ -219,7 +220,6 @@ class Connect:
"""Sends HTTP POST to router running a hyperglass API agent"""
log.debug(f"Query parameters: {self.query}")
# uri = Supported.map_rest(self.device.nos)
headers = {"Content-Type": "application/json"}
http_protocol = protocol_map.get(self.device.port, "https")
endpoint = "{protocol}://{addr}:{port}/query".format(

View File

@@ -1,4 +1,5 @@
"""
"""Validate query data.
Accepts raw input data from execute.py, passes it through specific
filters based on query type, returns validity boolean and specific
error message.
@@ -7,15 +8,12 @@ error message.
import ipaddress
import re
# Third Party Imports
from logzero import logger as log
# Project Imports
from hyperglass.configuration import logzero_config # noqa: F401
from hyperglass.configuration import params
from hyperglass.exceptions import HyperglassError
from hyperglass.exceptions import InputInvalid
from hyperglass.exceptions import InputNotAllowed
from hyperglass.util import log
class IPType:

View File

@@ -1,24 +1,22 @@
"""
Imports configuration varibles from configuration files and returns
default values if undefined.
"""
"""Import configuration files and returns default values if undefined."""
# Standard Library Imports
from pathlib import Path
# Third Party Imports
import logzero
import yaml
from logzero import logger as log
from pydantic import ValidationError
# Project Imports
from hyperglass.configuration.models import commands as _commands
from hyperglass.configuration.models import params as _params
from hyperglass.configuration.models import routers as _routers
from hyperglass.constants import LOG_HANDLER
from hyperglass.constants import LOG_LEVELS
from hyperglass.exceptions import ConfigError
from hyperglass.exceptions import ConfigInvalid
from hyperglass.exceptions import ConfigMissing
from hyperglass.util import log
# Project Directories
working_dir = Path(__file__).resolve().parent
@@ -82,19 +80,14 @@ except ValidationError as validation_errors:
)
# Logzero Configuration
log_level = 20
# Logging Config
if params.general.debug:
log_level = 10
log_format = (
"%(color)s[%(asctime)s.%(msecs)03d %(module)s:%(funcName)s:%(lineno)d "
"%(levelname)s]%(end_color)s %(message)s"
)
date_format = "%Y-%m-%d %H:%M:%S"
logzero_formatter = logzero.LogFormatter(fmt=log_format, datefmt=date_format)
logzero_config = logzero.setup_default_logger(
formatter=logzero_formatter, level=log_level
)
_log_level = "DEBUG"
LOG_HANDLER["level"] = _log_level
log.remove()
log.configure(handlers=[LOG_HANDLER], levels=LOG_LEVELS)
log.debug("Debugging Enabled")
def build_frontend_networks():

View File

@@ -1,6 +1,4 @@
"""
Utility Functions for Pydantic Models
"""
"""Utility Functions for Pydantic Models."""
# Standard Library Imports
import re
@@ -10,10 +8,17 @@ from pydantic import BaseSettings
def clean_name(_name):
"""
Converts any "desirable" seperators to underscore, then
removes all characters that are unsupported in Python class
variable names. Also removes leading numbers underscores.
"""Remove unsupported characters from field names.
Converts any "desirable" seperators to underscore, then removes all
characters that are unsupported in Python class variable names.
Also removes leading numbers underscores.
Arguments:
_name {str} -- Initial field name
Returns:
{str} -- Cleaned field name
"""
_replaced = re.sub(r"[\-|\.|\@|\~|\:\/|\s]", "_", _name)
_scrubbed = "".join(re.findall(r"([a-zA-Z]\w+|\_+)", _replaced))
@@ -21,12 +26,15 @@ def clean_name(_name):
class HyperglassModel(BaseSettings):
"""Base model for all hyperglass configuration models"""
"""Base model for all hyperglass configuration models."""
pass
class Config:
"""Default pydantic configuration"""
"""Default Pydantic configuration.
See https://pydantic-docs.helpmanual.io/usage/model_config
"""
validate_all = True
extra = "forbid"
@@ -35,11 +43,11 @@ class HyperglassModel(BaseSettings):
class HyperglassModelExtra(HyperglassModel):
"""Model for hyperglass configuration models with dynamic fields"""
"""Model for hyperglass configuration models with dynamic fields."""
pass
class Config:
"""Default pydantic configuration"""
"""Default pydantic configuration."""
extra = "allow"

View File

@@ -1,10 +1,4 @@
"""
Defines models for all Branding variables.
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
"""Validate branding configuration variables."""
# Third Party Imports
from pydantic import constr

View File

@@ -1,10 +1,5 @@
"""
Defines models for all config variables.
"""Validate command configuration variables."""
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
# Disable string length warnings so I can actually read these commands
# flake8: noqa: E501

View File

@@ -1,10 +1,4 @@
"""
Defines models for Credential config variables.
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
"""Validate credential configuration variables."""
# Third Party Imports
from pydantic import SecretStr
@@ -15,14 +9,14 @@ from hyperglass.configuration.models._utils import clean_name
class Credential(HyperglassModel):
"""Model for per-credential config in devices.yaml"""
"""Model for per-credential config in devices.yaml."""
username: str
password: SecretStr
class Credentials(HyperglassModel):
"""Base model for credentials class"""
"""Base model for credentials class."""
@classmethod
def import_params(cls, input_params):

View File

@@ -1,10 +1,5 @@
"""
Defines models for all Features variables.
"""Validate feature configuration variables."""
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
# Standard Library Imports
from math import ceil
@@ -16,20 +11,20 @@ from hyperglass.configuration.models._utils import HyperglassModel
class Features(HyperglassModel):
"""Class model for params.features"""
"""Validation model for params.features."""
class BgpRoute(HyperglassModel):
"""Class model for params.features.bgp_route"""
"""Validation model for params.features.bgp_route."""
enable: bool = True
class BgpCommunity(HyperglassModel):
"""Class model for params.features.bgp_community"""
"""Validation model for params.features.bgp_community."""
enable: bool = True
class Regex(HyperglassModel):
"""Class model for params.features.bgp_community.regex"""
"""Validation model for params.features.bgp_community.regex."""
decimal: str = r"^[0-9]{1,10}$"
extended_as: str = r"^([0-9]{0,5})\:([0-9]{1,5})$"
@@ -38,12 +33,12 @@ class Features(HyperglassModel):
regex: Regex = Regex()
class BgpAsPath(HyperglassModel):
"""Class model for params.features.bgp_aspath"""
"""Validation model for params.features.bgp_aspath."""
enable: bool = True
class Regex(HyperglassModel):
"""Class model for params.bgp_aspath.regex"""
"""Validation model for params.bgp_aspath.regex."""
mode: constr(regex="asplain|asdot") = "asplain"
asplain: str = r"^(\^|^\_)(\d+\_|\d+\$|\d+\(\_\.\+\_\))+$"
@@ -54,17 +49,17 @@ class Features(HyperglassModel):
regex: Regex = Regex()
class Ping(HyperglassModel):
"""Class model for params.features.ping"""
"""Validation model for params.features.ping."""
enable: bool = True
class Traceroute(HyperglassModel):
"""Class model for params.features.traceroute"""
"""Validation model for params.features.traceroute."""
enable: bool = True
class Cache(HyperglassModel):
"""Class model for params.features.cache"""
"""Validation model for params.features.cache."""
redis_id: int = 0
timeout: int = 120
@@ -74,7 +69,7 @@ class Features(HyperglassModel):
)
class MaxPrefix(HyperglassModel):
"""Class model for params.features.max_prefix"""
"""Validation model for params.features.max_prefix."""
enable: bool = False
ipv4: int = 24
@@ -84,12 +79,12 @@ class Features(HyperglassModel):
)
class RateLimit(HyperglassModel):
"""Class model for params.features.rate_limit"""
"""Validation model for params.features.rate_limit."""
redis_id: int = 1
class Query(HyperglassModel):
"""Class model for params.features.rate_limit.query"""
"""Validation model for params.features.rate_limit.query."""
rate: int = 5
period: str = "minute"
@@ -101,7 +96,7 @@ class Features(HyperglassModel):
button: str = "Try Again"
class Site(HyperglassModel):
"""Class model for params.features.rate_limit.site"""
"""Validation model for params.features.rate_limit.site."""
rate: int = 60
period: str = "minute"

View File

@@ -1,10 +1,5 @@
"""
Defines models for General config variables.
"""Validate general configuration variables."""
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
# Standard Library Imports
from typing import List
@@ -13,7 +8,7 @@ from hyperglass.configuration.models._utils import HyperglassModel
class General(HyperglassModel):
"""Class model for params.general"""
"""Validation model for params.general."""
debug: bool = False
primary_asn: str = "65001"

View File

@@ -1,17 +1,11 @@
"""
Defines models for Messages config variables.
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
"""Validate error message configuration variables."""
# Project Imports
from hyperglass.configuration.models._utils import HyperglassModel
class Messages(HyperglassModel):
"""Class model for params.messages"""
"""Validation model for params.messages."""
no_input: str = "{field} must be specified."
acl_denied: str = "{target} is a member of {denied_network}, which is not allowed."

View File

@@ -1,10 +1,4 @@
"""
Defines models for Networks config variables.
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
"""Validate network configuration variables."""
# Project Imports
from hyperglass.configuration.models._utils import HyperglassModel
@@ -12,14 +6,14 @@ from hyperglass.configuration.models._utils import clean_name
class Network(HyperglassModel):
"""Model for per-network/asn config in devices.yaml"""
"""Validation Model for per-network/asn config in devices.yaml."""
name: str
display_name: str
class Networks(HyperglassModel):
"""Base model for networks class"""
"""Base model for networks class."""
@classmethod
def import_params(cls, input_params):

View File

@@ -1,10 +1,4 @@
"""
Defines models for all Params variables.
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
"""Configuration validation entry point."""
# Project Imports
from hyperglass.configuration.models._utils import HyperglassModel
@@ -15,7 +9,7 @@ from hyperglass.configuration.models.messages import Messages
class Params(HyperglassModel):
"""Base model for params"""
"""Validation model for all configuration variables."""
general: General = General()
features: Features = Features()

View File

@@ -1,10 +1,4 @@
"""
Defines models for Router config variables.
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
"""Validate SSH proxy configuration variables."""
# Third Party Imports
from pydantic import validator
@@ -17,7 +11,7 @@ from hyperglass.exceptions import UnsupportedDevice
class Proxy(HyperglassModel):
"""Model for per-proxy config in devices.yaml"""
"""Validation model for per-proxy config in devices.yaml."""
name: str
address: str
@@ -26,17 +20,17 @@ class Proxy(HyperglassModel):
nos: str = "linux_ssh"
@validator("nos")
def supported_nos(cls, v): # noqa: N805
def supported_nos(cls, value): # noqa: N805
"""
Validates that passed nos string is supported by hyperglass.
"""
if not v == "linux_ssh":
raise UnsupportedDevice(f'"{v}" device type is not supported.')
return v
if not value == "linux_ssh":
raise UnsupportedDevice(f'"{value}" device type is not supported.')
return value
class Proxies(HyperglassModel):
"""Base model for proxies class"""
"""Validation model for SSH proxy configuration."""
@classmethod
def import_params(cls, input_params):

View File

@@ -1,10 +1,5 @@
"""
Defines models for Router config variables.
"""Validate router configuration variables."""
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
# Standard Library Imports
import re
from typing import List
@@ -12,7 +7,6 @@ from typing import Union
# Third Party Imports
from pydantic import validator
from logzero import logger as log
# Project Imports
from hyperglass.configuration.models._utils import HyperglassModel
@@ -22,14 +16,15 @@ from hyperglass.configuration.models.commands import Command
from hyperglass.configuration.models.credentials import Credential
from hyperglass.configuration.models.networks import Network
from hyperglass.configuration.models.proxies import Proxy
from hyperglass.configuration.models.vrfs import Vrf, DefaultVrf
from hyperglass.configuration.models.vrfs import DefaultVrf, Vrf
from hyperglass.constants import Supported
from hyperglass.exceptions import ConfigError
from hyperglass.exceptions import UnsupportedDevice
from hyperglass.util import log
class Router(HyperglassModel):
"""Model for per-router config in devices.yaml."""
"""Validation model for per-router config in devices.yaml."""
name: str
address: str
@@ -129,7 +124,7 @@ class Router(HyperglassModel):
class Routers(HyperglassModelExtra):
"""Base model for devices class."""
"""Validation model for device configurations."""
hostnames: List[str] = []
vrfs: List[str] = []

View File

@@ -1,10 +1,5 @@
"""
Defines models for VRF config variables.
"""Validate VRF configuration variables."""
Imports config variables and overrides default class attributes.
Validates input for overridden parameters.
"""
# Standard Library Imports
from ipaddress import IPv4Address
from ipaddress import IPv4Network
@@ -25,7 +20,7 @@ from hyperglass.exceptions import ConfigError
class DeviceVrf4(HyperglassModel):
"""Model for AFI definitions"""
"""Validation model for IPv4 AFI definitions."""
vrf_name: str
source_address: IPv4Address
@@ -46,7 +41,7 @@ class DeviceVrf4(HyperglassModel):
class DeviceVrf6(HyperglassModel):
"""Model for AFI definitions"""
"""Validation model for IPv6 AFI definitions."""
vrf_name: str
source_address: IPv6Address
@@ -67,7 +62,7 @@ class DeviceVrf6(HyperglassModel):
class Vrf(HyperglassModel):
"""Model for per VRF/afi config in devices.yaml"""
"""Validation model for per VRF/afi config in devices.yaml."""
name: str
display_name: str
@@ -94,16 +89,21 @@ class Vrf(HyperglassModel):
class DefaultVrf(HyperglassModel):
"""Validation model for default routing table VRF."""
name: str = "default"
display_name: str = "Global"
access_list = [{"allow": IPv4Network("0.0.0.0/0")}, {"allow": IPv6Network("::/0")}]
class DefaultVrf4(HyperglassModel):
"""Validation model for IPv4 default routing table VRF definition."""
vrf_name: str = "default"
source_address: IPv4Address = IPv4Address("127.0.0.1")
class DefaultVrf6(HyperglassModel):
"""Validation model for IPv6 default routing table VRF definition."""
vrf_name: str = "default"
source_address: IPv6Address = IPv6Address("::1")

View File

@@ -1,11 +1,25 @@
"""
Global Constants for hyperglass
"""
"""Constant definitions used throughout the application."""
import sys
protocol_map = {80: "http", 8080: "http", 443: "https", 8443: "https"}
target_format_space = ("huawei", "huawei_vrpv8")
LOG_FMT = (
"<lvl><b>[{level}]</b> {time:YYYYMMDD} <lw>|</lw> {time:HH:mm:ss} {name} "
"<lw>|</lw> {function}</lvl> <lvl><b>→</b></lvl> {message}"
)
LOG_LEVELS = [
{"name": "DEBUG", "no": 10, "color": "<c>"},
{"name": "INFO", "no": 20, "color": "<le>"},
{"name": "SUCCESS", "no": 25, "color": "<g>"},
{"name": "WARNING", "no": 30, "color": "<y>"},
{"name": "ERROR", "no": 40, "color": "<y>"},
{"name": "CRITICAL", "no": 50, "color": "<r>"},
]
LOG_HANDLER = {"sink": sys.stdout, "format": LOG_FMT, "level": "INFO"}
class Supported:
"""

View File

@@ -1,137 +1,161 @@
"""
Custom exceptions for hyperglass
"""
"""Custom exceptions for hyperglass."""
import json as _json
from hyperglass.util import log
class HyperglassError(Exception):
"""hyperglass base exception"""
"""hyperglass base exception."""
def __init__(self, message="", alert="warning", keywords=[]):
def __init__(self, message="", alert="warning", keywords=None):
"""Initialize the hyperglass base exception class.
Keyword Arguments:
message {str} -- Error message (default: {""})
alert {str} -- Error severity (default: {"warning"})
keywords {list} -- 'Important' keywords (default: {None})
"""
self.message = message
self.alert = alert
self.keywords = keywords
self.keywords = keywords or []
if self.alert == "warning":
log.error(repr(self))
elif self.alert == "danger":
log.critical(repr(self))
else:
log.info(repr(self))
def __str__(self):
"""Return the instance's error message.
Returns:
{str} -- Error Message
"""
return self.message
def __repr__(self):
"""Return the instance's severity & error message in a string.
Returns:
{str} -- Error message with code
"""
return f"[{self.alert.upper()}] {self.message}"
def __dict__(self):
"""Return the instance's attributes as a dictionary.
Returns:
{dict} -- Exception attributes in dict
"""
return {"message": self.message, "alert": self.alert, "keywords": self.keywords}
def json(self):
"""Return the instance's attributes as a JSON object.
class ConfigError(HyperglassError):
Returns:
{str} -- Exception attributes as JSON
"""
return _json.dumps(self.__dict__())
@property
def message(self):
"""Return the instance's `message` attribute.
Returns:
{str} -- Error Message
"""
return self.message
@property
def alert(self):
"""Return the instance's `alert` attribute.
Returns:
{str} -- Alert name
"""
return self.alert
@property
def keywords(self):
"""Return the instance's `keywords` attribute.
Returns:
{list} -- Keywords List
"""
return self.keywords
class _UnformattedHyperglassError(HyperglassError):
"""Base exception class for freeform error messages."""
def __init__(self, unformatted_msg, alert="warning", **kwargs):
"""Format error message with keyword arguments.
Keyword Arguments:
message {str} -- Error message (default: {""})
alert {str} -- Error severity (default: {"warning"})
keywords {list} -- 'Important' keywords (default: {None})
"""
self.message = unformatted_msg.format(**kwargs)
self.alert = alert
self.keywords = list(kwargs.values())
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
class ConfigError(_UnformattedHyperglassError):
"""Raised for generic user-config issues."""
def __init__(self, unformatted_msg, **kwargs):
self.message = unformatted_msg.format(**kwargs)
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, keywords=self.keywords)
class ConfigInvalid(_UnformattedHyperglassError):
"""Raised when a config item fails type or option validation."""
message = 'The value field "{field}" is invalid: {error_msg}'
class ConfigInvalid(HyperglassError):
"""Raised when a config item fails type or option validation"""
class ConfigMissing(_UnformattedHyperglassError):
"""Raised when a required config file or item is missing or undefined."""
def __init__(self, **kwargs):
self.message = 'The value field "{field}" is invalid: {error_msg}'.format(
**kwargs
)
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, keywords=self.keywords)
message = (
"{missing_item} is missing or undefined and is required to start "
"hyperglass. Please consult the installation documentation."
)
class ConfigMissing(HyperglassError):
"""
Raised when a required config file or item is missing or undefined.
"""
class ScrapeError(_UnformattedHyperglassError):
"""Raised when a scrape/netmiko error occurs."""
def __init__(self, **kwargs):
self.message = (
"{missing_item} is missing or undefined and is required to start "
"hyperglass. Please consult the installation documentation."
).format(**kwargs)
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, keywords=self.keywords)
alert = "danger"
class ScrapeError(HyperglassError):
"""Raised upon a scrape/netmiko error"""
class AuthError(_UnformattedHyperglassError):
"""Raised when authentication to a device fails."""
def __init__(self, msg, **kwargs):
self.message = msg.format(**kwargs)
self.alert = "danger"
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
alert = "danger"
class AuthError(HyperglassError):
"""Raised when authentication to a device fails"""
class RestError(_UnformattedHyperglassError):
"""Raised upon a rest API client error."""
def __init__(self, msg, **kwargs):
self.message = msg.format(**kwargs)
self.alert = "danger"
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
alert = "danger"
class RestError(HyperglassError):
"""Raised upon a rest API client error"""
def __init__(self, msg, **kwargs):
self.message = msg.format(**kwargs)
self.alert = "danger"
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
class InputInvalid(HyperglassError):
"""Raised when input validation fails"""
def __init__(self, unformatted_msg, **kwargs):
self.message = unformatted_msg.format(**kwargs)
self.alert = "warning"
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
class InputNotAllowed(HyperglassError):
"""
Raised when input validation fails due to a blacklist or
requires_ipv6_cidr check
"""
def __init__(self, unformatted_msg, **kwargs):
self.message = unformatted_msg.format(**kwargs)
self.alert = "warning"
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
class ResponseEmpty(HyperglassError):
"""
Raised when hyperglass is able to connect to the device and execute
a valid query, but the response is empty.
"""
def __init__(self, unformatted_msg, **kwargs):
self.message = unformatted_msg.format(**kwargs)
self.alert = "warning"
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
class UnsupportedDevice(HyperglassError):
"""Raised when an input NOS is not in the supported NOS list."""
def __init__(self, **kwargs):
self.message = "".format(**kwargs)
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, keywords=self.keywords)
class DeviceTimeout(HyperglassError):
class DeviceTimeout(_UnformattedHyperglassError):
"""Raised when the connection to a device times out."""
def __init__(self, msg, **kwargs):
self.message = msg.format(**kwargs)
self.alert = "danger"
self.keywords = [value for value in kwargs.values()]
super().__init__(message=self.message, alert=self.alert, keywords=self.keywords)
alert = "danger"
class InputInvalid(_UnformattedHyperglassError):
"""Raised when input validation fails."""
class InputNotAllowed(_UnformattedHyperglassError):
"""Raised when input validation fails due to a configured check."""
class ResponseEmpty(_UnformattedHyperglassError):
"""Raised when hyperglass can connect to the device but the response is empty."""
class UnsupportedDevice(_UnformattedHyperglassError):
"""Raised when an input NOS is not in the supported NOS list."""

View File

@@ -1,4 +1,4 @@
"""Hyperglass Front End"""
"""Hyperglass Front End."""
# Standard Library Imports
import operator
@@ -8,7 +8,6 @@ from pathlib import Path
# Third Party Imports
import aredis
import stackprinter
from logzero import logger as log
from prometheus_client import CONTENT_TYPE_LATEST
from prometheus_client import CollectorRegistry
from prometheus_client import Counter
@@ -27,7 +26,6 @@ from sanic_limiter import get_remote_address
# Project Imports
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.constants import Supported
from hyperglass.exceptions import AuthError
@@ -39,6 +37,7 @@ from hyperglass.exceptions import ResponseEmpty
from hyperglass.exceptions import RestError
from hyperglass.exceptions import ScrapeError
from hyperglass.render import render_html
from hyperglass.util import log
stackprinter.set_excepthook()

View File

@@ -1,20 +1,18 @@
"""
Renders Jinja2 & Sass templates for use by the front end application
"""
"""Renders Jinja2 & Sass templates for use by the front end application."""
# Standard Library Imports
from pathlib import Path
# Third Party Imports
import jinja2
import yaml
from logzero import logger as log
from markdown2 import Markdown
# Project Imports
from hyperglass.configuration import logzero_config # NOQA: F401
from hyperglass.configuration import networks
from hyperglass.configuration import params
from hyperglass.exceptions import HyperglassError
from hyperglass.util import log
# Module Directories
working_directory = Path(__file__).resolve().parent
@@ -190,7 +188,7 @@ def generate_markdown(section, file_name=None):
def render_html(template_name, **kwargs):
"""Renders Jinja2 HTML templates"""
"""Render Jinja2 HTML templates."""
details_name_list = ["footer", "bgp_aspath", "bgp_community"]
details_dict = {}
for details_name in details_name_list:

View File

@@ -1,6 +1,5 @@
"""
Renders Jinja2 & Sass templates for use by the front end application
"""
"""Renders Jinja2 & Sass templates for use by the front end application."""
# Standard Library Imports
import json
import subprocess
@@ -8,15 +7,14 @@ from pathlib import Path
# Third Party Imports
import jinja2
from logzero import logger as log
# Project Imports
from hyperglass.configuration import frontend_networks
from hyperglass.configuration import frontend_devices
from hyperglass.configuration import frontend_networks
from hyperglass.configuration import frontend_params
from hyperglass.configuration import logzero_config # NOQA: F401
from hyperglass.configuration import params
from hyperglass.exceptions import HyperglassError
from hyperglass.util import log
# Module Directories
working_directory = Path(__file__).resolve().parent

45
hyperglass/util.py Normal file
View File

@@ -0,0 +1,45 @@
"""Utility fuctions."""
# Third Party Imports
from loguru import logger as _loguru_logger
# Project Imports
from hyperglass.constants import LOG_HANDLER
from hyperglass.constants import LOG_LEVELS
from hyperglass.exceptions import ConfigInvalid
_loguru_logger.remove()
_loguru_logger.configure(handlers=[LOG_HANDLER], levels=LOG_LEVELS)
log = _loguru_logger
async def check_redis(host, port):
"""Validate if Redis is running.
Arguments:
host {str} -- IP address or hostname of Redis server
port {[type]} -- TCP port of Redis server
Raises:
ConfigInvalid: Raised if redis server is unreachable
Returns:
{bool} -- True if running, False if not
"""
import asyncio
from socket import gaierror
try:
_reader, _writer = await asyncio.open_connection(str(host), int(port))
except gaierror:
raise ConfigInvalid(
"Redis isn't running: {host}:{port} is unreachable/unresolvable.",
alert="danger",
host=host,
port=port,
)
if _reader or _writer:
return True
else:
return False