Skip to content

Commit 12694d6

Browse files
authored
Merge pull request #87 from networktocode/mzb-netbox-2.9
NetBox 2.9 support
2 parents 813ff83 + 14405f1 commit 12694d6

File tree

15 files changed

+336
-273
lines changed

15 files changed

+336
-273
lines changed

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)

netbox_onboarding/forms.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,8 @@
1515
from django import forms
1616
from django_rq import get_queue
1717

18-
from utilities.forms import BootstrapMixin
18+
from utilities.forms import BootstrapMixin, CSVModelForm
1919
from dcim.models import Site, Platform, DeviceRole, DeviceType
20-
from extras.forms import CustomFieldModelCSVForm
2120

2221
from .models import OnboardingTask
2322
from .choices import OnboardingStatusChoices, OnboardingFailChoices
@@ -33,7 +32,7 @@ class OnboardingTaskForm(BootstrapMixin, forms.ModelForm):
3332
required=True, label="IP address", help_text="IP Address/DNS Name of the device to onboard"
3433
)
3534

36-
site = forms.ModelChoiceField(required=True, queryset=Site.objects.all(), to_field_name="slug")
35+
site = forms.ModelChoiceField(required=True, queryset=Site.objects.all())
3736

3837
username = forms.CharField(required=False, help_text="Device username (will not be stored in database)")
3938
password = forms.CharField(
@@ -106,7 +105,7 @@ class Meta: # noqa: D106 "Missing docstring in public nested class"
106105
fields = ["q", "site", "platform", "status", "failed_reason"]
107106

108107

109-
class OnboardingTaskFeedCSVForm(CustomFieldModelCSVForm):
108+
class OnboardingTaskFeedCSVForm(CSVModelForm):
110109
"""Form for entering CSV to bulk-import OnboardingTask entries."""
111110

112111
site = forms.ModelChoiceField(
@@ -149,7 +148,14 @@ class OnboardingTaskFeedCSVForm(CustomFieldModelCSVForm):
149148

150149
class Meta: # noqa: D106 "Missing docstring in public nested class"
151150
model = OnboardingTask
152-
fields = OnboardingTask.csv_headers
151+
fields = [
152+
"site",
153+
"ip_address",
154+
"port",
155+
"timeout",
156+
"platform",
157+
"role",
158+
]
153159

154160
def save(self, commit=True, **kwargs):
155161
"""Save the model, and add it and the associated credentials to the onboarding worker queue."""

netbox_onboarding/models.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
limitations under the License.
1313
"""
1414
from django.db import models
15+
from django.urls import reverse
1516
from .choices import OnboardingStatusChoices, OnboardingFailChoices
17+
from .release import NETBOX_RELEASE_CURRENT, NETBOX_RELEASE_29
1618

1719

1820
class OnboardingTask(models.Model):
@@ -47,18 +49,18 @@ class OnboardingTask(models.Model):
4749

4850
created_on = models.DateTimeField(auto_now_add=True)
4951

50-
csv_headers = [
51-
"site",
52-
"ip_address",
53-
"port",
54-
"timeout",
55-
"platform",
56-
"role",
57-
]
58-
5952
class Meta: # noqa: D106 "missing docstring in public nested class"
6053
ordering = ["created_on"]
6154

6255
def __str__(self):
6356
"""String representation of an OnboardingTask."""
6457
return f"{self.site} : {self.ip_address}"
58+
59+
def get_absolute_url(self):
60+
"""Provide absolute URL to an OnboardingTask."""
61+
return reverse("plugins:netbox_onboarding:onboardingtask", kwargs={"pk": self.pk})
62+
63+
if NETBOX_RELEASE_CURRENT >= NETBOX_RELEASE_29:
64+
from utilities.querysets import RestrictedQuerySet # pylint: disable=no-name-in-module, import-outside-toplevel
65+
66+
objects = RestrictedQuerySet.as_manager()

netbox_onboarding/navigation.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,19 @@
1717

1818
menu_items = (
1919
PluginMenuItem(
20-
link="plugins:netbox_onboarding:onboarding_task_list",
20+
link="plugins:netbox_onboarding:onboardingtask_list",
2121
link_text="Onboarding Tasks",
2222
permissions=["netbox_onboarding.view_onboardingtask"],
2323
buttons=(
2424
PluginMenuButton(
25-
link="plugins:netbox_onboarding:onboarding_task_add",
25+
link="plugins:netbox_onboarding:onboardingtask_add",
2626
title="Onboard",
2727
icon_class="fa fa-plus",
2828
color=ButtonColorChoices.GREEN,
2929
permissions=["netbox_onboarding.add_onboardingtask"],
3030
),
3131
PluginMenuButton(
32-
link="plugins:netbox_onboarding:onboarding_task_import",
32+
link="plugins:netbox_onboarding:onboardingtask_import",
3333
title="Bulk Onboard",
3434
icon_class="fa fa-download",
3535
color=ButtonColorChoices.BLUE,

netbox_onboarding/netbox_keeper.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,10 @@ def ensure_primary_ip(self):
349349
address=f"{self.netdev_mgmt_ip_address}/{self.netdev_mgmt_pflen}"
350350
)
351351

352-
if created or not self.nb_primary_ip.interface:
352+
if created or not self.nb_primary_ip in self.nb_mgmt_ifname.ip_addresses.all():
353353
logging.info("ASSIGN: IP address %s to %s", self.nb_primary_ip.address, self.nb_mgmt_ifname.name)
354-
self.nb_primary_ip.interface = self.nb_mgmt_ifname
355-
self.nb_primary_ip.save()
354+
self.nb_mgmt_ifname.ip_addresses.add(self.nb_primary_ip)
355+
self.nb_mgmt_ifname.save()
356356

357357
# Ensure the primary IP is assigned to the device
358358
self.device.primary_ip4 = self.nb_primary_ip

netbox_onboarding/release.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"""Release variables of the NetBox.
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 packaging import version
16+
from django.conf import settings
17+
18+
NETBOX_RELEASE_CURRENT = version.parse(settings.VERSION)
19+
NETBOX_RELEASE_28 = version.parse("2.8")
20+
NETBOX_RELEASE_29 = version.parse("2.9")

netbox_onboarding/tables.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class OnboardingTaskTable(BaseTable):
2020
"""Table for displaying OnboardingTask instances."""
2121

2222
pk = ToggleColumn()
23+
id = tables.LinkColumn()
2324
site = tables.LinkColumn()
2425
platform = tables.LinkColumn()
2526
created_device = tables.LinkColumn()
@@ -28,6 +29,7 @@ class Meta(BaseTable.Meta): # noqa: D106 "Missing docstring in public nested cl
2829
model = OnboardingTask
2930
fields = (
3031
"pk",
32+
"id",
3133
"created_on",
3234
"ip_address",
3335
"site",

netbox_onboarding/templates/netbox_onboarding/onboarding_tasks_list.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
{% block content %}
55
<div class="pull-right noprint">
66
{% if permissions.add %}
7-
{% add_button 'plugins:netbox_onboarding:onboarding_task_add' %}
8-
{% import_button 'plugins:netbox_onboarding:onboarding_task_import' %}
7+
{% add_button 'plugins:netbox_onboarding:onboardingtask_add' %}
8+
{% import_button 'plugins:netbox_onboarding:onboardingtask_import' %}
99
{% endif %}
1010
</div>
1111
<h1>{% block title %}Onboarding Tasks{% endblock %}</h1>
1212
<div class="row">
1313
<div class="col-md-9">
14-
{% include 'utilities/obj_table.html' with bulk_delete_url="plugins:netbox_onboarding:onboarding_task_bulk_delete" %}
14+
{% include 'utilities/obj_table.html' with bulk_delete_url="plugins:netbox_onboarding:onboardingtask_bulk_delete" %}
1515
</div>
1616
<div class="col-md-3 noprint">
1717
{% include 'inc/search_panel.html' %}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{% extends 'base.html' %}
2+
{% load helpers %}
3+
{% load static %}
4+
5+
{% block header %}
6+
<div class="row noprint">
7+
<div class="col">
8+
<ol class="breadcrumb">
9+
<li><a href="{% url 'plugins:netbox_onboarding:onboardingtask_list' %}">Onboarding tasks</a></li>
10+
<li>{{ onboardingtask.pk }}</li>
11+
</ol>
12+
</div>
13+
</div>
14+
15+
<h1>{% block title %}Device: {{ onboardingtask.ip_address }}{% endblock %}</h1>
16+
17+
<ul class="nav nav-tabs">
18+
<li role="presentation"{% if not active_tab %} class="active"{% endif %}>
19+
<a href="{{ onboardingtask.get_absolute_url }}">Onboarding Task</a>
20+
</li>
21+
</ul>
22+
{% endblock %}
23+
24+
{% block content %}
25+
<div class="row">
26+
<div class="col-md-7">
27+
<div class="panel panel-default">
28+
<div class="panel-heading">
29+
<strong>Onboarding Task</strong>
30+
</div>
31+
<table class="table table-hover panel-body attr-table">
32+
<tr>
33+
<td>Created Device</td>
34+
<td>{{ onboardingtask.created_device|placeholder }}</td>
35+
</tr>
36+
<tr>
37+
<td>IP Address</td>
38+
<td>{{ onboardingtask.ip_address|placeholder }}</td>
39+
</tr>
40+
<tr>
41+
<td>Port</td>
42+
<td>{{ onboardingtask.port|placeholder }}</td>
43+
</tr>
44+
<tr>
45+
<td>Timeout</td>
46+
<td>{{ onboardingtask.timeout|placeholder }}</td>
47+
</tr>
48+
<tr>
49+
<td>Site</td>
50+
<td>{{ onboardingtask.site|placeholder }}</td>
51+
</tr>
52+
<tr>
53+
<td>Role</td>
54+
<td>{{ onboardingtask.role|placeholder }}</td>
55+
</tr>
56+
<tr>
57+
<td>Device Type</td>
58+
<td>{{ onboardingtask.device_type|placeholder }}</td>
59+
</tr>
60+
<tr>
61+
<td>Platform</td>
62+
<td>{{ onboardingtask.platform|placeholder }}</td>
63+
</tr>
64+
<tr>
65+
<td>Status</td>
66+
<td>{{ onboardingtask.status|placeholder }}</td>
67+
</tr>
68+
<tr>
69+
<td>Failed Reason</td>
70+
<td>{{ onboardingtask.failed_reason|placeholder }}</td>
71+
</tr>
72+
<tr>
73+
<td>Message</td>
74+
<td>{{ onboardingtask.message|placeholder }}</td>
75+
</tr>
76+
<tr>
77+
<td>Created On</td>
78+
<td>{{ onboardingtask.created_on|placeholder }}</td>
79+
</tr>
80+
</table>
81+
</div>
82+
</div>
83+
</div>
84+
{% endblock %}
85+
86+
{% block javascript %}
87+
<script src="{% static 'js/graphs.js' %}?v{{ settings.VERSION }}"></script>
88+
{% endblock %}

netbox_onboarding/tests/test_netbox_keeper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def test_ensure_primary_ip_not_exist(self):
308308
nbk.ensure_device()
309309

310310
self.assertIsInstance(nbk.nb_primary_ip, IPAddress)
311-
self.assertEqual(nbk.nb_primary_ip.interface.name, "ge-0/0/0")
311+
self.assertIn(nbk.nb_primary_ip, Interface.objects.get(device=nbk.device, name="ge-0/0/0").ip_addresses.all())
312312
self.assertEqual(nbk.device.primary_ip, nbk.nb_primary_ip)
313313

314314
def test_ensure_device_platform_missing(self):

0 commit comments

Comments
 (0)