Refactor Device.commands to Device.directives

This commit is contained in:
thatmattlove 2021-09-16 22:43:53 -07:00
parent 10b1c8d624
commit ab097d4b06
3 changed files with 37 additions and 37 deletions

View file

@ -1,11 +1,11 @@
"""hyperglass Configuration."""
# Local
from .main import params, devices, commands, ui_params
from .main import params, devices, directives, ui_params
__all__ = (
"params",
"devices",
"commands",
"directives",
"ui_params",
)

View file

@ -10,7 +10,6 @@ from pydantic import ValidationError
# Project
from hyperglass.log import log, enable_file_logging, enable_syslog_logging
from hyperglass.util import set_cache_env
from hyperglass.defaults import CREDIT
from hyperglass.settings import Settings
from hyperglass.constants import PARSED_RESPONSE_FIELDS, __version__
@ -33,7 +32,7 @@ WORKING_DIR = Path(__file__).resolve().parent
CONFIG_FILES = (
("hyperglass.yaml", False),
("devices.yaml", True),
("commands.yaml", False),
("directives.yaml", False),
)
@ -62,7 +61,7 @@ def _check_config_files(directory: Path):
return files
CONFIG_MAIN, CONFIG_DEVICES, CONFIG_COMMANDS = _check_config_files(CONFIG_PATH)
CONFIG_MAIN, CONFIG_DEVICES, CONFIG_DIRECTIVES = _check_config_files(CONFIG_PATH)
def _config_required(config_path: Path) -> Dict:
@ -97,29 +96,30 @@ def _config_optional(config_path: Path) -> Dict:
return config
def _get_commands(data: Dict) -> List[Directive]:
commands = []
for name, command in data.items():
def _get_directives(data: Dict) -> List[Directive]:
directives = []
for name, directive in data.items():
try:
commands.append(Directive(id=name, **command))
directives.append(Directive(id=name, **directive))
except ValidationError as err:
raise ConfigError(
message="Validation error in command '{c}': '{e}'", c=name, e=err
message="Validation error in directive '{d}': '{e}'", d=name, e=err
) from err
return commands
return directives
def _device_commands(device: Dict, directives: List[Directive]) -> Generator[Directive, None, None]:
device_commands = device.get("commands", [])
def _device_directives(
device: Dict, directives: List[Directive]
) -> Generator[Directive, None, None]:
for directive in directives:
if directive.id in device_commands:
if directive.id in device.get("directives", []):
yield directive
def _get_devices(data: List[Dict], directives: List[Directive]) -> Devices:
for device in data:
device_commands = list(_device_commands(device, directives))
device["commands"] = device_commands
directives = list(_device_directives(device, directives))
device["directives"] = directives
return Devices(data)
@ -131,19 +131,16 @@ user_config = _config_optional(CONFIG_MAIN)
log.debug("Unvalidated configuration from {}: {}", CONFIG_MAIN, user_config)
params = validate_config(config=user_config, importer=Params)
# Map imported user commands to expected schema.
_user_commands = _config_optional(CONFIG_COMMANDS)
log.debug("Unvalidated commands from {}: {}", CONFIG_COMMANDS, _user_commands)
commands = _get_commands(_user_commands)
# Map imported user directives to expected schema.
_user_directives = _config_optional(CONFIG_DIRECTIVES)
log.debug("Unvalidated directives from {!s}: {}", CONFIG_DIRECTIVES, _user_directives)
directives = _get_directives(_user_directives)
# Map imported user devices to expected schema.
_user_devices = _config_required(CONFIG_DEVICES)
log.debug("Unvalidated devices from {}: {}", CONFIG_DEVICES, _user_devices)
devices: Devices = _get_devices(_user_devices.get("routers", []), commands)
devices = _get_devices(_user_devices.get("devices", _user_devices.get("routers", [])), directives)
# Set cache configurations to environment variables, so they can be
# used without importing this module (Gunicorn, etc).
set_cache_env(db=params.cache.database, host=params.cache.host, port=params.cache.port)
# Set up file logging once configuration parameters are initialized.
enable_file_logging(
@ -198,5 +195,3 @@ ui_params = UIParameters(
parsed_data_fields=PARSED_RESPONSE_FIELDS,
content={"credit": content_credit, "greeting": content_greeting},
)
URL_PROD = "/api/"

View file

@ -46,7 +46,7 @@ class Device(HyperglassModelWithId, extra="allow"):
port: StrictInt = 22
ssl: Optional[Ssl]
platform: StrictStr
commands: List[Directive]
directives: List[Directive]
structured_output: Optional[StrictBool]
driver: Optional[SupportedDriver]
attrs: Dict[str, str] = {}
@ -95,12 +95,16 @@ class Device(HyperglassModelWithId, extra="allow"):
"network": self.network.display_name,
}
@property
def directive_builtins(self) -> List[str]:
...
@property
def directive_commands(self) -> List[str]:
"""Get all commands associated with the device."""
return [
command
for directive in self.commands
for directive in self.directives
for rule in directive.rules
for command in rule.commands
]
@ -108,7 +112,7 @@ class Device(HyperglassModelWithId, extra="allow"):
@property
def directive_ids(self) -> List[str]:
"""Get all directive IDs associated with the device."""
return [directive.id for directive in self.commands]
return [directive.id for directive in self.directives]
def has_directives(self, *directive_ids: str) -> bool:
"""Determine if a directive is used on this device."""
@ -184,8 +188,8 @@ class Device(HyperglassModelWithId, extra="allow"):
return value
@root_validator(pre=True)
def validate_device_commands(cls, values: Dict) -> Dict:
"""Validate & rewrite device platform, set default commands."""
def validate_device(cls, values: Dict[str, Any]) -> Dict[str, Any]:
"""Validate & rewrite device platform, set default directives."""
platform = values.get("platform")
if platform is None:
@ -206,10 +210,11 @@ class Device(HyperglassModelWithId, extra="allow"):
values["platform"] = platform
commands = values.get("commands")
directives = values.get("directives")
if commands is None:
# If no commands are defined, set commands to the NOS.
if directives is None:
# TODO: This should be different now, and could be removed after there's a way to associate default directives
# If no directive are defined, set directive to the NOS.
inferred = values["platform"]
# If the _telnet prefix is added, remove it from the command
@ -218,7 +223,7 @@ class Device(HyperglassModelWithId, extra="allow"):
if "_telnet" in inferred:
inferred = inferred.replace("_telnet", "")
values["commands"] = [inferred]
values["directives"] = [inferred]
return values
@ -293,7 +298,7 @@ class Devices(HyperglassModel, extra="allow"):
"id": device.id,
"name": device.name,
"network": device.network.display_name,
"directives": [c.frontend(params) for c in device.commands],
"directives": [d.frontend(params) for d in device.directives],
}
for device in self.objects
if device.network.display_name == name
@ -306,7 +311,7 @@ class Devices(HyperglassModel, extra="allow"):
"""Get a mapping of plugin paths to associated directive IDs."""
result: Dict[Path, Set[StrictStr]] = {}
# Unique set of all directives.
directives = {directive for device in self.objects for directive in device.commands}
directives = {directive for device in self.objects for directive in device.directives}
# Unique set of all plugin file names.
plugin_names = {plugin for directive in directives for plugin in directive.plugins}