netbox-toolkit-plugin 0.1.0__py3-none-any.whl → 0.1.1__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 +32 -0
- {netbox_toolkit → netbox_toolkit_plugin}/api/serializers.py +71 -35
- {netbox_toolkit → netbox_toolkit_plugin}/api/urls.py +3 -3
- {netbox_toolkit → netbox_toolkit_plugin}/config.py +80 -73
- {netbox_toolkit → netbox_toolkit_plugin}/connectors/factory.py +170 -111
- {netbox_toolkit → netbox_toolkit_plugin}/connectors/netmiko_connector.py +242 -179
- {netbox_toolkit → netbox_toolkit_plugin}/connectors/scrapli_connector.py +256 -172
- netbox_toolkit_plugin/migrations/0001_initial.py +108 -0
- netbox_toolkit_plugin/migrations/0002_alter_command_options_alter_command_unique_together_and_more.py +70 -0
- {netbox_toolkit → netbox_toolkit_plugin}/migrations/0003_permission_system_update.py +26 -12
- {netbox_toolkit → netbox_toolkit_plugin}/migrations/0004_remove_django_permissions.py +27 -29
- {netbox_toolkit → netbox_toolkit_plugin}/migrations/0005_alter_command_options_and_more.py +7 -8
- {netbox_toolkit → netbox_toolkit_plugin}/migrations/0006_commandlog_parsed_data_commandlog_parsing_success_and_more.py +7 -8
- {netbox_toolkit → netbox_toolkit_plugin}/migrations/0007_alter_commandlog_parsing_template.py +6 -4
- {netbox_toolkit → netbox_toolkit_plugin}/models.py +31 -32
- {netbox_toolkit → netbox_toolkit_plugin}/navigation.py +6 -6
- {netbox_toolkit → netbox_toolkit_plugin}/services/command_service.py +188 -128
- {netbox_toolkit → netbox_toolkit_plugin}/services/rate_limiting_service.py +104 -97
- netbox_toolkit_plugin/tables.py +51 -0
- netbox_toolkit_plugin/templates/netbox_toolkit/command.html +108 -0
- netbox_toolkit_plugin/templates/netbox_toolkit/command_list.html +12 -0
- netbox_toolkit_plugin/templates/netbox_toolkit/commandlog.html +170 -0
- netbox_toolkit_plugin/templates/netbox_toolkit/device_toolkit.html +557 -0
- {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/command.html +5 -5
- {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/command_list.html +2 -2
- {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/commandlog.html +2 -2
- {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/device_toolkit.html +6 -6
- netbox_toolkit_plugin/urls.py +38 -0
- {netbox_toolkit → netbox_toolkit_plugin}/utils/logging.py +20 -19
- {netbox_toolkit → netbox_toolkit_plugin}/views.py +251 -169
- {netbox_toolkit_plugin-0.1.0.dist-info → netbox_toolkit_plugin-0.1.1.dist-info}/METADATA +2 -2
- netbox_toolkit_plugin-0.1.1.dist-info/RECORD +60 -0
- netbox_toolkit_plugin-0.1.1.dist-info/entry_points.txt +2 -0
- netbox_toolkit_plugin-0.1.1.dist-info/top_level.txt +1 -0
- netbox_toolkit/__init__.py +0 -30
- netbox_toolkit/migrations/0001_initial.py +0 -54
- netbox_toolkit/migrations/0002_alter_command_options_alter_command_unique_together_and_more.py +0 -66
- netbox_toolkit/tables.py +0 -37
- netbox_toolkit/urls.py +0 -22
- netbox_toolkit_plugin-0.1.0.dist-info/RECORD +0 -56
- netbox_toolkit_plugin-0.1.0.dist-info/entry_points.txt +0 -2
- netbox_toolkit_plugin-0.1.0.dist-info/top_level.txt +0 -1
- {netbox_toolkit → netbox_toolkit_plugin}/admin.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/api/__init__.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/api/mixins.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/api/schemas.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/api/views/__init__.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/api/views/command_logs.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/api/views/commands.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/connectors/__init__.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/connectors/base.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/exceptions.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/filtersets.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/forms.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/migrations/__init__.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/search.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/services/__init__.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/services/device_service.py +0 -0
- {netbox_toolkit/static/netbox_toolkit → netbox_toolkit_plugin/static/netbox_toolkit_plugin}/css/toolkit.css +0 -0
- {netbox_toolkit/static/netbox_toolkit → netbox_toolkit_plugin/static/netbox_toolkit_plugin}/js/toolkit.js +0 -0
- {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/command_edit.html +0 -0
- {netbox_toolkit/templates/netbox_toolkit → netbox_toolkit_plugin/templates/netbox_toolkit_plugin}/commandlog_list.html +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/utils/__init__.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/utils/connection.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/utils/error_parser.py +0 -0
- {netbox_toolkit → netbox_toolkit_plugin}/utils/network.py +0 -0
- {netbox_toolkit_plugin-0.1.0.dist-info → netbox_toolkit_plugin-0.1.1.dist-info}/WHEEL +0 -0
- {netbox_toolkit_plugin-0.1.0.dist-info → netbox_toolkit_plugin-0.1.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,108 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2025-05-23 14:41
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
import taggit.managers
|
5
|
+
import utilities.json
|
6
|
+
from django.db import migrations, models
|
7
|
+
|
8
|
+
|
9
|
+
class Migration(migrations.Migration):
|
10
|
+
initial = True
|
11
|
+
|
12
|
+
dependencies = [
|
13
|
+
("dcim", "0200_populate_mac_addresses"),
|
14
|
+
("extras", "0122_charfield_null_choices"),
|
15
|
+
]
|
16
|
+
|
17
|
+
operations = [
|
18
|
+
migrations.CreateModel(
|
19
|
+
name="Command",
|
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
|
+
("name", models.CharField(max_length=100)),
|
38
|
+
("command", models.TextField()),
|
39
|
+
("description", models.TextField(blank=True)),
|
40
|
+
(
|
41
|
+
"device_type",
|
42
|
+
models.ForeignKey(
|
43
|
+
on_delete=django.db.models.deletion.CASCADE,
|
44
|
+
related_name="toolkit_commands",
|
45
|
+
to="dcim.devicetype",
|
46
|
+
),
|
47
|
+
),
|
48
|
+
(
|
49
|
+
"tags",
|
50
|
+
taggit.managers.TaggableManager(
|
51
|
+
through="extras.TaggedItem", to="extras.Tag"
|
52
|
+
),
|
53
|
+
),
|
54
|
+
],
|
55
|
+
options={
|
56
|
+
"abstract": False,
|
57
|
+
},
|
58
|
+
),
|
59
|
+
migrations.CreateModel(
|
60
|
+
name="CommandLog",
|
61
|
+
fields=[
|
62
|
+
(
|
63
|
+
"id",
|
64
|
+
models.BigAutoField(
|
65
|
+
auto_created=True, primary_key=True, serialize=False
|
66
|
+
),
|
67
|
+
),
|
68
|
+
("created", models.DateTimeField(auto_now_add=True, null=True)),
|
69
|
+
("last_updated", models.DateTimeField(auto_now=True, null=True)),
|
70
|
+
(
|
71
|
+
"custom_field_data",
|
72
|
+
models.JSONField(
|
73
|
+
blank=True,
|
74
|
+
default=dict,
|
75
|
+
encoder=utilities.json.CustomFieldJSONEncoder,
|
76
|
+
),
|
77
|
+
),
|
78
|
+
("output", models.TextField()),
|
79
|
+
("username", models.CharField(max_length=100)),
|
80
|
+
("execution_time", models.DateTimeField(auto_now_add=True)),
|
81
|
+
(
|
82
|
+
"command",
|
83
|
+
models.ForeignKey(
|
84
|
+
on_delete=django.db.models.deletion.CASCADE,
|
85
|
+
related_name="logs",
|
86
|
+
to="netbox_toolkit_plugin.command",
|
87
|
+
),
|
88
|
+
),
|
89
|
+
(
|
90
|
+
"device",
|
91
|
+
models.ForeignKey(
|
92
|
+
on_delete=django.db.models.deletion.CASCADE,
|
93
|
+
related_name="command_logs",
|
94
|
+
to="dcim.device",
|
95
|
+
),
|
96
|
+
),
|
97
|
+
(
|
98
|
+
"tags",
|
99
|
+
taggit.managers.TaggableManager(
|
100
|
+
through="extras.TaggedItem", to="extras.Tag"
|
101
|
+
),
|
102
|
+
),
|
103
|
+
],
|
104
|
+
options={
|
105
|
+
"abstract": False,
|
106
|
+
},
|
107
|
+
),
|
108
|
+
]
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Generated by Django 5.1.4 on 2025-05-26 12:11
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
|
7
|
+
class Migration(migrations.Migration):
|
8
|
+
dependencies = [
|
9
|
+
("dcim", "0200_populate_mac_addresses"),
|
10
|
+
("netbox_toolkit_plugin", "0001_initial"),
|
11
|
+
]
|
12
|
+
|
13
|
+
operations = [
|
14
|
+
# First remove the old field
|
15
|
+
migrations.RemoveField(
|
16
|
+
model_name="command",
|
17
|
+
name="device_type",
|
18
|
+
),
|
19
|
+
# Add all new fields
|
20
|
+
migrations.AddField(
|
21
|
+
model_name="command",
|
22
|
+
name="platform",
|
23
|
+
field=models.ForeignKey(
|
24
|
+
default=1,
|
25
|
+
on_delete=django.db.models.deletion.CASCADE,
|
26
|
+
related_name="toolkit_commands",
|
27
|
+
to="dcim.platform",
|
28
|
+
),
|
29
|
+
preserve_default=False,
|
30
|
+
),
|
31
|
+
migrations.AddField(
|
32
|
+
model_name="command",
|
33
|
+
name="command_type",
|
34
|
+
field=models.CharField(default="show", max_length=50),
|
35
|
+
),
|
36
|
+
migrations.AddField(
|
37
|
+
model_name="command",
|
38
|
+
name="requires_config_mode",
|
39
|
+
field=models.BooleanField(default=False),
|
40
|
+
),
|
41
|
+
migrations.AddField(
|
42
|
+
model_name="command",
|
43
|
+
name="requires_enable",
|
44
|
+
field=models.BooleanField(default=False),
|
45
|
+
),
|
46
|
+
migrations.AddField(
|
47
|
+
model_name="commandlog",
|
48
|
+
name="error_message",
|
49
|
+
field=models.TextField(blank=True),
|
50
|
+
),
|
51
|
+
migrations.AddField(
|
52
|
+
model_name="commandlog",
|
53
|
+
name="execution_duration",
|
54
|
+
field=models.FloatField(blank=True, null=True),
|
55
|
+
),
|
56
|
+
migrations.AddField(
|
57
|
+
model_name="commandlog",
|
58
|
+
name="success",
|
59
|
+
field=models.BooleanField(default=True),
|
60
|
+
),
|
61
|
+
# Then alter model options after fields exist
|
62
|
+
migrations.AlterModelOptions(
|
63
|
+
name="command",
|
64
|
+
options={"ordering": ["platform", "name"]},
|
65
|
+
),
|
66
|
+
migrations.AlterUniqueTogether(
|
67
|
+
name="command",
|
68
|
+
unique_together={("platform", "name")},
|
69
|
+
),
|
70
|
+
]
|
@@ -7,16 +7,22 @@ def migrate_command_types(apps, schema_editor):
|
|
7
7
|
"""
|
8
8
|
Migrate existing diagnostic and troubleshooting commands to 'show' type
|
9
9
|
"""
|
10
|
-
Command = apps.get_model(
|
11
|
-
|
10
|
+
Command = apps.get_model("netbox_toolkit_plugin", "Command")
|
11
|
+
|
12
12
|
# Update diagnostic commands to show
|
13
|
-
diagnostic_count = Command.objects.filter(command_type=
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
diagnostic_count = Command.objects.filter(command_type="diagnostic").update(
|
14
|
+
command_type="show"
|
15
|
+
)
|
16
|
+
|
17
|
+
# Update troubleshooting commands to show
|
18
|
+
troubleshooting_count = Command.objects.filter(
|
19
|
+
command_type="troubleshooting"
|
20
|
+
).update(command_type="show")
|
21
|
+
|
18
22
|
print(f"Migration: Updated {diagnostic_count} diagnostic commands to 'show' type")
|
19
|
-
print(
|
23
|
+
print(
|
24
|
+
f"Migration: Updated {troubleshooting_count} troubleshooting commands to 'show' type"
|
25
|
+
)
|
20
26
|
|
21
27
|
|
22
28
|
def reverse_migrate_command_types(apps, schema_editor):
|
@@ -31,15 +37,23 @@ def reverse_migrate_command_types(apps, schema_editor):
|
|
31
37
|
|
32
38
|
|
33
39
|
class Migration(migrations.Migration):
|
34
|
-
|
35
40
|
dependencies = [
|
36
|
-
(
|
41
|
+
(
|
42
|
+
"netbox_toolkit_plugin",
|
43
|
+
"0002_alter_command_options_alter_command_unique_together_and_more",
|
44
|
+
),
|
37
45
|
]
|
38
46
|
|
39
47
|
operations = [
|
40
48
|
migrations.AlterModelOptions(
|
41
|
-
name=
|
42
|
-
options={
|
49
|
+
name="command",
|
50
|
+
options={
|
51
|
+
"ordering": ["platform", "name"],
|
52
|
+
"permissions": [
|
53
|
+
("execute_show_command", "Can execute show commands"),
|
54
|
+
("execute_config_command", "Can execute configuration commands"),
|
55
|
+
],
|
56
|
+
},
|
43
57
|
),
|
44
58
|
migrations.RunPython(
|
45
59
|
migrate_command_types,
|
@@ -5,68 +5,66 @@ from django.db import migrations
|
|
5
5
|
|
6
6
|
def remove_django_permissions(apps, schema_editor):
|
7
7
|
"""Remove old Django permissions that are no longer needed"""
|
8
|
-
Permission = apps.get_model(
|
9
|
-
ContentType = apps.get_model(
|
10
|
-
|
8
|
+
Permission = apps.get_model("auth", "Permission")
|
9
|
+
ContentType = apps.get_model("contenttypes", "ContentType")
|
10
|
+
|
11
11
|
try:
|
12
12
|
# Get the Command content type
|
13
|
-
command_ct = ContentType.objects.get(
|
14
|
-
|
13
|
+
command_ct = ContentType.objects.get(
|
14
|
+
app_label="netbox_toolkit_plugin", model="command"
|
15
|
+
)
|
16
|
+
|
15
17
|
# Remove the custom Django permissions
|
16
|
-
custom_permissions = [
|
17
|
-
|
18
|
-
'execute_config_command'
|
19
|
-
]
|
20
|
-
|
18
|
+
custom_permissions = ["execute_show_command", "execute_config_command"]
|
19
|
+
|
21
20
|
deleted_count = 0
|
22
21
|
for codename in custom_permissions:
|
23
22
|
count, _ = Permission.objects.filter(
|
24
|
-
content_type=command_ct,
|
25
|
-
codename=codename
|
23
|
+
content_type=command_ct, codename=codename
|
26
24
|
).delete()
|
27
25
|
deleted_count += count
|
28
|
-
|
26
|
+
|
29
27
|
print(f"Removed {deleted_count} old Django permissions")
|
30
|
-
|
28
|
+
|
31
29
|
except ContentType.DoesNotExist:
|
32
30
|
# Command model doesn't exist yet, skip
|
33
31
|
print("Command model not found, skipping permission removal")
|
34
32
|
except Exception as e:
|
35
33
|
print(f"Warning: Could not remove old permissions: {e}")
|
36
34
|
|
35
|
+
|
37
36
|
def restore_django_permissions(apps, schema_editor):
|
38
37
|
"""Restore Django permissions if migration is reversed"""
|
39
|
-
Permission = apps.get_model(
|
40
|
-
ContentType = apps.get_model(
|
41
|
-
|
38
|
+
Permission = apps.get_model("auth", "Permission")
|
39
|
+
ContentType = apps.get_model("contenttypes", "ContentType")
|
40
|
+
|
42
41
|
try:
|
43
42
|
# Get the Command content type
|
44
|
-
command_ct = ContentType.objects.get(
|
45
|
-
|
43
|
+
command_ct = ContentType.objects.get(
|
44
|
+
app_label="netbox_toolkit_plugin", model="command"
|
45
|
+
)
|
46
|
+
|
46
47
|
# Recreate the custom Django permissions
|
47
48
|
permissions_to_create = [
|
48
|
-
(
|
49
|
-
(
|
49
|
+
("execute_show_command", "Can execute show commands"),
|
50
|
+
("execute_config_command", "Can execute configuration commands"),
|
50
51
|
]
|
51
|
-
|
52
|
+
|
52
53
|
for codename, name in permissions_to_create:
|
53
54
|
Permission.objects.get_or_create(
|
54
|
-
content_type=command_ct,
|
55
|
-
codename=codename,
|
56
|
-
defaults={'name': name}
|
55
|
+
content_type=command_ct, codename=codename, defaults={"name": name}
|
57
56
|
)
|
58
|
-
|
57
|
+
|
59
58
|
print("Restored old Django permissions")
|
60
|
-
|
59
|
+
|
61
60
|
except ContentType.DoesNotExist:
|
62
61
|
# Command model doesn't exist, skip
|
63
62
|
print("Command model not found, skipping permission restoration")
|
64
63
|
|
65
64
|
|
66
65
|
class Migration(migrations.Migration):
|
67
|
-
|
68
66
|
dependencies = [
|
69
|
-
(
|
67
|
+
("netbox_toolkit_plugin", "0003_permission_system_update"),
|
70
68
|
]
|
71
69
|
|
72
70
|
operations = [
|
@@ -4,22 +4,21 @@ from django.db import migrations
|
|
4
4
|
|
5
5
|
|
6
6
|
class Migration(migrations.Migration):
|
7
|
-
|
8
7
|
dependencies = [
|
9
|
-
(
|
8
|
+
("netbox_toolkit_plugin", "0004_remove_django_permissions"),
|
10
9
|
]
|
11
10
|
|
12
11
|
operations = [
|
13
12
|
migrations.AlterModelOptions(
|
14
|
-
name=
|
15
|
-
options={
|
13
|
+
name="command",
|
14
|
+
options={"ordering": ["platform", "name"]},
|
16
15
|
),
|
17
16
|
migrations.RemoveField(
|
18
|
-
model_name=
|
19
|
-
name=
|
17
|
+
model_name="command",
|
18
|
+
name="requires_config_mode",
|
20
19
|
),
|
21
20
|
migrations.RemoveField(
|
22
|
-
model_name=
|
23
|
-
name=
|
21
|
+
model_name="command",
|
22
|
+
name="requires_enable",
|
24
23
|
),
|
25
24
|
]
|
@@ -4,25 +4,24 @@ from django.db import migrations, models
|
|
4
4
|
|
5
5
|
|
6
6
|
class Migration(migrations.Migration):
|
7
|
-
|
8
7
|
dependencies = [
|
9
|
-
(
|
8
|
+
("netbox_toolkit_plugin", "0005_alter_command_options_and_more"),
|
10
9
|
]
|
11
10
|
|
12
11
|
operations = [
|
13
12
|
migrations.AddField(
|
14
|
-
model_name=
|
15
|
-
name=
|
13
|
+
model_name="commandlog",
|
14
|
+
name="parsed_data",
|
16
15
|
field=models.JSONField(blank=True, null=True),
|
17
16
|
),
|
18
17
|
migrations.AddField(
|
19
|
-
model_name=
|
20
|
-
name=
|
18
|
+
model_name="commandlog",
|
19
|
+
name="parsing_success",
|
21
20
|
field=models.BooleanField(default=False),
|
22
21
|
),
|
23
22
|
migrations.AddField(
|
24
|
-
model_name=
|
25
|
-
name=
|
23
|
+
model_name="commandlog",
|
24
|
+
name="parsing_template",
|
26
25
|
field=models.CharField(blank=True, max_length=255),
|
27
26
|
),
|
28
27
|
]
|
{netbox_toolkit → netbox_toolkit_plugin}/migrations/0007_alter_commandlog_parsing_template.py
RENAMED
@@ -4,15 +4,17 @@ from django.db import migrations, models
|
|
4
4
|
|
5
5
|
|
6
6
|
class Migration(migrations.Migration):
|
7
|
-
|
8
7
|
dependencies = [
|
9
|
-
(
|
8
|
+
(
|
9
|
+
"netbox_toolkit_plugin",
|
10
|
+
"0006_commandlog_parsed_data_commandlog_parsing_success_and_more",
|
11
|
+
),
|
10
12
|
]
|
11
13
|
|
12
14
|
operations = [
|
13
15
|
migrations.AlterField(
|
14
|
-
model_name=
|
15
|
-
name=
|
16
|
+
model_name="commandlog",
|
17
|
+
name="parsing_template",
|
16
18
|
field=models.CharField(blank=True, max_length=255, null=True),
|
17
19
|
),
|
18
20
|
]
|
@@ -3,87 +3,86 @@ from django.core.exceptions import ValidationError
|
|
3
3
|
from netbox.models import NetBoxModel
|
4
4
|
from dcim.models import Device
|
5
5
|
|
6
|
+
|
6
7
|
class Command(NetBoxModel):
|
7
8
|
name = models.CharField(max_length=100)
|
8
9
|
command = models.TextField()
|
9
10
|
description = models.TextField(blank=True)
|
10
|
-
|
11
|
+
|
11
12
|
# Platform-based association (required)
|
12
13
|
platform = models.ForeignKey(
|
13
|
-
to=
|
14
|
+
to="dcim.Platform",
|
14
15
|
on_delete=models.CASCADE,
|
15
|
-
related_name=
|
16
|
-
help_text="Platform this command is designed for (e.g., cisco_ios, cisco_nxos, generic)"
|
16
|
+
related_name="toolkit_commands",
|
17
|
+
help_text="Platform this command is designed for (e.g., cisco_ios, cisco_nxos, generic)",
|
17
18
|
)
|
18
|
-
|
19
|
+
|
19
20
|
# Command categorization
|
20
21
|
command_type = models.CharField(
|
21
22
|
max_length=50,
|
22
23
|
choices=[
|
23
|
-
(
|
24
|
-
(
|
24
|
+
("show", "Show Command"),
|
25
|
+
("config", "Configuration Command"),
|
25
26
|
],
|
26
|
-
default=
|
27
|
-
help_text="Type of command for categorization and permission control"
|
27
|
+
default="show",
|
28
|
+
help_text="Type of command for categorization and permission control",
|
28
29
|
)
|
29
30
|
|
30
31
|
class Meta:
|
31
|
-
ordering = [
|
32
|
-
unique_together = [[
|
32
|
+
ordering = ["platform", "name"]
|
33
|
+
unique_together = [["platform", "name"]]
|
33
34
|
|
34
35
|
def __str__(self):
|
35
36
|
return f"{self.name} ({self.platform})"
|
36
|
-
|
37
|
+
|
37
38
|
def get_absolute_url(self):
|
38
39
|
"""Return the URL for this object"""
|
39
40
|
from django.urls import reverse
|
40
|
-
|
41
|
+
|
42
|
+
return reverse(
|
43
|
+
"plugins:netbox_toolkit_plugin:command_detail", kwargs={"pk": self.pk}
|
44
|
+
)
|
45
|
+
|
41
46
|
|
42
47
|
class CommandLog(NetBoxModel):
|
43
48
|
command = models.ForeignKey(
|
44
|
-
to=Command,
|
45
|
-
on_delete=models.CASCADE,
|
46
|
-
related_name='logs'
|
49
|
+
to=Command, on_delete=models.CASCADE, related_name="logs"
|
47
50
|
)
|
48
51
|
device = models.ForeignKey(
|
49
|
-
to=
|
50
|
-
on_delete=models.CASCADE,
|
51
|
-
related_name='command_logs'
|
52
|
+
to="dcim.Device", on_delete=models.CASCADE, related_name="command_logs"
|
52
53
|
)
|
53
54
|
output = models.TextField()
|
54
55
|
username = models.CharField(max_length=100)
|
55
56
|
execution_time = models.DateTimeField(auto_now_add=True)
|
56
|
-
|
57
|
+
|
57
58
|
# Execution details added in migration
|
58
59
|
success = models.BooleanField(default=True)
|
59
60
|
error_message = models.TextField(blank=True)
|
60
61
|
execution_duration = models.FloatField(
|
61
|
-
blank=True,
|
62
|
-
null=True,
|
63
|
-
help_text="Command execution time in seconds"
|
62
|
+
blank=True, null=True, help_text="Command execution time in seconds"
|
64
63
|
)
|
65
|
-
|
64
|
+
|
66
65
|
# Parsing details for TextFSM
|
67
66
|
parsed_data = models.JSONField(
|
68
|
-
blank=True,
|
69
|
-
null=True,
|
70
|
-
help_text="Parsed structured data from command output"
|
67
|
+
blank=True, null=True, help_text="Parsed structured data from command output"
|
71
68
|
)
|
72
69
|
parsing_success = models.BooleanField(
|
73
|
-
default=False,
|
74
|
-
help_text="Whether the output was successfully parsed"
|
70
|
+
default=False, help_text="Whether the output was successfully parsed"
|
75
71
|
)
|
76
72
|
parsing_template = models.CharField(
|
77
73
|
max_length=255,
|
78
74
|
blank=True,
|
79
75
|
null=True,
|
80
|
-
help_text="Name of the TextFSM template used for parsing"
|
76
|
+
help_text="Name of the TextFSM template used for parsing",
|
81
77
|
)
|
82
78
|
|
83
79
|
def __str__(self):
|
84
80
|
return f"{self.command} on {self.device}"
|
85
|
-
|
81
|
+
|
86
82
|
def get_absolute_url(self):
|
87
83
|
"""Return the URL for this object"""
|
88
84
|
from django.urls import reverse
|
89
|
-
|
85
|
+
|
86
|
+
return reverse(
|
87
|
+
"plugins:netbox_toolkit_plugin:commandlog_view", kwargs={"pk": self.pk}
|
88
|
+
)
|
@@ -9,22 +9,22 @@ menu = PluginMenu(
|
|
9
9
|
"Commands",
|
10
10
|
(
|
11
11
|
PluginMenuItem(
|
12
|
-
link="plugins:
|
12
|
+
link="plugins:netbox_toolkit_plugin:command_list",
|
13
13
|
link_text="Commands",
|
14
14
|
buttons=(
|
15
15
|
PluginMenuButton(
|
16
|
-
"plugins:
|
16
|
+
"plugins:netbox_toolkit_plugin:command_add",
|
17
17
|
"Add",
|
18
18
|
"mdi mdi-plus-thick",
|
19
|
-
ButtonColorChoices.GRAY
|
19
|
+
ButtonColorChoices.GRAY,
|
20
20
|
),
|
21
|
-
)
|
21
|
+
),
|
22
22
|
),
|
23
23
|
PluginMenuItem(
|
24
|
-
link="plugins:
|
24
|
+
link="plugins:netbox_toolkit_plugin:commandlog_list",
|
25
25
|
link_text="Command Logs",
|
26
26
|
),
|
27
27
|
),
|
28
28
|
),
|
29
29
|
),
|
30
|
-
)
|
30
|
+
)
|