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

340 lines
11 KiB
Python
Raw Normal View History

"""Construct SSH command/API parameters from validated query data.
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.
"""
# Standard Library Imports
import ipaddress
import json
import operator
import re
2019-06-10 12:22:38 -07:00
# Project Imports
from hyperglass.configuration import commands
from hyperglass.constants import target_format_space
from hyperglass.exceptions import HyperglassError
from hyperglass.util import log
class Construct:
"""Construct SSH commands/REST API parameters from validated query data."""
def get_device_vrf(self):
2019-12-31 13:30:55 -07:00
"""Match query VRF to device VRF.
Raises:
HyperglassError: Raised if VRFs do not match.
Returns:
{object} -- Matched VRF object
"""
_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",
2020-01-21 17:30:14 -07:00
level="danger",
keywords=[self.query_vrf],
)
return _device_vrf
2019-09-09 00:18:01 -07:00
def __init__(self, device, query_data, transport):
2019-12-31 13:30:55 -07:00
"""Initialize command construction.
Arguments:
device {object} -- Device object
query_data {object} -- Validated query object
transport {str} -- Transport name; 'scrape' or 'rest'
"""
self.device = device
2019-09-09 00:18:01 -07:00
self.query_data = query_data
self.transport = transport
2020-01-16 02:36:56 -07:00
self.query_target = self.query_data.query_target
self.query_vrf = self.query_data.query_vrf
self.device_vrf = self.get_device_vrf()
def format_target(self, target):
2019-12-31 13:30:55 -07:00
"""Format query target based on NOS requirement.
Arguments:
target {str} -- Query target
Returns:
{str} -- Formatted target
"""
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-11-16 23:09:43 -07:00
target_string = str(_target)
log.debug(f"Formatted target: {target_string}")
return target_string
2019-05-22 23:27:57 -07:00
2019-07-07 23:28:23 -07:00
@staticmethod
def device_commands(nos, afi, query_type):
2019-12-31 13:30:55 -07:00
"""Construct class attribute path for device commansd.
This is required because class attributes are set dynamically
when devices.yaml is imported, so the attribute path is unknown
until runtime.
Arguments:
nos {str} -- NOS short name
afi {str} -- Address family
query_type {str} -- Query type
Returns:
{str} -- Dotted attribute path, e.g. 'cisco_ios.ipv4.bgp_route'
2019-07-07 23:28:23 -07:00
"""
cmd_path = f"{nos}.{afi}.{query_type}"
return operator.attrgetter(cmd_path)(commands)
2019-09-09 00:18:01 -07:00
@staticmethod
def get_cmd_type(query_protocol, query_vrf):
2019-12-31 13:30:55 -07:00
"""Construct AFI string.
If query_vrf is specified, AFI prefix is "vpnv".
If not, AFI prefix is "ipv".
Arguments:
query_protocol {str} -- 'ipv4' or 'ipv6'
query_vrf {str} -- Query VRF name
Returns:
{str} -- Constructed command name
2019-09-09 00:18:01 -07:00
"""
2019-09-25 23:47:22 -07:00
if query_vrf and query_vrf != "default":
cmd_type = f"{query_protocol}_vpn"
2019-09-09 00:18:01 -07:00
else:
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-12-31 13:30:55 -07:00
"""Construct ping query parameters from pre-validated input.
2019-09-09 00:18:01 -07:00
2019-12-31 13:30:55 -07:00
Returns:
{str} -- SSH command or stringified JSON
"""
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-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}"
afi = getattr(self.device_vrf, query_protocol)
2019-12-28 02:00:34 -07:00
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
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,
2019-12-28 02:00:34 -07:00
"afi": cmd_type,
2019-11-16 23:09:43 -07:00
"source": afi.source_address.compressed,
2019-09-25 11:06:57 -07:00
"target": self.query_target,
}
)
2019-09-25 23:47:22 -07:00
)
elif self.transport == "scrape":
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-12-31 13:30:55 -07:00
"""Construct traceroute query parameters from pre-validated input.
Returns:
{str} -- SSH command or stringified JSON
"""
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-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}"
afi = getattr(self.device_vrf, query_protocol)
2019-12-28 02:00:34 -07:00
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
2019-09-09 00:18:01 -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,
2019-12-28 02:00:34 -07:00
"afi": cmd_type,
2019-11-16 23:09:43 -07:00
"source": afi.source_address.compressed,
2019-09-30 07:51:17 -07:00
"target": self.query_target,
}
)
)
elif self.transport == "scrape":
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-09-09 00:18:01 -07:00
def bgp_route(self):
2019-12-31 13:30:55 -07:00
"""Construct bgp_route query parameters from pre-validated input.
Returns:
{str} -- SSH command or stringified JSON
"""
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-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}"
afi = getattr(self.device_vrf, query_protocol)
2019-12-28 02:00:34 -07:00
cmd_type = self.get_cmd_type(query_protocol, self.query_vrf)
2019-09-09 00:18:01 -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,
2019-12-28 02:00:34 -07:00
"afi": cmd_type,
"source": None,
2019-11-16 23:09:43 -07:00
"target": self.format_target(self.query_target),
2019-09-30 07:51:17 -07:00
}
)
2019-09-09 00:18:01 -07:00
)
elif self.transport == "scrape":
cmd = self.device_commands(self.device.commands, cmd_type, "bgp_route")
2019-09-30 07:51:17 -07:00
query.append(
cmd.format(
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-09-09 00:18:01 -07:00
def bgp_community(self):
2019-12-31 13:30:55 -07:00
"""Construct bgp_community query parameters from pre-validated input.
Returns:
{str} -- SSH command or stringified JSON
"""
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-09-09 00:18:01 -07:00
2019-09-30 07:51:17 -07:00
query = []
afis = []
for vrf_key, vrf_value in {
p: e for p, e in self.device_vrf.dict().items() if p in ("ipv4", "ipv6")
}.items():
if vrf_value:
afis.append(vrf_key)
for afi in afis:
afi_attr = getattr(self.device_vrf, afi)
2019-12-28 02:00:34 -07:00
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,
2019-12-28 02:00:34 -07:00
"afi": cmd_type,
"target": self.query_target,
2019-12-28 02:00:34 -07:00
"source": None,
}
)
2019-09-30 07:51:17 -07:00
)
elif self.transport == "scrape":
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}")
return query
2019-05-22 23:27:57 -07:00
2019-09-09 00:18:01 -07:00
def bgp_aspath(self):
2019-12-31 13:30:55 -07:00
"""Construct bgp_aspath query parameters from pre-validated input.
Returns:
{str} -- SSH command or stringified JSON
"""
2019-09-25 22:40:02 -07:00
log.debug(
2019-09-09 00:18:01 -07:00
(
f"Constructing bgp_aspath query for "
f"{self.query_target} via {self.transport}"
2019-09-09 00:18:01 -07:00
)
)
2019-09-09 00:18:01 -07:00
query = []
afis = []
for vrf_key, vrf_value in {
p: e for p, e in self.device_vrf.dict().items() if p in ("ipv4", "ipv6")
}.items():
if vrf_value:
afis.append(vrf_key)
for afi in afis:
afi_attr = getattr(self.device_vrf, afi)
2019-12-28 02:00:34 -07:00
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,
2019-12-28 02:00:34 -07:00
"afi": cmd_type,
"target": self.query_target,
2019-12-28 02:00:34 -07:00
"source": None,
}
)
)
elif self.transport == "scrape":
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}")
return query