-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* custom pollers * fix existing tests * tests * poller connect-disconnect * exclude custom poller form test from nb 3.7
- Loading branch information
1 parent
4e69071
commit 69361dd
Showing
28 changed files
with
412 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# User-defined Pollers | ||
|
||
Validity is able to perform device polling via custom user-defined pollers. This feature may be useful when: | ||
|
||
* existing polling methods must be adjusted to work with specific network equipment (e.g. slightly modify `netmiko` to interact with some ancient switch); | ||
* some completely new polling method must be introduced (e.g. gNMI-based). | ||
|
||
## Defining custom Poller | ||
|
||
To define your own Poller, two steps must be performed: | ||
|
||
* Inherit from `CustomPoller` class to implement your custom polling logic | ||
* Fill out `PollerInfo` structure with Poller meta info | ||
|
||
### Implementing Poller class | ||
|
||
Here is the minimal viable example of a custom poller class. It uses `scrapli` library to connect to devices via SSH. | ||
|
||
```python | ||
from scrapli import Scrapli | ||
from validity.pollers import CustomPoller | ||
from validity.models import Command | ||
|
||
|
||
class ScrapliPoller(CustomPoller): | ||
driver_factory = Scrapli | ||
host_param_name = 'host' # Scrapli expects "host" param containing ip address of the device | ||
driver_connect_method = 'open' # This driver method (if defined) will be called to open the connection. | ||
driver_disconnect_method = 'close' # This driver method (if defined) will be called to gracefully close the connection. | ||
|
||
def poll_one_command(self, driver, command) -> str: | ||
""" | ||
Arguments: | ||
driver - object returned by calling driver_factory, usually represents connection to a particular device | ||
command - Django model instance of the Command | ||
Returns: | ||
A string containing particular command execution result | ||
""" | ||
resp = driver.send_command(command.parameters["cli_command"]) | ||
return resp.result | ||
``` | ||
|
||
!!! note | ||
Be aware that every poller class instance is usually responsible for interaction with multiple devices. Hence, do not use poller fields for storing device-specific parameters. | ||
|
||
|
||
### Filling PollerInfo | ||
|
||
Poller Info is required to tell Validity about your custom poller. | ||
Here is the example of the plugin settings: | ||
|
||
```python | ||
# configuration.py | ||
|
||
from validity.settings import PollerInfo | ||
from my_awesome_poller import ScrapliPoller | ||
|
||
PLUGIN_SETTINGS = { | ||
'validity': { | ||
'custom_pollers' : [ | ||
PollerInfo(klass=ScrapliPoller, name='scrapli', color='pink', command_types=['CLI']) | ||
] | ||
} | ||
} | ||
``` | ||
|
||
PollerInfo parameters: | ||
|
||
* **klass** - class inherited from `CustomPoller` | ||
* **name** - system name of the poller, must contain lowercase letters only | ||
* **verbose_name** - optional verbose name of the poller. Will be used in NetBox GUI | ||
* **color** - badge color used for "Connection Type" field in the GUI | ||
* **command_types** - list of acceptable [Command](../entities/commands.md) types for this kind of Poller. Available choices are `CLI`, `netconf`, `json_api` and `custom` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
mkdocs==1.6.1 | ||
mkdocs-include-markdown-plugin==4.0.4 | ||
mkdocs-include-markdown-plugin==7.0.0 | ||
mkdocs-material==9.5.34 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from typing import TYPE_CHECKING, Collection | ||
|
||
from django.core.exceptions import ValidationError | ||
from django.utils.translation import gettext_lazy as _ | ||
|
||
|
||
if TYPE_CHECKING: | ||
from validity.models import Command | ||
|
||
|
||
def only_one_config_command(commands: Collection["Command"]) -> None: | ||
config_commands_count = sum(1 for cmd in commands if cmd.retrieves_config) | ||
if config_commands_count > 1: | ||
raise ValidationError( | ||
{ | ||
"commands": _("No more than 1 command to retrieve config is allowed, but %(cnt)s were specified") | ||
% {"cnt": config_commands_count} | ||
} | ||
) | ||
|
||
|
||
def commands_with_appropriate_type( | ||
commands: Collection["Command"], command_types: dict[str, list[str]], connection_type: str | ||
): | ||
acceptable_command_types = command_types.get(connection_type, []) | ||
if invalid_cmds := [cmd.label for cmd in commands if cmd.type not in acceptable_command_types]: | ||
raise ValidationError( | ||
{ | ||
"commands": _( | ||
"The following commands have inappropriate type and cannot be bound to this Poller: %(cmds)s" | ||
) | ||
% {"cmds": ", ".join(label for label in invalid_cmds)} | ||
} | ||
) |
Oops, something went wrong.