netbox-toolkit-plugin 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl
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_toolkit_plugin/__init__.py +1 -1
- netbox_toolkit_plugin/admin.py +11 -7
- netbox_toolkit_plugin/api/mixins.py +20 -16
- netbox_toolkit_plugin/api/schemas.py +53 -74
- netbox_toolkit_plugin/api/serializers.py +10 -11
- netbox_toolkit_plugin/api/urls.py +2 -1
- netbox_toolkit_plugin/api/views/__init__.py +4 -3
- netbox_toolkit_plugin/api/views/command_logs.py +80 -73
- netbox_toolkit_plugin/api/views/commands.py +140 -134
- netbox_toolkit_plugin/connectors/__init__.py +9 -9
- netbox_toolkit_plugin/connectors/base.py +30 -31
- netbox_toolkit_plugin/connectors/factory.py +21 -25
- netbox_toolkit_plugin/connectors/netmiko_connector.py +18 -28
- netbox_toolkit_plugin/connectors/scrapli_connector.py +17 -16
- netbox_toolkit_plugin/exceptions.py +0 -7
- netbox_toolkit_plugin/filtersets.py +26 -42
- netbox_toolkit_plugin/forms.py +13 -11
- netbox_toolkit_plugin/migrations/0008_remove_parsed_data_storage.py +26 -0
- netbox_toolkit_plugin/models.py +2 -17
- netbox_toolkit_plugin/navigation.py +3 -0
- netbox_toolkit_plugin/search.py +12 -9
- netbox_toolkit_plugin/services/__init__.py +1 -1
- netbox_toolkit_plugin/services/command_service.py +6 -9
- netbox_toolkit_plugin/services/device_service.py +40 -32
- netbox_toolkit_plugin/services/rate_limiting_service.py +4 -3
- netbox_toolkit_plugin/static/netbox_toolkit_plugin/js/toolkit.js +245 -119
- netbox_toolkit_plugin/tables.py +10 -1
- netbox_toolkit_plugin/templates/netbox_toolkit_plugin/commandlog.html +16 -84
- netbox_toolkit_plugin/templates/netbox_toolkit_plugin/device_toolkit.html +37 -33
- netbox_toolkit_plugin/urls.py +10 -3
- netbox_toolkit_plugin/utils/connection.py +54 -54
- netbox_toolkit_plugin/utils/error_parser.py +128 -109
- netbox_toolkit_plugin/utils/logging.py +1 -0
- netbox_toolkit_plugin/utils/network.py +74 -47
- netbox_toolkit_plugin/views.py +51 -22
- {netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/METADATA +2 -2
- netbox_toolkit_plugin-0.1.3.dist-info/RECORD +61 -0
- netbox_toolkit_plugin-0.1.2.dist-info/RECORD +0 -60
- {netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/WHEEL +0 -0
- {netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/entry_points.txt +0 -0
- {netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/licenses/LICENSE +0 -0
- {netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,9 @@
|
|
1
1
|
"""Network utility functions."""
|
2
|
+
|
3
|
+
import builtins
|
4
|
+
import contextlib
|
2
5
|
import socket
|
3
6
|
import time
|
4
|
-
from typing import Tuple, Optional
|
5
7
|
|
6
8
|
from ..exceptions import DeviceReachabilityError, SSHBannerError
|
7
9
|
from .logging import get_toolkit_logger
|
@@ -9,81 +11,93 @@ from .logging import get_toolkit_logger
|
|
9
11
|
logger = get_toolkit_logger(__name__)
|
10
12
|
|
11
13
|
|
12
|
-
def check_device_reachability(
|
14
|
+
def check_device_reachability(
|
15
|
+
hostname: str, port: int = 22, timeout: int = 3
|
16
|
+
) -> tuple[bool, bool, bytes | None]:
|
13
17
|
"""
|
14
18
|
Check if a device is reachable and if it's running SSH.
|
15
|
-
|
19
|
+
|
16
20
|
Args:
|
17
21
|
hostname: The hostname or IP address to check
|
18
22
|
port: The port to check (default: 22 for SSH)
|
19
23
|
timeout: Connection timeout in seconds
|
20
|
-
|
24
|
+
|
21
25
|
Returns:
|
22
26
|
Tuple of (is_reachable, is_ssh_server, ssh_banner)
|
23
|
-
|
27
|
+
|
24
28
|
Raises:
|
25
29
|
DeviceReachabilityError: If device is not reachable
|
26
30
|
SSHBannerError: If SSH banner cannot be read
|
27
31
|
"""
|
28
|
-
logger.debug(
|
29
|
-
|
32
|
+
logger.debug(
|
33
|
+
f"Checking device reachability for {hostname}:{port} with timeout {timeout}s"
|
34
|
+
)
|
35
|
+
|
30
36
|
is_reachable = False
|
31
37
|
is_ssh_server = False
|
32
38
|
ssh_banner = None
|
33
|
-
|
39
|
+
|
34
40
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
35
|
-
|
41
|
+
|
36
42
|
try:
|
37
43
|
sock.settimeout(timeout)
|
38
|
-
|
44
|
+
|
39
45
|
# Attempt connection
|
40
46
|
logger.debug(f"Attempting TCP connection to {hostname}:{port}")
|
41
47
|
sock.connect((hostname, port))
|
42
48
|
is_reachable = True
|
43
49
|
logger.debug(f"TCP connection successful to {hostname}:{port}")
|
44
|
-
|
50
|
+
|
45
51
|
# Try to read SSH banner
|
46
52
|
ssh_banner, is_ssh_server = _read_ssh_banner(sock, hostname)
|
47
|
-
logger.debug(
|
48
|
-
|
49
|
-
|
53
|
+
logger.debug(
|
54
|
+
f"SSH banner check: is_ssh_server={is_ssh_server}, banner_length={len(ssh_banner) if ssh_banner else 0}"
|
55
|
+
)
|
56
|
+
|
57
|
+
except TimeoutError as e:
|
50
58
|
logger.warning(f"Connection to {hostname}:{port} timed out after {timeout}s")
|
51
|
-
raise DeviceReachabilityError(
|
52
|
-
|
59
|
+
raise DeviceReachabilityError(
|
60
|
+
f"Connection to {hostname}:{port} timed out"
|
61
|
+
) from e
|
62
|
+
except ConnectionRefusedError as e:
|
53
63
|
logger.warning(f"Connection to {hostname}:{port} refused")
|
54
|
-
raise DeviceReachabilityError(f"Connection to {hostname}:{port} refused")
|
64
|
+
raise DeviceReachabilityError(f"Connection to {hostname}:{port} refused") from e
|
55
65
|
except socket.gaierror as e:
|
56
66
|
logger.error(f"Could not resolve hostname: {hostname} - {str(e)}")
|
57
|
-
raise DeviceReachabilityError(f"Could not resolve hostname: {hostname}")
|
67
|
+
raise DeviceReachabilityError(f"Could not resolve hostname: {hostname}") from e
|
58
68
|
except Exception as e:
|
59
69
|
logger.error(f"Socket error when connecting to {hostname}: {str(e)}")
|
60
|
-
raise DeviceReachabilityError(
|
70
|
+
raise DeviceReachabilityError(
|
71
|
+
f"Socket error when connecting to {hostname}: {str(e)}"
|
72
|
+
) from e
|
61
73
|
finally:
|
62
|
-
|
74
|
+
with contextlib.suppress(builtins.BaseException):
|
63
75
|
sock.close()
|
64
|
-
|
65
|
-
pass
|
66
|
-
|
76
|
+
|
67
77
|
return is_reachable, is_ssh_server, ssh_banner
|
68
78
|
|
69
79
|
|
70
|
-
def _read_ssh_banner(
|
80
|
+
def _read_ssh_banner(
|
81
|
+
sock: socket.socket, hostname: str, attempts: int = 3
|
82
|
+
) -> tuple[bytes | None, bool]:
|
71
83
|
"""
|
72
84
|
Try to read SSH banner from socket.
|
73
|
-
|
85
|
+
|
74
86
|
Args:
|
75
87
|
sock: Connected socket
|
76
88
|
hostname: Hostname for logging
|
77
89
|
attempts: Number of attempts to read banner
|
78
|
-
|
90
|
+
|
79
91
|
Returns:
|
80
92
|
Tuple of (banner, is_ssh_server)
|
81
93
|
"""
|
82
|
-
logger.debug(
|
83
|
-
|
94
|
+
logger.debug(
|
95
|
+
f"Attempting to read SSH banner from {hostname} with {attempts} attempts"
|
96
|
+
)
|
97
|
+
|
84
98
|
ssh_banner = None
|
85
99
|
is_ssh_server = False
|
86
|
-
|
100
|
+
|
87
101
|
for i in range(attempts):
|
88
102
|
try:
|
89
103
|
logger.debug(f"SSH banner read attempt {i + 1}/{attempts}")
|
@@ -91,29 +105,33 @@ def _read_ssh_banner(sock: socket.socket, hostname: str, attempts: int = 3) -> T
|
|
91
105
|
banner = sock.recv(1024)
|
92
106
|
if banner:
|
93
107
|
ssh_banner = banner
|
94
|
-
logger.debug(
|
95
|
-
|
108
|
+
logger.debug(
|
109
|
+
f"Received banner: {banner[:50]}..."
|
110
|
+
if len(banner) > 50
|
111
|
+
else f"Received banner: {banner}"
|
112
|
+
)
|
113
|
+
if banner.startswith(b"SSH-"):
|
96
114
|
is_ssh_server = True
|
97
115
|
logger.debug("Banner indicates SSH server")
|
98
116
|
break
|
99
117
|
else:
|
100
118
|
logger.debug("Banner received but not SSH protocol")
|
101
|
-
|
119
|
+
# Non-SSH banner received
|
102
120
|
else:
|
103
121
|
logger.debug("No banner data received")
|
104
|
-
|
122
|
+
|
105
123
|
# If no banner received but still connected, pause briefly and try again
|
106
124
|
if i < attempts - 1:
|
107
125
|
logger.debug("Waiting 0.5s before next banner read attempt")
|
108
126
|
time.sleep(0.5)
|
109
|
-
except
|
127
|
+
except TimeoutError:
|
110
128
|
logger.debug(f"Banner read attempt {i + 1} timed out")
|
111
129
|
if i < attempts - 1:
|
112
130
|
continue
|
113
131
|
except Exception as e:
|
114
132
|
logger.warning(f"Error reading SSH banner: {str(e)}")
|
115
133
|
break
|
116
|
-
|
134
|
+
|
117
135
|
logger.debug(f"SSH banner read completed: is_ssh_server={is_ssh_server}")
|
118
136
|
return ssh_banner, is_ssh_server
|
119
137
|
|
@@ -121,37 +139,46 @@ def _read_ssh_banner(sock: socket.socket, hostname: str, attempts: int = 3) -> T
|
|
121
139
|
def validate_device_connectivity(hostname: str, port: int = 22) -> None:
|
122
140
|
"""
|
123
141
|
Validate that a device is reachable and has SSH available.
|
124
|
-
|
142
|
+
|
125
143
|
Args:
|
126
144
|
hostname: The hostname or IP address to validate
|
127
145
|
port: The port to check (default: 22)
|
128
|
-
|
146
|
+
|
129
147
|
Raises:
|
130
148
|
DeviceReachabilityError: If device is not reachable
|
131
149
|
SSHBannerError: If SSH service issues are detected
|
132
150
|
"""
|
133
151
|
logger.debug(f"Validating device connectivity for {hostname}:{port}")
|
134
|
-
|
152
|
+
|
135
153
|
try:
|
136
|
-
is_reachable, is_ssh_server, ssh_banner = check_device_reachability(
|
137
|
-
|
154
|
+
is_reachable, is_ssh_server, ssh_banner = check_device_reachability(
|
155
|
+
hostname, port
|
156
|
+
)
|
157
|
+
|
138
158
|
if not is_reachable:
|
139
159
|
logger.error(f"Device {hostname}:{port} is not reachable")
|
140
160
|
raise DeviceReachabilityError(
|
141
161
|
f"Cannot connect to {hostname} on port {port}. "
|
142
162
|
f"Please verify the device is reachable and SSH is enabled."
|
143
163
|
)
|
144
|
-
|
164
|
+
|
145
165
|
if is_reachable and not is_ssh_server:
|
146
166
|
banner_msg = f" (received banner: {ssh_banner})" if ssh_banner else ""
|
147
|
-
logger.warning(
|
167
|
+
logger.warning(
|
168
|
+
f"Device {hostname}:{port} is reachable but SSH banner not detected{banner_msg}"
|
169
|
+
)
|
148
170
|
# Device is reachable but didn't provide SSH banner - connection might fail
|
149
|
-
pass
|
150
171
|
elif is_ssh_server:
|
151
|
-
logger.debug(
|
152
|
-
|
172
|
+
logger.debug(
|
173
|
+
f"Device {hostname}:{port} is reachable and SSH server detected"
|
174
|
+
)
|
175
|
+
|
153
176
|
except (DeviceReachabilityError, SSHBannerError):
|
154
177
|
raise
|
155
178
|
except Exception as e:
|
156
|
-
logger.error(
|
157
|
-
|
179
|
+
logger.error(
|
180
|
+
f"Unexpected error validating connectivity to {hostname}: {str(e)}"
|
181
|
+
)
|
182
|
+
raise DeviceReachabilityError(
|
183
|
+
f"Unexpected error validating connectivity to {hostname}: {str(e)}"
|
184
|
+
) from e
|
netbox_toolkit_plugin/views.py
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
from django.shortcuts import render
|
2
|
-
from django.views.generic import View
|
3
1
|
from django.contrib import messages
|
4
|
-
from django.
|
2
|
+
from django.shortcuts import render
|
3
|
+
|
5
4
|
from dcim.models import Device
|
6
|
-
from .models import Command, CommandLog
|
7
|
-
from .forms import CommandForm, CommandLogForm, CommandExecutionForm
|
8
5
|
from netbox.views.generic import (
|
9
|
-
ObjectView,
|
10
|
-
ObjectListView,
|
11
|
-
ObjectEditView,
|
12
|
-
ObjectDeleteView,
|
13
6
|
ObjectChangeLogView,
|
7
|
+
ObjectDeleteView,
|
8
|
+
ObjectEditView,
|
9
|
+
ObjectListView,
|
10
|
+
ObjectView,
|
14
11
|
)
|
15
12
|
from utilities.views import ViewTab, register_model_view
|
13
|
+
|
14
|
+
from .forms import CommandExecutionForm, CommandForm
|
15
|
+
from .models import Command, CommandLog
|
16
16
|
from .services.command_service import CommandExecutionService
|
17
17
|
from .services.device_service import DeviceService
|
18
18
|
from .services.rate_limiting_service import RateLimitingService
|
@@ -81,6 +81,7 @@ class DeviceToolkitView(ObjectView):
|
|
81
81
|
def _user_has_action_permission(self, user, obj, action):
|
82
82
|
"""Check if user has permission for a specific action on an object using NetBox's ObjectPermission system"""
|
83
83
|
from django.contrib.contenttypes.models import ContentType
|
84
|
+
|
84
85
|
from users.models import ObjectPermission
|
85
86
|
|
86
87
|
# Get content type for the object
|
@@ -128,13 +129,25 @@ class DeviceToolkitView(ObjectView):
|
|
128
129
|
# Check for 'execute_show' action permission
|
129
130
|
if self._user_has_action_permission(user, command, "execute_show"):
|
130
131
|
commands.append(command)
|
131
|
-
elif command.command_type == "config"
|
132
|
+
elif command.command_type == "config" and self._user_has_action_permission(
|
133
|
+
user, command, "execute_config"
|
134
|
+
):
|
132
135
|
# Check for 'execute_config' action permission
|
133
|
-
|
134
|
-
commands.append(command)
|
136
|
+
commands.append(command)
|
135
137
|
|
136
138
|
return commands
|
137
139
|
|
140
|
+
def _order_parsed_data(self, parsed_data):
|
141
|
+
"""
|
142
|
+
Return parsed data preserving original TextFSM template field order.
|
143
|
+
|
144
|
+
For live parsing results, we preserve the original order from TextFSM
|
145
|
+
since it represents the logical field sequence defined in the template.
|
146
|
+
"""
|
147
|
+
# For live parsing, the original order from TextFSM should be preserved
|
148
|
+
# No reordering needed as the data comes directly from TextFSM parsing
|
149
|
+
return parsed_data
|
150
|
+
|
138
151
|
def post(self, request, pk):
|
139
152
|
self.kwargs = {"pk": pk} # Set kwargs for get_object
|
140
153
|
device = self.get_object()
|
@@ -156,14 +169,13 @@ class DeviceToolkitView(ObjectView):
|
|
156
169
|
"You don't have permission to execute configuration commands.",
|
157
170
|
)
|
158
171
|
return self.get(request, pk)
|
159
|
-
elif command.command_type == "show"
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
return self.get(request, pk)
|
172
|
+
elif command.command_type == "show" and not self._user_has_action_permission(
|
173
|
+
request.user, command, "execute_show"
|
174
|
+
):
|
175
|
+
messages.error(
|
176
|
+
request, "You don't have permission to execute show commands."
|
177
|
+
)
|
178
|
+
return self.get(request, pk)
|
167
179
|
|
168
180
|
# Create a form with the POST data
|
169
181
|
form_data = {
|
@@ -263,7 +275,7 @@ class DeviceToolkitView(ObjectView):
|
|
263
275
|
"has_syntax_error": result.has_syntax_error,
|
264
276
|
"syntax_error_type": result.syntax_error_type,
|
265
277
|
"syntax_error_vendor": result.syntax_error_vendor,
|
266
|
-
"parsed_data": result.parsed_output,
|
278
|
+
"parsed_data": self._order_parsed_data(result.parsed_output),
|
267
279
|
"parsing_success": result.parsing_success,
|
268
280
|
"parsing_template": result.parsing_method,
|
269
281
|
"device_valid": is_valid,
|
@@ -387,6 +399,7 @@ class CommandView(ObjectView):
|
|
387
399
|
def _user_has_action_permission(self, user, obj, action):
|
388
400
|
"""Check if user has permission for a specific action on an object using NetBox's ObjectPermission system"""
|
389
401
|
from django.contrib.contenttypes.models import ContentType
|
402
|
+
|
390
403
|
from users.models import ObjectPermission
|
391
404
|
|
392
405
|
# Get content type for the object
|
@@ -463,5 +476,21 @@ class CommandLogView(ObjectView):
|
|
463
476
|
template_name = "netbox_toolkit_plugin/commandlog.html"
|
464
477
|
|
465
478
|
|
466
|
-
class
|
479
|
+
class CommandLogEditView(ObjectEditView):
|
480
|
+
queryset = CommandLog.objects.all()
|
481
|
+
form = None # No form since we don't want manual editing
|
482
|
+
template_name = "netbox_toolkit_plugin/commandlog_edit.html"
|
483
|
+
|
484
|
+
def get(self, request, *args, **kwargs):
|
485
|
+
# Redirect to the detail view since we don't allow editing
|
486
|
+
from django.shortcuts import redirect
|
487
|
+
|
488
|
+
if "pk" in kwargs:
|
489
|
+
return redirect(
|
490
|
+
"plugins:netbox_toolkit_plugin:commandlog_view", pk=kwargs["pk"]
|
491
|
+
)
|
492
|
+
return redirect("plugins:netbox_toolkit_plugin:commandlog_list")
|
493
|
+
|
494
|
+
|
495
|
+
class CommandLogDeleteView(ObjectDeleteView):
|
467
496
|
queryset = CommandLog.objects.all()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: netbox-toolkit-plugin
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.3
|
4
4
|
Summary: NetBox plugin for running pre-defined commands on network devices
|
5
5
|
Author: Andy Norwood
|
6
6
|
Classifier: Development Status :: 3 - Alpha
|
@@ -67,7 +67,7 @@ A NetBox plugin that allows you to run commands on network devices directly from
|
|
67
67
|
|
68
68
|
## Contributing
|
69
69
|
|
70
|
-
**🚀 Want to Contribute?** Start with the [Contributor Guide](./docs/contributing.md) for a fast overview of the codebase.
|
70
|
+
**🚀 Want to Contribute?** Start with the [Contributor Guide](./docs/development/contributing.md) for a fast overview of the codebase.
|
71
71
|
|
72
72
|
|
73
73
|
## Future ideas:
|
@@ -0,0 +1,61 @@
|
|
1
|
+
netbox_toolkit_plugin/__init__.py,sha256=wQLJVJSdFbNs5xiaujQ4fvErzbcjLdiXeV665hbd9Vw,848
|
2
|
+
netbox_toolkit_plugin/admin.py,sha256=PtGtgn29vnKCgq64N96Ks3-ZHFsGGssxzpeUyXQgFtY,694
|
3
|
+
netbox_toolkit_plugin/exceptions.py,sha256=jwY2nbkrkaYUVyDR7B-NirvfId4WulT1i_HsU9yBNhw,722
|
4
|
+
netbox_toolkit_plugin/filtersets.py,sha256=hFgeHWjq-OosPQ7mheR1aKLrsAk__oX632mULTWl5OY,2406
|
5
|
+
netbox_toolkit_plugin/forms.py,sha256=FOtM8uafX774YZaIRQlQroykESJ8LsZjsuH-3wO8T6g,969
|
6
|
+
netbox_toolkit_plugin/models.py,sha256=5G8EMhFNKKr_vLqmv43mbOHZievoETa3NKgB-3KYY74,2194
|
7
|
+
netbox_toolkit_plugin/navigation.py,sha256=UHW4HTTFlfUBW-Bxy9uMDMKx7N-kcDykQ5MmSquWEOo,1191
|
8
|
+
netbox_toolkit_plugin/search.py,sha256=sCS7O_GqT-t9xj-HBkoBRQhsXbmiJ3-thysG47l480Y,567
|
9
|
+
netbox_toolkit_plugin/settings.py,sha256=9Rc1kIPNbnJYEOpc1UQGULbIZUTN5VE7aFmeZyXPWo0,5797
|
10
|
+
netbox_toolkit_plugin/tables.py,sha256=8fDqdNzuc2x1FEKX1Juc2WESXAwnO1fO13O3i-MaN5A,1587
|
11
|
+
netbox_toolkit_plugin/urls.py,sha256=1r-O37neagk1h4hJc3vjyNPMIlIm2ad2n8Jbf3W68nY,1413
|
12
|
+
netbox_toolkit_plugin/views.py,sha256=8stAGxqDPnl7z-HFApP9Lt_Rfms_ogPwj6ORQiAKXCk,19762
|
13
|
+
netbox_toolkit_plugin/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
+
netbox_toolkit_plugin/api/mixins.py,sha256=n21RaQ-6QQ1VmSJYCCvdo0pg0uK0o-Qa80nW9fIXtRY,2222
|
15
|
+
netbox_toolkit_plugin/api/schemas.py,sha256=CSwIPrvlVL2P_wnKh63rTTn4Ewh7nGoZhGu7e3CUGqU,7059
|
16
|
+
netbox_toolkit_plugin/api/serializers.py,sha256=EIl69rNuzhEpKnJ4t6ZEY4ARO1JVlMN4vEPCULawhRQ,6071
|
17
|
+
netbox_toolkit_plugin/api/urls.py,sha256=S9Z02RXeIbj0yXkE0weLuIlxhnl2r6ZHb9BwVRem1do,281
|
18
|
+
netbox_toolkit_plugin/api/views/__init__.py,sha256=kMWS6HMq8RxU-kLtEjzmZIvrTj-50mPO-B3jWfXKmgM,190
|
19
|
+
netbox_toolkit_plugin/api/views/command_logs.py,sha256=sm3A9tYS0tcbicj1Yz-SM2bF3LNNB4lD15SHlsYAdUc,6171
|
20
|
+
netbox_toolkit_plugin/api/views/commands.py,sha256=FXKHfAquSxp6QsKqw7Oa-aj3y8Qe4btAiUsPAZP-M3A,10734
|
21
|
+
netbox_toolkit_plugin/connectors/__init__.py,sha256=LHbn3AIedoHFdz7FbsngNEf_ZzvkVTDw1EQrviCbv20,419
|
22
|
+
netbox_toolkit_plugin/connectors/base.py,sha256=vwyWe7GNqnDI81RvrnsxTabj6jaqOcNzr3w_M19Hv_I,2618
|
23
|
+
netbox_toolkit_plugin/connectors/factory.py,sha256=XwrcvC_CL_4aUyzYaXaNTA6OGutnAZQYjvDydO2HjUU,13660
|
24
|
+
netbox_toolkit_plugin/connectors/netmiko_connector.py,sha256=QSDfgDnZkffl6LwMr90Ip1z7ytWMsBgRwjAgIW0h4yM,18711
|
25
|
+
netbox_toolkit_plugin/connectors/scrapli_connector.py,sha256=fr1mNCaoXiApdSuJC7XhKYG6FN5cP2uxC2uHBm0h8DM,23330
|
26
|
+
netbox_toolkit_plugin/migrations/0001_initial.py,sha256=4fycU83wXx-sN73YTxAZekRDx9uVxzHg38Dl-G6EqxY,3729
|
27
|
+
netbox_toolkit_plugin/migrations/0002_alter_command_options_alter_command_unique_together_and_more.py,sha256=FrGCbl5BnnWzqjLsMZtykgnAjzpI0j6A-6SQxKwGiAM,2174
|
28
|
+
netbox_toolkit_plugin/migrations/0003_permission_system_update.py,sha256=BUBDkAnn04Snqj-EZdi0vfCIXjbakUMlmnCawUPwpbI,1965
|
29
|
+
netbox_toolkit_plugin/migrations/0004_remove_django_permissions.py,sha256=hj6UrpfmEk4gnEVziGJHFCPvvZfDlUFH1GvxQ4Aw-h8,2545
|
30
|
+
netbox_toolkit_plugin/migrations/0005_alter_command_options_and_more.py,sha256=TOiyo2QKporoA089Vjri5rSFQX3BH1IxY1hj1voN7Rs,609
|
31
|
+
netbox_toolkit_plugin/migrations/0006_commandlog_parsed_data_commandlog_parsing_success_and_more.py,sha256=cMIeOi0j3gXfwUYO3hQ4Kr5Uok6cslyUCEurtgKN2hQ,771
|
32
|
+
netbox_toolkit_plugin/migrations/0007_alter_commandlog_parsing_template.py,sha256=VedbEIA-54JL_2I-MC1YPqppKS8WdpedB1nbFIkBcLU,512
|
33
|
+
netbox_toolkit_plugin/migrations/0008_remove_parsed_data_storage.py,sha256=2DjgB73SKlB0vOb3Oy70kCeqdzMBJJ3xbIpHWqvPtzk,680
|
34
|
+
netbox_toolkit_plugin/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
+
netbox_toolkit_plugin/services/__init__.py,sha256=3TDwhBJgaxGW_PbXp2uFgK5Gkzfy6Mh1cgvDirhpzQY,273
|
36
|
+
netbox_toolkit_plugin/services/command_service.py,sha256=7NNVSV644ckiOAyZ0Nt1pkVS-Z5Q_aMYyDrY_j0oiEc,15816
|
37
|
+
netbox_toolkit_plugin/services/device_service.py,sha256=ZX5HKtKT4PoHANw5J9YIRN1gKyI_dh88TscAh0n21zE,2873
|
38
|
+
netbox_toolkit_plugin/services/rate_limiting_service.py,sha256=y-tXUq15cuCQLc72bnQ5sJ3UZ7p4f8YvYeQRWxwArAs,8515
|
39
|
+
netbox_toolkit_plugin/static/netbox_toolkit_plugin/css/toolkit.css,sha256=VmyM2_rBJhiP43whtMFaYYP4EW4MUGHPPr84mOo_0Qg,4236
|
40
|
+
netbox_toolkit_plugin/static/netbox_toolkit_plugin/js/toolkit.js,sha256=SY5aYCNgW_-ukjBcKZTVIb-DZ5IXGNAuaMQKIXcv4MM,29824
|
41
|
+
netbox_toolkit_plugin/templates/netbox_toolkit/command.html,sha256=Aol4n0LVRO_yuHf0iUnxkQlPSMOW-V_dT_rd89rZTDE,3191
|
42
|
+
netbox_toolkit_plugin/templates/netbox_toolkit/command_list.html,sha256=hFnVL58CNDce06ICITBjdEY8w_lNYxjb9_B24PRSTc0,365
|
43
|
+
netbox_toolkit_plugin/templates/netbox_toolkit/commandlog.html,sha256=u_vNBBWmYT4ln2Qz6DylkDSLNm9h4n2j1dYhFWgOk8I,5196
|
44
|
+
netbox_toolkit_plugin/templates/netbox_toolkit/device_toolkit.html,sha256=4muIExwJ6DU3IcmDexjpOxZ8hNnIQzfiTd-17rXa9A0,30731
|
45
|
+
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/command.html,sha256=WmRepyhomJZeFAuAGQ8x0K1EFmR8vh7htQBcw7FPv8I,3422
|
46
|
+
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/command_edit.html,sha256=Dx3QVrtLegViZl9_VWeVayZ1DIgtzWDnrmgS5_TfOCg,175
|
47
|
+
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/command_list.html,sha256=zPxg_c1cfNgF54u0nj03DeglXS8N6mSJIx11OXO8fGs,382
|
48
|
+
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/commandlog.html,sha256=Scn3OQABce6KPxqETaXImEccppdXHv0v6Sk_CHKC-Ig,3382
|
49
|
+
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/commandlog_list.html,sha256=ggZDtjUOx4kyyD0zAybImF4_gGqe7eTx6JOx_CxjnQ0,105
|
50
|
+
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/device_toolkit.html,sha256=gH7JpVxPZr_pmVDUCKNYrkO5cl6ZtvX_402EZdHyUuE,32588
|
51
|
+
netbox_toolkit_plugin/utils/__init__.py,sha256=YPk8W2lP8BYeYpZFzemTS4V4BK9s5DqXrAjyQrMAAeg,43
|
52
|
+
netbox_toolkit_plugin/utils/connection.py,sha256=lArX7IB990R5yPLeA3BEHK3NOw2LAeyhZB7ZFaEu3WY,4141
|
53
|
+
netbox_toolkit_plugin/utils/error_parser.py,sha256=ogvXZjO4O1VM3vu0WXIfnVhzWrYVY-OMsygtP6ZJwZw,16626
|
54
|
+
netbox_toolkit_plugin/utils/logging.py,sha256=BESBdwuHdGUzK0tIJhf3e_hLXTTB1ZOFW4qF3jJwU8U,1917
|
55
|
+
netbox_toolkit_plugin/utils/network.py,sha256=GubJMUixPpFuw1eaVW71sZ-27xhRPshqdrt2O6T34cI,6294
|
56
|
+
netbox_toolkit_plugin-0.1.3.dist-info/licenses/LICENSE,sha256=oxRw-SpalZWfCdc8ZALEDboD9OV22cBRrLIpXz2f7a8,11273
|
57
|
+
netbox_toolkit_plugin-0.1.3.dist-info/METADATA,sha256=4jxSlQc3_mwheeLRtNE8G1GpyedpgedwxdZNmlvQCw8,3169
|
58
|
+
netbox_toolkit_plugin-0.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
59
|
+
netbox_toolkit_plugin-0.1.3.dist-info/entry_points.txt,sha256=CwLAZ6veCye0uzfADprW9FSnOkWEPj2NGiO8usdW_oE,62
|
60
|
+
netbox_toolkit_plugin-0.1.3.dist-info/top_level.txt,sha256=XScXYui_2rj4aEFemGc-r5CqKgcmq_dwHgQy-SodK0Q,22
|
61
|
+
netbox_toolkit_plugin-0.1.3.dist-info/RECORD,,
|
@@ -1,60 +0,0 @@
|
|
1
|
-
netbox_toolkit_plugin/__init__.py,sha256=3QswdYHYy_jIlALcrIFznVfnJ0g_-OzQ9B2ACQagKh4,848
|
2
|
-
netbox_toolkit_plugin/admin.py,sha256=j0O2hke80XbGCfU3lkxl8__tRmBArNLoQtLyA39hepI,690
|
3
|
-
netbox_toolkit_plugin/exceptions.py,sha256=qh7SxXLTqwsduxUMiTA_pXQ67VHSpxRuQgdlfXMl6Bk,785
|
4
|
-
netbox_toolkit_plugin/filtersets.py,sha256=ppmnfQ8IUHm60BiJR9_cdn1ygvuFlMfj6YIFLJ-XeMc,2722
|
5
|
-
netbox_toolkit_plugin/forms.py,sha256=6aUaXuJtx3ZL2iEbIq2zXuiXCu2bAHDUMI2EJJBPsWg,1037
|
6
|
-
netbox_toolkit_plugin/models.py,sha256=-TyH0xJrHxqfM1XC5pAFesQF38oec6JcAJs81Ay6arE,2761
|
7
|
-
netbox_toolkit_plugin/navigation.py,sha256=SvJRHkvlFgG42sLwxCTG6-6X976IgXTKhiRCPe8ZG6U,965
|
8
|
-
netbox_toolkit_plugin/search.py,sha256=v8HPgp_0Nq-s_IoV7n4Kfi63_u535jVAoT-31ntdZlA,564
|
9
|
-
netbox_toolkit_plugin/settings.py,sha256=9Rc1kIPNbnJYEOpc1UQGULbIZUTN5VE7aFmeZyXPWo0,5797
|
10
|
-
netbox_toolkit_plugin/tables.py,sha256=kR90aUXuJxKiSNz7Mm62ZanodDBtExDj7AgROkh1rJw,1417
|
11
|
-
netbox_toolkit_plugin/urls.py,sha256=CbwZvFreUifZUFZUQrC-KyqVte_INKzMhnSIgzAFUVY,1215
|
12
|
-
netbox_toolkit_plugin/views.py,sha256=mmcxl70hgZ-W1R9gozXneeczcyP33InldLZRW1_p-yA,18782
|
13
|
-
netbox_toolkit_plugin/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
-
netbox_toolkit_plugin/api/mixins.py,sha256=Yxog3LQQqmzIiXjxZ5VxSbwV3er-Pxs2GpPEJUipvfY,2241
|
15
|
-
netbox_toolkit_plugin/api/schemas.py,sha256=Xza5-H2ZqBPCEPyMzDkbmSofY9nE73epu0PKvCB1_Ys,7334
|
16
|
-
netbox_toolkit_plugin/api/serializers.py,sha256=lPQLWffuRScwrmiMS24ejmwnaXqBCzlUNG92KW3dBB8,6123
|
17
|
-
netbox_toolkit_plugin/api/urls.py,sha256=_shol27G-7MlflSfLmfznLuw4xhZtrc0VBFQLxda-vE,280
|
18
|
-
netbox_toolkit_plugin/api/views/__init__.py,sha256=CksHVk9Jj81kImVlr_JnP9VGwFCAhtrnRzqw7H7pjcI,189
|
19
|
-
netbox_toolkit_plugin/api/views/command_logs.py,sha256=4PdUQPvle9R9pJcJalYS4MCKYhmG_5EbAUowbjVetgw,6255
|
20
|
-
netbox_toolkit_plugin/api/views/commands.py,sha256=dv6sjN3L0FTyAWmM4u7zZBPOug6H_WcIR6egd3XE3A4,10939
|
21
|
-
netbox_toolkit_plugin/connectors/__init__.py,sha256=lL1WCo-rlcjNGVwmwSN1PT592xr5LEPT8k5zEVZlltE,419
|
22
|
-
netbox_toolkit_plugin/connectors/base.py,sha256=Z88tVG87H8IXdub55t-_uu1ptdhKo0uaz9l9iO-Xi0I,2829
|
23
|
-
netbox_toolkit_plugin/connectors/factory.py,sha256=z_XULU26VuyfdwkqyFMvmTFqrPVDSmmmmlt5Slk0-lU,13722
|
24
|
-
netbox_toolkit_plugin/connectors/netmiko_connector.py,sha256=k2bNuKMCJjb1F8lXR05v19GMFURDqG6SammlIKBz_Kk,18965
|
25
|
-
netbox_toolkit_plugin/connectors/scrapli_connector.py,sha256=O3iuVczGophquhA5-QECZPa68rLp2DDh5Jk2JXKEk1M,23369
|
26
|
-
netbox_toolkit_plugin/migrations/0001_initial.py,sha256=4fycU83wXx-sN73YTxAZekRDx9uVxzHg38Dl-G6EqxY,3729
|
27
|
-
netbox_toolkit_plugin/migrations/0002_alter_command_options_alter_command_unique_together_and_more.py,sha256=FrGCbl5BnnWzqjLsMZtykgnAjzpI0j6A-6SQxKwGiAM,2174
|
28
|
-
netbox_toolkit_plugin/migrations/0003_permission_system_update.py,sha256=BUBDkAnn04Snqj-EZdi0vfCIXjbakUMlmnCawUPwpbI,1965
|
29
|
-
netbox_toolkit_plugin/migrations/0004_remove_django_permissions.py,sha256=hj6UrpfmEk4gnEVziGJHFCPvvZfDlUFH1GvxQ4Aw-h8,2545
|
30
|
-
netbox_toolkit_plugin/migrations/0005_alter_command_options_and_more.py,sha256=TOiyo2QKporoA089Vjri5rSFQX3BH1IxY1hj1voN7Rs,609
|
31
|
-
netbox_toolkit_plugin/migrations/0006_commandlog_parsed_data_commandlog_parsing_success_and_more.py,sha256=cMIeOi0j3gXfwUYO3hQ4Kr5Uok6cslyUCEurtgKN2hQ,771
|
32
|
-
netbox_toolkit_plugin/migrations/0007_alter_commandlog_parsing_template.py,sha256=VedbEIA-54JL_2I-MC1YPqppKS8WdpedB1nbFIkBcLU,512
|
33
|
-
netbox_toolkit_plugin/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
|
-
netbox_toolkit_plugin/services/__init__.py,sha256=nzdv0yOAyoAgm3ReKn-zLCbxkzEZfDpfnVDy9UExtyg,273
|
35
|
-
netbox_toolkit_plugin/services/command_service.py,sha256=e-PmGelmwZnTgxBf6L8-aditnj_10RlNVL8qjQVpkPo,15991
|
36
|
-
netbox_toolkit_plugin/services/device_service.py,sha256=SWqWw7c5cBhbXE_jCJwfgc3KvxchQq_6NeS2hlb3NDA,2945
|
37
|
-
netbox_toolkit_plugin/services/rate_limiting_service.py,sha256=prru5A8TZ9kVGsapNoxYxFyPONaHp2zmaVn1clFXBCU,8574
|
38
|
-
netbox_toolkit_plugin/static/netbox_toolkit_plugin/css/toolkit.css,sha256=VmyM2_rBJhiP43whtMFaYYP4EW4MUGHPPr84mOo_0Qg,4236
|
39
|
-
netbox_toolkit_plugin/static/netbox_toolkit_plugin/js/toolkit.js,sha256=0oF2p8g1Yu28hKQswj1-2Kctt_09YtT__Xeo39LfQ-I,25721
|
40
|
-
netbox_toolkit_plugin/templates/netbox_toolkit/command.html,sha256=Aol4n0LVRO_yuHf0iUnxkQlPSMOW-V_dT_rd89rZTDE,3191
|
41
|
-
netbox_toolkit_plugin/templates/netbox_toolkit/command_list.html,sha256=hFnVL58CNDce06ICITBjdEY8w_lNYxjb9_B24PRSTc0,365
|
42
|
-
netbox_toolkit_plugin/templates/netbox_toolkit/commandlog.html,sha256=u_vNBBWmYT4ln2Qz6DylkDSLNm9h4n2j1dYhFWgOk8I,5196
|
43
|
-
netbox_toolkit_plugin/templates/netbox_toolkit/device_toolkit.html,sha256=4muIExwJ6DU3IcmDexjpOxZ8hNnIQzfiTd-17rXa9A0,30731
|
44
|
-
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/command.html,sha256=WmRepyhomJZeFAuAGQ8x0K1EFmR8vh7htQBcw7FPv8I,3422
|
45
|
-
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/command_edit.html,sha256=Dx3QVrtLegViZl9_VWeVayZ1DIgtzWDnrmgS5_TfOCg,175
|
46
|
-
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/command_list.html,sha256=zPxg_c1cfNgF54u0nj03DeglXS8N6mSJIx11OXO8fGs,382
|
47
|
-
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/commandlog.html,sha256=3oXOw27_q8kC1d9PqPvzbnDUGQyHhCfKLyYtcV5AWDs,5672
|
48
|
-
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/commandlog_list.html,sha256=ggZDtjUOx4kyyD0zAybImF4_gGqe7eTx6JOx_CxjnQ0,105
|
49
|
-
netbox_toolkit_plugin/templates/netbox_toolkit_plugin/device_toolkit.html,sha256=WzoQwG9w1-vnpAfbPJ-m6-LyT8qJas9c2CfMkf2EanU,32356
|
50
|
-
netbox_toolkit_plugin/utils/__init__.py,sha256=YPk8W2lP8BYeYpZFzemTS4V4BK9s5DqXrAjyQrMAAeg,43
|
51
|
-
netbox_toolkit_plugin/utils/connection.py,sha256=XWUNOaJ9TBIO6XuESTPi3RSwe8bKlyZ0MLV4_b-ZJiY,4349
|
52
|
-
netbox_toolkit_plugin/utils/error_parser.py,sha256=tl6QrFW_0bugZKXHl5V_UPY3VDKdp6jDskLtM5oaYAI,16811
|
53
|
-
netbox_toolkit_plugin/utils/logging.py,sha256=AfIPUNUUKYyVqGqTiS7xi96KBNs5BYZjEK8_61SPnOk,1916
|
54
|
-
netbox_toolkit_plugin/utils/network.py,sha256=__Xz3pYhd7FtMYAsnFZGbW2akQ8uRY2tjs4axIoZMhA,6100
|
55
|
-
netbox_toolkit_plugin-0.1.2.dist-info/licenses/LICENSE,sha256=oxRw-SpalZWfCdc8ZALEDboD9OV22cBRrLIpXz2f7a8,11273
|
56
|
-
netbox_toolkit_plugin-0.1.2.dist-info/METADATA,sha256=IgLYRDTT9MX-4Xb1aDUSgPKB-baSFJi__Pa1v8El7vA,3157
|
57
|
-
netbox_toolkit_plugin-0.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
58
|
-
netbox_toolkit_plugin-0.1.2.dist-info/entry_points.txt,sha256=CwLAZ6veCye0uzfADprW9FSnOkWEPj2NGiO8usdW_oE,62
|
59
|
-
netbox_toolkit_plugin-0.1.2.dist-info/top_level.txt,sha256=XScXYui_2rj4aEFemGc-r5CqKgcmq_dwHgQy-SodK0Q,22
|
60
|
-
netbox_toolkit_plugin-0.1.2.dist-info/RECORD,,
|
File without changes
|
{netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/entry_points.txt
RENAMED
File without changes
|
{netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
{netbox_toolkit_plugin-0.1.2.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/top_level.txt
RENAMED
File without changes
|