netbox-toolkit-plugin 0.1.0__py3-none-any.whl → 0.1.2__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 (69) hide show
  1. netbox_toolkit_plugin/__init__.py +32 -0
  2. {netbox_toolkit → netbox_toolkit_plugin}/api/serializers.py +71 -35
  3. {netbox_toolkit → netbox_toolkit_plugin}/api/urls.py +3 -3
  4. {netbox_toolkit → netbox_toolkit_plugin}/connectors/factory.py +170 -111
  5. {netbox_toolkit → netbox_toolkit_plugin}/connectors/netmiko_connector.py +242 -179
  6. {netbox_toolkit → netbox_toolkit_plugin}/connectors/scrapli_connector.py +256 -172
  7. netbox_toolkit_plugin/migrations/0001_initial.py +108 -0
  8. netbox_toolkit_plugin/migrations/0002_alter_command_options_alter_command_unique_together_and_more.py +70 -0
  9. {netbox_toolkit → netbox_toolkit_plugin}/migrations/0003_permission_system_update.py +26 -12
  10. {netbox_toolkit → netbox_toolkit_plugin}/migrations/0004_remove_django_permissions.py +27 -29
  11. {netbox_toolkit → netbox_toolkit_plugin}/migrations/0005_alter_command_options_and_more.py +7 -8
  12. {netbox_toolkit → netbox_toolkit_plugin}/migrations/0006_commandlog_parsed_data_commandlog_parsing_success_and_more.py +7 -8
  13. {netbox_toolkit → netbox_toolkit_plugin}/migrations/0007_alter_commandlog_parsing_template.py +6 -4
  14. {netbox_toolkit → netbox_toolkit_plugin}/models.py +31 -32
  15. {netbox_toolkit → netbox_toolkit_plugin}/navigation.py +6 -6
  16. {netbox_toolkit → netbox_toolkit_plugin}/services/command_service.py +188 -128
  17. {netbox_toolkit → netbox_toolkit_plugin}/services/rate_limiting_service.py +104 -97
  18. netbox_toolkit_plugin/settings.py +176 -0
  19. netbox_toolkit_plugin/tables.py +51 -0
  20. netbox_toolkit_plugin/templates/netbox_toolkit/command.html +108 -0
  21. netbox_toolkit_plugin/templates/netbox_toolkit/command_list.html +12 -0
  22. netbox_toolkit_plugin/templates/netbox_toolkit/commandlog.html +170 -0
  23. netbox_toolkit_plugin/templates/netbox_toolkit/device_toolkit.html +557 -0
  24. {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/command.html +5 -5
  25. {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/command_list.html +2 -2
  26. {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/commandlog.html +2 -2
  27. {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/device_toolkit.html +6 -6
  28. netbox_toolkit_plugin/urls.py +38 -0
  29. {netbox_toolkit → netbox_toolkit_plugin}/utils/logging.py +20 -19
  30. {netbox_toolkit → netbox_toolkit_plugin}/views.py +251 -169
  31. {netbox_toolkit_plugin-0.1.0.dist-info → netbox_toolkit_plugin-0.1.2.dist-info}/METADATA +2 -2
  32. netbox_toolkit_plugin-0.1.2.dist-info/RECORD +60 -0
  33. netbox_toolkit_plugin-0.1.2.dist-info/entry_points.txt +2 -0
  34. netbox_toolkit_plugin-0.1.2.dist-info/top_level.txt +1 -0
  35. netbox_toolkit/__init__.py +0 -30
  36. netbox_toolkit/config.py +0 -159
  37. netbox_toolkit/migrations/0001_initial.py +0 -54
  38. netbox_toolkit/migrations/0002_alter_command_options_alter_command_unique_together_and_more.py +0 -66
  39. netbox_toolkit/tables.py +0 -37
  40. netbox_toolkit/urls.py +0 -22
  41. netbox_toolkit_plugin-0.1.0.dist-info/RECORD +0 -56
  42. netbox_toolkit_plugin-0.1.0.dist-info/entry_points.txt +0 -2
  43. netbox_toolkit_plugin-0.1.0.dist-info/top_level.txt +0 -1
  44. {netbox_toolkit → netbox_toolkit_plugin}/admin.py +0 -0
  45. {netbox_toolkit → netbox_toolkit_plugin}/api/__init__.py +0 -0
  46. {netbox_toolkit → netbox_toolkit_plugin}/api/mixins.py +0 -0
  47. {netbox_toolkit → netbox_toolkit_plugin}/api/schemas.py +0 -0
  48. {netbox_toolkit → netbox_toolkit_plugin}/api/views/__init__.py +0 -0
  49. {netbox_toolkit → netbox_toolkit_plugin}/api/views/command_logs.py +0 -0
  50. {netbox_toolkit → netbox_toolkit_plugin}/api/views/commands.py +0 -0
  51. {netbox_toolkit → netbox_toolkit_plugin}/connectors/__init__.py +0 -0
  52. {netbox_toolkit → netbox_toolkit_plugin}/connectors/base.py +0 -0
  53. {netbox_toolkit → netbox_toolkit_plugin}/exceptions.py +0 -0
  54. {netbox_toolkit → netbox_toolkit_plugin}/filtersets.py +0 -0
  55. {netbox_toolkit → netbox_toolkit_plugin}/forms.py +0 -0
  56. {netbox_toolkit → netbox_toolkit_plugin}/migrations/__init__.py +0 -0
  57. {netbox_toolkit → netbox_toolkit_plugin}/search.py +0 -0
  58. {netbox_toolkit → netbox_toolkit_plugin}/services/__init__.py +0 -0
  59. {netbox_toolkit → netbox_toolkit_plugin}/services/device_service.py +0 -0
  60. {netbox_toolkit/static/netbox_toolkit → netbox_toolkit_plugin/static/netbox_toolkit_plugin}/css/toolkit.css +0 -0
  61. {netbox_toolkit/static/netbox_toolkit → netbox_toolkit_plugin/static/netbox_toolkit_plugin}/js/toolkit.js +0 -0
  62. {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/command_edit.html +0 -0
  63. {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/commandlog_list.html +0 -0
  64. {netbox_toolkit → netbox_toolkit_plugin}/utils/__init__.py +0 -0
  65. {netbox_toolkit → netbox_toolkit_plugin}/utils/connection.py +0 -0
  66. {netbox_toolkit → netbox_toolkit_plugin}/utils/error_parser.py +0 -0
  67. {netbox_toolkit → netbox_toolkit_plugin}/utils/network.py +0 -0
  68. {netbox_toolkit_plugin-0.1.0.dist-info → netbox_toolkit_plugin-0.1.2.dist-info}/WHEEL +0 -0
  69. {netbox_toolkit_plugin-0.1.0.dist-info → netbox_toolkit_plugin-0.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,32 @@
1
+ from netbox.plugins import PluginConfig
2
+
3
+ __author__ = "Andy Norwood"
4
+ __version__ = "0.1.2"
5
+
6
+
7
+ class ToolkitPluginConfig(PluginConfig):
8
+ """NetBox plugin configuration for the Toolkit plugin."""
9
+
10
+ name = "netbox_toolkit_plugin"
11
+ verbose_name = "Command Toolkit Plugin"
12
+ description = "NetBox plugin for running pre-defined commands on network devices"
13
+ version = __version__
14
+ author = __author__
15
+ base_url = "toolkit"
16
+ min_version = "4.2.0"
17
+
18
+ # Database migrations
19
+ required_settings = []
20
+
21
+ # Default plugin settings
22
+ default_settings = {
23
+ "rate_limiting_enabled": True,
24
+ "device_command_limit": 10,
25
+ "time_window_minutes": 5,
26
+ "bypass_users": [],
27
+ "bypass_groups": [],
28
+ "debug_logging": False, # Enable debug logging for this plugin
29
+ }
30
+
31
+
32
+ config = ToolkitPluginConfig
@@ -3,33 +3,36 @@ from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializ
3
3
  from dcim.api.serializers import PlatformSerializer, DeviceSerializer
4
4
  from ..models import Command, CommandLog
5
5
 
6
+
6
7
  class CommandExecutionSerializer(serializers.Serializer):
7
8
  """Serializer for command execution input validation"""
9
+
8
10
  device_id = serializers.IntegerField(
9
11
  help_text="ID of the device to execute the command on"
10
12
  )
11
13
  username = serializers.CharField(
12
14
  max_length=100,
13
15
  help_text="Username for device authentication",
14
- trim_whitespace=True
16
+ trim_whitespace=True,
15
17
  )
16
18
  password = serializers.CharField(
17
19
  max_length=255,
18
- style={'input_type': 'password'},
20
+ style={"input_type": "password"},
19
21
  help_text="Password for device authentication",
20
- trim_whitespace=False
22
+ trim_whitespace=False,
21
23
  )
22
24
  timeout = serializers.IntegerField(
23
25
  required=False,
24
26
  default=30,
25
27
  min_value=5,
26
28
  max_value=300,
27
- help_text="Command execution timeout in seconds (5-300)"
29
+ help_text="Command execution timeout in seconds (5-300)",
28
30
  )
29
-
31
+
30
32
  def validate_device_id(self, value):
31
33
  """Validate that the device exists and has required attributes"""
32
34
  from dcim.models import Device
35
+
33
36
  try:
34
37
  device = Device.objects.get(id=value)
35
38
  if not device.platform:
@@ -43,17 +46,17 @@ class CommandExecutionSerializer(serializers.Serializer):
43
46
  return value
44
47
  except Device.DoesNotExist:
45
48
  raise serializers.ValidationError("Device not found")
46
-
49
+
47
50
  def validate(self, data):
48
51
  """Cross-field validation and object retrieval"""
49
52
  from dcim.models import Device
50
-
53
+
51
54
  # Get the actual device object for use in views
52
- device = Device.objects.get(id=data['device_id'])
53
- data['device'] = device
54
-
55
+ device = Device.objects.get(id=data["device_id"])
56
+ data["device"] = device
57
+
55
58
  return data
56
-
59
+
57
60
  def validate_username(self, value):
58
61
  """Validate username format"""
59
62
  if not value.strip():
@@ -61,7 +64,7 @@ class CommandExecutionSerializer(serializers.Serializer):
61
64
  if len(value.strip()) < 2:
62
65
  raise serializers.ValidationError("Username must be at least 2 characters")
63
66
  return value.strip()
64
-
67
+
65
68
  def validate_password(self, value):
66
69
  """Validate password"""
67
70
  if not value:
@@ -70,33 +73,45 @@ class CommandExecutionSerializer(serializers.Serializer):
70
73
  raise serializers.ValidationError("Password must be at least 3 characters")
71
74
  return value
72
75
 
76
+
73
77
  class NestedCommandSerializer(WritableNestedSerializer):
74
78
  url = serializers.HyperlinkedIdentityField(
75
- view_name='plugins-api:netbox_toolkit-api:command-detail'
79
+ view_name="plugins-api:netbox_toolkit_plugin-api:command-detail"
76
80
  )
77
81
 
78
82
  class Meta:
79
83
  model = Command
80
- fields = ('id', 'url', 'name', 'display')
84
+ fields = ("id", "url", "name", "display")
85
+
81
86
 
82
87
  class CommandSerializer(NetBoxModelSerializer):
83
88
  url = serializers.HyperlinkedIdentityField(
84
- view_name='plugins-api:netbox_toolkit-api:command-detail'
89
+ view_name="plugins-api:netbox_toolkit_plugin-api:command-detail"
85
90
  )
86
91
  platform = PlatformSerializer(nested=True)
87
92
 
88
93
  class Meta:
89
94
  model = Command
90
95
  fields = (
91
- 'id', 'url', 'display', 'name', 'command', 'description',
92
- 'platform', 'command_type',
93
- 'tags', 'custom_fields', 'created', 'last_updated'
96
+ "id",
97
+ "url",
98
+ "display",
99
+ "name",
100
+ "command",
101
+ "description",
102
+ "platform",
103
+ "command_type",
104
+ "tags",
105
+ "custom_fields",
106
+ "created",
107
+ "last_updated",
94
108
  )
95
- brief_fields = ('id', 'url', 'display', 'name', 'command_type', 'platform')
109
+ brief_fields = ("id", "url", "display", "name", "command_type", "platform")
110
+
96
111
 
97
112
  class CommandLogSerializer(NetBoxModelSerializer):
98
113
  url = serializers.HyperlinkedIdentityField(
99
- view_name='plugins-api:netbox_toolkit-api:commandlog-detail'
114
+ view_name="plugins-api:netbox_toolkit_plugin-api:commandlog-detail"
100
115
  )
101
116
  command = NestedCommandSerializer()
102
117
  device = DeviceSerializer(nested=True)
@@ -104,38 +119,58 @@ class CommandLogSerializer(NetBoxModelSerializer):
104
119
  class Meta:
105
120
  model = CommandLog
106
121
  fields = (
107
- 'id', 'url', 'display', 'command', 'device', 'output',
108
- 'username', 'execution_time', 'success', 'error_message', 'execution_duration',
109
- 'parsed_data', 'parsing_success', 'parsing_template',
110
- 'created', 'last_updated'
122
+ "id",
123
+ "url",
124
+ "display",
125
+ "command",
126
+ "device",
127
+ "output",
128
+ "username",
129
+ "execution_time",
130
+ "success",
131
+ "error_message",
132
+ "execution_duration",
133
+ "parsed_data",
134
+ "parsing_success",
135
+ "parsing_template",
136
+ "created",
137
+ "last_updated",
138
+ )
139
+ brief_fields = (
140
+ "id",
141
+ "url",
142
+ "display",
143
+ "command",
144
+ "device",
145
+ "username",
146
+ "execution_time",
147
+ "success",
111
148
  )
112
- brief_fields = ('id', 'url', 'display', 'command', 'device', 'username', 'execution_time', 'success')
149
+
113
150
 
114
151
  class BulkCommandExecutionSerializer(serializers.Serializer):
115
152
  """Serializer for bulk command execution validation"""
116
- command_id = serializers.IntegerField(
117
- help_text="ID of the command to execute"
118
- )
153
+
154
+ command_id = serializers.IntegerField(help_text="ID of the command to execute")
119
155
  device_id = serializers.IntegerField(
120
156
  help_text="ID of the device to execute the command on"
121
157
  )
122
158
  username = serializers.CharField(
123
- max_length=100,
124
- help_text="Username for device authentication"
159
+ max_length=100, help_text="Username for device authentication"
125
160
  )
126
161
  password = serializers.CharField(
127
162
  max_length=255,
128
- style={'input_type': 'password'},
129
- help_text="Password for device authentication"
163
+ style={"input_type": "password"},
164
+ help_text="Password for device authentication",
130
165
  )
131
166
  timeout = serializers.IntegerField(
132
167
  required=False,
133
168
  default=30,
134
169
  min_value=5,
135
170
  max_value=300,
136
- help_text="Command execution timeout in seconds"
171
+ help_text="Command execution timeout in seconds",
137
172
  )
138
-
173
+
139
174
  def validate_command_id(self, value):
140
175
  """Validate that the command exists"""
141
176
  try:
@@ -143,10 +178,11 @@ class BulkCommandExecutionSerializer(serializers.Serializer):
143
178
  return value
144
179
  except Command.DoesNotExist:
145
180
  raise serializers.ValidationError("Command not found")
146
-
181
+
147
182
  def validate_device_id(self, value):
148
183
  """Validate that the device exists"""
149
184
  from dcim.models import Device
185
+
150
186
  try:
151
187
  device = Device.objects.get(id=value)
152
188
  if not device.platform:
@@ -1,10 +1,10 @@
1
1
  from netbox.api.routers import NetBoxRouter
2
2
  from .views import CommandViewSet, CommandLogViewSet
3
3
 
4
- app_name = 'netbox_toolkit'
4
+ app_name = "netbox_toolkit_plugin"
5
5
 
6
6
  router = NetBoxRouter()
7
- router.register('commands', CommandViewSet)
8
- router.register('command-logs', CommandLogViewSet)
7
+ router.register("commands", CommandViewSet)
8
+ router.register("command-logs", CommandLogViewSet)
9
9
 
10
10
  urlpatterns = router.urls