forked from mirrors/thatmattlove-hyperglass
Refactor Device.type to Device.platform
This commit is contained in:
parent
cb5459a72a
commit
85d7f8876e
12 changed files with 53 additions and 52 deletions
|
|
@ -17,9 +17,9 @@ class ExternalError(PrivateHyperglassError):
|
|||
|
||||
|
||||
class UnsupportedDevice(PrivateHyperglassError):
|
||||
"""Raised when an input NOS is not in the supported NOS list."""
|
||||
"""Raised when an input platform is not in the supported platform list."""
|
||||
|
||||
def __init__(self, device_type: str) -> None:
|
||||
def __init__(self, platform: str) -> None:
|
||||
"""Show the unsupported device type and a list of supported drivers."""
|
||||
# Third Party
|
||||
from netmiko.ssh_dispatcher import CLASS_MAPPER # type: ignore
|
||||
|
|
@ -29,7 +29,7 @@ class UnsupportedDevice(PrivateHyperglassError):
|
|||
|
||||
drivers = ("", *[*DRIVER_MAP.keys(), *CLASS_MAPPER.keys()].sort())
|
||||
driver_list = "\n - ".join(drivers)
|
||||
super().__init__(message=f"'{device_type}' is not supported. Must be one of:{driver_list}")
|
||||
super().__init__(message=f"'{platform}' is not supported. Must be one of:{driver_list}")
|
||||
|
||||
|
||||
class InputValidationError(PrivateHyperglassError):
|
||||
|
|
|
|||
|
|
@ -45,14 +45,14 @@ class Construct:
|
|||
|
||||
# Set transport method based on NOS type
|
||||
self.transport = "scrape"
|
||||
if self.device.type in TRANSPORT_REST:
|
||||
if self.device.platform in TRANSPORT_REST:
|
||||
self.transport = "rest"
|
||||
|
||||
# Remove slashes from target for required platforms
|
||||
if self.device.type in TARGET_FORMAT_SPACE:
|
||||
if self.device.platform in TARGET_FORMAT_SPACE:
|
||||
self.target = re.sub(r"\/", r" ", str(self.query.query_target))
|
||||
|
||||
with Formatter(self.device.type, self.query.query_type) as formatter:
|
||||
with Formatter(self.device.platform, self.query.query_type) as formatter:
|
||||
self.target = formatter(self.query.query_target)
|
||||
|
||||
def json(self, afi):
|
||||
|
|
@ -105,9 +105,9 @@ class Construct:
|
|||
class Formatter:
|
||||
"""Modify query target based on the device's NOS requirements and the query type."""
|
||||
|
||||
def __init__(self, device_type: str, query_type: str) -> None:
|
||||
def __init__(self, platform: str, query_type: str) -> None:
|
||||
"""Initialize target formatting."""
|
||||
self.device_type = device_type
|
||||
self.platform = platform
|
||||
self.query_type = query_type
|
||||
|
||||
def __enter__(self):
|
||||
|
|
@ -121,10 +121,10 @@ class Formatter:
|
|||
pass
|
||||
|
||||
def _get_formatter(self):
|
||||
if self.device_type in ("juniper", "juniper_junos"):
|
||||
if self.platform in ("juniper", "juniper_junos"):
|
||||
if self.query_type == "bgp_aspath":
|
||||
return self._juniper_bgp_aspath
|
||||
if self.device_type in ("bird", "bird_ssh"):
|
||||
if self.platform in ("bird", "bird_ssh"):
|
||||
if self.query_type == "bgp_aspath":
|
||||
return self._bird_bgp_aspath
|
||||
elif self.query_type == "bgp_community":
|
||||
|
|
|
|||
|
|
@ -57,14 +57,14 @@ class NetmikoConnection(SSHConnection):
|
|||
else:
|
||||
log.debug("Connecting directly to {}", self.device.name)
|
||||
|
||||
global_args = netmiko_device_globals.get(self.device.type, {})
|
||||
global_args = netmiko_device_globals.get(self.device.platform, {})
|
||||
|
||||
send_args = netmiko_device_send_args.get(self.device.type, {})
|
||||
send_args = netmiko_device_send_args.get(self.device.platform, {})
|
||||
|
||||
driver_kwargs = {
|
||||
"host": host or self.device._target,
|
||||
"port": port or self.device.port,
|
||||
"device_type": self.device.type,
|
||||
"device_type": self.device.platform,
|
||||
"username": self.device.credential.username,
|
||||
"global_delay_factor": params.netmiko_delay_factor,
|
||||
"timeout": math.floor(params.request_timeout * 1.25),
|
||||
|
|
@ -72,7 +72,7 @@ class NetmikoConnection(SSHConnection):
|
|||
**global_args,
|
||||
}
|
||||
|
||||
if "_telnet" in self.device.type:
|
||||
if "_telnet" in self.device.platform:
|
||||
# Telnet devices with a low delay factor (default) tend to
|
||||
# throw login errors.
|
||||
driver_kwargs["global_delay_factor"] = 2
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class ScrapliConnection(SSHConnection):
|
|||
command output.
|
||||
"""
|
||||
params = use_state("params")
|
||||
driver = _map_driver(self.device.type)
|
||||
driver = _map_driver(self.device.platform)
|
||||
|
||||
if host is not None:
|
||||
log.debug(
|
||||
|
|
@ -84,7 +84,7 @@ class ScrapliConnection(SSHConnection):
|
|||
else:
|
||||
log.debug("Connecting directly to {}", self.device.name)
|
||||
|
||||
global_args = driver_global_args.get(self.device.type, {})
|
||||
global_args = driver_global_args.get(self.device.platform, {})
|
||||
|
||||
driver_kwargs = {
|
||||
"host": host or self.device._target,
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ class Commands(HyperglassModel, extra="allow", validate_all=False):
|
|||
def import_params(cls, **input_params):
|
||||
"""Import loaded YAML, initialize per-command definitions."""
|
||||
obj = Commands()
|
||||
for device_type, cmds in input_params.items():
|
||||
cmd_set = _DEVICE_TYPE_MAP.get(device_type, CommandGroup)
|
||||
for platform, cmds in input_params.items():
|
||||
cmd_set = _DEVICE_TYPE_MAP.get(platform, CommandGroup)
|
||||
cmds = cmd_set(**cmds)
|
||||
setattr(obj, device_type, cmds)
|
||||
setattr(obj, platform, cmds)
|
||||
return obj
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ from hyperglass.util import (
|
|||
get_driver,
|
||||
get_fmt_keys,
|
||||
resolve_hostname,
|
||||
validate_device_type,
|
||||
validate_platform,
|
||||
)
|
||||
from hyperglass.settings import Settings
|
||||
from hyperglass.constants import SCRAPE_HELPERS, SUPPORTED_STRUCTURED_OUTPUT
|
||||
|
|
@ -45,7 +45,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
|||
display_name: Optional[StrictStr]
|
||||
port: StrictInt = 22
|
||||
ssl: Optional[Ssl]
|
||||
type: StrictStr
|
||||
platform: StrictStr
|
||||
commands: List[Directive]
|
||||
structured_output: Optional[StrictBool]
|
||||
driver: Optional[SupportedDriver]
|
||||
|
|
@ -156,15 +156,15 @@ class Device(HyperglassModelWithId, extra="allow"):
|
|||
"""Validate structured output is supported on the device & set a default."""
|
||||
|
||||
if value is True:
|
||||
if values["type"] not in SUPPORTED_STRUCTURED_OUTPUT:
|
||||
if values["platform"] not in SUPPORTED_STRUCTURED_OUTPUT:
|
||||
raise ConfigError(
|
||||
"The 'structured_output' field is set to 'true' on device '{d}' with "
|
||||
+ "NOS '{n}', which does not support structured output",
|
||||
+ "platform '{p}', which does not support structured output",
|
||||
d=values["name"],
|
||||
n=values["type"],
|
||||
p=values["platform"],
|
||||
)
|
||||
return value
|
||||
elif value is None and values["type"] in SUPPORTED_STRUCTURED_OUTPUT:
|
||||
elif value is None and values["platform"] in SUPPORTED_STRUCTURED_OUTPUT:
|
||||
value = True
|
||||
else:
|
||||
value = False
|
||||
|
|
@ -185,31 +185,32 @@ class Device(HyperglassModelWithId, extra="allow"):
|
|||
|
||||
@root_validator(pre=True)
|
||||
def validate_device_commands(cls, values: Dict) -> Dict:
|
||||
"""Validate & rewrite device type, set default commands."""
|
||||
"""Validate & rewrite device platform, set default commands."""
|
||||
|
||||
_type = values.get("type")
|
||||
if _type is None:
|
||||
# Ensure device type is defined.
|
||||
raise ValueError(
|
||||
f"Device {values['name']} is missing a 'type' (Network Operating System) property."
|
||||
platform = values.get("platform")
|
||||
if platform is None:
|
||||
# Ensure device platform is defined.
|
||||
raise ConfigError(
|
||||
"Device '{device}' is missing a 'platform' (Network Operating System) property",
|
||||
device={values["name"]},
|
||||
)
|
||||
|
||||
if _type in SCRAPE_HELPERS.keys():
|
||||
if platform in SCRAPE_HELPERS.keys():
|
||||
# Rewrite NOS to helper value if needed.
|
||||
_type = SCRAPE_HELPERS[_type]
|
||||
platform = SCRAPE_HELPERS[platform]
|
||||
|
||||
# Verify device type is supported by hyperglass.
|
||||
supported, _ = validate_device_type(_type)
|
||||
# Verify device platform is supported by hyperglass.
|
||||
supported, _ = validate_platform(platform)
|
||||
if not supported:
|
||||
raise UnsupportedDevice(_type)
|
||||
raise UnsupportedDevice(platform)
|
||||
|
||||
values["type"] = _type
|
||||
values["platform"] = platform
|
||||
|
||||
commands = values.get("commands")
|
||||
|
||||
if commands is None:
|
||||
# If no commands are defined, set commands to the NOS.
|
||||
inferred = values["type"]
|
||||
inferred = values["platform"]
|
||||
|
||||
# If the _telnet prefix is added, remove it from the command
|
||||
# profile so the commands are the same regardless of
|
||||
|
|
@ -224,7 +225,7 @@ class Device(HyperglassModelWithId, extra="allow"):
|
|||
@validator("driver")
|
||||
def validate_driver(cls, value: Optional[str], values: Dict) -> Dict:
|
||||
"""Set the correct driver and override if supported."""
|
||||
return get_driver(values["type"], value)
|
||||
return get_driver(values["platform"], value)
|
||||
|
||||
|
||||
class Devices(HyperglassModel, extra="allow"):
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class Proxy(HyperglassModel):
|
|||
address: Union[IPv4Address, IPv6Address, StrictStr]
|
||||
port: StrictInt = 22
|
||||
credential: Credential
|
||||
type: StrictStr = "linux_ssh"
|
||||
platform: StrictStr = "linux_ssh"
|
||||
|
||||
def __init__(self: "Proxy", **kwargs: Any) -> None:
|
||||
"""Check for legacy fields."""
|
||||
|
|
@ -48,13 +48,13 @@ class Proxy(HyperglassModel):
|
|||
)
|
||||
return value
|
||||
|
||||
@validator("type", pre=True, always=True)
|
||||
@validator("platform", pre=True, always=True)
|
||||
def validate_type(cls: "Proxy", value: Any, values: Dict[str, Any]) -> str:
|
||||
"""Validate device type."""
|
||||
|
||||
if value != "linux_ssh":
|
||||
raise UnsupportedDevice(
|
||||
"Proxy '{p}' uses type '{t}', which is currently unsupported.",
|
||||
"Proxy '{p}' uses platform '{t}', which is currently unsupported.",
|
||||
p=values["name"],
|
||||
t=value,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ from typing import Any, Dict, Tuple
|
|||
from hyperglass.log import log
|
||||
|
||||
LEGACY_FIELDS: Dict[str, Tuple[Tuple[str, str], ...]] = {
|
||||
"Device": (("nos", "type"),),
|
||||
"Proxy": (("nos", "type"),),
|
||||
"Device": (("nos", "platform"),),
|
||||
"Proxy": (("nos", "platform"),),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -63,10 +63,10 @@ class DirectivePlugin(BaseModel):
|
|||
directives: Sequence[str] = ()
|
||||
|
||||
|
||||
class DeviceTypePlugin(BaseModel):
|
||||
"""Plugin associated with specific device types.
|
||||
class PlatformPlugin(BaseModel):
|
||||
"""Plugin associated with specific device platform.
|
||||
|
||||
Should always be subclassed with `HyperglassPlugin`.
|
||||
"""
|
||||
|
||||
device_types: Sequence[str] = ()
|
||||
platforms: Sequence[str] = ()
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ class BGPRoutePluginJuniper(OutputPlugin):
|
|||
"""Coerce a Juniper route table in XML format to a standard BGP Table structure."""
|
||||
|
||||
__hyperglass_builtin__: bool = PrivateAttr(True)
|
||||
device_types: Sequence[str] = ("juniper",)
|
||||
platforms: Sequence[str] = ("juniper",)
|
||||
directives: Sequence[str] = (
|
||||
"__hyperglass_juniper_bgp_route__",
|
||||
"__hyperglass_juniper_bgp_aspath__",
|
||||
|
|
@ -132,7 +132,7 @@ class BGPRoutePluginJuniper(OutputPlugin):
|
|||
should_process = all(
|
||||
(
|
||||
isinstance(output, (list, tuple)),
|
||||
device.type in self.device_types,
|
||||
device.platform in self.platforms,
|
||||
device.structured_output is True,
|
||||
device.has_directives(*self.directives),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from hyperglass.log import log
|
|||
from hyperglass.types import Series
|
||||
|
||||
# Local
|
||||
from ._base import DirectivePlugin, DeviceTypePlugin, HyperglassPlugin
|
||||
from ._base import DirectivePlugin, PlatformPlugin, HyperglassPlugin
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# Project
|
||||
|
|
@ -18,7 +18,7 @@ if TYPE_CHECKING:
|
|||
OutputType = Union["OutputDataModel", Series[str]]
|
||||
|
||||
|
||||
class OutputPlugin(HyperglassPlugin, DirectivePlugin, DeviceTypePlugin):
|
||||
class OutputPlugin(HyperglassPlugin, DirectivePlugin, PlatformPlugin):
|
||||
"""Plugin to interact with device command output."""
|
||||
|
||||
def process(self, output: OutputType, device: "Device") -> OutputType:
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ def repr_from_attrs(obj: object, attrs: Series[str]) -> str:
|
|||
return f"{obj.__class__.__name__}({','.join(pairs)})"
|
||||
|
||||
|
||||
def validate_device_type(_type: str) -> t.Tuple[bool, t.Union[None, str]]:
|
||||
def validate_platform(_type: str) -> t.Tuple[bool, t.Union[None, str]]:
|
||||
"""Validate device type is supported."""
|
||||
|
||||
result = (False, None)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue