2019-06-07 18:33:49 -07:00
|
|
|
"""
|
2019-07-07 23:28:23 -07:00
|
|
|
Accepts filtered & validated input from execute.py, constructs SSH
|
|
|
|
command for Netmiko library or API call parameters for supported
|
|
|
|
hyperglass API modules.
|
2019-06-07 18:33:49 -07:00
|
|
|
"""
|
2019-07-10 15:57:21 -07:00
|
|
|
# Standard Library Imports
|
|
|
|
import ipaddress
|
2019-05-20 11:20:54 -07:00
|
|
|
import json
|
2019-07-07 02:49:54 -07:00
|
|
|
import operator
|
2019-10-09 03:10:52 -07:00
|
|
|
import re
|
2019-06-10 12:22:38 -07:00
|
|
|
|
2019-07-10 15:57:21 -07:00
|
|
|
# Third Party Imports
|
2019-09-25 22:40:02 -07:00
|
|
|
from logzero import logger as log
|
2019-06-07 18:33:49 -07:00
|
|
|
|
2019-05-26 18:46:43 -07:00
|
|
|
# Project Imports
|
2019-07-10 15:57:21 -07:00
|
|
|
from hyperglass.configuration import commands
|
2019-10-04 17:17:08 -07:00
|
|
|
from hyperglass.configuration import logzero_config # NOQA: F401
|
2019-10-01 01:04:23 -07:00
|
|
|
from hyperglass.constants import target_format_space
|
2019-10-09 03:10:52 -07:00
|
|
|
from hyperglass.exceptions import HyperglassError
|
2019-06-07 18:33:49 -07:00
|
|
|
|
|
|
|
|
|
|
|
class Construct:
|
2019-07-07 02:49:54 -07:00
|
|
|
"""
|
|
|
|
Constructs SSH commands or REST API queries based on validated
|
|
|
|
input parameters.
|
|
|
|
"""
|
2019-06-07 18:33:49 -07:00
|
|
|
|
2019-10-09 03:10:52 -07:00
|
|
|
def get_device_vrf(self):
|
|
|
|
_device_vrf = None
|
|
|
|
for vrf in self.device.vrfs:
|
|
|
|
if vrf.name == self.query_vrf:
|
|
|
|
_device_vrf = vrf
|
|
|
|
if not _device_vrf:
|
|
|
|
raise HyperglassError(
|
|
|
|
message="Unable to match query VRF to any configured VRFs",
|
|
|
|
alert="danger",
|
|
|
|
keywords=[self.query_vrf],
|
|
|
|
)
|
|
|
|
return _device_vrf
|
|
|
|
|
2019-09-09 00:18:01 -07:00
|
|
|
def __init__(self, device, query_data, transport):
|
2019-06-07 18:33:49 -07:00
|
|
|
self.device = device
|
2019-09-09 00:18:01 -07:00
|
|
|
self.query_data = query_data
|
2019-07-15 02:30:42 -07:00
|
|
|
self.transport = transport
|
2019-09-09 23:05:10 -07:00
|
|
|
self.query_target = self.query_data["query_target"]
|
|
|
|
self.query_vrf = self.query_data["query_vrf"]
|
2019-10-09 03:10:52 -07:00
|
|
|
self.device_vrf = self.get_device_vrf()
|
2019-06-07 18:33:49 -07:00
|
|
|
|
2019-10-01 01:04:23 -07:00
|
|
|
def format_target(self, target):
|
|
|
|
"""Formats query target based on NOS requirement"""
|
|
|
|
if self.device.nos in target_format_space:
|
|
|
|
_target = re.sub(r"\/", r" ", target)
|
2019-10-02 01:18:01 -07:00
|
|
|
else:
|
|
|
|
_target = target
|
2019-10-01 01:04:23 -07:00
|
|
|
log.debug(f"Formatted target: {_target}")
|
|
|
|
return _target
|
2019-05-22 23:27:57 -07:00
|
|
|
|
2019-07-07 23:28:23 -07:00
|
|
|
@staticmethod
|
|
|
|
def device_commands(nos, afi, query_type):
|
|
|
|
"""
|
|
|
|
Constructs class attribute path from input parameters, returns
|
|
|
|
class attribute value for command. This is required because
|
|
|
|
class attributes are set dynamically when devices.yaml is
|
|
|
|
imported, so the attribute path is unknown until runtime.
|
|
|
|
"""
|
2019-07-07 02:49:54 -07:00
|
|
|
cmd_path = f"{nos}.{afi}.{query_type}"
|
|
|
|
return operator.attrgetter(cmd_path)(commands)
|
|
|
|
|
2019-09-09 00:18:01 -07:00
|
|
|
@staticmethod
|
2019-09-30 23:48:15 -07:00
|
|
|
def get_cmd_type(query_protocol, query_vrf):
|
2019-09-09 00:18:01 -07:00
|
|
|
"""
|
|
|
|
Constructs AFI string. If query_vrf is specified, AFI prefix is
|
|
|
|
"vpnv", if not, AFI prefix is "ipv"
|
|
|
|
"""
|
2019-09-25 23:47:22 -07:00
|
|
|
if query_vrf and query_vrf != "default":
|
2019-10-09 03:10:52 -07:00
|
|
|
cmd_type = f"{query_protocol}_vpn"
|
2019-09-09 00:18:01 -07:00
|
|
|
else:
|
2019-09-30 23:48:15 -07:00
|
|
|
cmd_type = f"{query_protocol}_default"
|
2019-09-30 07:51:17 -07:00
|
|
|
return cmd_type
|
2019-09-09 00:18:01 -07:00
|
|
|
|
|
|
|
def ping(self):
|
2019-06-07 18:33:49 -07:00
|
|
|
"""Constructs ping query parameters from pre-validated input"""
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(
|
2019-09-09 00:18:01 -07:00
|
|
|
f"Constructing ping query for {self.query_target} via {self.transport}"
|
2019-07-15 02:30:42 -07:00
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
|
|
|
query = []
|
2019-09-30 07:51:17 -07:00
|
|
|
query_protocol = f"ipv{ipaddress.ip_network(self.query_target).version}"
|
2019-10-09 03:10:52 -07:00
|
|
|
afi = getattr(self.device_vrf, query_protocol)
|
2019-09-25 23:47:22 -07:00
|
|
|
|
|
|
|
if self.transport == "rest":
|
|
|
|
query.append(
|
|
|
|
json.dumps(
|
2019-09-25 11:06:57 -07:00
|
|
|
{
|
|
|
|
"query_type": "ping",
|
2019-09-30 07:51:17 -07:00
|
|
|
"vrf": afi.vrf_name,
|
|
|
|
"source": afi.source_address,
|
2019-09-25 11:06:57 -07:00
|
|
|
"target": self.query_target,
|
|
|
|
}
|
|
|
|
)
|
2019-09-25 23:47:22 -07:00
|
|
|
)
|
|
|
|
elif self.transport == "scrape":
|
2019-10-09 03:10:52 -07:00
|
|
|
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
|
2019-09-30 23:48:15 -07:00
|
|
|
cmd = self.device_commands(self.device.commands, cmd_type, "ping")
|
2019-09-25 23:47:22 -07:00
|
|
|
query.append(
|
2019-09-30 07:51:17 -07:00
|
|
|
cmd.format(
|
|
|
|
target=self.query_target,
|
|
|
|
source=afi.source_address,
|
|
|
|
vrf=afi.vrf_name,
|
|
|
|
)
|
2019-09-25 23:47:22 -07:00
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(f"Constructed query: {query}")
|
2019-09-25 11:06:57 -07:00
|
|
|
return query
|
2019-05-22 23:27:57 -07:00
|
|
|
|
2019-09-09 00:18:01 -07:00
|
|
|
def traceroute(self):
|
2019-07-07 02:49:54 -07:00
|
|
|
"""
|
|
|
|
Constructs traceroute query parameters from pre-validated input.
|
|
|
|
"""
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(
|
2019-09-09 00:18:01 -07:00
|
|
|
(
|
|
|
|
f"Constructing traceroute query for {self.query_target} "
|
|
|
|
f"via {self.transport}"
|
|
|
|
)
|
2019-07-15 02:30:42 -07:00
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-30 07:51:17 -07:00
|
|
|
query = []
|
|
|
|
query_protocol = f"ipv{ipaddress.ip_network(self.query_target).version}"
|
2019-10-09 03:10:52 -07:00
|
|
|
afi = getattr(self.device_vrf, query_protocol)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-07-15 02:30:42 -07:00
|
|
|
if self.transport == "rest":
|
2019-09-30 07:51:17 -07:00
|
|
|
query.append(
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"query_type": "traceroute",
|
|
|
|
"vrf": afi.vrf_name,
|
|
|
|
"source": afi.source_address,
|
|
|
|
"target": self.query_target,
|
|
|
|
}
|
|
|
|
)
|
2019-06-07 18:33:49 -07:00
|
|
|
)
|
2019-07-15 02:30:42 -07:00
|
|
|
elif self.transport == "scrape":
|
2019-10-09 03:10:52 -07:00
|
|
|
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
|
2019-09-30 23:48:15 -07:00
|
|
|
cmd = self.device_commands(self.device.commands, cmd_type, "traceroute")
|
2019-09-30 07:51:17 -07:00
|
|
|
query.append(
|
|
|
|
cmd.format(
|
|
|
|
target=self.query_target,
|
|
|
|
source=afi.source_address,
|
|
|
|
vrf=afi.vrf_name,
|
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
)
|
|
|
|
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(f"Constructed query: {query}")
|
2019-09-30 07:51:17 -07:00
|
|
|
return query
|
2019-05-20 11:20:54 -07:00
|
|
|
|
2019-09-09 00:18:01 -07:00
|
|
|
def bgp_route(self):
|
2019-07-07 02:49:54 -07:00
|
|
|
"""
|
|
|
|
Constructs bgp_route query parameters from pre-validated input.
|
|
|
|
"""
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(
|
2019-09-09 00:18:01 -07:00
|
|
|
f"Constructing bgp_route query for {self.query_target} via {self.transport}"
|
2019-07-15 02:30:42 -07:00
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-30 07:51:17 -07:00
|
|
|
query = []
|
|
|
|
query_protocol = f"ipv{ipaddress.ip_network(self.query_target).version}"
|
2019-10-09 03:10:52 -07:00
|
|
|
afi = getattr(self.device_vrf, query_protocol)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-07-15 02:30:42 -07:00
|
|
|
if self.transport == "rest":
|
2019-09-30 07:51:17 -07:00
|
|
|
query.append(
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"query_type": "bgp_route",
|
|
|
|
"vrf": afi.vrf_name,
|
|
|
|
"source": afi.source_address,
|
|
|
|
"target": self.query_target,
|
|
|
|
}
|
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
)
|
2019-07-15 02:30:42 -07:00
|
|
|
elif self.transport == "scrape":
|
2019-10-09 03:10:52 -07:00
|
|
|
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
|
2019-09-30 23:48:15 -07:00
|
|
|
cmd = self.device_commands(self.device.commands, cmd_type, "bgp_route")
|
2019-09-30 07:51:17 -07:00
|
|
|
query.append(
|
|
|
|
cmd.format(
|
2019-10-01 01:04:23 -07:00
|
|
|
target=self.format_target(self.query_target),
|
2019-09-30 07:51:17 -07:00
|
|
|
source=afi.source_address,
|
|
|
|
vrf=afi.vrf_name,
|
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
)
|
|
|
|
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(f"Constructed query: {query}")
|
2019-09-30 07:51:17 -07:00
|
|
|
return query
|
2019-05-20 11:20:54 -07:00
|
|
|
|
2019-09-09 00:18:01 -07:00
|
|
|
def bgp_community(self):
|
2019-07-07 02:49:54 -07:00
|
|
|
"""
|
|
|
|
Constructs bgp_community query parameters from pre-validated
|
|
|
|
input.
|
|
|
|
"""
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(
|
2019-09-09 00:18:01 -07:00
|
|
|
(
|
2019-09-30 07:51:17 -07:00
|
|
|
f"Constructing bgp_community query for "
|
|
|
|
f"{self.query_target} via {self.transport}"
|
2019-09-09 00:18:01 -07:00
|
|
|
)
|
2019-07-15 02:30:42 -07:00
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-30 07:51:17 -07:00
|
|
|
query = []
|
2019-09-30 23:48:15 -07:00
|
|
|
afis = []
|
|
|
|
|
|
|
|
for vrf_key, vrf_value in {
|
2019-10-09 03:10:52 -07:00
|
|
|
p: e for p, e in self.device_vrf.dict().items() if p in ("ipv4", "ipv6")
|
2019-09-30 23:48:15 -07:00
|
|
|
}.items():
|
|
|
|
if vrf_value:
|
|
|
|
afis.append(vrf_key)
|
|
|
|
|
|
|
|
for afi in afis:
|
2019-10-09 03:10:52 -07:00
|
|
|
afi_attr = getattr(self.device_vrf, afi)
|
2019-09-30 23:48:15 -07:00
|
|
|
if self.transport == "rest":
|
|
|
|
query.append(
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"query_type": "bgp_community",
|
|
|
|
"vrf": afi_attr.vrf_name,
|
|
|
|
"source": afi_attr.source_address,
|
|
|
|
"target": self.query_target,
|
|
|
|
}
|
|
|
|
)
|
2019-09-30 07:51:17 -07:00
|
|
|
)
|
2019-09-30 23:48:15 -07:00
|
|
|
elif self.transport == "scrape":
|
2019-10-09 03:10:52 -07:00
|
|
|
cmd_type = self.get_cmd_type(afi, self.query_vrf)
|
2019-09-30 23:48:15 -07:00
|
|
|
cmd = self.device_commands(
|
|
|
|
self.device.commands, cmd_type, "bgp_community"
|
|
|
|
)
|
|
|
|
query.append(
|
|
|
|
cmd.format(
|
|
|
|
target=self.query_target,
|
|
|
|
source=afi_attr.source_address,
|
|
|
|
vrf=afi_attr.vrf_name,
|
|
|
|
)
|
2019-09-30 07:51:17 -07:00
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(f"Constructed query: {query}")
|
2019-06-07 18:33:49 -07:00
|
|
|
return query
|
2019-05-22 23:27:57 -07:00
|
|
|
|
2019-09-09 00:18:01 -07:00
|
|
|
def bgp_aspath(self):
|
2019-07-07 02:49:54 -07:00
|
|
|
"""
|
|
|
|
Constructs bgp_aspath query parameters from pre-validated input.
|
|
|
|
"""
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(
|
2019-09-09 00:18:01 -07:00
|
|
|
(
|
2019-09-30 23:48:15 -07:00
|
|
|
f"Constructing bgp_aspath query for "
|
|
|
|
f"{self.query_target} via {self.transport}"
|
2019-09-09 00:18:01 -07:00
|
|
|
)
|
2019-07-15 02:30:42 -07:00
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-30 23:48:15 -07:00
|
|
|
query = []
|
|
|
|
afis = []
|
|
|
|
|
|
|
|
for vrf_key, vrf_value in {
|
2019-10-09 03:10:52 -07:00
|
|
|
p: e for p, e in self.device_vrf.dict().items() if p in ("ipv4", "ipv6")
|
2019-09-30 23:48:15 -07:00
|
|
|
}.items():
|
|
|
|
if vrf_value:
|
|
|
|
afis.append(vrf_key)
|
|
|
|
|
|
|
|
for afi in afis:
|
2019-10-09 03:10:52 -07:00
|
|
|
afi_attr = getattr(self.device_vrf, afi)
|
2019-09-30 23:48:15 -07:00
|
|
|
if self.transport == "rest":
|
|
|
|
query.append(
|
|
|
|
json.dumps(
|
|
|
|
{
|
|
|
|
"query_type": "bgp_aspath",
|
|
|
|
"vrf": afi_attr.vrf_name,
|
|
|
|
"source": afi_attr.source_address,
|
|
|
|
"target": self.query_target,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
)
|
|
|
|
elif self.transport == "scrape":
|
2019-10-09 03:10:52 -07:00
|
|
|
cmd_type = self.get_cmd_type(afi, self.query_vrf)
|
2019-09-30 23:48:15 -07:00
|
|
|
cmd = self.device_commands(self.device.commands, cmd_type, "bgp_aspath")
|
|
|
|
query.append(
|
|
|
|
cmd.format(
|
|
|
|
target=self.query_target,
|
|
|
|
source=afi_attr.source_address,
|
|
|
|
vrf=afi_attr.vrf_name,
|
|
|
|
)
|
|
|
|
)
|
2019-09-09 00:18:01 -07:00
|
|
|
|
2019-09-25 22:40:02 -07:00
|
|
|
log.debug(f"Constructed query: {query}")
|
2019-06-07 18:33:49 -07:00
|
|
|
return query
|