netbox-device-view 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- netbox-device-view-0.1.0/PKG-INFO +82 -0
- netbox-device-view-0.1.0/README.md +71 -0
- netbox-device-view-0.1.0/netbox_device_view/__init__.py +18 -0
- netbox-device-view-0.1.0/netbox_device_view/api/__init__.py +0 -0
- netbox-device-view-0.1.0/netbox_device_view/api/serializers.py +19 -0
- netbox-device-view-0.1.0/netbox_device_view/api/urls.py +9 -0
- netbox-device-view-0.1.0/netbox_device_view/api/views.py +9 -0
- netbox-device-view-0.1.0/netbox_device_view/filtersets.py +8 -0
- netbox-device-view-0.1.0/netbox_device_view/forms.py +8 -0
- netbox-device-view-0.1.0/netbox_device_view/migrations/0001_initial.py +57 -0
- netbox-device-view-0.1.0/netbox_device_view/migrations/__init__.py +0 -0
- netbox-device-view-0.1.0/netbox_device_view/models.py +22 -0
- netbox-device-view-0.1.0/netbox_device_view/navigation.py +19 -0
- netbox-device-view-0.1.0/netbox_device_view/tables.py +11 -0
- netbox-device-view-0.1.0/netbox_device_view/template_content.py +36 -0
- netbox-device-view-0.1.0/netbox_device_view/urls.py +25 -0
- netbox-device-view-0.1.0/netbox_device_view/utils.py +66 -0
- netbox-device-view-0.1.0/netbox_device_view/views.py +51 -0
- netbox-device-view-0.1.0/netbox_device_view.egg-info/PKG-INFO +82 -0
- netbox-device-view-0.1.0/netbox_device_view.egg-info/SOURCES.txt +23 -0
- netbox-device-view-0.1.0/netbox_device_view.egg-info/dependency_links.txt +1 -0
- netbox-device-view-0.1.0/netbox_device_view.egg-info/not-zip-safe +1 -0
- netbox-device-view-0.1.0/netbox_device_view.egg-info/top_level.txt +1 -0
- netbox-device-view-0.1.0/setup.cfg +4 -0
- netbox-device-view-0.1.0/setup.py +23 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: netbox-device-view
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: NetBox Device View plugin
|
|
5
|
+
Home-page: https://github.com/peterbaumert/netbox-device-view
|
|
6
|
+
Author: Peter Baumert
|
|
7
|
+
Keywords: netbox,netbox-plugin
|
|
8
|
+
Classifier: Framework :: Django
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# Netbox Device View Plugin
|
|
13
|
+
 
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
The plugin is available as a Python package and can be installed with pip.
|
|
18
|
+
|
|
19
|
+
Run `pip install netbox-device-view` in your virtual env.
|
|
20
|
+
|
|
21
|
+
To ensure NetBox Device View 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 `netbox-device-view` package:
|
|
22
|
+
|
|
23
|
+
```no-highlight
|
|
24
|
+
# echo netbox-device-view >> local_requirements.txt
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Once installed, the plugin needs to be enabled in your `configuration.py` and optionally the `show_on_device_tab` setting enabled.
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# In your configuration.py
|
|
31
|
+
PLUGINS = ["netbox-device-view"]
|
|
32
|
+
|
|
33
|
+
PLUGINS_CONFIG = {
|
|
34
|
+
'netbox_device_view': {
|
|
35
|
+
'show_on_device_tab': True,
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
First run `source /opt/netbox/venv/bin/activate` to enter the Python virtual environment.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
Then run
|
|
44
|
+
```bash
|
|
45
|
+
cd /opt/netbox/netbox
|
|
46
|
+
pip3 install netbox-device-view
|
|
47
|
+
python3 manage.py migrate netbox-device-view
|
|
48
|
+
python3 manage.py collectstatic --no-input
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## How To Use
|
|
52
|
+
|
|
53
|
+
For each Device Type you need to add a DeviceView.
|
|
54
|
+
|
|
55
|
+
It is based on a CSS grid view with 32 columns and 2 rows.
|
|
56
|
+
You need to specify the grid-template-areas.
|
|
57
|
+
- Interface positions will use the following format: {interfacename}{module}-{port}
|
|
58
|
+
- leading "empties" can be specified as x
|
|
59
|
+
- trailing "empties" can be specified as z
|
|
60
|
+
- between "empties" can be named s{0-99}
|
|
61
|
+
|
|
62
|
+
Example for Cisco C9300-24T with 8x 10G module
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
/* C9300-24T */
|
|
66
|
+
.switchview.area {
|
|
67
|
+
grid-template-areas:
|
|
68
|
+
"x x x x x x x x x x x x x x gigabitethernet0-1 gigabitethernet0-3 gigabitethernet0-5 gigabitethernet0-7 gigabitethernet0-9 gigabitethernet0-11 s0 gigabitethernet0-13 gigabitethernet0-15 gigabitethernet0-17 gigabitethernet0-19 gigabitethernet0-21 gigabitethernet0-23 z z z z z"
|
|
69
|
+
"x x x x x x x x x x x x x x gigabitethernet0-2 gigabitethernet0-4 gigabitethernet0-6 gigabitethernet0-8 gigabitethernet0-10 gigabitethernet0-12 s0 gigabitethernet0-14 gigabitethernet0-16 gigabitethernet0-18 gigabitethernet0-20 gigabitethernet0-22 gigabitethernet0-24 z z z z z";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* C9300-24T with C9300-NM-8X */
|
|
73
|
+
.switchview.moduleC9300-NM-8X.area {
|
|
74
|
+
grid-template-areas:
|
|
75
|
+
"x x x x x x x x x x x x x x gigabitethernet0-1 gigabitethernet0-3 gigabitethernet0-5 gigabitethernet0-7 gigabitethernet0-9 gigabitethernet0-11 s0 gigabitethernet0-13 gigabitethernet0-15 gigabitethernet0-17 gigabitethernet0-19 gigabitethernet0-21 gigabitethernet0-23 s1 tengigabitethernet1-1 tengigabitethernet1-3 tengigabitethernet1-5 tengigabitethernet1-7"
|
|
76
|
+
"x x x x x x x x x x x x x x gigabitethernet0-2 gigabitethernet0-4 gigabitethernet0-6 gigabitethernet0-8 gigabitethernet0-10 gigabitethernet0-12 s0 gigabitethernet0-14 gigabitethernet0-16 gigabitethernet0-18 gigabitethernet0-20 gigabitethernet0-22 gigabitethernet0-24 s1 tengigabitethernet1-2 tengigabitethernet1-4 tengigabitethernet1-6 tengigabitethernet1-8";
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
It will look like
|
|
81
|
+
|
|
82
|
+

|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Netbox Device View Plugin
|
|
2
|
+
 
|
|
3
|
+
|
|
4
|
+
## Install
|
|
5
|
+
|
|
6
|
+
The plugin is available as a Python package and can be installed with pip.
|
|
7
|
+
|
|
8
|
+
Run `pip install netbox-device-view` in your virtual env.
|
|
9
|
+
|
|
10
|
+
To ensure NetBox Device View 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 `netbox-device-view` package:
|
|
11
|
+
|
|
12
|
+
```no-highlight
|
|
13
|
+
# echo netbox-device-view >> local_requirements.txt
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Once installed, the plugin needs to be enabled in your `configuration.py` and optionally the `show_on_device_tab` setting enabled.
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
# In your configuration.py
|
|
20
|
+
PLUGINS = ["netbox-device-view"]
|
|
21
|
+
|
|
22
|
+
PLUGINS_CONFIG = {
|
|
23
|
+
'netbox_device_view': {
|
|
24
|
+
'show_on_device_tab': True,
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
First run `source /opt/netbox/venv/bin/activate` to enter the Python virtual environment.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
Then run
|
|
33
|
+
```bash
|
|
34
|
+
cd /opt/netbox/netbox
|
|
35
|
+
pip3 install netbox-device-view
|
|
36
|
+
python3 manage.py migrate netbox-device-view
|
|
37
|
+
python3 manage.py collectstatic --no-input
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## How To Use
|
|
41
|
+
|
|
42
|
+
For each Device Type you need to add a DeviceView.
|
|
43
|
+
|
|
44
|
+
It is based on a CSS grid view with 32 columns and 2 rows.
|
|
45
|
+
You need to specify the grid-template-areas.
|
|
46
|
+
- Interface positions will use the following format: {interfacename}{module}-{port}
|
|
47
|
+
- leading "empties" can be specified as x
|
|
48
|
+
- trailing "empties" can be specified as z
|
|
49
|
+
- between "empties" can be named s{0-99}
|
|
50
|
+
|
|
51
|
+
Example for Cisco C9300-24T with 8x 10G module
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
/* C9300-24T */
|
|
55
|
+
.switchview.area {
|
|
56
|
+
grid-template-areas:
|
|
57
|
+
"x x x x x x x x x x x x x x gigabitethernet0-1 gigabitethernet0-3 gigabitethernet0-5 gigabitethernet0-7 gigabitethernet0-9 gigabitethernet0-11 s0 gigabitethernet0-13 gigabitethernet0-15 gigabitethernet0-17 gigabitethernet0-19 gigabitethernet0-21 gigabitethernet0-23 z z z z z"
|
|
58
|
+
"x x x x x x x x x x x x x x gigabitethernet0-2 gigabitethernet0-4 gigabitethernet0-6 gigabitethernet0-8 gigabitethernet0-10 gigabitethernet0-12 s0 gigabitethernet0-14 gigabitethernet0-16 gigabitethernet0-18 gigabitethernet0-20 gigabitethernet0-22 gigabitethernet0-24 z z z z z";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* C9300-24T with C9300-NM-8X */
|
|
62
|
+
.switchview.moduleC9300-NM-8X.area {
|
|
63
|
+
grid-template-areas:
|
|
64
|
+
"x x x x x x x x x x x x x x gigabitethernet0-1 gigabitethernet0-3 gigabitethernet0-5 gigabitethernet0-7 gigabitethernet0-9 gigabitethernet0-11 s0 gigabitethernet0-13 gigabitethernet0-15 gigabitethernet0-17 gigabitethernet0-19 gigabitethernet0-21 gigabitethernet0-23 s1 tengigabitethernet1-1 tengigabitethernet1-3 tengigabitethernet1-5 tengigabitethernet1-7"
|
|
65
|
+
"x x x x x x x x x x x x x x gigabitethernet0-2 gigabitethernet0-4 gigabitethernet0-6 gigabitethernet0-8 gigabitethernet0-10 gigabitethernet0-12 s0 gigabitethernet0-14 gigabitethernet0-16 gigabitethernet0-18 gigabitethernet0-20 gigabitethernet0-22 gigabitethernet0-24 s1 tengigabitethernet1-2 tengigabitethernet1-4 tengigabitethernet1-6 tengigabitethernet1-8";
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
It will look like
|
|
70
|
+
|
|
71
|
+

|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from extras.plugins import PluginConfig
|
|
2
|
+
from importlib.metadata import metadata
|
|
3
|
+
|
|
4
|
+
metadata = metadata("netbox_device_view")
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class NetBoxDeviceViewConfig(PluginConfig):
|
|
8
|
+
name = metadata.get("Name").replace("-", "_")
|
|
9
|
+
verbose_name = metadata.get("Summary")
|
|
10
|
+
description = metadata.get("Description")
|
|
11
|
+
version = metadata.get("Version")
|
|
12
|
+
author = metadata.get("Author")
|
|
13
|
+
base_url = "device_view"
|
|
14
|
+
required_settings = []
|
|
15
|
+
default_settings = {"show_on_device_tab": False}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
config = NetBoxDeviceViewConfig
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from rest_framework import serializers
|
|
2
|
+
|
|
3
|
+
from netbox.api.serializers import NetBoxModelSerializer
|
|
4
|
+
from ..models import DeviceView
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DeviceViewSerializer(NetBoxModelSerializer):
|
|
8
|
+
class Meta:
|
|
9
|
+
model = DeviceView
|
|
10
|
+
fields = (
|
|
11
|
+
"id",
|
|
12
|
+
"display",
|
|
13
|
+
"device_type",
|
|
14
|
+
"grid_template_area",
|
|
15
|
+
"tags",
|
|
16
|
+
"custom_fields",
|
|
17
|
+
"created",
|
|
18
|
+
"last_updated",
|
|
19
|
+
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from netbox.api.viewsets import NetBoxModelViewSet
|
|
2
|
+
|
|
3
|
+
from .. import filtersets, models
|
|
4
|
+
from .serializers import DeviceViewSerializer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DeviceViewViewSet(NetBoxModelViewSet):
|
|
8
|
+
queryset = models.DeviceView.objects.prefetch_related("tags")
|
|
9
|
+
serializer_class = DeviceViewSerializer
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Generated by Django 4.1.9 on 2023-06-01 07:26
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
import django.db.models.deletion
|
|
5
|
+
import taggit.managers
|
|
6
|
+
import utilities.json
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Migration(migrations.Migration):
|
|
10
|
+
initial = True
|
|
11
|
+
|
|
12
|
+
dependencies = [
|
|
13
|
+
("dcim", "0172_larger_power_draw_values"),
|
|
14
|
+
("extras", "0092_delete_jobresult"),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
operations = [
|
|
18
|
+
migrations.CreateModel(
|
|
19
|
+
name="DeviceView",
|
|
20
|
+
fields=[
|
|
21
|
+
(
|
|
22
|
+
"id",
|
|
23
|
+
models.BigAutoField(
|
|
24
|
+
auto_created=True, primary_key=True, serialize=False
|
|
25
|
+
),
|
|
26
|
+
),
|
|
27
|
+
("created", models.DateTimeField(auto_now_add=True, null=True)),
|
|
28
|
+
("last_updated", models.DateTimeField(auto_now=True, null=True)),
|
|
29
|
+
(
|
|
30
|
+
"custom_field_data",
|
|
31
|
+
models.JSONField(
|
|
32
|
+
blank=True,
|
|
33
|
+
default=dict,
|
|
34
|
+
encoder=utilities.json.CustomFieldJSONEncoder,
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
("grid_template_area", models.TextField()),
|
|
38
|
+
(
|
|
39
|
+
"device_type",
|
|
40
|
+
models.ForeignKey(
|
|
41
|
+
on_delete=django.db.models.deletion.PROTECT,
|
|
42
|
+
related_name="+",
|
|
43
|
+
to="dcim.devicetype",
|
|
44
|
+
),
|
|
45
|
+
),
|
|
46
|
+
(
|
|
47
|
+
"tags",
|
|
48
|
+
taggit.managers.TaggableManager(
|
|
49
|
+
through="extras.TaggedItem", to="extras.Tag"
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
],
|
|
53
|
+
options={
|
|
54
|
+
"ordering": ("device_type",),
|
|
55
|
+
},
|
|
56
|
+
),
|
|
57
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from django.contrib.postgres.fields import ArrayField
|
|
2
|
+
from django.db import models
|
|
3
|
+
|
|
4
|
+
from netbox.models import NetBoxModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DeviceView(NetBoxModel):
|
|
8
|
+
device_type = models.ForeignKey(
|
|
9
|
+
to="dcim.DeviceType",
|
|
10
|
+
on_delete=models.PROTECT,
|
|
11
|
+
related_name="+",
|
|
12
|
+
blank=False,
|
|
13
|
+
null=False,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
grid_template_area = models.TextField(blank=False)
|
|
17
|
+
|
|
18
|
+
class Meta:
|
|
19
|
+
ordering = ("device_type",)
|
|
20
|
+
|
|
21
|
+
def __str__(self):
|
|
22
|
+
return self.device_type.model
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from extras.plugins import PluginMenuButton, PluginMenuItem
|
|
2
|
+
from utilities.choices import ButtonColorChoices
|
|
3
|
+
|
|
4
|
+
deviceview_buttons = [
|
|
5
|
+
PluginMenuButton(
|
|
6
|
+
link="plugins:netbox_device_view:deviceview_add",
|
|
7
|
+
title="Add",
|
|
8
|
+
icon_class="mdi mdi-plus-thick",
|
|
9
|
+
color=ButtonColorChoices.GREEN,
|
|
10
|
+
)
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
menu_items = (
|
|
14
|
+
PluginMenuItem(
|
|
15
|
+
link="plugins:netbox_device_view:deviceview_list",
|
|
16
|
+
link_text="Device Views",
|
|
17
|
+
buttons=deviceview_buttons,
|
|
18
|
+
),
|
|
19
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import django_tables2 as tables
|
|
2
|
+
|
|
3
|
+
from netbox.tables import NetBoxTable, ChoiceFieldColumn
|
|
4
|
+
from .models import DeviceView
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class DeviceViewTable(NetBoxTable):
|
|
8
|
+
class Meta(NetBoxTable.Meta):
|
|
9
|
+
model = DeviceView
|
|
10
|
+
fields = ("pk", "id", "device_type", "grid_template_area")
|
|
11
|
+
default_columns = ("device_type", "grid_template_area")
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from extras.plugins import PluginTemplateExtension
|
|
2
|
+
from .utils import prepare
|
|
3
|
+
from django.conf import settings
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Ports(PluginTemplateExtension):
|
|
7
|
+
def page(self):
|
|
8
|
+
obj = self.context["object"]
|
|
9
|
+
request = self.context["request"]
|
|
10
|
+
url = request.build_absolute_uri(obj.get_absolute_url())
|
|
11
|
+
|
|
12
|
+
dv, modules, ports_chassis = prepare(obj)
|
|
13
|
+
|
|
14
|
+
if dv is None or modules is None or ports_chassis is None:
|
|
15
|
+
return ""
|
|
16
|
+
|
|
17
|
+
return self.render(
|
|
18
|
+
"netbox_device_view/ports.html",
|
|
19
|
+
extra_context={
|
|
20
|
+
"ports_chassis": ports_chassis,
|
|
21
|
+
"dv": dv,
|
|
22
|
+
"modules": modules,
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DevicePorts(Ports):
|
|
28
|
+
model = "dcim.device"
|
|
29
|
+
|
|
30
|
+
def full_width_page(self):
|
|
31
|
+
if settings.PLUGINS_CONFIG["netbox_device_view"]["show_on_device_tab"] == False:
|
|
32
|
+
return ""
|
|
33
|
+
return self.page()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
template_extensions = [DevicePorts]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from django.urls import path
|
|
2
|
+
from . import models, views
|
|
3
|
+
from netbox.views.generic import ObjectChangeLogView
|
|
4
|
+
|
|
5
|
+
urlpatterns = (
|
|
6
|
+
path("device-view/", views.DeviceViewListView.as_view(), name="deviceview_list"),
|
|
7
|
+
path("device-view/add/", views.DeviceViewEditView.as_view(), name="deviceview_add"),
|
|
8
|
+
path("device-view/<int:pk>/", views.DeviceViewView.as_view(), name="deviceview"),
|
|
9
|
+
path(
|
|
10
|
+
"device-view/<int:pk>/edit/",
|
|
11
|
+
views.DeviceViewEditView.as_view(),
|
|
12
|
+
name="deviceview_edit",
|
|
13
|
+
),
|
|
14
|
+
path(
|
|
15
|
+
"device-view/<int:pk>/delete/",
|
|
16
|
+
views.DeviceViewDeleteView.as_view(),
|
|
17
|
+
name="deviceview_delete",
|
|
18
|
+
),
|
|
19
|
+
path(
|
|
20
|
+
"device-view/<int:pk>/changelog/",
|
|
21
|
+
ObjectChangeLogView.as_view(),
|
|
22
|
+
name="deviceview_changelog",
|
|
23
|
+
kwargs={"model": models.DeviceView},
|
|
24
|
+
),
|
|
25
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from dcim.models import ConsolePort
|
|
2
|
+
from .models import DeviceView
|
|
3
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def process_interfaces(interfaces, ports_chassis, switch=1):
|
|
9
|
+
if interfaces is not None:
|
|
10
|
+
for itf in interfaces:
|
|
11
|
+
regex = r"^(?P<type>([a-z]+))((?P<switch>[0-9]+)\/)?((?P<module>[0-9]+)\/)?((?P<port>[0-9]+))$"
|
|
12
|
+
matches = re.search(regex, itf.name.lower())
|
|
13
|
+
if matches:
|
|
14
|
+
itf.stylename = (
|
|
15
|
+
(matches["type"] or "")
|
|
16
|
+
+ (matches["module"] or "")
|
|
17
|
+
+ "-"
|
|
18
|
+
+ matches["port"]
|
|
19
|
+
)
|
|
20
|
+
sw = int(matches["switch"] or 0)
|
|
21
|
+
if (
|
|
22
|
+
hasattr(itf, "mgmt_only")
|
|
23
|
+
and itf.mgmt_only
|
|
24
|
+
and itf.type != "virtual"
|
|
25
|
+
) or hasattr(itf, "mgmt_only") == False:
|
|
26
|
+
sw = switch
|
|
27
|
+
if sw not in ports_chassis and sw != 0:
|
|
28
|
+
ports_chassis[sw] = []
|
|
29
|
+
if sw != 0:
|
|
30
|
+
ports_chassis[sw].append(itf)
|
|
31
|
+
return ports_chassis
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def prepare(obj):
|
|
35
|
+
ports_chassis = {}
|
|
36
|
+
dv = {}
|
|
37
|
+
modules = {}
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
if obj.virtual_chassis is None:
|
|
41
|
+
dv[1] = DeviceView.objects.get(
|
|
42
|
+
device_type=obj.device_type
|
|
43
|
+
).grid_template_area.replace(".area", ".area1")
|
|
44
|
+
modules[1] = obj.modules.all()
|
|
45
|
+
ports_chassis = process_interfaces(obj.interfaces.all(), ports_chassis)
|
|
46
|
+
ports_chassis = process_interfaces(
|
|
47
|
+
ConsolePort.objects.filter(device_id=obj.id), ports_chassis
|
|
48
|
+
)
|
|
49
|
+
else:
|
|
50
|
+
for member in obj.virtual_chassis.members.all():
|
|
51
|
+
dv[member.vc_position] = DeviceView.objects.get(
|
|
52
|
+
device_type=member.device_type
|
|
53
|
+
).grid_template_area.replace(".area", ".area" + str(member.vc_position))
|
|
54
|
+
modules[member.vc_position] = member.modules.all()
|
|
55
|
+
ports_chassis = process_interfaces(
|
|
56
|
+
member.interfaces.all(), ports_chassis, member.vc_position
|
|
57
|
+
)
|
|
58
|
+
ports_chassis = process_interfaces(
|
|
59
|
+
ConsolePort.objects.filter(device_id=member.id),
|
|
60
|
+
ports_chassis,
|
|
61
|
+
member.vc_position,
|
|
62
|
+
)
|
|
63
|
+
except ObjectDoesNotExist:
|
|
64
|
+
return None, None, None
|
|
65
|
+
|
|
66
|
+
return dv, modules, ports_chassis
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from netbox.views import generic
|
|
2
|
+
from dcim.models import Device
|
|
3
|
+
from . import forms, models, tables, filtersets
|
|
4
|
+
from utilities.views import ViewTab, register_model_view
|
|
5
|
+
from .utils import prepare
|
|
6
|
+
import pprint
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DeviceViewView(generic.ObjectView):
|
|
10
|
+
queryset = models.DeviceView.objects
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DeviceViewListView(generic.ObjectListView):
|
|
14
|
+
queryset = models.DeviceView.objects
|
|
15
|
+
table = tables.DeviceViewTable
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DeviceViewEditView(generic.ObjectEditView):
|
|
19
|
+
queryset = models.DeviceView.objects
|
|
20
|
+
form = forms.DeviceViewForm
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DeviceViewDeleteView(generic.ObjectDeleteView):
|
|
24
|
+
queryset = models.DeviceView.objects
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@register_model_view(Device, "deviceview", path="device-view")
|
|
28
|
+
class DeviceDeviceView(generic.ObjectView):
|
|
29
|
+
queryset = models.DeviceView.objects
|
|
30
|
+
|
|
31
|
+
tab = ViewTab(
|
|
32
|
+
label="Device View",
|
|
33
|
+
badge=lambda obj: models.DeviceView.objects.filter(
|
|
34
|
+
device_type=obj.device_type
|
|
35
|
+
).count(),
|
|
36
|
+
hide_if_empty=True,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def get_extra_context(self, request, instance):
|
|
40
|
+
dv, modules, ports_chassis = prepare(instance)
|
|
41
|
+
return {
|
|
42
|
+
"device_view": models.DeviceView.objects.filter(
|
|
43
|
+
device_type=instance.device_type
|
|
44
|
+
).first(),
|
|
45
|
+
"dv": dv,
|
|
46
|
+
"moduels": modules,
|
|
47
|
+
"ports_chassis": ports_chassis,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
def get_object(self, **kwargs):
|
|
51
|
+
return Device.objects.get(pk=kwargs.get("pk"))
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: netbox-device-view
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: NetBox Device View plugin
|
|
5
|
+
Home-page: https://github.com/peterbaumert/netbox-device-view
|
|
6
|
+
Author: Peter Baumert
|
|
7
|
+
Keywords: netbox,netbox-plugin
|
|
8
|
+
Classifier: Framework :: Django
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# Netbox Device View Plugin
|
|
13
|
+
 
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
The plugin is available as a Python package and can be installed with pip.
|
|
18
|
+
|
|
19
|
+
Run `pip install netbox-device-view` in your virtual env.
|
|
20
|
+
|
|
21
|
+
To ensure NetBox Device View 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 `netbox-device-view` package:
|
|
22
|
+
|
|
23
|
+
```no-highlight
|
|
24
|
+
# echo netbox-device-view >> local_requirements.txt
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Once installed, the plugin needs to be enabled in your `configuration.py` and optionally the `show_on_device_tab` setting enabled.
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# In your configuration.py
|
|
31
|
+
PLUGINS = ["netbox-device-view"]
|
|
32
|
+
|
|
33
|
+
PLUGINS_CONFIG = {
|
|
34
|
+
'netbox_device_view': {
|
|
35
|
+
'show_on_device_tab': True,
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
First run `source /opt/netbox/venv/bin/activate` to enter the Python virtual environment.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
Then run
|
|
44
|
+
```bash
|
|
45
|
+
cd /opt/netbox/netbox
|
|
46
|
+
pip3 install netbox-device-view
|
|
47
|
+
python3 manage.py migrate netbox-device-view
|
|
48
|
+
python3 manage.py collectstatic --no-input
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## How To Use
|
|
52
|
+
|
|
53
|
+
For each Device Type you need to add a DeviceView.
|
|
54
|
+
|
|
55
|
+
It is based on a CSS grid view with 32 columns and 2 rows.
|
|
56
|
+
You need to specify the grid-template-areas.
|
|
57
|
+
- Interface positions will use the following format: {interfacename}{module}-{port}
|
|
58
|
+
- leading "empties" can be specified as x
|
|
59
|
+
- trailing "empties" can be specified as z
|
|
60
|
+
- between "empties" can be named s{0-99}
|
|
61
|
+
|
|
62
|
+
Example for Cisco C9300-24T with 8x 10G module
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
/* C9300-24T */
|
|
66
|
+
.switchview.area {
|
|
67
|
+
grid-template-areas:
|
|
68
|
+
"x x x x x x x x x x x x x x gigabitethernet0-1 gigabitethernet0-3 gigabitethernet0-5 gigabitethernet0-7 gigabitethernet0-9 gigabitethernet0-11 s0 gigabitethernet0-13 gigabitethernet0-15 gigabitethernet0-17 gigabitethernet0-19 gigabitethernet0-21 gigabitethernet0-23 z z z z z"
|
|
69
|
+
"x x x x x x x x x x x x x x gigabitethernet0-2 gigabitethernet0-4 gigabitethernet0-6 gigabitethernet0-8 gigabitethernet0-10 gigabitethernet0-12 s0 gigabitethernet0-14 gigabitethernet0-16 gigabitethernet0-18 gigabitethernet0-20 gigabitethernet0-22 gigabitethernet0-24 z z z z z";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* C9300-24T with C9300-NM-8X */
|
|
73
|
+
.switchview.moduleC9300-NM-8X.area {
|
|
74
|
+
grid-template-areas:
|
|
75
|
+
"x x x x x x x x x x x x x x gigabitethernet0-1 gigabitethernet0-3 gigabitethernet0-5 gigabitethernet0-7 gigabitethernet0-9 gigabitethernet0-11 s0 gigabitethernet0-13 gigabitethernet0-15 gigabitethernet0-17 gigabitethernet0-19 gigabitethernet0-21 gigabitethernet0-23 s1 tengigabitethernet1-1 tengigabitethernet1-3 tengigabitethernet1-5 tengigabitethernet1-7"
|
|
76
|
+
"x x x x x x x x x x x x x x gigabitethernet0-2 gigabitethernet0-4 gigabitethernet0-6 gigabitethernet0-8 gigabitethernet0-10 gigabitethernet0-12 s0 gigabitethernet0-14 gigabitethernet0-16 gigabitethernet0-18 gigabitethernet0-20 gigabitethernet0-22 gigabitethernet0-24 s1 tengigabitethernet1-2 tengigabitethernet1-4 tengigabitethernet1-6 tengigabitethernet1-8";
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
It will look like
|
|
81
|
+
|
|
82
|
+

|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
netbox_device_view/__init__.py
|
|
4
|
+
netbox_device_view/filtersets.py
|
|
5
|
+
netbox_device_view/forms.py
|
|
6
|
+
netbox_device_view/models.py
|
|
7
|
+
netbox_device_view/navigation.py
|
|
8
|
+
netbox_device_view/tables.py
|
|
9
|
+
netbox_device_view/template_content.py
|
|
10
|
+
netbox_device_view/urls.py
|
|
11
|
+
netbox_device_view/utils.py
|
|
12
|
+
netbox_device_view/views.py
|
|
13
|
+
netbox_device_view.egg-info/PKG-INFO
|
|
14
|
+
netbox_device_view.egg-info/SOURCES.txt
|
|
15
|
+
netbox_device_view.egg-info/dependency_links.txt
|
|
16
|
+
netbox_device_view.egg-info/not-zip-safe
|
|
17
|
+
netbox_device_view.egg-info/top_level.txt
|
|
18
|
+
netbox_device_view/api/__init__.py
|
|
19
|
+
netbox_device_view/api/serializers.py
|
|
20
|
+
netbox_device_view/api/urls.py
|
|
21
|
+
netbox_device_view/api/views.py
|
|
22
|
+
netbox_device_view/migrations/0001_initial.py
|
|
23
|
+
netbox_device_view/migrations/__init__.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
netbox_device_view
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from setuptools import find_packages, setup
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="netbox-device-view",
|
|
8
|
+
version="0.1.0",
|
|
9
|
+
description="NetBox Device View plugin",
|
|
10
|
+
packages=find_packages(),
|
|
11
|
+
author="Peter Baumert",
|
|
12
|
+
include_package_data=True,
|
|
13
|
+
zip_safe=False,
|
|
14
|
+
install_requires=[],
|
|
15
|
+
long_description=long_description,
|
|
16
|
+
long_description_content_type="text/markdown",
|
|
17
|
+
url="https://github.com/peterbaumert/netbox-device-view",
|
|
18
|
+
keywords=["netbox", "netbox-plugin"],
|
|
19
|
+
classifiers=[
|
|
20
|
+
"Framework :: Django",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
],
|
|
23
|
+
)
|