Clean up docs

This commit is contained in:
Jeremy Stretch 2024-02-07 10:28:52 -05:00
parent 7a10b4ef89
commit 9aabcb2d4f
3 changed files with 104 additions and 100 deletions

View File

@ -5,10 +5,9 @@ Custom scripting was introduced to provide a way for users to execute custom log
* Automatically populate new devices and cables in preparation for a new site deployment * Automatically populate new devices and cables in preparation for a new site deployment
* Create a range of new reserved prefixes or IP addresses * Create a range of new reserved prefixes or IP addresses
* Fetch data from an external source and import it to NetBox * Fetch data from an external source and import it to NetBox
* Update objects with invalid or incomplete data
Custom scripts are Python code and exist outside of the official NetBox code base, so they can be updated and changed without interfering with the core NetBox installation. And because they're completely custom, there is no inherent limitation on what a script can accomplish. They can also be used as a mechanism for validating the integrity of data within NetBox. Script authors can define test to check object against specific rules and conditions. For example, you can write script to check that:
Custom scripts can also be used as a mechanism for validating the integrity of data within NetBox. Running a script can allow the user to verify that the objects defined within NetBox meet certain arbitrary conditions. For example, you can write script to check that:
* All top-of-rack switches have a console connection * All top-of-rack switches have a console connection
* Every router has a loopback interface with an IP address assigned * Every router has a loopback interface with an IP address assigned
@ -16,6 +15,8 @@ Custom scripts can also be used as a mechanism for validating the integrity of d
* Every site has a minimum set of VLANs defined * Every site has a minimum set of VLANs defined
* All IP addresses have a parent prefix * All IP addresses have a parent prefix
Custom scripts are Python code which exists outside the NetBox code base, so they can be updated and changed without interfering with the core NetBox installation. And because they're completely custom, there is no inherent limitation on what a script can accomplish.
## Writing Custom Scripts ## Writing Custom Scripts
All custom scripts must inherit from the `extras.scripts.Script` base class. This class provides the functionality necessary to generate forms and log activity. All custom scripts must inherit from the `extras.scripts.Script` base class. This class provides the functionality necessary to generate forms and log activity.
@ -143,13 +144,73 @@ These two methods will load data in YAML or JSON format, respectively, from file
The Script object provides a set of convenient functions for recording messages at different severity levels: The Script object provides a set of convenient functions for recording messages at different severity levels:
* `log(message)` * `log_debug(message, object=None)`
* `log_success(message, object=None)` * `log_success(message, object=None)`
* `log_info(message, object=None)` * `log_info(message, object=None)`
* `log_warning(message, object=None)` * `log_warning(message, object=None)`
* `log_failure(message, object=None)` * `log_failure(message, object=None)`
Log messages are returned to the user upon execution of the script. Markdown rendering is supported for log messages. An optional object can be passed that will be linked in the rendered message. Log messages are returned to the user upon execution of the script. Markdown rendering is supported for log messages. A message may optionally be associated with a particular object by passing it as the second argument to the logging method.
## Test Methods
A script can define one or more test methods to report on certain conditions. All test methods must have a name beginning with `test_` and accept no arguments beyond `self`.
These methods are detected and run automatically when the script is executed, unless its `run()` method has been overridden. (When overriding `run()`, `run_tests()` can be called to run all test methods present in the script.)
!!! info
This functionality was ported from [legacy reports](./reports.md) in NetBox v4.0.
### Example
```
from dcim.choices import DeviceStatusChoices
from dcim.models import ConsolePort, Device, PowerPort
from extras.scripts import Script
class DeviceConnectionsReport(Script):
description = "Validate the minimum physical connections for each device"
def test_console_connection(self):
# Check that every console port for every active device has a connection defined.
active = DeviceStatusChoices.STATUS_ACTIVE
for console_port in ConsolePort.objects.prefetch_related('device').filter(device__status=active):
if not console_port.connected_endpoints:
self.log_failure(
f"No console connection defined for {console_port.name}",
console_port.device,
)
elif not console_port.connection_status:
self.log_warning(
f"Console connection for {console_port.name} marked as planned",
console_port.device,
)
else:
self.log_success("Passed", console_port.device)
def test_power_connections(self):
# Check that every active device has at least two connected power supplies.
for device in Device.objects.filter(status=DeviceStatusChoices.STATUS_ACTIVE):
connected_ports = 0
for power_port in PowerPort.objects.filter(device=device):
if power_port.connected_endpoints:
connected_ports += 1
if not power_port.path.is_active:
self.log_warning(
f"Power connection for {power_port.name} marked as planned",
device,
)
if connected_ports < 2:
self.log_failure(
f"{connected_ports} connected power supplies found (2 needed)",
device,
)
else:
self.log_success("Passed", device)
```
## Change Logging ## Change Logging
@ -418,62 +479,3 @@ class NewBranchScript(Script):
return '\n'.join(output) return '\n'.join(output)
``` ```
## Test Methods
Within each script class, we can create a number of test methods to validate the integrity of various data. In DeviceConnectionsReport, for instance, we want to ensure that every live device has a console connection, an out-of-band management connection, and two power connections.
```
from dcim.choices import DeviceStatusChoices
from dcim.models import ConsolePort, Device, PowerPort
from extras.scripts import Script
class DeviceConnectionsReport(Script):
description = "Validate the minimum physical connections for each device"
def test_console_connection(self):
# Check that every console port for every active device has a connection defined.
active = DeviceStatusChoices.STATUS_ACTIVE
for console_port in ConsolePort.objects.prefetch_related('device').filter(device__status=active):
if not console_port.connected_endpoints:
self.log_failure(
"No console connection defined for {}".format(console_port.name),
console_port.device,
)
elif not console_port.connection_status:
self.log_warning(
"Console connection for {} marked as planned".format(console_port.name),
console_port.device,
)
else:
self.log_success("success", console_port.device)
def test_power_connections(self):
# Check that every active device has at least two connected power supplies.
for device in Device.objects.filter(status=DeviceStatusChoices.STATUS_ACTIVE):
connected_ports = 0
for power_port in PowerPort.objects.filter(device=device):
if power_port.connected_endpoints:
connected_ports += 1
if not power_port.path.is_active:
self.log_warning(
"Power connection for {} marked as planned".format(power_port.name),
device,
)
if connected_ports < 2:
self.log_failure(
"{} connected power supplies found (2 needed)".format(connected_ports),
device,
)
else:
self.log_success("success", device)
def run(self, data, commit):
self.run_tests()
```
`run_tests()` is a helper function that will run every method that starts with `test_`

View File

@ -1,62 +1,63 @@
# NetBox Reports # NetBox Reports
!!! warning !!! warning
Reports are deprecated and merged with [custom scripts](./custom-scripts.md) as of NetBox 4.0. You should convert any legacy reports to use Script as described below Reports are deprecated beginning with NetBox v4.0, and their functionality has been merged with [custom scripts](./custom-scripts.md). While backward compatibility has been maintained, users are advised to convert legacy reports into custom scripts soon, as support for legacy reports will be removed in a future release.
## Converting Reports to Scripts ## Converting Reports to Scripts
### Step 1: Change Class Definition ### Step 1: Update Class Definition
First change the import and class definition to use Script. For example: Change the parent class from `Report` to `Script`:
``` ```python title="Old code"
from extras.reports import Report from extras.reports import Report
class DeviceConnectionsReport(Report): class MyReport(Report):
``` ```
change to:
``` ```python title="New code"
from extras.scripts import Script from extras.scripts import Script
class DeviceConnectionsReport(Script): class MyReport(Script):
``` ```
### Step 2: Change Logging Calls ### Step 2: Update Logging Calls
The logging methods require the object and message in the logging call to be swapped. For example: Reports and scripts both provide logging methods, however their signatures differ. All script logging methods accept a message as the first parameter, and accept an object as an optional second parameter.
Additionally, the Report class' generic `log()` method is **not** available on Script. Users are advised to replace calls of this method with `log_info()`.
``` Use the table below as a reference when updating these methods.
| Report (old) | Script (New) |
|-------------------------------|-----------------------------|
| `log(message)` | `log_info(message)` |
| `log_debug(obj, message)`[^1] | `log_debug(message, obj)` |
| `log_info(obj, message)` | `log_info(message, obj)` |
| `log_success(obj, message)` | `log_success(message, obj)` |
| `log_warning(obj, message)` | `log_warning(message, obj)` |
| `log_failure(obj, message)` | `log_failure(message, obj)` |
[^1]: `log_debug()` was added to the Report class in v4.0 to avoid confusion with the same method on Script
```python title="Old code"
self.log_failure( self.log_failure(
console_port.device, console_port.device,
"No console connection defined for {}".format(console_port.name) f"No console connection defined for {console_port.name}"
) )
``` ```
should be changed to: ```python title="New code"
```
self.log_failure( self.log_failure(
"No console connection defined for {}".format(console_port.name), f"No console connection defined for {console_port.name}",
console_port.device, obj=console_port.device,
) )
``` ```
This applies to all log_ functions: ### Other Notes
* log_success(object, message) -> log_success(message, object) Existing reports will be converted to scripts automatically upon upgrading to NetBox v4.0, and previous job history will be retained. However, users are advised to convert legacy reports into custom scripts at the earliest opportunity, as support for legacy reports will be removed in a future release.
* log_info(object, message) -> log_info(message, object)
* log_warning(object, message) -> log_warning(message, object)
* log_failure(object, message) -> log_failure(message, object)
### Optional Run Method The `pre_run()` and `post_run()` Report methods have been carried over to Script. These are called automatically by Script's `run()` method. (Note that if you opt to override this method, you are responsible for calling `pre_run()` and `post_run()` where applicable.)
Scripts have a default run method that will automatically run all the `test_` methods as well as the pre_run and post_run functions. You can also define a run method and call `run_tests()` to call all the `test_` functions: The `is_valid()` method on Report is no longer needed and has been removed.
```
def run(self, data, commit):
self.run_tests()
```
Any functionality needed for pre or post run can just be put into the the run method before or after the call to run_tests.

View File

@ -52,6 +52,7 @@ extra_css:
markdown_extensions: markdown_extensions:
- admonition - admonition
- attr_list - attr_list
- footnotes
- pymdownx.emoji: - pymdownx.emoji:
emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg emoji_generator: !!python/name:material.extensions.emoji.to_svg