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

add support for hyperglass-agent

This commit is contained in:
checktheroads
2019-12-28 02:00:34 -07:00
parent ea83cb4e99
commit c805e9290e
4 changed files with 82 additions and 49 deletions

View File

@@ -89,6 +89,7 @@ class Construct:
query = []
query_protocol = f"ipv{ipaddress.ip_network(self.query_target).version}"
afi = getattr(self.device_vrf, query_protocol)
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
if self.transport == "rest":
query.append(
@@ -96,14 +97,13 @@ class Construct:
{
"query_type": "ping",
"vrf": afi.vrf_name,
"afi": query_protocol,
"afi": cmd_type,
"source": afi.source_address.compressed,
"target": self.query_target,
}
)
)
elif self.transport == "scrape":
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
cmd = self.device_commands(self.device.commands, cmd_type, "ping")
query.append(
cmd.format(
@@ -130,6 +130,7 @@ class Construct:
query = []
query_protocol = f"ipv{ipaddress.ip_network(self.query_target).version}"
afi = getattr(self.device_vrf, query_protocol)
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
if self.transport == "rest":
query.append(
@@ -137,14 +138,13 @@ class Construct:
{
"query_type": "traceroute",
"vrf": afi.vrf_name,
"afi": query_protocol,
"afi": cmd_type,
"source": afi.source_address.compressed,
"target": self.query_target,
}
)
)
elif self.transport == "scrape":
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
cmd = self.device_commands(self.device.commands, cmd_type, "traceroute")
query.append(
cmd.format(
@@ -168,6 +168,7 @@ class Construct:
query = []
query_protocol = f"ipv{ipaddress.ip_network(self.query_target).version}"
afi = getattr(self.device_vrf, query_protocol)
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
if self.transport == "rest":
query.append(
@@ -175,14 +176,13 @@ class Construct:
{
"query_type": "bgp_route",
"vrf": afi.vrf_name,
"afi": query_protocol,
"source": afi.source_address.compressed,
"afi": cmd_type,
"source": None,
"target": self.format_target(self.query_target),
}
)
)
elif self.transport == "scrape":
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
cmd = self.device_commands(self.device.commands, cmd_type, "bgp_route")
query.append(
cmd.format(
@@ -218,19 +218,20 @@ class Construct:
for afi in afis:
afi_attr = getattr(self.device_vrf, afi)
cmd_type = self.get_cmd_type(afi, self.query_vrf)
if self.transport == "rest":
query.append(
json.dumps(
{
"query_type": "bgp_community",
"vrf": afi_attr.vrf_name,
"afi": afi,
"afi": cmd_type,
"target": self.query_target,
"source": None,
}
)
)
elif self.transport == "scrape":
cmd_type = self.get_cmd_type(afi, self.query_vrf)
cmd = self.device_commands(
self.device.commands, cmd_type, "bgp_community"
)
@@ -267,19 +268,20 @@ class Construct:
for afi in afis:
afi_attr = getattr(self.device_vrf, afi)
cmd_type = self.get_cmd_type(afi, self.query_vrf)
if self.transport == "rest":
query.append(
json.dumps(
{
"query_type": "bgp_aspath",
"vrf": afi_attr.vrf_name,
"afi": afi,
"afi": cmd_type,
"target": self.query_target,
"source": None,
}
)
)
elif self.transport == "scrape":
cmd_type = self.get_cmd_type(afi, self.query_vrf)
cmd = self.device_commands(self.device.commands, cmd_type, "bgp_aspath")
query.append(
cmd.format(

View File

@@ -0,0 +1,30 @@
# Standard Library Imports
import datetime
# Third Party Imports
import jwt
# Project Imports
from hyperglass.exceptions import RestError
async def jwt_decode(payload, secret):
"""Decode & validate an encoded JSON Web Token (JWT)"""
try:
decoded = jwt.decode(payload, secret, algorithm="HS256")
decoded = decoded["payload"]
return decoded
except (KeyError, jwt.PyJWTError) as exp:
raise RestError(str(exp)) from None
async def jwt_encode(payload, secret, duration):
"""Encode a query to a JSON Web Token (JWT)"""
token = {
"payload": payload,
"nbf": datetime.datetime.utcnow(),
"iat": datetime.datetime.utcnow(),
"exp": datetime.datetime.utcnow() + datetime.timedelta(seconds=duration),
}
encoded = jwt.encode(token, secret, algorithm="HS256").decode("utf-8")
return encoded

View File

@@ -21,6 +21,7 @@ from netmiko import NetMikoTimeoutException
# Project Imports
from hyperglass.command.construct import Construct
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
@@ -218,53 +219,51 @@ 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",
"X-API-Key": self.device.credential.password.get_secret_value(),
}
http_protocol = protocol_map.get(self.device.port, "http")
endpoint = "{protocol}://{addr}:{port}/{uri}".format(
protocol=http_protocol,
addr=self.device.address,
port=self.device.port,
uri=uri,
# 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(
protocol=http_protocol, addr=self.device.address, port=self.device.port
)
log.debug(f"HTTP Headers: {headers}")
log.debug(f"URL endpoint: {endpoint}")
try:
http_client = httpx.AsyncClient()
async with httpx.Client() as http_client:
responses = []
for query in self.query:
encoded_query = await jwt_encode(
payload=query,
secret=self.device.credential.password.get_secret_value(),
duration=params.general.request_timeout,
)
log.debug(f"Encoded JWT: {encoded_query}")
raw_response = await http_client.post(
endpoint, headers=headers, json=query, timeout=7
endpoint,
headers=headers,
json={"encoded": encoded_query},
timeout=params.general.request_timeout,
)
log.debug(f"HTTP status code: {raw_response.status_code}")
raw = raw_response.text
responses.append(raw)
log.debug(f"Raw Response: {raw}")
if raw_response.status_code == 200:
decoded = await jwt_decode(
payload=raw_response.json()["encoded"],
secret=self.device.credential.password.get_secret_value(),
)
log.debug(f"Decoded Response: {decoded}")
responses.append(decoded)
else:
log.error(raw_response.text)
response = "\n\n".join(responses)
log.debug(f"Output for query {self.query}:\n{response}")
except (
httpx.exceptions.ConnectTimeout,
httpx.exceptions.CookieConflict,
httpx.exceptions.DecodingError,
httpx.exceptions.InvalidURL,
httpx.exceptions.PoolTimeout,
httpx.exceptions.ProtocolError,
httpx.exceptions.ReadTimeout,
httpx.exceptions.RedirectBodyUnavailable,
httpx.exceptions.RedirectLoop,
httpx.exceptions.ResponseClosed,
httpx.exceptions.ResponseNotRead,
httpx.exceptions.StreamConsumed,
httpx.exceptions.Timeout,
httpx.exceptions.TooManyRedirects,
httpx.exceptions.WriteTimeout,
) as rest_error:
except httpx.exceptions.HTTPError as rest_error:
rest_msg = " ".join(
re.findall(r"[A-Z][^A-Z]*", rest_error.__class__.__name__)
)

View File

@@ -1,7 +1,8 @@
aredis==1.1.5
click==7.0
cryptography==2.8
hiredis==1.0.0
httpx==0.6.8
httpx==0.9.*
jinja2==2.10.1
logzero==1.5.0
markdown2==2.3.8
@@ -9,6 +10,7 @@ netmiko==2.4.1
passlib==1.7.1
prometheus_client==0.7.1
pydantic==0.32.2
pyjwt==1.7.1
pyyaml==5.1.1
redis==3.2.1
sanic-limiter==0.1.3