Skip to content

Commit 7e144e2

Browse files
authored
Merge pull request #101 from networktocode/develop
Publish 2.0 to Master
2 parents 09764a0 + 986fe8b commit 7e144e2

39 files changed

+2332
-1071
lines changed

README.md

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,26 @@ The goal of this plugin is not to import everything about a device into NetBox b
1010

1111
## Installation
1212

13-
The plugin is available as a Python package in pypi and can be installed with pip
13+
If using the installation pattern from the NetBox Documentation, you will need to activate the
14+
virtual environment before installing so that you install the package into the virtual environment.
15+
16+
```shell
17+
cd /opt/netbox
18+
source venv/bin/activate
19+
```
20+
21+
The plugin is available as a Python package in pypi and can be installed with pip. Once the
22+
installation is completed, then NetBox and the NetBox worker must be restarted.
23+
1424
```shell
1525
pip install ntc-netbox-plugin-onboarding
26+
systemctl restart netbox netbox-rq
1627
```
1728

18-
> The plugin is compatible with NetBox 2.8.1 and higher
19-
29+
> The ntc-netbox-plugin-onboarding v1.3 is compatible with NetBox 2.8
30+
31+
> The ntc-netbox-plugin-onboarding v2 is compatible with NetBox 2.8 and NetBox 2.9
32+
2033
To ensure NetBox Onboarding plugin is automatically re-installed during future upgrades, create a file named `local_requirements.txt` (if not already existing) in the NetBox root directory (alongside `requirements.txt`) and list the `ntc-netbox-plugin-onboarding` package:
2134

2235
```no-highlight
@@ -53,26 +66,38 @@ The plugin behavior can be controlled with the following list of settings
5366
- `default_device_role_color` string (default FF0000), color assigned to the device role if it needs to be created.
5467
- `default_management_interface` string (default "PLACEHOLDER"), name of the management interface that will be created, if one can't be identified on the device.
5568
- `default_management_prefix_length` integer ( default 0), length of the prefix that will be used for the management IP address, if the IP can't be found.
69+
- `skip_device_type_on_update` boolean (default False), If True, an existing NetBox device will not get its device type updated. If False, device type will be updated with one discovered on a device.
70+
- `skip_manufacturer_on_update` boolean (default False), If True, an existing NetBox device will not get its manufacturer updated. If False, manufacturer will be updated with one discovered on a device.
5671
- `platform_map` (dictionary), mapping of an **auto-detected** Netmiko platform to the **NetBox slug** name of your Platform. The dictionary should be in the format:
5772
```python
5873
{
59-
<Netmiko Platform>: <NetBox Slug>
74+
<Netmiko Platform>: <NetBox Slug>
75+
}
76+
```
77+
- `onboarding_extensions_map` (dictionary), mapping of a NAPALM driver name to the loadable Python module used as an onboarding extension. The dictionary should be in the format:
78+
```python
79+
{
80+
<Napalm Driver Name>: <Loadable Python Module>
6081
}
6182
```
83+
- `object_match_strategy` (string), defines the method for searching models. There are
84+
currently two strategies, strict and loose. Strict has to be a direct match, normally
85+
using a slug. Loose allows a range of search criteria to match a single object. If multiple
86+
objects are returned an error is raised.
6287

6388
## Usage
6489

6590
### Preparation
6691

67-
To work properly the plugin needs to know the Site, Platform, Device Type, Device Role of each
68-
device as well as its primary IP address or DNS Name. It's recommended to create these objects in
69-
NetBox ahead of time and to provide them when you want to start the onboarding process.
92+
To properly onboard a device, the plugin needs to only know the Site as well as device's primary IP address or DNS Name.
7093

7194
> For DNS Name Resolution to work, the instance of NetBox must be able to resolve the name of the
7295
> device to IP address.
7396

97+
Providing other attributes (`Platform`, `Device Type`, `Device Role`) is optional - if any of these attributes is provided, plugin will use provided value for the onboarded device.
7498
If `Platform`, `Device Type` and/or `Device Role` are not provided, the plugin will try to identify these information automatically and, based on the settings, it can create them in NetBox as needed.
75-
> If the Platform is provided, it must contains a valid Napalm driver available to the worker in Python
99+
> If the Platform is provided, it must point to an existing NetBox Platform. NAPALM driver of this platform will be used only if it is defined for the platform in NetBox.
100+
> To use a preferred NAPALM driver, either define it in NetBox per platform or in the plugins settings under `platform_map`
76101

77102
### Onboard a new device
78103

development/base_configuration.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,20 @@
114114

115115
# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs:
116116
# https://docs.djangoproject.com/en/1.11/topics/logging/
117-
LOGGING = {}
117+
LOGGING = {
118+
"version": 1,
119+
"disable_existing_loggers": False,
120+
"formatters": {"rq_console": {"format": "%(asctime)s %(message)s", "datefmt": "%H:%M:%S",},},
121+
"handlers": {
122+
"rq_console": {
123+
"level": "DEBUG",
124+
"class": "rq.utils.ColorizingStreamHandler",
125+
"formatter": "rq_console",
126+
"exclude": ["%(asctime)s"],
127+
},
128+
},
129+
"loggers": {"rq.worker": {"handlers": ["rq_console"], "level": "DEBUG"},},
130+
}
118131

119132
# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users
120133
# are permitted to access most data in NetBox (excluding secrets) but not make any changes.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
"""Example of custom onboarding class.
2+
3+
(c) 2020 Network To Code
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
"""
14+
15+
from netbox_onboarding.netbox_keeper import NetboxKeeper
16+
from netbox_onboarding.onboarding.onboarding import Onboarding
17+
18+
19+
class MyOnboardingClass(Onboarding):
20+
"""Custom onboarding class example.
21+
22+
Main purpose of this class is to access and modify the onboarding_kwargs.
23+
By accessing the onboarding kwargs, user gains ability to modify
24+
onboarding parameters before the objects are created in NetBox.
25+
26+
This class adds the get_device_role method that does the static
27+
string comparison and returns the device role.
28+
"""
29+
30+
def run(self, onboarding_kwargs):
31+
"""Ensures network device."""
32+
# Access hostname from onboarding_kwargs and get device role automatically
33+
device_new_role = self.get_device_role(hostname=onboarding_kwargs["netdev_hostname"])
34+
35+
# Update the device role in onboarding kwargs dictionary
36+
onboarding_kwargs["netdev_nb_role_slug"] = device_new_role
37+
38+
nb_k = NetboxKeeper(**onboarding_kwargs)
39+
nb_k.ensure_device()
40+
41+
self.created_device = nb_k.device
42+
43+
@staticmethod
44+
def get_device_role(hostname):
45+
"""Returns the device role based on hostname data.
46+
47+
This is a static analysis of hostname string content only
48+
"""
49+
hostname_lower = hostname.lower()
50+
if ("rtr" in hostname_lower) or ("router" in hostname_lower):
51+
role = "router"
52+
elif ("sw" in hostname_lower) or ("switch" in hostname_lower):
53+
role = "switch"
54+
elif ("fw" in hostname_lower) or ("firewall" in hostname_lower):
55+
role = "firewall"
56+
elif "dc" in hostname_lower:
57+
role = "datacenter"
58+
else:
59+
role = "generic"
60+
61+
return role
62+
63+
64+
class OnboardingDriverExtensions:
65+
"""This is an example of a custom onboarding driver extension.
66+
67+
This extension sets the onboarding_class to MyOnboardingClass,
68+
which is an example class of how to access and modify the device
69+
role automatically through the onboarding process.
70+
"""
71+
72+
def __init__(self, napalm_device):
73+
"""Inits the class."""
74+
self.napalm_device = napalm_device
75+
self.onboarding_class = MyOnboardingClass
76+
self.ext_result = None
77+
78+
def get_onboarding_class(self):
79+
"""Return onboarding class for IOS driver.
80+
81+
Currently supported is Standalone Onboarding Process
82+
83+
Result of this method is used by the OnboardingManager to
84+
initiate the instance of the onboarding class.
85+
"""
86+
return self.onboarding_class
87+
88+
def get_ext_result(self):
89+
"""This method is used to store any object as a return value.
90+
91+
Result of this method is passed to the onboarding class as
92+
driver_addon_result argument.
93+
94+
:return: Any()
95+
"""
96+
return self.ext_result

docs/release-notes/version-2.0.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# ntc-netbox-plugin-onboarding v2.0 Release Notes
2+
3+
## v2.0
4+
5+
### Enhancements
6+
7+
* NetBox 2.9 support - Supported releases 2.8 and 2.9
8+
* Onboarding extensions - Customizable onboarding process through Python modules.
9+
* Onboarding details exposed in a device view - Date, Status, Last success and Latest task id related to the onboarded device are presented under the device view.
10+
* Onboarding task view - Onboarding details exposed in a dedicated view, including NetBox's ChangeLog.
11+
* Onboarding Changelog - Onboarding uses NetBox's ChangeLog to display user and changes made to the Onboarding Task object.
12+
* Skip onboarding feature - New attribute in the OnboardingDevice model allows to skip the onboarding request on devices with disabled onboarding setting.
13+
14+
### Bug Fixes
15+
16+
* Fixed race condition in `worker.py`
17+
* Improved logging
18+
19+
### Additional Changes
20+
21+
* Platform map now includes NAPALM drivers as defined in NetBox
22+
* Tests have been refactored to inherit NetBox's tests
23+
* Onboarding process will update the Device found by the IP-address lookup. In case of no existing device with onboarded IP-address is found in NetBox, onboarding might update the existing NetBox' looking up by network device's hostname.
24+
* Onboarding will raise Exception when `create_device_type_if_missing` is set to `False` for existing Device with DeviceType mismatch (behaviour pre https://github.com/networktocode/ntc-netbox-plugin-onboarding/issues/74)

netbox_onboarding/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
limitations under the License.
1313
"""
1414

15-
__version__ = "1.3.0"
15+
__version__ = "2.0.0"
1616

1717
from extras.plugins import PluginConfig
1818

@@ -39,7 +39,11 @@ class OnboardingConfig(PluginConfig):
3939
"default_management_prefix_length": 0,
4040
"default_device_status": "active",
4141
"create_management_interface_if_missing": True,
42+
"skip_device_type_on_update": False,
43+
"skip_manufacturer_on_update": False,
4244
"platform_map": {},
45+
"onboarding_extensions_map": {"ios": "netbox_onboarding.onboarding_extensions.ios",},
46+
"object_match_strategy": "loose",
4347
}
4448
caching_config = {}
4549

netbox_onboarding/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ class OnboardingTaskAdmin(admin.ModelAdmin):
3232
"failed_reason",
3333
"port",
3434
"timeout",
35-
"created_on",
35+
"created",
3636
)

netbox_onboarding/choices.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ class OnboardingStatusChoices(ChoiceSet):
2222
STATUS_PENDING = "pending"
2323
STATUS_RUNNING = "running"
2424
STATUS_SUCCEEDED = "succeeded"
25+
STATUS_SKIPPED = "skipped"
2526

2627
CHOICES = (
2728
(STATUS_FAILED, "failed"),
2829
(STATUS_PENDING, "pending"),
2930
(STATUS_RUNNING, "running"),
3031
(STATUS_SUCCEEDED, "succeeded"),
32+
(STATUS_SKIPPED, "skipped"),
3133
)
3234

3335

netbox_onboarding/constants.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Constants for netbox_onboarding plugin."""
2-
NETMIKO_TO_NAPALM = {
2+
3+
NETMIKO_TO_NAPALM_STATIC = {
34
"cisco_ios": "ios",
45
"cisco_nxos": "nxos_ssh",
56
"arista_eos": "eos",

netbox_onboarding/exceptions.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Exceptions.
2+
3+
(c) 2020 Network To Code
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
Unless required by applicable law or agreed to in writing, software
9+
distributed under the License is distributed on an "AS IS" BASIS,
10+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
See the License for the specific language governing permissions and
12+
limitations under the License.
13+
"""
14+
15+
16+
class OnboardException(Exception):
17+
"""A failure occurred during the onboarding process.
18+
19+
The exception includes a reason "slug" as defined below as well as a humanized message.
20+
"""
21+
22+
REASONS = (
23+
"fail-config", # config provided is not valid
24+
"fail-connect", # device is unreachable at IP:PORT
25+
"fail-execute", # unable to execute device/API command
26+
"fail-login", # bad username/password
27+
"fail-dns", # failed to get IP address from name resolution
28+
"fail-general", # other error
29+
)
30+
31+
def __init__(self, reason, message, **kwargs):
32+
"""Exception Init."""
33+
super(OnboardException, self).__init__(kwargs)
34+
self.reason = reason
35+
self.message = message
36+
37+
def __str__(self):
38+
"""Exception __str__."""
39+
return f"{self.__class__.__name__}: {self.reason}: {self.message}"

netbox_onboarding/filters.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ class OnboardingTaskFilter(NameSlugSearchFilterSet):
2626

2727
q = django_filters.CharFilter(method="search", label="Search",)
2828

29-
site_id = django_filters.ModelMultipleChoiceFilter(queryset=Site.objects.all(), label="Site (ID)",)
30-
3129
site = django_filters.ModelMultipleChoiceFilter(
3230
field_name="site__slug", queryset=Site.objects.all(), to_field_name="slug", label="Site (slug)",
3331
)
@@ -46,7 +44,7 @@ class Meta: # noqa: D106 "Missing docstring in public nested class"
4644
model = OnboardingTask
4745
fields = ["id", "site", "site_id", "platform", "role", "status", "failed_reason"]
4846

49-
def search(self, queryset, name, value):
47+
def search(self, queryset, name, value): # pylint: disable=unused-argument, no-self-use
5048
"""Perform the filtered search."""
5149
if not value.strip():
5250
return queryset
@@ -55,7 +53,7 @@ def search(self, queryset, name, value):
5553
| Q(ip_address__icontains=value)
5654
| Q(site__name__icontains=value)
5755
| Q(platform__name__icontains=value)
58-
| Q(device__icontains=value)
56+
| Q(created_device__name__icontains=value)
5957
| Q(status__icontains=value)
6058
| Q(failed_reason__icontains=value)
6159
| Q(message__icontains=value)

0 commit comments

Comments
 (0)