netbox-toolkit-plugin 0.1.1__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.
Files changed (43) hide show
  1. netbox_toolkit_plugin/__init__.py +1 -1
  2. netbox_toolkit_plugin/admin.py +11 -7
  3. netbox_toolkit_plugin/api/mixins.py +20 -16
  4. netbox_toolkit_plugin/api/schemas.py +53 -74
  5. netbox_toolkit_plugin/api/serializers.py +10 -11
  6. netbox_toolkit_plugin/api/urls.py +2 -1
  7. netbox_toolkit_plugin/api/views/__init__.py +4 -3
  8. netbox_toolkit_plugin/api/views/command_logs.py +80 -73
  9. netbox_toolkit_plugin/api/views/commands.py +140 -134
  10. netbox_toolkit_plugin/connectors/__init__.py +9 -9
  11. netbox_toolkit_plugin/connectors/base.py +30 -31
  12. netbox_toolkit_plugin/connectors/factory.py +22 -26
  13. netbox_toolkit_plugin/connectors/netmiko_connector.py +18 -28
  14. netbox_toolkit_plugin/connectors/scrapli_connector.py +17 -16
  15. netbox_toolkit_plugin/exceptions.py +0 -7
  16. netbox_toolkit_plugin/filtersets.py +26 -42
  17. netbox_toolkit_plugin/forms.py +13 -11
  18. netbox_toolkit_plugin/migrations/0008_remove_parsed_data_storage.py +26 -0
  19. netbox_toolkit_plugin/models.py +2 -17
  20. netbox_toolkit_plugin/navigation.py +3 -0
  21. netbox_toolkit_plugin/search.py +12 -9
  22. netbox_toolkit_plugin/services/__init__.py +1 -1
  23. netbox_toolkit_plugin/services/command_service.py +7 -10
  24. netbox_toolkit_plugin/services/device_service.py +40 -32
  25. netbox_toolkit_plugin/services/rate_limiting_service.py +4 -3
  26. netbox_toolkit_plugin/{config.py → settings.py} +17 -7
  27. netbox_toolkit_plugin/static/netbox_toolkit_plugin/js/toolkit.js +245 -119
  28. netbox_toolkit_plugin/tables.py +10 -1
  29. netbox_toolkit_plugin/templates/netbox_toolkit_plugin/commandlog.html +16 -84
  30. netbox_toolkit_plugin/templates/netbox_toolkit_plugin/device_toolkit.html +37 -33
  31. netbox_toolkit_plugin/urls.py +10 -3
  32. netbox_toolkit_plugin/utils/connection.py +54 -54
  33. netbox_toolkit_plugin/utils/error_parser.py +128 -109
  34. netbox_toolkit_plugin/utils/logging.py +1 -0
  35. netbox_toolkit_plugin/utils/network.py +74 -47
  36. netbox_toolkit_plugin/views.py +51 -22
  37. {netbox_toolkit_plugin-0.1.1.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/METADATA +2 -2
  38. netbox_toolkit_plugin-0.1.3.dist-info/RECORD +61 -0
  39. netbox_toolkit_plugin-0.1.1.dist-info/RECORD +0 -60
  40. {netbox_toolkit_plugin-0.1.1.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/WHEEL +0 -0
  41. {netbox_toolkit_plugin-0.1.1.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/entry_points.txt +0 -0
  42. {netbox_toolkit_plugin-0.1.1.dist-info → netbox_toolkit_plugin-0.1.3.dist-info}/licenses/LICENSE +0 -0
  43. {netbox_toolkit_plugin-0.1.1.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(hostname: str, port: int = 22, timeout: int = 3) -> Tuple[bool, bool, Optional[bytes]]:
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(f"Checking device reachability for {hostname}:{port} with timeout {timeout}s")
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(f"SSH banner check: is_ssh_server={is_ssh_server}, banner_length={len(ssh_banner) if ssh_banner else 0}")
48
-
49
- except socket.timeout:
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(f"Connection to {hostname}:{port} timed out")
52
- except ConnectionRefusedError:
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(f"Socket error when connecting to {hostname}: {str(e)}")
70
+ raise DeviceReachabilityError(
71
+ f"Socket error when connecting to {hostname}: {str(e)}"
72
+ ) from e
61
73
  finally:
62
- try:
74
+ with contextlib.suppress(builtins.BaseException):
63
75
  sock.close()
64
- except:
65
- pass
66
-
76
+
67
77
  return is_reachable, is_ssh_server, ssh_banner
68
78
 
69
79
 
70
- def _read_ssh_banner(sock: socket.socket, hostname: str, attempts: int = 3) -> Tuple[Optional[bytes], bool]:
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(f"Attempting to read SSH banner from {hostname} with {attempts} attempts")
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(f"Received banner: {banner[:50]}..." if len(banner) > 50 else f"Received banner: {banner}")
95
- if banner.startswith(b'SSH-'):
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
- pass # Non-SSH banner received
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 socket.timeout:
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(hostname, port)
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(f"Device {hostname}:{port} is reachable but SSH banner not detected{banner_msg}")
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(f"Device {hostname}:{port} is reachable and SSH server detected")
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(f"Unexpected error validating connectivity to {hostname}: {str(e)}")
157
- raise DeviceReachabilityError(f"Unexpected error validating connectivity to {hostname}: {str(e)}")
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
@@ -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.core.exceptions import PermissionDenied
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
- if self._user_has_action_permission(user, command, "execute_config"):
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
- if not self._user_has_action_permission(
161
- request.user, command, "execute_show"
162
- ):
163
- messages.error(
164
- request, "You don't have permission to execute show commands."
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 CommandLogChangeLogView(ObjectChangeLogView):
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.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=pfAgtNX_fMjsJ_XrZC_-SbndIlqNBZnwhjtzdPXBurk,848
2
- netbox_toolkit_plugin/admin.py,sha256=j0O2hke80XbGCfU3lkxl8__tRmBArNLoQtLyA39hepI,690
3
- netbox_toolkit_plugin/config.py,sha256=jaiEm75PT043X4v6lvkEd4ku9fBgjNZs6B_lHxaazu0,5489
4
- netbox_toolkit_plugin/exceptions.py,sha256=qh7SxXLTqwsduxUMiTA_pXQ67VHSpxRuQgdlfXMl6Bk,785
5
- netbox_toolkit_plugin/filtersets.py,sha256=ppmnfQ8IUHm60BiJR9_cdn1ygvuFlMfj6YIFLJ-XeMc,2722
6
- netbox_toolkit_plugin/forms.py,sha256=6aUaXuJtx3ZL2iEbIq2zXuiXCu2bAHDUMI2EJJBPsWg,1037
7
- netbox_toolkit_plugin/models.py,sha256=-TyH0xJrHxqfM1XC5pAFesQF38oec6JcAJs81Ay6arE,2761
8
- netbox_toolkit_plugin/navigation.py,sha256=SvJRHkvlFgG42sLwxCTG6-6X976IgXTKhiRCPe8ZG6U,965
9
- netbox_toolkit_plugin/search.py,sha256=v8HPgp_0Nq-s_IoV7n4Kfi63_u535jVAoT-31ntdZlA,564
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=kWVwVE2SFibcUxl9sFAWoAWl0ehh4vd7uxMmZQU3C7o,13720
24
- netbox_toolkit_plugin/connectors/netmiko_connector.py,sha256=6gOO3xlUDghRWjKzB__TTPQESN11djqaBZaESd2BWYY,18963
25
- netbox_toolkit_plugin/connectors/scrapli_connector.py,sha256=FjMIFmWt-B7W3W9fdO6gauVLxH7JnLt-s99kPGvvOzg,23367
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=MCxIasZkdt6xfry2dDGCr1O28LmXxfz4A-vDwNL2uV4,15989
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.1.dist-info/licenses/LICENSE,sha256=oxRw-SpalZWfCdc8ZALEDboD9OV22cBRrLIpXz2f7a8,11273
56
- netbox_toolkit_plugin-0.1.1.dist-info/METADATA,sha256=6wdLBUUcGI4wxXIimULs9thtBz90eWKpfWIkqC7_W80,3157
57
- netbox_toolkit_plugin-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
58
- netbox_toolkit_plugin-0.1.1.dist-info/entry_points.txt,sha256=CwLAZ6veCye0uzfADprW9FSnOkWEPj2NGiO8usdW_oE,62
59
- netbox_toolkit_plugin-0.1.1.dist-info/top_level.txt,sha256=XScXYui_2rj4aEFemGc-r5CqKgcmq_dwHgQy-SodK0Q,22
60
- netbox_toolkit_plugin-0.1.1.dist-info/RECORD,,