From 1a2658990c50c8cd9a54d4eac72e84ff8a1df758 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 5 Dec 2024 16:50:24 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=A5=20Remove=20provider=20creation?= =?UTF-8?q?=20and=20provider=20type=20creation=20from=20user?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 71 ++----------------- .../netbox_sys_plugin/create_vm.html | 46 ++---------- 2 files changed, 13 insertions(+), 104 deletions(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index 6f96ce9..6b71a49 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -165,10 +165,6 @@ class CreateVmForm(NetBoxModelForm): self.fields.pop('tags', None) # Initialize formsets - # Cluster + Cluster type - self.cluster_formsets = [] - empty_cluster_formset = ClusterFormSet(data=data, prefix='clusters') - self.cluster_formsets.append(('new', empty_cluster_formset)) # Virtual Machine self.virtual_machine_formsets = [] empty_vm_formset = VirtualMachineFormSet(data=data, prefix='vms_new') @@ -206,19 +202,6 @@ class CreateVmForm(NetBoxModelForm): empty_tagformset = TagFormSet(data=data, prefix='tag_new') self.tagformsets.append(('new', empty_tagformset)) - @staticmethod - def check_cluster_exist(data): - """Validate whether a cluster already exists based on the input.""" - new_clustertype = data.get('name', '').strip() - new_cluster = data.get('clusters-0-name', '').strip() - existing_cluster_type = data.get('cl_list_new-cluster_type', '').strip() - existing_cluster = data.get('cl_list_new-cluster', '').strip() - - if new_clustertype and new_cluster and existing_cluster_type and existing_cluster: - raise ValueError("Cannot create a provider and choose an existing one at the same time.") - - return bool(existing_cluster_type and existing_cluster) - @staticmethod def parse_ports(ports_field): """Parse the port numbers.""" @@ -254,43 +237,7 @@ class CreateVmForm(NetBoxModelForm): ) @staticmethod - def create_cluster_type(data): - """Create and save a ClusterType object.""" - cluster_type = ClusterType( - name=data.get('name', ''), - slug=data.get('slug', ''), - description=data.get('description', ''), - tags = CreateVmForm.get_parse_tags(data) - ) - cluster_type.full_clean() - cluster_type.save() - CreateVmForm.assign_tags(cluster_type,data) - return cluster_type - - @staticmethod - def create_cluster(data, cluster_type): - """Create and save a Cluster object.""" - site_id = data.get('clusters-0-site', '') - try: - site = Site.objects.get(pk=site_id) - except Site.DoesNotExist: - raise ValueError(f"Invalid Site ID: {site_id}") - - cluster = Cluster( - name=data.get('clusters-0-name', ''), - type=cluster_type, - status=data.get('clusters-0-status', ''), - site=site, - description=data.get('clusters-0-description', ''), - tags = CreateVmForm.get_parse_tags(data) - ) - cluster.full_clean() - cluster.save() - CreateVmForm.assign_tags(cluster,data) - return cluster - - @staticmethod - def create_virtual_machine(data, cluster, cluster_existence): + def create_virtual_machine(data, cluster): """Create and save a VirtualMachine object.""" role_id = data.get('vms_new-0-role', '') try: @@ -380,22 +327,16 @@ class CreateVmForm(NetBoxModelForm): return ip_address - def create_all_ip_adresses(self, data, vm_interface,): - self.create_ip_address(data,vm_interface,'ip_new','IP Address') - self.create_ip_address(data,vm_interface,'gateway_new','Gateway') + def create_all_ip_adresses(self, data, vm_interface): + self.create_ip_address(data,vm_interface,'ip_new','Network IP Address') + self.create_ip_address(data,vm_interface,'gateway_new','Network Gateway') def process_creation(self, data): """Object creation""" try: with transaction.atomic(): - cluster_exists = self.check_cluster_exist(data) - if not cluster_exists: - cluster_type = self.create_cluster_type(data) - cluster = self.create_cluster(data, cluster_type) - else: - cluster = Cluster.objects.get(pk=data.get('cl_list_new-cluster', '')) - - vm = self.create_virtual_machine(data, cluster, cluster_exists) + cluster = Cluster.objects.get(pk=data.get('cl_list_new-cluster', '')) + vm = self.create_virtual_machine(data, cluster) vmi = self.create_vm_interface(data, vm) self.create_all_services(data, vm) self.create_all_ip_adresses(data, vmi) diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html b/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html index d1d14b2..3e562fd 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html @@ -37,46 +37,14 @@ SYS - Virtual Machine <form method="post" enctype="multipart/form-data" class="form-object-edit mt-5"> {% csrf_token %} <div class="field-group my-5"> - <div class="row mb-2"> - <ul class="nav nav-pills" role="tablist"> - <li role="presentation" class="nav-item"> - <button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link active"> - New Provider - </button> - </li> - <li role="presentation" class="nav-item"> - <button role="tab" type="button" id="vm_tab" data-bs-toggle="tab" aria-controls="vm" data-bs-target="#vm" class="nav-link"> - Existing Provider - </button> - </li> - </ul> - </div> - <div class="tab-content p-0 border-0"> - <div class="tab-pane active" id="device" role="tabpanel" aria-labeled-by="device_tab"> - <h5>Provider Type</h5> - <div class="form-group" class="field-group mb-5"> - {{ form.as_p }} - </div> - <h5>Provider</h5> - {% for cluster_formset in form.cluster_formsets %} - {% for vl_form in cluster_formset %} - <div class="form-group" class="field-group mb-5"> - {{ vl_form.as_p }} - </div> - {% endfor %} - {% endfor %} - </div> - <div class="tab-pane" id="vm" role="tabpanel" aria-labeled-by="vm_tab"> - <h5>Provider</h5> - {% for cl_list_formset in form.cl_list_formsets %} - {% for ct_form in cl_list_formset %} - <div class="form-group" class="field-group mb-5"> - {{ ct_form.as_p }} - </div> - {% endfor %} - {% endfor %} - </div> + <h5>Provider</h5> + {% for cl_list_formset in form.cl_list_formsets %} + {% for ct_form in cl_list_formset %} + <div class="form-group" class="field-group mb-5"> + {{ ct_form.as_p }} </div> + {% endfor %} + {% endfor %} </div> <div class="field-group my-5"> <h5>Virtual Machine</h5> -- GitLab From d2bd08a06740935b34124ca07f1e54a1245eac9b Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Fri, 6 Dec 2024 17:57:24 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=E2=9C=A8=20Add=20extention=20for=20virtual?= =?UTF-8?q?=20machine=20to=20include=20a=20list=20of=20domain=20names?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/model/netbox_sys_domain_names.md | 11 +++ .../netbox_sys_virtual_machine_maintenance.md | 2 +- netbox_sys_plugin/api/serializers.py | 17 ++++- netbox_sys_plugin/api/urls.py | 1 + netbox_sys_plugin/api/views.py | 6 +- netbox_sys_plugin/forms/machine.py | 74 ++++++++++++++++++- .../migrations/0006_domainnames.py | 37 ++++++++++ ..._alter_domainnames_assigned_object_type.py | 20 +++++ netbox_sys_plugin/models/machine.py | 43 +++++++++++ netbox_sys_plugin/navigation.py | 17 +++++ netbox_sys_plugin/tables.py | 31 ++++++++ netbox_sys_plugin/template_content.py | 11 ++- .../netbox_sys_plugin/domainnames.html | 46 ++++++++++++ .../netbox_sys_plugin/vm_domainnames.html | 33 +++++++++ netbox_sys_plugin/urls.py | 11 ++- netbox_sys_plugin/views.py | 31 +++++++- 16 files changed, 378 insertions(+), 13 deletions(-) create mode 100644 docs/model/netbox_sys_domain_names.md create mode 100644 netbox_sys_plugin/migrations/0006_domainnames.py create mode 100644 netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py create mode 100644 netbox_sys_plugin/templates/netbox_sys_plugin/domainnames.html create mode 100644 netbox_sys_plugin/templates/netbox_sys_plugin/vm_domainnames.html diff --git a/docs/model/netbox_sys_domain_names.md b/docs/model/netbox_sys_domain_names.md new file mode 100644 index 0000000..9bef37a --- /dev/null +++ b/docs/model/netbox_sys_domain_names.md @@ -0,0 +1,11 @@ +## netbox_sys_domain_names + +**Virtual Machine domain names definition class** + +| FIELD | TYPE | DESCRIPTION | +|----------------------------------------------------|----------------------------------|---------------------------------------------------------------------------| +| id | Big (8 byte) integer | Unique ID | +| assigned_object_type_id | Big (8 byte) integer | virtual machine Type ID | +| assigned_object_id | Big (8 byte) integer | virtual machine unique ID | +| domain_names | Json | Information about all the domains for a Virtual Machine in a Json format| + diff --git a/docs/model/netbox_sys_virtual_machine_maintenance.md b/docs/model/netbox_sys_virtual_machine_maintenance.md index c8b181d..4c5fb9d 100644 --- a/docs/model/netbox_sys_virtual_machine_maintenance.md +++ b/docs/model/netbox_sys_virtual_machine_maintenance.md @@ -5,7 +5,7 @@ | FIELD | TYPE | DESCRIPTION | |----------------------------------------------------|----------------------------------|---------------------------------------------------------------------------| | id | Big (8 byte) integer | Unique ID | -| assigned_object_type_id | Big (8 byte) integer | virtual machine type ID | +| assigned_object_type_id | Big (8 byte) integer | virtual machine Type ID | | assigned_object_id | Big (8 byte) integer | virtual machine unique ID | | virtual_machine_maintenance_window | String | A string representing a day of the week and a time of the day, 0 = Sunday , 1 = monday | diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index bc249e4..afba76e 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -8,7 +8,7 @@ from dcim.api.nested_serializers import ( from ipam.api.nested_serializers import ( NestedIPAddressSerializer, NestedServiceSerializer ) -from .. models import VirtualMachineMaintenance, ProviderCredentials,VmAssignedVirtualMachineType, VirtualMachineType +from .. models import VirtualMachineMaintenance, ProviderCredentials,VmAssignedVirtualMachineType, VirtualMachineType,DomainNames from django.contrib.contenttypes.models import ContentType from .nested_serializers import * from virtualization.choices import * @@ -34,13 +34,11 @@ class ClusterSerializer(serializers.ModelSerializer): ) return NestedProviderCredentialsSerializer(provider_credentials, many=True).data - class ClusterTypeSerializer(serializers.ModelSerializer): class Meta: model = ClusterType fields = ['id', 'name'] - #Plugin Data Serializer class VirtualMachineMaintenanceSerializer(serializers.ModelSerializer): id = serializers.IntegerField(read_only=True) @@ -63,6 +61,7 @@ class ProviderCredentialsSerializer(serializers.ModelSerializer): model = ProviderCredentials #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' + class VirtualMachineTypeSerializer(serializers.ModelSerializer): id = serializers.IntegerField(read_only=True) cluster_type = ClusterTypeSerializer(source='assigned_object', read_only=True) @@ -74,7 +73,6 @@ class VirtualMachineTypeSerializer(serializers.ModelSerializer): #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' - class VmAssignedVirtualMachineTypeSerializer(serializers.ModelSerializer): id = serializers.IntegerField(read_only=True) virtual_machine = VirtualMachineSerializer(source='assigned_object', read_only=True) @@ -87,6 +85,17 @@ class VmAssignedVirtualMachineTypeSerializer(serializers.ModelSerializer): #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' +class DomainNamesSerializer(serializers.ModelSerializer): + id = serializers.IntegerField(read_only=True) + virtual_machine = VirtualMachineSerializer(source='assigned_object', read_only=True) + assigned_object_id = serializers.IntegerField(write_only=True) + assigned_object_type = serializers.CharField(write_only=True) + + class Meta: + model = DomainNames + #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] + fields = '__all__' + class VirtualMachineSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail') status = ChoiceField(choices=VirtualMachineStatusChoices, required=False) diff --git a/netbox_sys_plugin/api/urls.py b/netbox_sys_plugin/api/urls.py index 47d606c..51e074e 100644 --- a/netbox_sys_plugin/api/urls.py +++ b/netbox_sys_plugin/api/urls.py @@ -6,6 +6,7 @@ router.register(r'MaintenanceWindow', VirtualMachineMaintenanceViewSet) router.register(r'ProviderCredentials', ProviderCredentialsViewSet) router.register(r'AssignedVmType', VmAssignedVirtualMachineTypeViewSet) router.register(r'VmType', VirtualMachineTypeViewSet) +router.register(r'DomainNames', VirtualMachineTypeViewSet) router.register(r'VirtualMachine', VirtualMachineViewSet) app_name = "netbox_sys_plugin" diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index 094873d..bc4c63e 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -4,7 +4,7 @@ from rest_framework.response import Response from django.db.models import Prefetch from netbox.api.viewsets import NetBoxModelViewSet from virtualization import filtersets -from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType +from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType,DomainNames from . serializers import * class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): @@ -12,6 +12,10 @@ class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): serializer_class = VirtualMachineMaintenanceSerializer http_method_names = ["get", "post", "patch", "delete", "options"] +class DomainNamesViewSet(viewsets.ModelViewSet): + queryset = VirtualMachineMaintenance.objects.all() + serializer_class = DomainNamesSerializer + http_method_names = ["get", "post", "patch", "delete", "options"] class ProviderCredentialsViewSet(viewsets.ModelViewSet): queryset = ProviderCredentials.objects.all() diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py index 4396562..a217ed7 100644 --- a/netbox_sys_plugin/forms/machine.py +++ b/netbox_sys_plugin/forms/machine.py @@ -10,8 +10,8 @@ from netbox.forms import ( NetBoxModelForm, NetBoxModelFilterSetForm, ) -from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField -from ..models import VmAssignedVirtualMachineType, VirtualMachineMaintenance, VirtualMachineType +from utilities.forms.fields import DynamicModelChoiceField, JSONField +from ..models import VmAssignedVirtualMachineType, VirtualMachineMaintenance, VirtualMachineType, DomainNames class VmAssignedVmTypeForm(NetBoxModelForm): """ @@ -214,4 +214,74 @@ class VmMaitenanceForm(NetBoxModelForm): class VmMaintenanceFilterForm(NetBoxModelFilterSetForm): """MacAddress filter form definition class""" + model = VirtualMachineMaintenance + +class DomainNamesForm(NetBoxModelForm): + """ + GUI form to add or edit a VM Maitenance. + """ + virtual_machine = DynamicModelChoiceField( + queryset=VirtualMachine.objects.none(), required=True, label="Virtual Machine" + ) + domain_names = JSONField( + label=_('Domain Names'), + required=False + ) + + def __init__(self, *args, **kwargs): + # Initialize helper selectors + instance = kwargs.get("instance") + initial = kwargs.get("initial", {}).copy() + if instance: + if isinstance(instance.assigned_object, VirtualMachine): + initial["virtual_machine"] = instance.assigned_object + kwargs["initial"] = initial + super().__init__(*args, **kwargs) + + if instance: + current_vm_id = instance.assigned_object.id if instance.assigned_object else None + else: + current_vm_id = None + + assigned_vms = DomainNames.objects.filter( + assigned_object_type=ContentType.objects.get_for_model(VirtualMachine) + ).exclude(assigned_object_id=current_vm_id).values_list('assigned_object_id', flat=True) + self.fields['virtual_machine'].queryset = VirtualMachine.objects.exclude(id__in=assigned_vms) + + class Meta: + """Meta class""" + model = DomainNames + fields = ( 'virtual_machine','domain_names','tags') + + + def clean(self): + """ + Validates form inputs before submitting: + """ + super().clean() + + + vm = self.cleaned_data.get("virtual_machine") + + #Check if Virtual Machine is assigned corretly + if (not vm): + raise ValidationError( + {"__all__": "Can't assign more than one Maintenance Window to the same Virtual Machine"}, + ) + + if self.errors.get("virtual_machine"): + return + + + + def save(self, *args, **kwargs): + # Set assigned object + self.instance.assigned_object = ( + self.cleaned_data.get("virtual_machine") + ) + return super().save(*args, **kwargs) + +class DomainNamesFilterForm(NetBoxModelFilterSetForm): + """MacAddress filter form definition class""" + model = VirtualMachineMaintenance \ No newline at end of file diff --git a/netbox_sys_plugin/migrations/0006_domainnames.py b/netbox_sys_plugin/migrations/0006_domainnames.py new file mode 100644 index 0000000..b0fbbf9 --- /dev/null +++ b/netbox_sys_plugin/migrations/0006_domainnames.py @@ -0,0 +1,37 @@ +# Generated by Django 4.2.16 on 2024-12-06 12:19 + +from django.db import migrations, models +import django.db.models.deletion +import taggit.managers +import utilities.json + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0098_webhook_custom_field_data_webhook_tags'), + ('contenttypes', '0002_remove_content_type_name'), + ('netbox_sys_plugin', '0005_remove_providercredentials_provider_url_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='DomainNames', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), + ('created', models.DateTimeField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ('domain_names', models.JSONField(blank=True, null=True)), + ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)), + ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'ipam'), ('model', 'IPAddress'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ], + options={ + 'verbose_name': 'Domain Name', + 'verbose_name_plural': 'Domain Names', + 'ordering': ['assigned_object_id'], + 'unique_together': {('assigned_object_id',)}, + }, + ), + ] diff --git a/netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py b/netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py new file mode 100644 index 0000000..2d74afe --- /dev/null +++ b/netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.16 on 2024-12-06 14:58 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('netbox_sys_plugin', '0006_domainnames'), + ] + + operations = [ + migrations.AlterField( + model_name='domainnames', + name='assigned_object_type', + field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'VirtualMachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + ), + ] diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index 690faa7..f1e195b 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -165,3 +165,46 @@ GenericRelation( related_query_name="VirtualMachine", ).contribute_to_class(VirtualMachine, "VirtualMachineMaintenance") +#Domain Names +class DomainNames(NetBoxModel): + """Cluster ProviderInfo definition class""" + + domain_names = models.JSONField( + blank=True, + null=True, + ) + + assigned_object_type = models.ForeignKey( + to=ContentType, + limit_choices_to=VM_ASSIGNMENT_MODELS, + on_delete=models.PROTECT, + null=True, + blank=True, + ) + assigned_object_id = models.PositiveBigIntegerField(null=True, blank=True) + assigned_object = GenericForeignKey( + ct_field="assigned_object_type", + fk_field="assigned_object_id", + ) + + class Meta: + """Meta class""" + unique_together = ["assigned_object_id"] + ordering = ["assigned_object_id"] + verbose_name = "Domain Name" + verbose_name_plural = "Domain Names" + + + def __str__(self): + return f"for Virtual Machine Address {self.assigned_object_id}" + + def get_absolute_url(self): + """override""" + return reverse("plugins:netbox_sys_plugin:domainnames", args=[self.pk]) + +GenericRelation( + to=DomainNames, + content_type_field="assigned_object_type", + object_id_field="assigned_object_id", + related_query_name="VirtualMachine", +).contribute_to_class(VirtualMachine, "DomainNames") \ No newline at end of file diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index bd6fefc..ca9245d 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -57,6 +57,17 @@ create_vm_buttons = [ ), ] +create_domainnames_buttons = [ + PluginMenuButton( + link="plugins:netbox_sys_plugin:domainnames_add", + title="Add", + icon_class="mdi mdi-plus-thick", + color=ButtonColorChoices.GREEN, + permissions=["netbox_sys_plugin.add_domainnames"], + ), +] + + #Items clusterProviderCredentialsItem = [ @@ -87,6 +98,12 @@ vmMachineItem = [ buttons=vm_maintenance_buttons, permissions=["netbox_sys_plugin.list_maintenance"], ), + PluginMenuItem( + link="plugins:netbox_sys_plugin:domainnames_list", + link_text="VM Domain Names", + buttons=create_domainnames_buttons, + permissions=["netbox_sys_plugin.add_domainnames"], + ), PluginMenuItem( link="plugins:netbox_sys_plugin:creatvm_add", link_text="Create VM", diff --git a/netbox_sys_plugin/tables.py b/netbox_sys_plugin/tables.py index 374b9b2..a922227 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -145,3 +145,34 @@ class VmTypeTable(NetBoxTable): ) default_columns = ('id','virtual_machine_type_name','assigned_object','virtual_machine_type_desc') + +#DomainNames +class DomainNamesTable(NetBoxTable): + """VM Maintenance Table definition class""" + + pk = columns.ToggleColumn() + id = tables.Column( + linkify=True, + ) + + assigned_object = tables.Column( + linkify=True, + orderable=False, + verbose_name="Virtual Machine", + ) + + domain_names = tables.Column( + linkify=True, + verbose_name="Domain Names", + ) + + class Meta(NetBoxTable.Meta): + """Meta class""" + model = VirtualMachineType + fields = ( + "pk", + "id", + "domain_names", + ) + + default_columns = ('id','domain_names','assigned_object') \ No newline at end of file diff --git a/netbox_sys_plugin/template_content.py b/netbox_sys_plugin/template_content.py index 4400d88..99b8625 100644 --- a/netbox_sys_plugin/template_content.py +++ b/netbox_sys_plugin/template_content.py @@ -15,6 +15,15 @@ class VmTable(PluginTemplateExtension): def right_page(self): return self.render('netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html', extra_context={'vmassigntypeinfo': models.VmAssignedVirtualMachineType.objects.filter(VirtualMachine=self.context['object'])}) +class VmTableDomainNames(PluginTemplateExtension): + """VM Domain names object template""" + + model = 'virtualization.virtualmachine' + + def left_page(self): + return self.render('netbox_sys_plugin/vm_domainnames.html', extra_context={'domainnamesinfo': models.DomainNames.objects.filter(VirtualMachine=self.context['object'])}) + + class VmTypeTable(PluginTemplateExtension): """Cluster object template""" @@ -33,4 +42,4 @@ class ProviderCredentialsTable(PluginTemplateExtension): return self.render('netbox_sys_plugin/cluster_providercredentials.html', extra_context={'providercredentialsinfo': models.ProviderCredentials.objects.filter(Cluster=self.context['object'])}) -template_extensions = [VmTable,ProviderCredentialsTable,VmTypeTable] +template_extensions = [VmTable,ProviderCredentialsTable,VmTypeTable,VmTableDomainNames] diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/domainnames.html b/netbox_sys_plugin/templates/netbox_sys_plugin/domainnames.html new file mode 100644 index 0000000..a203221 --- /dev/null +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/domainnames.html @@ -0,0 +1,46 @@ +{% extends 'generic/object.html' %} + +{% block title%} +{{ object.assigned_object }} Domain Names +{% endblock title%} + +{% block content %} +<div class="row mb-3"> + <div class="col col-md-6"> + <div class="card"> + <h5 class="card-header">Virtual Machine Maintenance</h5> + + <div class="card-body"> + <table class="table table-hover attr-table"> + <tr> + <th scope="row">Domain Names</th> + <td>{% include 'extras/inc/configcontext_data.html' with data=object.domain_names format=json %}</td> + + </tr> + </table> + </div> + </div> + {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/tags.html' %} + </div> + <div class="col col-md-6"> + <div class="card"> + <h5 class="card-header">Details</h5> + <div class="card-body"> + <table class="table table-hover attr-table"> + <tr> + <th scope="row">{{ object.assigned_object_type|cut:"virtualization | " }}</th> + <td> + {% if object.assigned_object %} + <a href="{{ object.assigned_object.get_absolute_url }}">{{ object.assigned_object }}</a> + {% else %} + {{ ''|placeholder }} + {% endif %} + </td> + </tr> + </table> + </div> + </div> + </div> +</div> +{% endblock content %} diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/vm_domainnames.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_domainnames.html new file mode 100644 index 0000000..0293a29 --- /dev/null +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_domainnames.html @@ -0,0 +1,33 @@ +{% block content %} + <div class="row mb-3"> + <div class="col col-md-12"> + <div class="card"> + <h5 class="card-header">Domain Names Information</h5> + <div class="card-body"> + <table class="table table-responsive"> + <th scope="row">ID</th> + <th scope="row">Domain Names</th> + {% for domainnames in domainnamesinfo %} + <tr> + <td>{{ domainnames.id }}</td> + <td> + {% if domainnames.domain_names %} + <a href="{{ domainnames.get_absolute_url }}">{{ domainnames.domain_names }}</a> + {% else %} + {{ ''|placeholder }} + {% endif %} + </td> + </tr> + {% empty %} + <tr> + <td colspan="3">No domain names found.</td> + </tr> + {% endfor %} + </tr> + </table> + </div> + </div> + {% include 'inc/panels/custom_fields.html' %} + </div> + </div> +{% endblock content %} \ No newline at end of file diff --git a/netbox_sys_plugin/urls.py b/netbox_sys_plugin/urls.py index 299078a..c43d9b1 100644 --- a/netbox_sys_plugin/urls.py +++ b/netbox_sys_plugin/urls.py @@ -38,10 +38,15 @@ urlpatterns = ( path('vm-type/<int:pk>/delete/', views.VmTypeDeleteView.as_view(), name='virtualmachinetype_delete'), path('vm-type/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualmachinetype_changelog', kwargs={'model': models.VirtualMachineType}), path('vm-type/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinetype_journal', kwargs={'model': models.VirtualMachineType}), - + #DomainNames + path('domain-names/<int:pk>/', views.DomainNamesView.as_view(), name='domainnames'), + path('domain-names/', views.DomainNamesListView.as_view(), name='domainnames_list'), + path('domain-names/add/', views.DomainNamesEditView.as_view(), name='domainnames_add'), + path('domain-names/<int:pk>/edit/', views.DomainNamesEditView.as_view(), name='domainnames_edit'), + path('domain-names/<int:pk>/delete/', views.DomainNamesDeleteView.as_view(), name='domainnames_delete'), + path('domain-names/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='domainnames_changelog', kwargs={'model': models.DomainNames}), + path('domain-names/<int:pk>/journal/', ObjectJournalView.as_view(), name='domainnames_journal', kwargs={'model': models.DomainNames}), #CreateVM - path('create-vm/', CreateVmView.as_view(), name='creatvm_add'), - ) diff --git a/netbox_sys_plugin/views.py b/netbox_sys_plugin/views.py index fd8bbc9..0b1f59b 100644 --- a/netbox_sys_plugin/views.py +++ b/netbox_sys_plugin/views.py @@ -141,4 +141,33 @@ class CreateVmView(generic.ObjectView): return redirect(reverse('virtualization:virtualmachine_list')) except ValueError as e: messages.error(request, f"Error: {str(e)}") - return render(request, self.template_name, {'form': form}) \ No newline at end of file + return render(request, self.template_name, {'form': form}) + +#Domain Names +class DomainNamesView(generic.ObjectView): + + """ Domain names view definition""" + + queryset = ( + models.DomainNames.objects.all() + ) + +class DomainNamesListView(generic.ObjectListView): + """Domain Names list view definition""" + + queryset = models.DomainNames.objects.all() + table = tables.DomainNamesTable + #filterset = filtersets.VmTypeFilterSet + filterset_form = forms.DomainNamesFilterForm + +class DomainNamesEditView(generic.ObjectEditView): + """ + Defines the edit view for the Domain Names django model. + """ + queryset = models.DomainNames.objects.all() + form = forms.DomainNamesForm + +class DomainNamesDeleteView(generic.ObjectDeleteView): + """Domain Names delete view definition""" + + queryset = models.DomainNames.objects.all() \ No newline at end of file -- GitLab