netbox-toolkit-plugin 0.1.0__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 (56) hide show
  1. netbox_toolkit/__init__.py +30 -0
  2. netbox_toolkit/admin.py +16 -0
  3. netbox_toolkit/api/__init__.py +0 -0
  4. netbox_toolkit/api/mixins.py +54 -0
  5. netbox_toolkit/api/schemas.py +234 -0
  6. netbox_toolkit/api/serializers.py +158 -0
  7. netbox_toolkit/api/urls.py +10 -0
  8. netbox_toolkit/api/views/__init__.py +10 -0
  9. netbox_toolkit/api/views/command_logs.py +170 -0
  10. netbox_toolkit/api/views/commands.py +267 -0
  11. netbox_toolkit/config.py +159 -0
  12. netbox_toolkit/connectors/__init__.py +15 -0
  13. netbox_toolkit/connectors/base.py +97 -0
  14. netbox_toolkit/connectors/factory.py +301 -0
  15. netbox_toolkit/connectors/netmiko_connector.py +443 -0
  16. netbox_toolkit/connectors/scrapli_connector.py +486 -0
  17. netbox_toolkit/exceptions.py +36 -0
  18. netbox_toolkit/filtersets.py +85 -0
  19. netbox_toolkit/forms.py +31 -0
  20. netbox_toolkit/migrations/0001_initial.py +54 -0
  21. netbox_toolkit/migrations/0002_alter_command_options_alter_command_unique_together_and_more.py +66 -0
  22. netbox_toolkit/migrations/0003_permission_system_update.py +48 -0
  23. netbox_toolkit/migrations/0004_remove_django_permissions.py +77 -0
  24. netbox_toolkit/migrations/0005_alter_command_options_and_more.py +25 -0
  25. netbox_toolkit/migrations/0006_commandlog_parsed_data_commandlog_parsing_success_and_more.py +28 -0
  26. netbox_toolkit/migrations/0007_alter_commandlog_parsing_template.py +18 -0
  27. netbox_toolkit/migrations/__init__.py +0 -0
  28. netbox_toolkit/models.py +89 -0
  29. netbox_toolkit/navigation.py +30 -0
  30. netbox_toolkit/search.py +21 -0
  31. netbox_toolkit/services/__init__.py +7 -0
  32. netbox_toolkit/services/command_service.py +357 -0
  33. netbox_toolkit/services/device_service.py +87 -0
  34. netbox_toolkit/services/rate_limiting_service.py +228 -0
  35. netbox_toolkit/static/netbox_toolkit/css/toolkit.css +143 -0
  36. netbox_toolkit/static/netbox_toolkit/js/toolkit.js +657 -0
  37. netbox_toolkit/tables.py +37 -0
  38. netbox_toolkit/templates/netbox_toolkit/command.html +108 -0
  39. netbox_toolkit/templates/netbox_toolkit/command_edit.html +10 -0
  40. netbox_toolkit/templates/netbox_toolkit/command_list.html +12 -0
  41. netbox_toolkit/templates/netbox_toolkit/commandlog.html +170 -0
  42. netbox_toolkit/templates/netbox_toolkit/commandlog_list.html +4 -0
  43. netbox_toolkit/templates/netbox_toolkit/device_toolkit.html +536 -0
  44. netbox_toolkit/urls.py +22 -0
  45. netbox_toolkit/utils/__init__.py +1 -0
  46. netbox_toolkit/utils/connection.py +125 -0
  47. netbox_toolkit/utils/error_parser.py +428 -0
  48. netbox_toolkit/utils/logging.py +58 -0
  49. netbox_toolkit/utils/network.py +157 -0
  50. netbox_toolkit/views.py +385 -0
  51. netbox_toolkit_plugin-0.1.0.dist-info/METADATA +76 -0
  52. netbox_toolkit_plugin-0.1.0.dist-info/RECORD +56 -0
  53. netbox_toolkit_plugin-0.1.0.dist-info/WHEEL +5 -0
  54. netbox_toolkit_plugin-0.1.0.dist-info/entry_points.txt +2 -0
  55. netbox_toolkit_plugin-0.1.0.dist-info/licenses/LICENSE +200 -0
  56. netbox_toolkit_plugin-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,108 @@
1
+ {% extends 'generic/object.html' %}
2
+ {% load helpers %}
3
+ {% load static %}
4
+
5
+ {% block style %}
6
+ <link href="{% static 'netbox_toolkit/css/toolkit.css' %}" rel="stylesheet">
7
+ {% endblock %}
8
+
9
+ {% block buttons %}
10
+ {% if perms.netbox_toolkit.change_command %}
11
+ <a href="{% url 'plugins:netbox_toolkit:command_edit' pk=object.pk %}" class="btn btn-warning">
12
+ <i class="mdi mdi-pencil" aria-hidden="true"></i> Edit
13
+ </a>
14
+ {% endif %}
15
+ {% if perms.netbox_toolkit.delete_command %}
16
+ <a href="{% url 'plugins:netbox_toolkit:command_delete' pk=object.pk %}" class="btn btn-danger">
17
+ <i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete
18
+ </a>
19
+ {% endif %}
20
+ {% endblock %}
21
+
22
+ {% block content %}
23
+ <div class="row mb-3">
24
+ <div class="col col-md-6">
25
+ <div class="card">
26
+ <div class="card-header">
27
+ <h3 class="card-title">Command</h3>
28
+ </div>
29
+ <div class="card-body">
30
+ <table class="table table-hover attr-table">
31
+ <tr>
32
+ <th scope="row">Name</th>
33
+ <td>{{ object.name }}</td>
34
+ </tr>
35
+ <tr>
36
+ <th scope="row">Platform</th>
37
+ <td>{{ object.platform|linkify }}</td>
38
+ </tr>
39
+ <tr>
40
+ <th scope="row">Command Type</th>
41
+ <td>
42
+ {{ object.get_command_type_display }}
43
+ {% if can_execute %}
44
+ <span class="badge bg-success ms-2">
45
+ <i class="mdi mdi-check"></i> Executable
46
+ </span>
47
+ {% else %}
48
+ <span class="badge bg-secondary ms-2">
49
+ <i class="mdi mdi-lock"></i> No Execute Permission
50
+ </span>
51
+ {% endif %}
52
+ </td>
53
+ </tr>
54
+ <tr>
55
+ <th scope="row">Description</th>
56
+ <td>{{ object.description|placeholder }}</td>
57
+ </tr>
58
+ </table>
59
+ </div>
60
+ </div>
61
+ {% include 'inc/panels/custom_fields.html' %}
62
+ {% include 'inc/panels/tags.html' %}
63
+ </div>
64
+ <div class="col col-md-6">
65
+ <div class="card">
66
+ <div class="card-header">
67
+ <h3 class="card-title">Command Detail</h3>
68
+ </div>
69
+ <div class="card-body">
70
+ <pre>{{ object.command }}</pre>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ </div>
75
+ <div class="row">
76
+ <div class="col col-md-12">
77
+ <div class="card">
78
+ <div class="card-header">
79
+ <h3 class="card-title">Recent Command Logs</h3>
80
+ </div>
81
+ <div class="card-body">
82
+ <table class="table table-hover table-headings">
83
+ <thead>
84
+ <tr>
85
+ <th>Device</th>
86
+ <th>Username</th>
87
+ <th>Execution Time</th>
88
+ </tr>
89
+ </thead>
90
+ <tbody>
91
+ {% for log in object.logs.all|slice:":5" %}
92
+ <tr>
93
+ <td>{{ log.device|linkify }}</td>
94
+ <td>{{ log.username }}</td>
95
+ <td>{{ log.execution_time }}</td>
96
+ </tr>
97
+ {% empty %}
98
+ <tr>
99
+ <td colspan="3" class="text-muted">No command executions recorded</td>
100
+ </tr>
101
+ {% endfor %}
102
+ </tbody>
103
+ </table>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ {% endblock %}
@@ -0,0 +1,10 @@
1
+ {% extends 'generic/object_edit.html' %}
2
+ {% load helpers %}
3
+
4
+ {% block title %}
5
+ {% if object.pk %}
6
+ Edit Command
7
+ {% else %}
8
+ Add Command
9
+ {% endif %}
10
+ {% endblock %}
@@ -0,0 +1,12 @@
1
+ {% extends 'generic/object_list.html' %}
2
+ {% load helpers %}
3
+
4
+ {% block title %}Commands{% endblock %}
5
+
6
+ {% block buttons %}
7
+ {% if perms.netbox_toolkit.add_command %}
8
+ <a href="{% url 'plugins:netbox_toolkit:command_add' %}" class="btn btn-primary">
9
+ <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Command
10
+ </a>
11
+ {% endif %}
12
+ {% endblock %}
@@ -0,0 +1,170 @@
1
+ {% extends 'generic/object.html' %}
2
+ {% load helpers %}
3
+ {% load static %}
4
+
5
+ {% block style %}
6
+ <link href="{% static 'netbox_toolkit/css/toolkit.css' %}" rel="stylesheet">
7
+ {% endblock %}
8
+
9
+ {% block content %}
10
+ <div class="row mb-3">
11
+ <div class="col col-md-6">
12
+ <div class="card">
13
+ <div class="card-header">
14
+ <h3 class="card-title">Command Log</h3>
15
+ </div>
16
+ <div class="card-body">
17
+ <table class="table table-hover attr-table">
18
+ <tr>
19
+ <th scope="row">Command</th>
20
+ <td>{{ object.command|linkify }}</td>
21
+ </tr>
22
+ <tr>
23
+ <th scope="row">Device</th>
24
+ <td>{{ object.device|linkify }}</td>
25
+ </tr>
26
+ <tr>
27
+ <th scope="row">Username</th>
28
+ <td>{{ object.username }}</td>
29
+ </tr>
30
+ <tr>
31
+ <th scope="row">Execution Time</th>
32
+ <td>{{ object.execution_time }}</td>
33
+ </tr>
34
+ <tr>
35
+ <th scope="row">Status</th>
36
+ <td>
37
+ {% if object.success %}
38
+ <span class="badge bg-success">Success</span>
39
+ {% else %}
40
+ <span class="badge bg-danger">Failed</span>
41
+ {% endif %}
42
+ </td>
43
+ </tr>
44
+ {% if object.execution_duration %}
45
+ <tr>
46
+ <th scope="row">Duration</th>
47
+ <td>{{ object.execution_duration|floatformat:3 }}s</td>
48
+ </tr>
49
+ {% endif %}
50
+ {% if object.parsing_success %}
51
+ <tr>
52
+ <th scope="row">Parsing Status</th>
53
+ <td>
54
+ <span class="badge bg-success">
55
+ <i class="mdi mdi-check-circle me-1"></i>
56
+ Successfully Parsed
57
+ </span>
58
+ {% if object.parsing_template %}
59
+ <br><small class="text-muted">Template: {{ object.parsing_template }}</small>
60
+ {% endif %}
61
+ </td>
62
+ </tr>
63
+ {% elif object.parsed_data is not None %}
64
+ <tr>
65
+ <th scope="row">Parsing Status</th>
66
+ <td>
67
+ <span class="badge bg-warning">
68
+ <i class="mdi mdi-alert-circle me-1"></i>
69
+ Parsing Attempted
70
+ </span>
71
+ </td>
72
+ </tr>
73
+ {% endif %}
74
+ {% if not object.success and object.error_message %}
75
+ <tr>
76
+ <th scope="row">Error</th>
77
+ <td><code>{{ object.error_message }}</code></td>
78
+ </tr>
79
+ {% endif %}
80
+ </table>
81
+ </div>
82
+ </div>
83
+ </div>
84
+ </div>
85
+ <div class="row">
86
+ <div class="col col-md-12">
87
+ <div class="card">
88
+ <div class="card-header">
89
+ <h3 class="card-title">Command Output</h3>
90
+ </div>
91
+ <div class="card-body">
92
+ <pre>{{ object.output }}</pre>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ {% if object.parsed_data %}
99
+ <div class="row mt-3">
100
+ <div class="col col-md-12">
101
+ <div class="card">
102
+ <div class="card-header">
103
+ <h3 class="card-title">
104
+ <i class="mdi mdi-table me-1"></i>
105
+ Parsed Data
106
+ </h3>
107
+ {% if object.parsing_template %}
108
+ <div class="card-subtitle">
109
+ <small class="text-muted">Template: {{ object.parsing_template }}</small>
110
+ </div>
111
+ {% endif %}
112
+ </div>
113
+ <div class="card-body">
114
+ {% if object.parsed_data|length > 0 %}
115
+ {% if object.parsed_data.0 %}
116
+ <!-- Table format for structured data -->
117
+ <div class="table-responsive">
118
+ <table class="table table-sm table-striped">
119
+ <thead>
120
+ <tr>
121
+ {% for key in object.parsed_data.0.keys %}
122
+ <th>{{ key|title }}</th>
123
+ {% endfor %}
124
+ </tr>
125
+ </thead>
126
+ <tbody>
127
+ {% for row in object.parsed_data %}
128
+ <tr>
129
+ {% for value in row.values %}
130
+ <td>{{ value }}</td>
131
+ {% endfor %}
132
+ </tr>
133
+ {% endfor %}
134
+ </tbody>
135
+ </table>
136
+ </div>
137
+ {% else %}
138
+ <!-- JSON format for other data types -->
139
+ <pre class="bg-light p-3 rounded">{{ object.parsed_data|pprint }}</pre>
140
+ {% endif %}
141
+ {% else %}
142
+ <div class="alert alert-info mb-0">
143
+ <i class="mdi mdi-information-outline me-1"></i>
144
+ No structured data found in the output.
145
+ </div>
146
+ {% endif %}
147
+
148
+ <!-- Copy parsed data button -->
149
+ {% if object.parsed_data|length > 0 %}
150
+ {{ object.parsed_data|json_script:"commandlog-parsed-data-json" }}
151
+ <div class="mt-3">
152
+ <div class="btn-list">
153
+ <button type="button" class="btn btn-sm btn-outline-primary copy-parsed-btn"
154
+ title="Copy parsed data as JSON">
155
+ <i class="mdi mdi-content-copy me-1"></i>Copy Parsed Data
156
+ </button>
157
+ </div>
158
+ </div>
159
+ {% endif %}
160
+ </div>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ {% endif %}
165
+ {% endblock %}
166
+
167
+ {% block javascript %}
168
+ <!-- Load NetBox Toolkit consolidated JavaScript -->
169
+ <script src="{% static 'netbox_toolkit/js/toolkit.js' %}"></script>
170
+ {% endblock %}
@@ -0,0 +1,4 @@
1
+ {% extends 'generic/object_list.html' %}
2
+ {% load helpers %}
3
+
4
+ {% block title %}Command Logs{% endblock %}