From ce2282b428eaecbc7a72d93803ff8d95f2f3270e Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Mon, 18 Nov 2024 17:00:35 +0000 Subject: [PATCH 01/11] =?UTF-8?q?=E2=9C=A8=20Add=20machine=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0003_machinetype.py | 38 +++++++++++ netbox_sys_plugin/models/__init__.py | 3 +- netbox_sys_plugin/models/machine.py | 66 +++++++++++++++++++ netbox_sys_plugin/navigation.py | 21 ++++++ 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 netbox_sys_plugin/migrations/0003_machinetype.py create mode 100644 netbox_sys_plugin/models/machine.py diff --git a/netbox_sys_plugin/migrations/0003_machinetype.py b/netbox_sys_plugin/migrations/0003_machinetype.py new file mode 100644 index 0000000..9bca12a --- /dev/null +++ b/netbox_sys_plugin/migrations/0003_machinetype.py @@ -0,0 +1,38 @@ +# Generated by Django 4.2.16 on 2024-11-18 16:43 + +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', '0002_alter_virtualmachinemaintenance_maintenance_window_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='MachineType', + 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)), + ('machine_type_name', models.CharField(blank=True, default=None, max_length=50, null=True)), + ('machine_type_desc', models.CharField(blank=True, default=None, max_length=100, 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', 'virtualization'), ('model', 'ClusterType'))), 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': 'Machine Type', + 'verbose_name_plural': 'Machine Types', + 'ordering': ['assigned_object_id'], + 'unique_together': {('assigned_object_id',)}, + }, + ), + ] diff --git a/netbox_sys_plugin/models/__init__.py b/netbox_sys_plugin/models/__init__.py index cef638b..44d7d4f 100644 --- a/netbox_sys_plugin/models/__init__.py +++ b/netbox_sys_plugin/models/__init__.py @@ -1,4 +1,5 @@ """Models definitions""" from .maintenance import VirtualMachineMaintenance -from .provider import ProviderCredentials \ No newline at end of file +from .provider import ProviderCredentials +from .machine import MachineType \ No newline at end of file diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py new file mode 100644 index 0000000..95525da --- /dev/null +++ b/netbox_sys_plugin/models/machine.py @@ -0,0 +1,66 @@ +"""Models definitions""" + +from django.core.validators import ( + RegexValidator, +) +from django.urls import reverse +from django.core.validators import ( + URLValidator, +) # pylint: disable=import-error +from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation +from django.contrib.contenttypes.models import ContentType +from django.db import models +from virtualization.models import ClusterType +from netbox.models import NetBoxModel + +CLUSTERTYPE_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="ClusterType")) + + + +class MachineType(NetBoxModel): + """Cluster ProviderInfo definition class""" + + machine_type_name = models.CharField( + default=None, blank=True, null=True, + max_length=50, + ) + + machine_type_desc = models.CharField( + default=None, blank=True, null=True, + max_length=100) + + assigned_object_type = models.ForeignKey( + to=ContentType, + limit_choices_to=CLUSTERTYPE_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 = "Machine Type" + verbose_name_plural = "Machine Types" + + + def __str__(self): + return f"for Cluster Type ID {self.assigned_object_id}" + + def get_absolute_url(self): + """override""" + return reverse("plugins:netbox_sys_plugin:machinetype", args=[self.pk]) + +GenericRelation( + to=MachineType, + content_type_field="assigned_object_type", + object_id_field="assigned_object_id", + related_query_name="ClusterType", +).contribute_to_class(ClusterType, "MachineType") + diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index 2a39a83..d4188d3 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -3,6 +3,7 @@ from extras.plugins import PluginMenuButton, PluginMenuItem, PluginMenu from utilities.choices import ButtonColorChoices +#Buttons vm_maintenance_buttons = [ PluginMenuButton( link="plugins:netbox_sys_plugin:virtualmachinemaintenance_add", @@ -21,6 +22,16 @@ cluster_provider_credentials_buttons = [ ), ] +clutertype_machine_type_buttons = [ + PluginMenuButton( + link="plugins:netbox_sys_plugin:providercredentials_add", + title="Add", + icon_class="mdi mdi-plus-thick", + color=ButtonColorChoices.GREEN, + ), +] + +#Items vmMaintenanceItem = [ PluginMenuItem( link="plugins:netbox_sys_plugin:virtualmachinemaintenance_list", @@ -37,11 +48,21 @@ clusterProviderCredentialsItem = [ ), ] +clusterTypeMachineTypeItem = [ + PluginMenuItem( + link="plugins:netbox_sys_plugin:providercredentials_list", + link_text="Machine Type", + buttons=cluster_provider_credentials_buttons, + ), +] + +#Menu menu = PluginMenu( label="Sys", groups=( ("Maintenance", vmMaintenanceItem), ("Provider", clusterProviderCredentialsItem), + ("Machine", clusterTypeMachineTypeItem), ), icon_class="mdi mdi-all-inclusive-box-outline", ) -- GitLab From b94201cd450fbf7a83db0dffc95894a208669020 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 19 Nov 2024 14:10:28 +0000 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=9A=A7=20Add=20working=20forms=20fo?= =?UTF-8?q?r=20CRUDS=20operations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 23 ++++- netbox_sys_plugin/api/urls.py | 3 +- netbox_sys_plugin/api/views.py | 10 +- netbox_sys_plugin/forms/__init__.py | 3 +- netbox_sys_plugin/forms/machine.py | 96 +++++++++++++++++++ ...hinetype.py => 0003_virtualmachinetype.py} | 8 +- netbox_sys_plugin/models/__init__.py | 2 +- netbox_sys_plugin/models/machine.py | 12 +-- netbox_sys_plugin/navigation.py | 6 +- netbox_sys_plugin/tables.py | 42 +++++++- .../netbox_sys_plugin/virtualmachinetype.html | 44 +++++++++ netbox_sys_plugin/urls.py | 31 +++--- netbox_sys_plugin/views.py | 33 ++++++- 13 files changed, 273 insertions(+), 40 deletions(-) create mode 100644 netbox_sys_plugin/forms/machine.py rename netbox_sys_plugin/migrations/{0003_machinetype.py => 0003_virtualmachinetype.py} (83%) create mode 100644 netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index 4e7d712..a5502fd 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -1,8 +1,9 @@ from rest_framework import serializers -from virtualization.models import VirtualMachine, Cluster -from .. models import VirtualMachineMaintenance, ProviderCredentials +from virtualization.models import VirtualMachine, Cluster, ClusterType +from .. models import VirtualMachineMaintenance, ProviderCredentials,VirtualMachineType from django.contrib.contenttypes.models import ContentType +#Netbox Data Serializer class VirtualMachineSerializer(serializers.ModelSerializer): class Meta: model = VirtualMachine @@ -13,6 +14,13 @@ class ClusterSerializer(serializers.ModelSerializer): model = Cluster fields = ['id', 'name'] +class ClusterTypeSerializer(serializers.ModelSerializer): + class Meta: + model = ClusterType + fields = ['id', 'name'] + + +#Plugin Data Serializer class VirtualMachineMaintenanceSerializer(serializers.ModelSerializer): id = serializers.IntegerField(read_only=True) virtual_machine = VirtualMachineSerializer(source='assigned_object', read_only=True) @@ -33,4 +41,15 @@ class ProviderCredentialsSerializer(serializers.ModelSerializer): class Meta: 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) + assigned_object_id = serializers.IntegerField(write_only=True) + assigned_object_type = serializers.CharField(write_only=True) + + class Meta: + model = VirtualMachineType + #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' \ No newline at end of file diff --git a/netbox_sys_plugin/api/urls.py b/netbox_sys_plugin/api/urls.py index 6f3fb34..8454336 100644 --- a/netbox_sys_plugin/api/urls.py +++ b/netbox_sys_plugin/api/urls.py @@ -1,9 +1,10 @@ from rest_framework.routers import DefaultRouter -from .views import VirtualMachineMaintenanceViewSet, ProviderCredentialsViewSet +from .views import VirtualMachineMaintenanceViewSet, ProviderCredentialsViewSet, VirtualMachineTypeViewSet router = DefaultRouter() router.register(r'MaintenanceWindow', VirtualMachineMaintenanceViewSet) router.register(r'ProviderCredentials', ProviderCredentialsViewSet) +router.register(r'VmType', VirtualMachineTypeViewSet) app_name = "netbox_sys_plugin" diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index b375333..40331ea 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -1,8 +1,8 @@ from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.response import Response -from .. models import VirtualMachineMaintenance, ProviderCredentials -from . serializers import VirtualMachineMaintenanceSerializer, ProviderCredentialsSerializer +from .. models import VirtualMachineMaintenance, ProviderCredentials, VirtualMachineType +from . serializers import VirtualMachineMaintenanceSerializer, ProviderCredentialsSerializer, VirtualMachineTypeSerializer class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): queryset = VirtualMachineMaintenance.objects.all() @@ -13,4 +13,10 @@ class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): class ProviderCredentialsViewSet(viewsets.ModelViewSet): queryset = ProviderCredentials.objects.all() serializer_class = ProviderCredentialsSerializer + http_method_names = ["get", "post", "patch", "delete", "options"] + + +class VirtualMachineTypeViewSet(viewsets.ModelViewSet): + queryset = VirtualMachineType.objects.all() + serializer_class = VirtualMachineTypeSerializer http_method_names = ["get", "post", "patch", "delete", "options"] \ No newline at end of file diff --git a/netbox_sys_plugin/forms/__init__.py b/netbox_sys_plugin/forms/__init__.py index 0f3ba6e..70c47d7 100644 --- a/netbox_sys_plugin/forms/__init__.py +++ b/netbox_sys_plugin/forms/__init__.py @@ -1,4 +1,5 @@ """Forms definitions""" from .maintenance import * -from .provider import * \ No newline at end of file +from .provider import * +from .machine import * \ No newline at end of file diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py new file mode 100644 index 0000000..914243f --- /dev/null +++ b/netbox_sys_plugin/forms/machine.py @@ -0,0 +1,96 @@ +"""Forms definitions""" + +from virtualization.models import ClusterType +from django.contrib.contenttypes.models import ContentType +from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError +from django import forms +from netbox.forms import ( + NetBoxModelForm, + NetBoxModelFilterSetForm, +) +from utilities.forms.fields import DynamicModelChoiceField +from ..models import VirtualMachineType + +class VmTypeForm(NetBoxModelForm): + """ + GUI form to add or edit a Virtual Machine Type. + """ + + cluster_type = DynamicModelChoiceField( + queryset=ClusterType.objects.all(), required=True, label="Cluster Type" + ) + virtual_machine_type_name = forms.CharField( + max_length=200, min_length=1, required=True, label="Name" + ) + virtual_machine_type_desc = forms.CharField( + max_length=50, min_length=1, required=False, label="Description" + ) + + + def __init__(self, *args, **kwargs): + # Initialize helper selectors + instance = kwargs.get("instance") + initial = kwargs.get("initial", {}).copy() + if instance: + if isinstance(instance.assigned_object, ClusterType): + initial["cluster_type"] = instance.assigned_object + kwargs["initial"] = initial + super().__init__(*args, **kwargs) + + if instance: + current_cluster_type_id = instance.assigned_object.id if instance.assigned_object else None + else: + current_cluster_type_id = None + + assigned_cluster_types = VirtualMachineType.objects.filter( + assigned_object_type=ContentType.objects.get_for_model(ClusterType) + ).exclude(assigned_object_id=current_cluster_type_id).values_list('assigned_object_id', flat=True) + self.fields['cluster_type'].queryset = ClusterType.objects.exclude(id__in=assigned_cluster_types) + + class Meta: + """Meta class""" + model = VirtualMachineType + fields = ('cluster_type','virtual_machine_type_name', 'virtual_machine_type_desc','tags') + + def clean_cluster(self): + + cluster_type = self.cleaned_data.get("cluster_type") + + cluster_type_ct = ContentType.objects.get_for_model(ClusterType) + + if VirtualMachineType.objects.filter( + assigned_object_type=cluster_type_ct, + assigned_object_id=cluster_type.id + ).exclude(pk=self.instance.pk).exists(): + raise ValidationError() + return cluster_type + + def clean(self): + """ + Validates form inputs before submitting: + """ + super().clean() + + if self.errors.get(f"virtual_machine_type_name"): + return + + cluster_type = self.cleaned_data.get("cluster_type") + + #Check if cluster is assigned corretly + if (not cluster_type): + raise ValidationError( + {"__all__": "A Virtual Machine Type needs to be associated with the Cluster Type"}, + ) + + def save(self, *args, **kwargs): + # Set assigned object + self.instance.assigned_object = ( + self.cleaned_data.get("cluster_type") + ) + return super().save(*args, **kwargs) + +class VmTypeFilterForm(NetBoxModelFilterSetForm): + """Virtual Machine Type filter form definition class""" + + model = VirtualMachineType \ No newline at end of file diff --git a/netbox_sys_plugin/migrations/0003_machinetype.py b/netbox_sys_plugin/migrations/0003_virtualmachinetype.py similarity index 83% rename from netbox_sys_plugin/migrations/0003_machinetype.py rename to netbox_sys_plugin/migrations/0003_virtualmachinetype.py index 9bca12a..d7d0a5c 100644 --- a/netbox_sys_plugin/migrations/0003_machinetype.py +++ b/netbox_sys_plugin/migrations/0003_virtualmachinetype.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2024-11-18 16:43 +# Generated by Django 4.2.16 on 2024-11-18 17:19 from django.db import migrations, models import django.db.models.deletion @@ -16,14 +16,14 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='MachineType', + name='VirtualMachineType', 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)), - ('machine_type_name', models.CharField(blank=True, default=None, max_length=50, null=True)), - ('machine_type_desc', models.CharField(blank=True, default=None, max_length=100, null=True)), + ('virtual_machine_type_name', models.CharField(blank=True, default=None, max_length=50, null=True)), + ('virtual_machine_type_desc', models.CharField(blank=True, default=None, max_length=100, 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', 'virtualization'), ('model', 'ClusterType'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), diff --git a/netbox_sys_plugin/models/__init__.py b/netbox_sys_plugin/models/__init__.py index 44d7d4f..da5e1b1 100644 --- a/netbox_sys_plugin/models/__init__.py +++ b/netbox_sys_plugin/models/__init__.py @@ -2,4 +2,4 @@ from .maintenance import VirtualMachineMaintenance from .provider import ProviderCredentials -from .machine import MachineType \ No newline at end of file +from .machine import VirtualMachineType \ No newline at end of file diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index 95525da..c3e510c 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -17,15 +17,15 @@ CLUSTERTYPE_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", mo -class MachineType(NetBoxModel): +class VirtualMachineType(NetBoxModel): """Cluster ProviderInfo definition class""" - machine_type_name = models.CharField( + virtual_machine_type_name = models.CharField( default=None, blank=True, null=True, max_length=50, ) - machine_type_desc = models.CharField( + virtual_machine_type_desc = models.CharField( default=None, blank=True, null=True, max_length=100) @@ -55,12 +55,12 @@ class MachineType(NetBoxModel): def get_absolute_url(self): """override""" - return reverse("plugins:netbox_sys_plugin:machinetype", args=[self.pk]) + return reverse("plugins:netbox_sys_plugin:virtualmachinetype", args=[self.pk]) GenericRelation( - to=MachineType, + to=VirtualMachineType, content_type_field="assigned_object_type", object_id_field="assigned_object_id", related_query_name="ClusterType", -).contribute_to_class(ClusterType, "MachineType") +).contribute_to_class(ClusterType, "VirtualMachineType") diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index d4188d3..c105859 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -24,7 +24,7 @@ cluster_provider_credentials_buttons = [ clutertype_machine_type_buttons = [ PluginMenuButton( - link="plugins:netbox_sys_plugin:providercredentials_add", + link="plugins:netbox_sys_plugin:virtualmachinetype_add", title="Add", icon_class="mdi mdi-plus-thick", color=ButtonColorChoices.GREEN, @@ -50,9 +50,9 @@ clusterProviderCredentialsItem = [ clusterTypeMachineTypeItem = [ PluginMenuItem( - link="plugins:netbox_sys_plugin:providercredentials_list", + link="plugins:netbox_sys_plugin:virtualmachinetype_list", link_text="Machine Type", - buttons=cluster_provider_credentials_buttons, + buttons=clutertype_machine_type_buttons, ), ] diff --git a/netbox_sys_plugin/tables.py b/netbox_sys_plugin/tables.py index bea34c6..8cb536b 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -2,9 +2,9 @@ import django_tables2 as tables from netbox.tables import NetBoxTable, columns -from .models import VirtualMachineMaintenance, ProviderCredentials - +from .models import VirtualMachineMaintenance, ProviderCredentials, VirtualMachineType +#VmMaintenance class VmMaintenanceTable(NetBoxTable): """VM Maintenance Table definition class""" @@ -35,7 +35,7 @@ class VmMaintenanceTable(NetBoxTable): default_columns = ('id','maintenance_window','assigned_object') - +#ProviderCredentials class ProviderCredentialsTable(NetBoxTable): """VM Maintenance Table definition class""" @@ -79,3 +79,39 @@ class ProviderCredentialsTable(NetBoxTable): ) default_columns = ('id','provider_url','provider_username','provider_password_vault_url','assigned_object') + +#ProviderCredentials +class VmTypeTable(NetBoxTable): + """VM Maintenance Table definition class""" + + pk = columns.ToggleColumn() + id = tables.Column( + linkify=False, + ) + + assigned_object = tables.Column( + linkify=True, + orderable=False, + verbose_name="Cluster Type", + ) + + virtual_machine_type_name = tables.Column( + linkify=True, + verbose_name="Machine Type Name", + ) + virtual_machine_type_desc = tables.Column( + linkify=True, + verbose_name="Machine Type Descritpion", + ) + + class Meta(NetBoxTable.Meta): + """Meta class""" + model = VirtualMachineType + fields = ( + "pk", + "id", + "virtual_machine_type_name", + "virtual_machine_type_desc", + ) + + default_columns = ('id','virtual_machine_type_name','virtual_machine_type_desc','assigned_object') diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html new file mode 100644 index 0000000..ee2c51d --- /dev/null +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html @@ -0,0 +1,44 @@ +{% extends 'generic/object.html' %} + +{% block content %} +<div class="row mb-3"> + <div class="col col-md-6"> + <div class="card"> + <h5 class="card-header">Virtual Machine Types</h5> + <div class="card-body"> + <table class="table table-hover attr-table"> + <tr> + <th scope="row">Name</th> + <td>{{ object.virtual_machine_type_name }}</td> + </tr> + <tr> + <th scope="row">Description</th> + <td>{{ object.virtual_machine_type_desc }}</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">Assigned Object</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/urls.py b/netbox_sys_plugin/urls.py index 4d3e076..ac9e61f 100644 --- a/netbox_sys_plugin/urls.py +++ b/netbox_sys_plugin/urls.py @@ -5,29 +5,30 @@ from netbox.views.generic import ObjectChangeLogView, ObjectJournalView from netbox_sys_plugin import models, views urlpatterns = ( - + #maintenance + path('vm-maintenance/<int:pk>/', views.VmMaintenanceView.as_view(), name='virtualmachinemaintenance'), path('vm-maintenance/', views.VmMaintenanceListView.as_view(), name='virtualmachinemaintenance_list'), path('vm-maintenance/add/', views.VmMaintenanceEditView.as_view(), name='virtualmachinemaintenance_add'), - path('vm-maintenance/<int:pk>/', views.VmMaintenanceView.as_view(), name='virtualmachinemaintenance'), path('vm-maintenance/<int:pk>/edit/', views.VmMaintenanceEditView.as_view(), name='virtualmachinemaintenance_edit'), path('vm-maintenance/<int:pk>/delete/', views.VmMaintenanceDeleteView.as_view(), name='virtualmachinemaintenance_delete'), - path('vm-maintenance/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualmachinemaintenance_changelog', kwargs={ - 'model': models.VirtualMachineMaintenance - }), - path('vm-maintenance/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinemaintenance_journal', kwargs={ - 'model': models.VirtualMachineMaintenance - }), + path('vm-maintenance/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualmachinemaintenance_changelog', kwargs={'model': models.VirtualMachineMaintenance }), + path('vm-maintenance/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinemaintenance_journal', kwargs={'model': models.VirtualMachineMaintenance}), + #providerCredentials + path('provider-credentials/<int:pk>/', views.ProviderCredentialsView.as_view(), name='providercredentials'), path('provider-credentials/', views.ProviderCredentialsListView.as_view(), name='providercredentials_list'), path('provider-credentials/add/', views.ProviderCredentialsEditView.as_view(), name='providercredentials_add'), - path('provider-credentials/<int:pk>/', views.ProviderCredentialsView.as_view(), name='providercredentials'), path('provider-credentials/<int:pk>/edit/', views.ProviderCredentialsEditView.as_view(), name='providercredentials_edit'), path('provider-credentials/<int:pk>/delete/', views.ProviderCredentialsDeleteView.as_view(), name='providercredentials_delete'), - path('provider-credentials/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providercredentials_changelog', kwargs={ - 'model': models.VirtualMachineMaintenance - }), - path('provider-credentials/<int:pk>/journal/', ObjectJournalView.as_view(), name='providercredentials_journal', kwargs={ - 'model': models.VirtualMachineMaintenance - }), + path('provider-credentials/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providercredentials_changelog', kwargs={'model': models.VirtualMachineMaintenance}), + path('provider-credentials/<int:pk>/journal/', ObjectJournalView.as_view(), name='providercredentials_journal', kwargs={'model': models.VirtualMachineMaintenance}), + #virtualMachineType + path('vm-type/<int:pk>/', views.VmTypeView.as_view(), name='virtualmachinetype'), + path('vm-type/', views.VmTypeListView.as_view(), name='virtualmachinetype_list'), + path('vm-type/add/', views.VmTypeEditView.as_view(), name='virtualmachinetype_add'), + path('vm-type/<int:pk>/edit/', views.VmTypeEditView.as_view(), name='virtualmachinetype_edit'), + 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}), ) diff --git a/netbox_sys_plugin/views.py b/netbox_sys_plugin/views.py index f80387d..e346a1b 100644 --- a/netbox_sys_plugin/views.py +++ b/netbox_sys_plugin/views.py @@ -3,6 +3,7 @@ from netbox.views import generic from . import forms, models, tables, filtersets +#VmMaintenance class VmMaintenanceView(generic.ObjectView): """ Vm maintenance view definition""" @@ -30,7 +31,7 @@ class VmMaintenanceDeleteView(generic.ObjectDeleteView): queryset = models.VirtualMachineMaintenance.objects.all() - +#ProviderCredentials class ProviderCredentialsView(generic.ObjectView): """ Provider Credentials view definition""" @@ -56,4 +57,32 @@ class ProviderCredentialsEditView(generic.ObjectEditView): Defines the edit view for the Vm maintenance django model. """ queryset = models.ProviderCredentials.objects.all() - form = forms.ProviderCredentialsForm \ No newline at end of file + form = forms.ProviderCredentialsForm + +#VmType +class VmTypeView(generic.ObjectView): + """ Virtual Machine Type view definition""" + + queryset = ( + models.VirtualMachineType.objects.all() + ) + +class VmTypeListView(generic.ObjectListView): + """Cluster Type Virtual Machine Type list view definition""" + + queryset = models.VirtualMachineType.objects.all() + table = tables.VmTypeTable + #filterset = filtersets.ProviderCredentialsFilterSet + #filterset_form = forms.VmTypeFilterForm + +class VmTypeDeleteView(generic.ObjectDeleteView): + """Vm maintenance delete view definition""" + + queryset = models.VirtualMachineType.objects.all() + +class VmTypeEditView(generic.ObjectEditView): + """ + Defines the edit view for the Vm maintenance django model. + """ + queryset = models.VirtualMachineType.objects.all() + form = forms.VmTypeForm \ No newline at end of file -- GitLab From a507e6c93e39ef2195e6be029c5324cbe4e0ecbf Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 19 Nov 2024 15:40:01 +0000 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=9A=A7=20New=20structure,=20validat?= =?UTF-8?q?ion=20and=20templates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 8 +- netbox_sys_plugin/filtersets.py | 24 +++- netbox_sys_plugin/forms/__init__.py | 1 - netbox_sys_plugin/forms/machine.py | 136 ++++++++++++++---- netbox_sys_plugin/forms/maintenance.py | 99 ------------- .../migrations/0003_virtualmachinetype.py | 4 +- netbox_sys_plugin/models/__init__.py | 3 +- netbox_sys_plugin/models/machine.py | 63 +++++++- netbox_sys_plugin/models/maintenance.py | 66 --------- netbox_sys_plugin/navigation.py | 33 +++-- netbox_sys_plugin/tables.py | 12 +- netbox_sys_plugin/template_content.py | 9 +- .../netbox_sys_plugin/virtualmachinetype.html | 4 + .../vm_virtualmachinetype.html | 41 ++++++ ...nance_table.html => vm_vmmaintenance.html} | 0 netbox_sys_plugin/views.py | 4 +- 16 files changed, 272 insertions(+), 235 deletions(-) delete mode 100644 netbox_sys_plugin/forms/maintenance.py delete mode 100644 netbox_sys_plugin/models/maintenance.py create mode 100644 netbox_sys_plugin/templates/netbox_sys_plugin/vm_virtualmachinetype.html rename netbox_sys_plugin/templates/netbox_sys_plugin/{vm_vmmaintenance_table.html => vm_vmmaintenance.html} (100%) diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index a5502fd..e4c45da 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -14,12 +14,6 @@ class ClusterSerializer(serializers.ModelSerializer): model = Cluster fields = ['id', 'name'] -class ClusterTypeSerializer(serializers.ModelSerializer): - class Meta: - model = ClusterType - fields = ['id', 'name'] - - #Plugin Data Serializer class VirtualMachineMaintenanceSerializer(serializers.ModelSerializer): id = serializers.IntegerField(read_only=True) @@ -45,7 +39,7 @@ class ProviderCredentialsSerializer(serializers.ModelSerializer): class VirtualMachineTypeSerializer(serializers.ModelSerializer): id = serializers.IntegerField(read_only=True) - cluster_type = ClusterTypeSerializer(source='assigned_object', 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) diff --git a/netbox_sys_plugin/filtersets.py b/netbox_sys_plugin/filtersets.py index 75a77e0..6dae0a4 100644 --- a/netbox_sys_plugin/filtersets.py +++ b/netbox_sys_plugin/filtersets.py @@ -4,7 +4,7 @@ import django_filters from netbox.filtersets import NetBoxModelFilterSet from virtualization.models import VirtualMachine, Cluster from django.db.models import Q -from .models import VirtualMachineMaintenance, ProviderCredentials +from .models import VirtualMachineMaintenance, ProviderCredentials, VirtualMachineType class VmMaintenanceFilterSet(NetBoxModelFilterSet): @@ -28,6 +28,28 @@ class VmMaintenanceFilterSet(NetBoxModelFilterSet): if not value.strip(): return queryset return queryset.filter(Q(maintenance_window__icontains=value)) + +class VmTypeFilterSet(NetBoxModelFilterSet): + """VirtualMachineType filterset definition class""" + + virtualmachine = django_filters.ModelMultipleChoiceFilter( + field_name="VirtualMachine__name", + queryset=VirtualMachine.objects.all(), + to_field_name="name", + label="Virtual Machine (name)", + ) + + class Meta: + """Meta class""" + model = VirtualMachineType + fields = ('virtual_machine_type_name','virtual_machine_type_desc', 'virtualmachine') + + # pylint: disable=W0613 + def search(self, queryset, name, value): + """override""" + if not value.strip(): + return queryset + return queryset.filter(Q(virtual_machine_type_name__icontains=value)|Q(virtual_machine_type_desc__icontains=value)) class ProviderCredentialsFilterSet(NetBoxModelFilterSet): """ProviderCredentials filterset definition class""" diff --git a/netbox_sys_plugin/forms/__init__.py b/netbox_sys_plugin/forms/__init__.py index 70c47d7..c3fb247 100644 --- a/netbox_sys_plugin/forms/__init__.py +++ b/netbox_sys_plugin/forms/__init__.py @@ -1,5 +1,4 @@ """Forms definitions""" -from .maintenance import * from .provider import * from .machine import * \ No newline at end of file diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py index 914243f..e678197 100644 --- a/netbox_sys_plugin/forms/machine.py +++ b/netbox_sys_plugin/forms/machine.py @@ -1,28 +1,31 @@ """Forms definitions""" -from virtualization.models import ClusterType +from virtualization.models import VirtualMachine from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError from django import forms +from django.utils.safestring import mark_safe from netbox.forms import ( NetBoxModelForm, NetBoxModelFilterSetForm, ) from utilities.forms.fields import DynamicModelChoiceField -from ..models import VirtualMachineType +from ..models import VirtualMachineType, VirtualMachineMaintenance class VmTypeForm(NetBoxModelForm): """ GUI form to add or edit a Virtual Machine Type. """ - cluster_type = DynamicModelChoiceField( - queryset=ClusterType.objects.all(), required=True, label="Cluster Type" + virtual_machine = DynamicModelChoiceField( + queryset=VirtualMachine.objects.all(), required=True, label="Virtual Machine" ) + virtual_machine_type_name = forms.CharField( max_length=200, min_length=1, required=True, label="Name" ) + virtual_machine_type_desc = forms.CharField( max_length=50, min_length=1, required=False, label="Description" ) @@ -33,38 +36,38 @@ class VmTypeForm(NetBoxModelForm): instance = kwargs.get("instance") initial = kwargs.get("initial", {}).copy() if instance: - if isinstance(instance.assigned_object, ClusterType): - initial["cluster_type"] = instance.assigned_object + if isinstance(instance.assigned_object, VirtualMachine): + initial["virtual_machine"] = instance.assigned_object kwargs["initial"] = initial super().__init__(*args, **kwargs) if instance: - current_cluster_type_id = instance.assigned_object.id if instance.assigned_object else None + current_virtual_machine_id = instance.assigned_object.id if instance.assigned_object else None else: - current_cluster_type_id = None + current_virtual_machine_id = None - assigned_cluster_types = VirtualMachineType.objects.filter( - assigned_object_type=ContentType.objects.get_for_model(ClusterType) - ).exclude(assigned_object_id=current_cluster_type_id).values_list('assigned_object_id', flat=True) - self.fields['cluster_type'].queryset = ClusterType.objects.exclude(id__in=assigned_cluster_types) + assigned_virtual_machines = VirtualMachineType.objects.filter( + assigned_object_type=ContentType.objects.get_for_model(VirtualMachine) + ).exclude(assigned_object_id=current_virtual_machine_id).values_list('assigned_object_id', flat=True) + self.fields['virtual_machine'].queryset = VirtualMachine.objects.exclude(id__in=assigned_virtual_machines) class Meta: """Meta class""" model = VirtualMachineType - fields = ('cluster_type','virtual_machine_type_name', 'virtual_machine_type_desc','tags') + fields = ('virtual_machine','virtual_machine_type_name', 'virtual_machine_type_desc','tags') def clean_cluster(self): - cluster_type = self.cleaned_data.get("cluster_type") + virtual_machine = self.cleaned_data.get("virtual_machine") - cluster_type_ct = ContentType.objects.get_for_model(ClusterType) + virtual_machine_ct = ContentType.objects.get_for_model(VirtualMachine) if VirtualMachineType.objects.filter( - assigned_object_type=cluster_type_ct, - assigned_object_id=cluster_type.id + assigned_object_type=virtual_machine_ct, + assigned_object_id=virtual_machine.id ).exclude(pk=self.instance.pk).exists(): raise ValidationError() - return cluster_type + return virtual_machine def clean(self): """ @@ -75,22 +78,107 @@ class VmTypeForm(NetBoxModelForm): if self.errors.get(f"virtual_machine_type_name"): return - cluster_type = self.cleaned_data.get("cluster_type") + virtual_machine = self.cleaned_data.get("virtual_machine") - #Check if cluster is assigned corretly - if (not cluster_type): + #Check if VM is assigned corretly + if (not virtual_machine): raise ValidationError( - {"__all__": "A Virtual Machine Type needs to be associated with the Cluster Type"}, + {"__all__": "A Virtual Machine Type needs to be associated with the Virtual Machine"}, ) def save(self, *args, **kwargs): # Set assigned object self.instance.assigned_object = ( - self.cleaned_data.get("cluster_type") + self.cleaned_data.get("virtual_machine") ) return super().save(*args, **kwargs) class VmTypeFilterForm(NetBoxModelFilterSetForm): """Virtual Machine Type filter form definition class""" - model = VirtualMachineType \ No newline at end of file + model = VirtualMachineType + +class VmMaitenanceForm(NetBoxModelForm): + """ + GUI form to add or edit a VM Maitenance. + """ + virtual_machine = DynamicModelChoiceField( + queryset=VirtualMachine.objects.none(), required=True, label="Virtual Machine" + ) + maintenance_window = forms.CharField( + max_length=7, min_length=1, required=True, label="Maintenance Window", + help_text=mark_safe( + "<b>*Note:</b> Day of the week and a time of the day, 0 = Sunday , 1 = monday. Format 0-00:00", + ), + ) + + 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 = VirtualMachineMaintenance.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 = VirtualMachineMaintenance + fields = ( 'virtual_machine','maintenance_window','tags') + + def clean_virtual_machine(self): + + virtual_machine = self.cleaned_data.get("virtual_machine") + + virtual_machine_ct = ContentType.objects.get_for_model(VirtualMachine) + + if VirtualMachineMaintenance.objects.filter( + assigned_object_type=virtual_machine_ct, + assigned_object_id=virtual_machine.id + ).exclude(pk=self.instance.pk).exists(): + raise ValidationError() + return virtual_machine + + + + def clean(self): + """ + Validates form inputs before submitting: + """ + super().clean() + + if self.errors.get("maintenance_window"): + return + + virtual_machine = self.cleaned_data.get("virtual_machine") + + #Check if VM is assigned corretly + if (not virtual_machine): + raise ValidationError( + {"__all__": "A Virtual Machine needs to be associated with the maintenance window"}, + ) + + + + def save(self, *args, **kwargs): + # Set assigned object + self.instance.assigned_object = ( + self.cleaned_data.get("virtual_machine") + ) + return super().save(*args, **kwargs) + +class VmMaintenanceFilterForm(NetBoxModelFilterSetForm): + """MacAddress filter form definition class""" + + model = VirtualMachineMaintenance \ No newline at end of file diff --git a/netbox_sys_plugin/forms/maintenance.py b/netbox_sys_plugin/forms/maintenance.py deleted file mode 100644 index 46618c6..0000000 --- a/netbox_sys_plugin/forms/maintenance.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Forms definitions""" - -from virtualization.models import VirtualMachine -from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext_lazy as _ -from django.core.exceptions import ValidationError -from django import forms -from django.utils.safestring import mark_safe -from netbox.forms import ( - NetBoxModelForm, - NetBoxModelFilterSetForm, -) -from utilities.forms.fields import DynamicModelChoiceField -from ..models import VirtualMachineMaintenance - -class VmMaitenanceForm(NetBoxModelForm): - """ - GUI form to add or edit a VM Maitenance. - """ - virtual_machine = DynamicModelChoiceField( - queryset=VirtualMachine.objects.none(), required=True, label="Virtual Machine" - ) - maintenance_window = forms.CharField( - max_length=7, min_length=1, required=True, label="Maintenance Window", - help_text=mark_safe( - "<b>*Note:</b> Day of the week and a time of the day, 0 = Sunday , 1 = monday. Format 0-00:00", - ), - ) - - 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 = VirtualMachineMaintenance.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 = VirtualMachineMaintenance - fields = ( 'virtual_machine','maintenance_window','tags') - - def clean_virtual_machine(self): - - virtual_machine = self.cleaned_data.get("virtual_machine") - - virtual_machine_ct = ContentType.objects.get_for_model(VirtualMachine) - - if VirtualMachineMaintenance.objects.filter( - assigned_object_type=virtual_machine_ct, - assigned_object_id=virtual_machine.id - ).exclude(pk=self.instance.pk).exists(): - raise ValidationError() - return virtual_machine - - - - def clean(self): - """ - Validates form inputs before submitting: - """ - super().clean() - - if self.errors.get("maintenance_window"): - return - - virtual_machine = self.cleaned_data.get("virtual_machine") - - #Check if VM is assigned corretly - if (not virtual_machine): - raise ValidationError( - {"__all__": "A Virtual Machine needs to be associated with the maintenance window"}, - ) - - - - def save(self, *args, **kwargs): - # Set assigned object - self.instance.assigned_object = ( - self.cleaned_data.get("virtual_machine") - ) - return super().save(*args, **kwargs) - -class VmMaintenanceFilterForm(NetBoxModelFilterSetForm): - """MacAddress filter form definition class""" - - model = VirtualMachineMaintenance \ No newline at end of file diff --git a/netbox_sys_plugin/migrations/0003_virtualmachinetype.py b/netbox_sys_plugin/migrations/0003_virtualmachinetype.py index d7d0a5c..c7e67e7 100644 --- a/netbox_sys_plugin/migrations/0003_virtualmachinetype.py +++ b/netbox_sys_plugin/migrations/0003_virtualmachinetype.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2024-11-18 17:19 +# Generated by Django 4.2.16 on 2024-11-19 15:30 from django.db import migrations, models import django.db.models.deletion @@ -25,7 +25,7 @@ class Migration(migrations.Migration): ('virtual_machine_type_name', models.CharField(blank=True, default=None, max_length=50, null=True)), ('virtual_machine_type_desc', models.CharField(blank=True, default=None, max_length=100, 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', 'virtualization'), ('model', 'ClusterType'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), + ('assigned_object_type', 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')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ diff --git a/netbox_sys_plugin/models/__init__.py b/netbox_sys_plugin/models/__init__.py index da5e1b1..d300513 100644 --- a/netbox_sys_plugin/models/__init__.py +++ b/netbox_sys_plugin/models/__init__.py @@ -1,5 +1,4 @@ """Models definitions""" -from .maintenance import VirtualMachineMaintenance from .provider import ProviderCredentials -from .machine import VirtualMachineType \ No newline at end of file +from .machine import VirtualMachineType, VirtualMachineMaintenance \ No newline at end of file diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index c3e510c..d2dd85c 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -10,15 +10,15 @@ from django.core.validators import ( from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType from django.db import models -from virtualization.models import ClusterType +from virtualization.models import VirtualMachine from netbox.models import NetBoxModel -CLUSTERTYPE_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="ClusterType")) +VM_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="VirtualMachine")) class VirtualMachineType(NetBoxModel): - """Cluster ProviderInfo definition class""" + """Virtual Machine Type Info definition class""" virtual_machine_type_name = models.CharField( default=None, blank=True, null=True, @@ -31,7 +31,7 @@ class VirtualMachineType(NetBoxModel): assigned_object_type = models.ForeignKey( to=ContentType, - limit_choices_to=CLUSTERTYPE_ASSIGNMENT_MODELS, + limit_choices_to=VM_ASSIGNMENT_MODELS, on_delete=models.PROTECT, null=True, blank=True, @@ -51,7 +51,7 @@ class VirtualMachineType(NetBoxModel): def __str__(self): - return f"for Cluster Type ID {self.assigned_object_id}" + return f"For Virtual machine ID {self.assigned_object_id}" def get_absolute_url(self): """override""" @@ -61,6 +61,55 @@ GenericRelation( to=VirtualMachineType, content_type_field="assigned_object_type", object_id_field="assigned_object_id", - related_query_name="ClusterType", -).contribute_to_class(ClusterType, "VirtualMachineType") + related_query_name="VirtualMachine", +).contribute_to_class(VirtualMachine, "VirtualMachineType") + +class VirtualMachineMaintenance(NetBoxModel): + """virtual machine maintenance definition class""" + + maintenance_window = models.CharField( + default=None, blank=True, null=True, + max_length=200, + validators=[ + RegexValidator( + regex='(^([0-6])-[0-1]?[0-9]|2[0-3]):[0-5][0-9]$', + message='Incorrect maintenance window format', + ), + ], + ) + + 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 = "Maintenance Information" + verbose_name_plural = "Maintenance Informations" + + + def __str__(self): + return f"For Virtual machine ID {self.assigned_object_id}" + + def get_absolute_url(self): + """override""" + return reverse("plugins:netbox_sys_plugin:virtualmachinemaintenance", args=[self.pk]) + +GenericRelation( + to=VirtualMachineMaintenance, + content_type_field="assigned_object_type", + object_id_field="assigned_object_id", + related_query_name="VirtualMachine", +).contribute_to_class(VirtualMachine, "VirtualMachineMaintenance") diff --git a/netbox_sys_plugin/models/maintenance.py b/netbox_sys_plugin/models/maintenance.py deleted file mode 100644 index 53e1a81..0000000 --- a/netbox_sys_plugin/models/maintenance.py +++ /dev/null @@ -1,66 +0,0 @@ -"""Models definitions""" - -from django.core.validators import ( - RegexValidator, -) -from django.urls import reverse -from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation -from django.contrib.contenttypes.models import ContentType -from django.db import models -from django.db.models import Q -from virtualization.models import VirtualMachine -from netbox.models import NetBoxModel - -MAINT_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="VirtualMachine")) - - - -class VirtualMachineMaintenance(NetBoxModel): - """virtual machine maintenance definition class""" - - maintenance_window = models.CharField( - default=None, blank=True, null=True, - max_length=200, - validators=[ - RegexValidator( - regex='(^([0-6])-[0-1]?[0-9]|2[0-3]):[0-5][0-9]$', - message='Incorrect maintenance window format', - ), - ], - ) - - assigned_object_type = models.ForeignKey( - to=ContentType, - limit_choices_to=MAINT_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 = "Maintenance Information" - verbose_name_plural = "Maintenance Informations" - - - def __str__(self): - return f"For Virtual machine ID {self.assigned_object_id}" - - def get_absolute_url(self): - """override""" - return reverse("plugins:netbox_sys_plugin:virtualmachinemaintenance", args=[self.pk]) - -GenericRelation( - to=VirtualMachineMaintenance, - content_type_field="assigned_object_type", - object_id_field="assigned_object_id", - related_query_name="VirtualMachine", -).contribute_to_class(VirtualMachine, "VirtualMachineMaintenance") - diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index c105859..a2db5e9 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -1,7 +1,10 @@ """Navigation Menu definitions""" +from django.utils.translation import gettext as _ from extras.plugins import PluginMenuButton, PluginMenuItem, PluginMenu +from netbox.registry import registry from utilities.choices import ButtonColorChoices +from . import * #Buttons vm_maintenance_buttons = [ @@ -10,6 +13,7 @@ vm_maintenance_buttons = [ title="Add", icon_class="mdi mdi-plus-thick", color=ButtonColorChoices.GREEN, + permissions=["netbox_sys_plugin.add_maintenance"], ), ] @@ -19,40 +23,40 @@ cluster_provider_credentials_buttons = [ title="Add", icon_class="mdi mdi-plus-thick", color=ButtonColorChoices.GREEN, + permissions=["netbox_sys_plugin.add_providercredentials"], ), ] -clutertype_machine_type_buttons = [ +vm_machine_type_buttons = [ PluginMenuButton( link="plugins:netbox_sys_plugin:virtualmachinetype_add", title="Add", icon_class="mdi mdi-plus-thick", color=ButtonColorChoices.GREEN, + permissions=["netbox_sys_plugin.add_machinetype"], ), ] #Items -vmMaintenanceItem = [ - PluginMenuItem( - link="plugins:netbox_sys_plugin:virtualmachinemaintenance_list", - link_text="Virtual Machine Maintenance", - buttons=vm_maintenance_buttons, - ), -] clusterProviderCredentialsItem = [ PluginMenuItem( link="plugins:netbox_sys_plugin:providercredentials_list", - link_text="Provider Credentials", + link_text="Credentials", buttons=cluster_provider_credentials_buttons, ), ] -clusterTypeMachineTypeItem = [ +vmMachineItem = [ PluginMenuItem( link="plugins:netbox_sys_plugin:virtualmachinetype_list", - link_text="Machine Type", - buttons=clutertype_machine_type_buttons, + link_text="Type", + buttons=vm_machine_type_buttons, + ), + PluginMenuItem( + link="plugins:netbox_sys_plugin:virtualmachinemaintenance_list", + link_text="Maintenance", + buttons=vm_maintenance_buttons, ), ] @@ -60,9 +64,8 @@ clusterTypeMachineTypeItem = [ menu = PluginMenu( label="Sys", groups=( - ("Maintenance", vmMaintenanceItem), + ("Virtual Machine", (vmMachineItem)), ("Provider", clusterProviderCredentialsItem), - ("Machine", clusterTypeMachineTypeItem), ), icon_class="mdi mdi-all-inclusive-box-outline", -) +) \ No newline at end of file diff --git a/netbox_sys_plugin/tables.py b/netbox_sys_plugin/tables.py index 8cb536b..2385d86 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -47,7 +47,7 @@ class ProviderCredentialsTable(NetBoxTable): assigned_object = tables.Column( linkify=True, orderable=False, - verbose_name="Cluster", + verbose_name="Virtual Machine", ) provider_url = tables.Column( @@ -80,7 +80,7 @@ class ProviderCredentialsTable(NetBoxTable): default_columns = ('id','provider_url','provider_username','provider_password_vault_url','assigned_object') -#ProviderCredentials +#VmType class VmTypeTable(NetBoxTable): """VM Maintenance Table definition class""" @@ -92,16 +92,16 @@ class VmTypeTable(NetBoxTable): assigned_object = tables.Column( linkify=True, orderable=False, - verbose_name="Cluster Type", + verbose_name="Virtual Machine", ) virtual_machine_type_name = tables.Column( linkify=True, - verbose_name="Machine Type Name", + verbose_name="Type Name", ) virtual_machine_type_desc = tables.Column( - linkify=True, - verbose_name="Machine Type Descritpion", + linkify=False, + verbose_name="Type Description", ) class Meta(NetBoxTable.Meta): diff --git a/netbox_sys_plugin/template_content.py b/netbox_sys_plugin/template_content.py index d23d99b..4260247 100644 --- a/netbox_sys_plugin/template_content.py +++ b/netbox_sys_plugin/template_content.py @@ -4,13 +4,16 @@ from extras.plugins import PluginTemplateExtension from netbox_sys_plugin import models -class VmMaintenanceTable(PluginTemplateExtension): +class VmTable(PluginTemplateExtension): """VM Maintenance object template""" model = 'virtualization.virtualmachine' def left_page(self): - return self.render('netbox_sys_plugin/vm_vmmaintenance_table.html', extra_context={'vmmaintenanceinfo': models.VirtualMachineMaintenance.objects.filter(VirtualMachine=self.context['object'])}) + return self.render('netbox_sys_plugin/vm_vmmaintenance.html', extra_context={'vmmaintenanceinfo': models.VirtualMachineMaintenance.objects.filter(VirtualMachine=self.context['object'])}) + + def right_page(self): + return self.render('netbox_sys_plugin/vm_virtualmachinetype.html', extra_context={'vmtypeinfo': models.VirtualMachineType.objects.filter(VirtualMachine=self.context['object'])}) class ProviderCredentialsTable(PluginTemplateExtension): """Provider Credentials object template""" @@ -21,4 +24,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 = [VmMaintenanceTable,ProviderCredentialsTable] +template_extensions = [VmTable,ProviderCredentialsTable] diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html index ee2c51d..e7a8e89 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html @@ -1,5 +1,9 @@ {% extends 'generic/object.html' %} +{% block title%} +Virtual Machine Type for {{ object.assigned_object }} +{% endblock title%} + {% block content %} <div class="row mb-3"> <div class="col col-md-6"> diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/vm_virtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_virtualmachinetype.html new file mode 100644 index 0000000..dbf759f --- /dev/null +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_virtualmachinetype.html @@ -0,0 +1,41 @@ +{% block content %} + <div class="row mb-3"> + <div class="col col-md-12"> + <div class="card"> + <h5 class="card-header">Virtual Machine Type</h5> + <div class="card-body"> + <table class="table table-responsive"> + <th scope="row">ID</th> + <th scope="row">Type</th> + <th scope="row">Description</th> + {% for vmtype in vmtypeinfo %} + <tr> + <td>{{ vmtype.id }}</td> + <td> + {% if vmtype.virtual_machine_type_name %} + <a href="{{ vmtype.get_absolute_url }}">{{ vmtype.virtual_machine_type_name }}</a> + {% else %} + {{ ''|placeholder }} + {% endif %} + </td> + <td> + {% if vmtype.virtual_machine_type_desc %} + {{ vmtype.virtual_machine_type_desc }} + {% else %} + {{ ''|placeholder }} + {% endif %} + </td> + </tr> + {% empty %} + <tr> + <td colspan="3">No maintenance window 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/templates/netbox_sys_plugin/vm_vmmaintenance_table.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmmaintenance.html similarity index 100% rename from netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmmaintenance_table.html rename to netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmmaintenance.html diff --git a/netbox_sys_plugin/views.py b/netbox_sys_plugin/views.py index e346a1b..fe34158 100644 --- a/netbox_sys_plugin/views.py +++ b/netbox_sys_plugin/views.py @@ -72,8 +72,8 @@ class VmTypeListView(generic.ObjectListView): queryset = models.VirtualMachineType.objects.all() table = tables.VmTypeTable - #filterset = filtersets.ProviderCredentialsFilterSet - #filterset_form = forms.VmTypeFilterForm + filterset = filtersets.VmTypeFilterSet + filterset_form = forms.VmTypeFilterForm class VmTypeDeleteView(generic.ObjectDeleteView): """Vm maintenance delete view definition""" -- GitLab From a7acde89a364486882bdbe96665c03a8c1d228e6 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 19 Nov 2024 15:46:31 +0000 Subject: [PATCH 04/11] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20Typo=20in=20ta?= =?UTF-8?q?ble?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/tables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_sys_plugin/tables.py b/netbox_sys_plugin/tables.py index 2385d86..07a313d 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -47,7 +47,7 @@ class ProviderCredentialsTable(NetBoxTable): assigned_object = tables.Column( linkify=True, orderable=False, - verbose_name="Virtual Machine", + verbose_name="Cluster", ) provider_url = tables.Column( -- GitLab From 7058f5232ed4b84656ef85806228fe2003936d91 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 19 Nov 2024 16:09:05 +0000 Subject: [PATCH 05/11] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20typo=20in=20cl?= =?UTF-8?q?ean?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/machine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py index e678197..645391a 100644 --- a/netbox_sys_plugin/forms/machine.py +++ b/netbox_sys_plugin/forms/machine.py @@ -56,7 +56,7 @@ class VmTypeForm(NetBoxModelForm): model = VirtualMachineType fields = ('virtual_machine','virtual_machine_type_name', 'virtual_machine_type_desc','tags') - def clean_cluster(self): + def clean_virtual_machine(self): virtual_machine = self.cleaned_data.get("virtual_machine") -- GitLab From c4914bb8a9c2b0c246319f034bdc642700a2a70a Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Wed, 20 Nov 2024 14:59:45 +0000 Subject: [PATCH 06/11] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=20Naming=20of=20obj?= =?UTF-8?q?ects=20changed=20and=20included=20Type=20Table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 23 ++++- netbox_sys_plugin/api/urls.py | 3 +- netbox_sys_plugin/api/views.py | 11 ++- netbox_sys_plugin/filtersets.py | 6 +- netbox_sys_plugin/forms/machine.py | 94 +++++++++++++++++-- ...dvirtualmachinetype_virtualmachinetype.py} | 24 ++++- ...lter_virtualmachinetype_unique_together.py | 17 ++++ netbox_sys_plugin/models/__init__.py | 4 +- netbox_sys_plugin/models/machine.py | 63 +++++++++++-- netbox_sys_plugin/navigation.py | 27 +++++- netbox_sys_plugin/tables.py | 42 ++++++++- netbox_sys_plugin/template_content.py | 2 +- ...l => vm_vmassignedvirtualmachinetype.html} | 0 .../vmassignedvirtualmachinetype.html | 48 ++++++++++ netbox_sys_plugin/urls.py | 13 ++- netbox_sys_plugin/views.py | 35 ++++++- 16 files changed, 372 insertions(+), 40 deletions(-) rename netbox_sys_plugin/migrations/{0003_virtualmachinetype.py => 0003_vmassignedvirtualmachinetype_virtualmachinetype.py} (55%) create mode 100644 netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py rename netbox_sys_plugin/templates/netbox_sys_plugin/{vm_virtualmachinetype.html => vm_vmassignedvirtualmachinetype.html} (100%) create mode 100644 netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index e4c45da..d180901 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers from virtualization.models import VirtualMachine, Cluster, ClusterType -from .. models import VirtualMachineMaintenance, ProviderCredentials,VirtualMachineType +from .. models import VirtualMachineMaintenance, ProviderCredentials,VmAssignedVirtualMachineType, VirtualMachineType from django.contrib.contenttypes.models import ContentType #Netbox Data Serializer @@ -14,6 +14,12 @@ class ClusterSerializer(serializers.ModelSerializer): model = Cluster fields = ['id', 'name'] +class ClusterTypeSerializer(serializers.ModelSerializer): + class Meta: + model = ClusterType + fields = ['id', 'name'] + + #Plugin Data Serializer class VirtualMachineMaintenanceSerializer(serializers.ModelSerializer): id = serializers.IntegerField(read_only=True) @@ -37,13 +43,24 @@ class ProviderCredentialsSerializer(serializers.ModelSerializer): #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' -class VirtualMachineTypeSerializer(serializers.ModelSerializer): +class VmAssignedVirtualMachineTypeSerializer(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 = VmAssignedVirtualMachineType + #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) + assigned_object_id = serializers.IntegerField(write_only=True) + assigned_object_type = serializers.CharField(write_only=True) + class Meta: model = VirtualMachineType #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] - fields = '__all__' \ No newline at end of file + fields = '__all__' diff --git a/netbox_sys_plugin/api/urls.py b/netbox_sys_plugin/api/urls.py index 8454336..95a045a 100644 --- a/netbox_sys_plugin/api/urls.py +++ b/netbox_sys_plugin/api/urls.py @@ -1,9 +1,10 @@ from rest_framework.routers import DefaultRouter -from .views import VirtualMachineMaintenanceViewSet, ProviderCredentialsViewSet, VirtualMachineTypeViewSet +from .views import VirtualMachineMaintenanceViewSet, ProviderCredentialsViewSet, VmAssignedVirtualMachineTypeViewSet, VirtualMachineTypeViewSet router = DefaultRouter() router.register(r'MaintenanceWindow', VirtualMachineMaintenanceViewSet) router.register(r'ProviderCredentials', ProviderCredentialsViewSet) +router.register(r'AssignedVmType', VmAssignedVirtualMachineTypeViewSet) router.register(r'VmType', VirtualMachineTypeViewSet) app_name = "netbox_sys_plugin" diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index 40331ea..9666730 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -1,8 +1,8 @@ from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.response import Response -from .. models import VirtualMachineMaintenance, ProviderCredentials, VirtualMachineType -from . serializers import VirtualMachineMaintenanceSerializer, ProviderCredentialsSerializer, VirtualMachineTypeSerializer +from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType +from . serializers import VirtualMachineMaintenanceSerializer, ProviderCredentialsSerializer, VmAssignedVirtualMachineTypeSerializer, VirtualMachineTypeSerializer class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): queryset = VirtualMachineMaintenance.objects.all() @@ -16,7 +16,12 @@ class ProviderCredentialsViewSet(viewsets.ModelViewSet): http_method_names = ["get", "post", "patch", "delete", "options"] +class VmAssignedVirtualMachineTypeViewSet(viewsets.ModelViewSet): + queryset = VmAssignedVirtualMachineType.objects.all() + serializer_class = VmAssignedVirtualMachineTypeSerializer + http_method_names = ["get", "post", "patch", "delete", "options"] + class VirtualMachineTypeViewSet(viewsets.ModelViewSet): queryset = VirtualMachineType.objects.all() serializer_class = VirtualMachineTypeSerializer - http_method_names = ["get", "post", "patch", "delete", "options"] \ No newline at end of file + http_method_names = ["get", "post", "patch", "delete", "options"] diff --git a/netbox_sys_plugin/filtersets.py b/netbox_sys_plugin/filtersets.py index 6dae0a4..fae3a5d 100644 --- a/netbox_sys_plugin/filtersets.py +++ b/netbox_sys_plugin/filtersets.py @@ -4,7 +4,7 @@ import django_filters from netbox.filtersets import NetBoxModelFilterSet from virtualization.models import VirtualMachine, Cluster from django.db.models import Q -from .models import VirtualMachineMaintenance, ProviderCredentials, VirtualMachineType +from .models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType class VmMaintenanceFilterSet(NetBoxModelFilterSet): @@ -29,7 +29,7 @@ class VmMaintenanceFilterSet(NetBoxModelFilterSet): return queryset return queryset.filter(Q(maintenance_window__icontains=value)) -class VmTypeFilterSet(NetBoxModelFilterSet): +class VmAssignedVmTypeFilterSet(NetBoxModelFilterSet): """VirtualMachineType filterset definition class""" virtualmachine = django_filters.ModelMultipleChoiceFilter( @@ -41,7 +41,7 @@ class VmTypeFilterSet(NetBoxModelFilterSet): class Meta: """Meta class""" - model = VirtualMachineType + model = VmAssignedVirtualMachineType fields = ('virtual_machine_type_name','virtual_machine_type_desc', 'virtualmachine') # pylint: disable=W0613 diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py index 645391a..71e36b2 100644 --- a/netbox_sys_plugin/forms/machine.py +++ b/netbox_sys_plugin/forms/machine.py @@ -1,6 +1,6 @@ """Forms definitions""" -from virtualization.models import VirtualMachine +from virtualization.models import VirtualMachine, ClusterType from django.contrib.contenttypes.models import ContentType from django.utils.translation import gettext_lazy as _ from django.core.exceptions import ValidationError @@ -11,9 +11,9 @@ from netbox.forms import ( NetBoxModelFilterSetForm, ) from utilities.forms.fields import DynamicModelChoiceField -from ..models import VirtualMachineType, VirtualMachineMaintenance +from ..models import VmAssignedVirtualMachineType, VirtualMachineMaintenance, VirtualMachineType -class VmTypeForm(NetBoxModelForm): +class VmAssignedVmTypeForm(NetBoxModelForm): """ GUI form to add or edit a Virtual Machine Type. """ @@ -46,14 +46,14 @@ class VmTypeForm(NetBoxModelForm): else: current_virtual_machine_id = None - assigned_virtual_machines = VirtualMachineType.objects.filter( + assigned_virtual_machines = VmAssignedVirtualMachineType.objects.filter( assigned_object_type=ContentType.objects.get_for_model(VirtualMachine) ).exclude(assigned_object_id=current_virtual_machine_id).values_list('assigned_object_id', flat=True) self.fields['virtual_machine'].queryset = VirtualMachine.objects.exclude(id__in=assigned_virtual_machines) class Meta: """Meta class""" - model = VirtualMachineType + model = VmAssignedVirtualMachineType fields = ('virtual_machine','virtual_machine_type_name', 'virtual_machine_type_desc','tags') def clean_virtual_machine(self): @@ -62,7 +62,7 @@ class VmTypeForm(NetBoxModelForm): virtual_machine_ct = ContentType.objects.get_for_model(VirtualMachine) - if VirtualMachineType.objects.filter( + if VmAssignedVirtualMachineType.objects.filter( assigned_object_type=virtual_machine_ct, assigned_object_id=virtual_machine.id ).exclude(pk=self.instance.pk).exists(): @@ -93,6 +93,88 @@ class VmTypeForm(NetBoxModelForm): ) return super().save(*args, **kwargs) +class VmAssignedVmTypeFilterForm(NetBoxModelFilterSetForm): + """Virtual Machine Type filter form definition class""" + + model = VmAssignedVirtualMachineType + +class VmTypeForm(NetBoxModelForm): + """ + GUI form to add or edit a Virtual Machine Type. + """ + + cluster_type = DynamicModelChoiceField( + queryset=ClusterType.objects.all(), required=True, label="Cluster Type" + ) + virtual_machine_type_name = forms.CharField( + max_length=200, min_length=1, required=True, label="Name" + ) + virtual_machine_type_desc = forms.CharField( + max_length=50, min_length=1, required=False, label="Description" + ) + + + def __init__(self, *args, **kwargs): + # Initialize helper selectors + instance = kwargs.get("instance") + initial = kwargs.get("initial", {}).copy() + if instance: + if isinstance(instance.assigned_object, ClusterType): + initial["cluster_type"] = instance.assigned_object + kwargs["initial"] = initial + super().__init__(*args, **kwargs) + + if instance: + current_cluster_type_id = instance.assigned_object.id if instance.assigned_object else None + else: + current_cluster_type_id = None + + assigned_cluster_types = VirtualMachineType.objects.filter( + assigned_object_type=ContentType.objects.get_for_model(ClusterType) + ).exclude(assigned_object_id=current_cluster_type_id).values_list('assigned_object_id', flat=True) + self.fields['cluster_type'].queryset = ClusterType.objects.exclude(id__in=assigned_cluster_types) + + class Meta: + """Meta class""" + model = VirtualMachineType + fields = ('cluster_type','virtual_machine_type_name', 'virtual_machine_type_desc','tags') + + def clean_cluster(self): + + cluster_type = self.cleaned_data.get("cluster_type") + + cluster_type_ct = ContentType.objects.get_for_model(ClusterType) + + if VirtualMachineType.objects.filter( + assigned_object_type=cluster_type_ct,assigned_object_id=cluster_type.id + ).exclude(pk=self.instance.pk).exists(): + raise ValidationError() + return cluster_type + + def clean(self): + """ + Validates form inputs before submitting: + """ + super().clean() + + if self.errors.get(f"virtual_machine_type_name"): + return + + cluster_type = self.cleaned_data.get("cluster_type") + + #Check if cluster is assigned corretly + if (not cluster_type): + raise ValidationError( + {"__all__": "A Virtual Machine Type needs to be associated with the Cluster Type"}, + ) + + def save(self, *args, **kwargs): + # Set assigned object + self.instance.assigned_object = ( + self.cleaned_data.get("cluster_type") + ) + return super().save(*args, **kwargs) + class VmTypeFilterForm(NetBoxModelFilterSetForm): """Virtual Machine Type filter form definition class""" diff --git a/netbox_sys_plugin/migrations/0003_virtualmachinetype.py b/netbox_sys_plugin/migrations/0003_vmassignedvirtualmachinetype_virtualmachinetype.py similarity index 55% rename from netbox_sys_plugin/migrations/0003_virtualmachinetype.py rename to netbox_sys_plugin/migrations/0003_vmassignedvirtualmachinetype_virtualmachinetype.py index c7e67e7..c35fd43 100644 --- a/netbox_sys_plugin/migrations/0003_virtualmachinetype.py +++ b/netbox_sys_plugin/migrations/0003_vmassignedvirtualmachinetype_virtualmachinetype.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2024-11-19 15:30 +# Generated by Django 4.2.16 on 2024-11-20 14:43 from django.db import migrations, models import django.db.models.deletion @@ -16,7 +16,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='VirtualMachineType', + name='VmAssignedVirtualMachineType', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), @@ -28,6 +28,26 @@ class Migration(migrations.Migration): ('assigned_object_type', 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')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], + options={ + 'verbose_name': 'Assigned Machine Type', + 'verbose_name_plural': 'Assigned Machine Types', + 'ordering': ['assigned_object_id'], + 'unique_together': {('assigned_object_id',)}, + }, + ), + migrations.CreateModel( + name='VirtualMachineType', + 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)), + ('virtual_machine_type_name', models.CharField(blank=True, default=None, max_length=50, null=True)), + ('virtual_machine_type_desc', models.CharField(blank=True, default=None, max_length=100, 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', 'virtualization'), ('model', 'ClusterType'))), 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': 'Machine Type', 'verbose_name_plural': 'Machine Types', diff --git a/netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py b/netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py new file mode 100644 index 0000000..1d662ad --- /dev/null +++ b/netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.16 on 2024-11-20 14:54 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0003_vmassignedvirtualmachinetype_virtualmachinetype'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='virtualmachinetype', + unique_together={('assigned_object_id', 'virtual_machine_type_name')}, + ), + ] diff --git a/netbox_sys_plugin/models/__init__.py b/netbox_sys_plugin/models/__init__.py index d300513..bf52380 100644 --- a/netbox_sys_plugin/models/__init__.py +++ b/netbox_sys_plugin/models/__init__.py @@ -1,4 +1,4 @@ """Models definitions""" -from .provider import ProviderCredentials -from .machine import VirtualMachineType, VirtualMachineMaintenance \ No newline at end of file +from .provider import * +from .machine import * \ No newline at end of file diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index d2dd85c..310d3c2 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -10,14 +10,62 @@ from django.core.validators import ( from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType from django.db import models -from virtualization.models import VirtualMachine +from virtualization.models import VirtualMachine, ClusterType from netbox.models import NetBoxModel VM_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="VirtualMachine")) +CLUSTERTYPE_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="ClusterType")) +#VM Type +class VirtualMachineType(NetBoxModel): + """Cluster ProviderInfo definition class""" + virtual_machine_type_name = models.CharField( + default=None, blank=True, null=True, + max_length=50, + ) + + virtual_machine_type_desc = models.CharField( + default=None, blank=True, null=True, + max_length=100) -class VirtualMachineType(NetBoxModel): + assigned_object_type = models.ForeignKey( + to=ContentType, + limit_choices_to=CLUSTERTYPE_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","virtual_machine_type_name"] + ordering = ["assigned_object_id"] + verbose_name = "Machine Type" + verbose_name_plural = "Machine Types" + + + def __str__(self): + return f"for Cluster Type ID {self.assigned_object_id}" + + def get_absolute_url(self): + """override""" + return reverse("plugins:netbox_sys_plugin:virtualmachinetype", args=[self.pk]) + +GenericRelation( + to=VirtualMachineType, + content_type_field="assigned_object_type", + object_id_field="assigned_object_id", + related_query_name="ClusterType", +).contribute_to_class(ClusterType, "VirtualMachineType") + +#VM Assigned Type +class VmAssignedVirtualMachineType(NetBoxModel): """Virtual Machine Type Info definition class""" virtual_machine_type_name = models.CharField( @@ -46,8 +94,8 @@ class VirtualMachineType(NetBoxModel): """Meta class""" unique_together = ["assigned_object_id"] ordering = ["assigned_object_id"] - verbose_name = "Machine Type" - verbose_name_plural = "Machine Types" + verbose_name = "Assigned Machine Type" + verbose_name_plural = "Assigned Machine Types" def __str__(self): @@ -55,15 +103,16 @@ class VirtualMachineType(NetBoxModel): def get_absolute_url(self): """override""" - return reverse("plugins:netbox_sys_plugin:virtualmachinetype", args=[self.pk]) + return reverse("plugins:netbox_sys_plugin:vmassignedvirtualmachinetype", args=[self.pk]) GenericRelation( - to=VirtualMachineType, + to=VmAssignedVirtualMachineType, content_type_field="assigned_object_type", object_id_field="assigned_object_id", related_query_name="VirtualMachine", -).contribute_to_class(VirtualMachine, "VirtualMachineType") +).contribute_to_class(VirtualMachine, "VmAssignedVirtualMachineType") +#VM Maintenance class VirtualMachineMaintenance(NetBoxModel): """virtual machine maintenance definition class""" diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index a2db5e9..c9e7582 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -27,13 +27,23 @@ cluster_provider_credentials_buttons = [ ), ] +vm_assigned_machine_type_buttons = [ + PluginMenuButton( + link="plugins:netbox_sys_plugin:vmassignedvirtualmachinetype_add", + title="Add", + icon_class="mdi mdi-plus-thick", + color=ButtonColorChoices.GREEN, + permissions=["netbox_sys_plugin.add_vmassignedmachinetype"], + ), +] + vm_machine_type_buttons = [ PluginMenuButton( link="plugins:netbox_sys_plugin:virtualmachinetype_add", title="Add", icon_class="mdi mdi-plus-thick", color=ButtonColorChoices.GREEN, - permissions=["netbox_sys_plugin.add_machinetype"], + permissions=["netbox_sys_plugin.add_vmmachinetype"], ), ] @@ -49,9 +59,9 @@ clusterProviderCredentialsItem = [ vmMachineItem = [ PluginMenuItem( - link="plugins:netbox_sys_plugin:virtualmachinetype_list", - link_text="Type", - buttons=vm_machine_type_buttons, + link="plugins:netbox_sys_plugin:vmassignedvirtualmachinetype_list", + link_text="Type Assignment", + buttons=vm_assigned_machine_type_buttons, ), PluginMenuItem( link="plugins:netbox_sys_plugin:virtualmachinemaintenance_list", @@ -60,12 +70,21 @@ vmMachineItem = [ ), ] +operItem =[ + PluginMenuItem( + link="plugins:netbox_sys_plugin:virtualmachinetype_list", + link_text="Virtual Machine Types", + buttons=vm_machine_type_buttons, + ), + +] #Menu menu = PluginMenu( label="Sys", groups=( ("Virtual Machine", (vmMachineItem)), ("Provider", clusterProviderCredentialsItem), + ("Operation", (operItem)), ), icon_class="mdi mdi-all-inclusive-box-outline", ) \ No newline at end of file diff --git a/netbox_sys_plugin/tables.py b/netbox_sys_plugin/tables.py index 07a313d..4d4b80a 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -2,7 +2,7 @@ import django_tables2 as tables from netbox.tables import NetBoxTable, columns -from .models import VirtualMachineMaintenance, ProviderCredentials, VirtualMachineType +from .models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType #VmMaintenance class VmMaintenanceTable(NetBoxTable): @@ -80,8 +80,8 @@ class ProviderCredentialsTable(NetBoxTable): default_columns = ('id','provider_url','provider_username','provider_password_vault_url','assigned_object') -#VmType -class VmTypeTable(NetBoxTable): +#VmAssignedType +class VmAssignedVmTypeTable(NetBoxTable): """VM Maintenance Table definition class""" pk = columns.ToggleColumn() @@ -104,6 +104,42 @@ class VmTypeTable(NetBoxTable): verbose_name="Type Description", ) + class Meta(NetBoxTable.Meta): + """Meta class""" + model = VmAssignedVirtualMachineType + fields = ( + "pk", + "id", + "virtual_machine_type_name", + "virtual_machine_type_desc", + ) + + default_columns = ('id','virtual_machine_type_name','virtual_machine_type_desc','assigned_object') + +#VmType +class VmTypeTable(NetBoxTable): + """VM Maintenance Table definition class""" + + pk = columns.ToggleColumn() + id = tables.Column( + linkify=False, + ) + + assigned_object = tables.Column( + linkify=True, + orderable=False, + verbose_name="Cluster Type", + ) + + virtual_machine_type_name = tables.Column( + linkify=True, + verbose_name="Machine Type Name", + ) + virtual_machine_type_desc = tables.Column( + linkify=True, + verbose_name="Machine Type Descritpion", + ) + class Meta(NetBoxTable.Meta): """Meta class""" model = VirtualMachineType diff --git a/netbox_sys_plugin/template_content.py b/netbox_sys_plugin/template_content.py index 4260247..f390d53 100644 --- a/netbox_sys_plugin/template_content.py +++ b/netbox_sys_plugin/template_content.py @@ -13,7 +13,7 @@ class VmTable(PluginTemplateExtension): return self.render('netbox_sys_plugin/vm_vmmaintenance.html', extra_context={'vmmaintenanceinfo': models.VirtualMachineMaintenance.objects.filter(VirtualMachine=self.context['object'])}) def right_page(self): - return self.render('netbox_sys_plugin/vm_virtualmachinetype.html', extra_context={'vmtypeinfo': models.VirtualMachineType.objects.filter(VirtualMachine=self.context['object'])}) + return self.render('netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html', extra_context={'vmtypeinfo': models.VmAssignedVirtualMachineType.objects.filter(VirtualMachine=self.context['object'])}) class ProviderCredentialsTable(PluginTemplateExtension): """Provider Credentials object template""" diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/vm_virtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html similarity index 100% rename from netbox_sys_plugin/templates/netbox_sys_plugin/vm_virtualmachinetype.html rename to netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html new file mode 100644 index 0000000..e7a8e89 --- /dev/null +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html @@ -0,0 +1,48 @@ +{% extends 'generic/object.html' %} + +{% block title%} +Virtual Machine Type for {{ object.assigned_object }} +{% endblock title%} + +{% block content %} +<div class="row mb-3"> + <div class="col col-md-6"> + <div class="card"> + <h5 class="card-header">Virtual Machine Types</h5> + <div class="card-body"> + <table class="table table-hover attr-table"> + <tr> + <th scope="row">Name</th> + <td>{{ object.virtual_machine_type_name }}</td> + </tr> + <tr> + <th scope="row">Description</th> + <td>{{ object.virtual_machine_type_desc }}</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">Assigned Object</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/urls.py b/netbox_sys_plugin/urls.py index ac9e61f..94b7d55 100644 --- a/netbox_sys_plugin/urls.py +++ b/netbox_sys_plugin/urls.py @@ -19,8 +19,16 @@ urlpatterns = ( path('provider-credentials/add/', views.ProviderCredentialsEditView.as_view(), name='providercredentials_add'), path('provider-credentials/<int:pk>/edit/', views.ProviderCredentialsEditView.as_view(), name='providercredentials_edit'), path('provider-credentials/<int:pk>/delete/', views.ProviderCredentialsDeleteView.as_view(), name='providercredentials_delete'), - path('provider-credentials/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providercredentials_changelog', kwargs={'model': models.VirtualMachineMaintenance}), - path('provider-credentials/<int:pk>/journal/', ObjectJournalView.as_view(), name='providercredentials_journal', kwargs={'model': models.VirtualMachineMaintenance}), + path('provider-credentials/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providercredentials_changelog', kwargs={'model': models.ProviderCredentials}), + path('provider-credentials/<int:pk>/journal/', ObjectJournalView.as_view(), name='providercredentials_journal', kwargs={'model': models.ProviderCredentials}), + #virtualMachineAssignedType + path('vm-assigned-type/<int:pk>/', views.VmAssignedVmTypeView.as_view(), name='vmassignedvirtualmachinetype'), + path('vm-assigned-type/', views.VmAssignedVmTypeListView.as_view(), name='vmassignedvirtualmachinetype_list'), + path('vm-assigned-type/add/', views.VmAssignedVmTypeEditView.as_view(), name='vmassignedvirtualmachinetype_add'), + path('vm-assigned-type/<int:pk>/edit/', views.VmAssignedVmTypeEditView.as_view(), name='vmassignedvirtualmachinetype_edit'), + path('vm-assigned-type/<int:pk>/delete/', views.VmAssignedVmTypeDeleteView.as_view(), name='vmassignedvirtualmachinetype_delete'), + path('vm-assigned-type/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='vmassignedvirtualmachinetype_changelog', kwargs={'model': models.VmAssignedVirtualMachineType}), + path('vm-assigned-type/<int:pk>/journal/', ObjectJournalView.as_view(), name='vmassignedvirtualmachinetype_journal', kwargs={'model': models.VmAssignedVirtualMachineType}), #virtualMachineType path('vm-type/<int:pk>/', views.VmTypeView.as_view(), name='virtualmachinetype'), path('vm-type/', views.VmTypeListView.as_view(), name='virtualmachinetype_list'), @@ -31,4 +39,5 @@ urlpatterns = ( path('vm-type/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinetype_journal', kwargs={'model': models.VirtualMachineType}), + ) diff --git a/netbox_sys_plugin/views.py b/netbox_sys_plugin/views.py index fe34158..123e31e 100644 --- a/netbox_sys_plugin/views.py +++ b/netbox_sys_plugin/views.py @@ -59,6 +59,35 @@ class ProviderCredentialsEditView(generic.ObjectEditView): queryset = models.ProviderCredentials.objects.all() form = forms.ProviderCredentialsForm +#VmAssignedType +class VmAssignedVmTypeView(generic.ObjectView): + """ Virtual Machine Type view definition""" + + queryset = ( + models.VmAssignedVirtualMachineType.objects.all() + ) + +class VmAssignedVmTypeListView(generic.ObjectListView): + """Cluster Type Virtual Machine Type list view definition""" + + queryset = models.VmAssignedVirtualMachineType.objects.all() + table = tables.VmAssignedVmTypeTable + filterset = filtersets.VmAssignedVmTypeFilterSet + filterset_form = forms.VmAssignedVmTypeFilterForm + +class VmAssignedVmTypeDeleteView(generic.ObjectDeleteView): + """Vm maintenance delete view definition""" + + queryset = models.VmAssignedVirtualMachineType.objects.all() + +class VmAssignedVmTypeEditView(generic.ObjectEditView): + """ + Defines the edit view for the Vm maintenance django model. + """ + queryset = models.VmAssignedVirtualMachineType.objects.all() + form = forms.VmAssignedVmTypeForm + + #VmType class VmTypeView(generic.ObjectView): """ Virtual Machine Type view definition""" @@ -72,8 +101,8 @@ class VmTypeListView(generic.ObjectListView): queryset = models.VirtualMachineType.objects.all() table = tables.VmTypeTable - filterset = filtersets.VmTypeFilterSet - filterset_form = forms.VmTypeFilterForm + #filterset = filtersets.VmTypeFilterSet + #filterset_form = forms.VmTypeFilterForm class VmTypeDeleteView(generic.ObjectDeleteView): """Vm maintenance delete view definition""" @@ -85,4 +114,4 @@ class VmTypeEditView(generic.ObjectEditView): Defines the edit view for the Vm maintenance django model. """ queryset = models.VirtualMachineType.objects.all() - form = forms.VmTypeForm \ No newline at end of file + form = forms.VmTypeForm -- GitLab From 3e2f5e8b09e495d21364003785c995a2a72e2f92 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Wed, 20 Nov 2024 16:54:28 +0000 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=9A=A7=20Fix=20Type=20table=20conne?= =?UTF-8?q?ction=20and=20fix=20UI=20elements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ox_sys_vm_assigned_virtual_machine_type.md | 11 ++++++ netbox_sys_plugin/filtersets.py | 2 +- netbox_sys_plugin/forms/machine.py | 34 ++++--------------- ...005_vmassignedvirtualmachinetype_vmtype.py | 20 +++++++++++ ...ignedvirtualmachinetype_vmtype_and_more.py | 24 +++++++++++++ ...machinetype_virtualmachinetype_and_more.py | 23 +++++++++++++ ..._virtual_machine_type_assignment_desc_a.py | 28 +++++++++++++++ netbox_sys_plugin/models/machine.py | 17 ++++++---- netbox_sys_plugin/tables.py | 21 ++++++------ .../cluster_providercredentials.html | 2 +- .../netbox_sys_plugin/virtualmachinetype.html | 2 +- .../vm_vmassignedvirtualmachinetype.html | 6 ++-- .../vmassignedvirtualmachinetype.html | 13 +++++-- 13 files changed, 149 insertions(+), 54 deletions(-) create mode 100644 docs/model/netbox_sys_vm_assigned_virtual_machine_type.md create mode 100644 netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py create mode 100644 netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py create mode 100644 netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py create mode 100644 netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py diff --git a/docs/model/netbox_sys_vm_assigned_virtual_machine_type.md b/docs/model/netbox_sys_vm_assigned_virtual_machine_type.md new file mode 100644 index 0000000..791b6da --- /dev/null +++ b/docs/model/netbox_sys_vm_assigned_virtual_machine_type.md @@ -0,0 +1,11 @@ +## netbox_sys_virtual_machine_type + +**Mapping Redirect definition class** + +| FIELD | TYPE | DESCRIPTION | +|------------------------------- |-----------------------------------|---------------------------------------------------------------------------| +| id | Big (8 byte) integer | Unique ID | +| assigned_object_type_id | Big (8 byte) integer | cluster type type ID | +| assigned_object_id | Big (8 byte) integer | cluster type unique ID | +| virtual_machine_type_assignment_id | String | Virtual Machine type ID (refers to the table virtual_machine_tye) | +| virtual_machine_type_assignment_desc | String | Virtual Machine type assignment description | \ No newline at end of file diff --git a/netbox_sys_plugin/filtersets.py b/netbox_sys_plugin/filtersets.py index fae3a5d..6574a70 100644 --- a/netbox_sys_plugin/filtersets.py +++ b/netbox_sys_plugin/filtersets.py @@ -42,7 +42,7 @@ class VmAssignedVmTypeFilterSet(NetBoxModelFilterSet): class Meta: """Meta class""" model = VmAssignedVirtualMachineType - fields = ('virtual_machine_type_name','virtual_machine_type_desc', 'virtualmachine') + fields = ('virtual_machine_type_name','virtual_machine_type_assignment_desc', 'virtualmachine') # pylint: disable=W0613 def search(self, queryset, name, value): diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py index 71e36b2..a936746 100644 --- a/netbox_sys_plugin/forms/machine.py +++ b/netbox_sys_plugin/forms/machine.py @@ -10,7 +10,7 @@ from netbox.forms import ( NetBoxModelForm, NetBoxModelFilterSetForm, ) -from utilities.forms.fields import DynamicModelChoiceField +from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField from ..models import VmAssignedVirtualMachineType, VirtualMachineMaintenance, VirtualMachineType class VmAssignedVmTypeForm(NetBoxModelForm): @@ -22,11 +22,12 @@ class VmAssignedVmTypeForm(NetBoxModelForm): queryset=VirtualMachine.objects.all(), required=True, label="Virtual Machine" ) - virtual_machine_type_name = forms.CharField( - max_length=200, min_length=1, required=True, label="Name" + virtual_machine_type_name = DynamicModelChoiceField( + queryset=VirtualMachineType.objects.all(), + required=True, label="Virtual Machine Type" ) - virtual_machine_type_desc = forms.CharField( + virtual_machine_type_assignment_desc = forms.CharField( max_length=50, min_length=1, required=False, label="Description" ) @@ -54,7 +55,7 @@ class VmAssignedVmTypeForm(NetBoxModelForm): class Meta: """Meta class""" model = VmAssignedVirtualMachineType - fields = ('virtual_machine','virtual_machine_type_name', 'virtual_machine_type_desc','tags') + fields = ('virtual_machine','virtual_machine_type_name', 'virtual_machine_type_assignment_desc','tags') def clean_virtual_machine(self): @@ -83,7 +84,7 @@ class VmAssignedVmTypeForm(NetBoxModelForm): #Check if VM is assigned corretly if (not virtual_machine): raise ValidationError( - {"__all__": "A Virtual Machine Type needs to be associated with the Virtual Machine"}, + {"__all__": "The virtual machine you picked already has a Type assigned"}, ) def save(self, *args, **kwargs): @@ -124,33 +125,12 @@ class VmTypeForm(NetBoxModelForm): kwargs["initial"] = initial super().__init__(*args, **kwargs) - if instance: - current_cluster_type_id = instance.assigned_object.id if instance.assigned_object else None - else: - current_cluster_type_id = None - - assigned_cluster_types = VirtualMachineType.objects.filter( - assigned_object_type=ContentType.objects.get_for_model(ClusterType) - ).exclude(assigned_object_id=current_cluster_type_id).values_list('assigned_object_id', flat=True) - self.fields['cluster_type'].queryset = ClusterType.objects.exclude(id__in=assigned_cluster_types) class Meta: """Meta class""" model = VirtualMachineType fields = ('cluster_type','virtual_machine_type_name', 'virtual_machine_type_desc','tags') - def clean_cluster(self): - - cluster_type = self.cleaned_data.get("cluster_type") - - cluster_type_ct = ContentType.objects.get_for_model(ClusterType) - - if VirtualMachineType.objects.filter( - assigned_object_type=cluster_type_ct,assigned_object_id=cluster_type.id - ).exclude(pk=self.instance.pk).exists(): - raise ValidationError() - return cluster_type - def clean(self): """ Validates form inputs before submitting: diff --git a/netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py b/netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py new file mode 100644 index 0000000..de15b2e --- /dev/null +++ b/netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.16 on 2024-11-20 15:07 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0004_alter_virtualmachinetype_unique_together'), + ] + + operations = [ + migrations.AddField( + model_name='vmassignedvirtualmachinetype', + name='vmtype', + field=models.OneToOneField(db_column='vm_type_id', default=0, on_delete=django.db.models.deletion.CASCADE, related_name='vmtype', to='netbox_sys_plugin.virtualmachinetype'), + preserve_default=False, + ), + ] diff --git a/netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py b/netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py new file mode 100644 index 0000000..c038afe --- /dev/null +++ b/netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.16 on 2024-11-20 15:19 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0005_vmassignedvirtualmachinetype_vmtype'), + ] + + operations = [ + migrations.RemoveField( + model_name='vmassignedvirtualmachinetype', + name='vmtype', + ), + migrations.AddField( + model_name='vmassignedvirtualmachinetype', + name='VirtualMachineType', + field=models.OneToOneField(db_column='virtual_machine_type_id', default=0, on_delete=django.db.models.deletion.CASCADE, related_name='VirtualMachineType', to='netbox_sys_plugin.virtualmachinetype'), + preserve_default=False, + ), + ] diff --git a/netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py b/netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py new file mode 100644 index 0000000..cc3e70f --- /dev/null +++ b/netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.16 on 2024-11-20 15:30 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0006_remove_vmassignedvirtualmachinetype_vmtype_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='vmassignedvirtualmachinetype', + name='VirtualMachineType', + ), + migrations.AddField( + model_name='vmassignedvirtualmachinetype', + name='virtual_machine_type_id', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_vm_types', to='netbox_sys_plugin.virtualmachinetype'), + ), + ] diff --git a/netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py b/netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py new file mode 100644 index 0000000..bd812dd --- /dev/null +++ b/netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py @@ -0,0 +1,28 @@ +# Generated by Django 4.2.16 on 2024-11-20 16:16 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more'), + ] + + operations = [ + migrations.RenameField( + model_name='vmassignedvirtualmachinetype', + old_name='virtual_machine_type_desc', + new_name='virtual_machine_type_assignment_desc', + ), + migrations.RemoveField( + model_name='vmassignedvirtualmachinetype', + name='virtual_machine_type_id', + ), + migrations.AlterField( + model_name='vmassignedvirtualmachinetype', + name='virtual_machine_type_name', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype'), + ), + ] diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index 310d3c2..66aef0c 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -51,7 +51,7 @@ class VirtualMachineType(NetBoxModel): def __str__(self): - return f"for Cluster Type ID {self.assigned_object_id}" + return self.virtual_machine_type_name or f"for Cluster Type ID {self.assigned_object_id}" def get_absolute_url(self): """override""" @@ -67,13 +67,16 @@ GenericRelation( #VM Assigned Type class VmAssignedVirtualMachineType(NetBoxModel): """Virtual Machine Type Info definition class""" - - virtual_machine_type_name = models.CharField( - default=None, blank=True, null=True, - max_length=50, - ) + + virtual_machine_type_name = models.ForeignKey( + to="VirtualMachineType", + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name="assigned_vm_type" + ) - virtual_machine_type_desc = models.CharField( + virtual_machine_type_assignment_desc = models.CharField( default=None, blank=True, null=True, max_length=100) diff --git a/netbox_sys_plugin/tables.py b/netbox_sys_plugin/tables.py index 4d4b80a..bb9049b 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -86,7 +86,7 @@ class VmAssignedVmTypeTable(NetBoxTable): pk = columns.ToggleColumn() id = tables.Column( - linkify=False, + linkify=True, ) assigned_object = tables.Column( @@ -94,14 +94,13 @@ class VmAssignedVmTypeTable(NetBoxTable): orderable=False, verbose_name="Virtual Machine", ) - virtual_machine_type_name = tables.Column( linkify=True, - verbose_name="Type Name", + verbose_name="Virtual Machine Type", ) - virtual_machine_type_desc = tables.Column( + virtual_machine_type_assignment_desc = tables.Column( linkify=False, - verbose_name="Type Description", + verbose_name="Description", ) class Meta(NetBoxTable.Meta): @@ -111,10 +110,10 @@ class VmAssignedVmTypeTable(NetBoxTable): "pk", "id", "virtual_machine_type_name", - "virtual_machine_type_desc", + "virtual_machine_type_assignment_desc", ) - default_columns = ('id','virtual_machine_type_name','virtual_machine_type_desc','assigned_object') + default_columns = ('id','assigned_object','virtual_machine_type_name','virtual_machine_type_assignment_desc') #VmType class VmTypeTable(NetBoxTable): @@ -122,7 +121,7 @@ class VmTypeTable(NetBoxTable): pk = columns.ToggleColumn() id = tables.Column( - linkify=False, + linkify=True, ) assigned_object = tables.Column( @@ -133,11 +132,11 @@ class VmTypeTable(NetBoxTable): virtual_machine_type_name = tables.Column( linkify=True, - verbose_name="Machine Type Name", + verbose_name="Virtual Machine Type", ) virtual_machine_type_desc = tables.Column( linkify=True, - verbose_name="Machine Type Descritpion", + verbose_name="Descritpion", ) class Meta(NetBoxTable.Meta): @@ -150,4 +149,4 @@ class VmTypeTable(NetBoxTable): "virtual_machine_type_desc", ) - default_columns = ('id','virtual_machine_type_name','virtual_machine_type_desc','assigned_object') + default_columns = ('id','virtual_machine_type_name','assigned_object','virtual_machine_type_desc') diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/cluster_providercredentials.html b/netbox_sys_plugin/templates/netbox_sys_plugin/cluster_providercredentials.html index 82082e0..71616af 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/cluster_providercredentials.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/cluster_providercredentials.html @@ -34,7 +34,7 @@ </tr> {% empty %} <tr> - <td colspan="3">No maintenance window found.</td> + <td colspan="3">No Provider Credentials found.</td> </tr> {% endfor %} </tr> diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html index e7a8e89..c33372a 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/virtualmachinetype.html @@ -8,7 +8,7 @@ Virtual Machine Type for {{ object.assigned_object }} <div class="row mb-3"> <div class="col col-md-6"> <div class="card"> - <h5 class="card-header">Virtual Machine Types</h5> + <h5 class="card-header">Virtual Machine Type</h5> <div class="card-body"> <table class="table table-hover attr-table"> <tr> diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html index dbf759f..4154da8 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html @@ -19,8 +19,8 @@ {% endif %} </td> <td> - {% if vmtype.virtual_machine_type_desc %} - {{ vmtype.virtual_machine_type_desc }} + {% if vmtype.virtual_machine_type_assignment_desc %} + {{ vmtype.virtual_machine_type_assignment_desc }} {% else %} {{ ''|placeholder }} {% endif %} @@ -28,7 +28,7 @@ </tr> {% empty %} <tr> - <td colspan="3">No maintenance window found.</td> + <td colspan="3">Virtual Machine Types Found</td> </tr> {% endfor %} </tr> diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html index e7a8e89..aadce1c 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html @@ -8,16 +8,23 @@ Virtual Machine Type for {{ object.assigned_object }} <div class="row mb-3"> <div class="col col-md-6"> <div class="card"> - <h5 class="card-header">Virtual Machine Types</h5> + <h5 class="card-header">Virtual Machine Type Assignedment </h5> <div class="card-body"> <table class="table table-hover attr-table"> <tr> <th scope="row">Name</th> - <td>{{ object.virtual_machine_type_name }}</td> + <td> + {% if object.virtual_machine_type_name %} + <a href="{{ object.virtual_machine_type_name.get_absolute_url }}">{{ object.virtual_machine_type_name }}</a> + {% else %} + {{ ''|placeholder }} + {% endif %} + </td> </tr> + <tr> <th scope="row">Description</th> - <td>{{ object.virtual_machine_type_desc }}</td> + <td>{{ object.virtual_machine_type_assignment_desc }}</td> </tr> </table> </div> -- GitLab From 5c74e0935a10f135d3d1a4213cde9b2b1a8c3144 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 21 Nov 2024 15:54:27 +0000 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=8E=A8=20Improve=20structure=20and?= =?UTF-8?q?=20add=20validations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/machine.py | 99 +++++++------------ netbox_sys_plugin/forms/provider.py | 20 +--- ...type_virtual_machine_type_name_and_more.py | 25 +++++ ...almachinetype_virtual_machine_type_name.py | 19 ++++ netbox_sys_plugin/models/machine.py | 16 +-- 5 files changed, 90 insertions(+), 89 deletions(-) create mode 100644 netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py create mode 100644 netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py index a936746..d90b2f7 100644 --- a/netbox_sys_plugin/forms/machine.py +++ b/netbox_sys_plugin/forms/machine.py @@ -22,15 +22,6 @@ class VmAssignedVmTypeForm(NetBoxModelForm): queryset=VirtualMachine.objects.all(), required=True, label="Virtual Machine" ) - virtual_machine_type_name = DynamicModelChoiceField( - queryset=VirtualMachineType.objects.all(), - required=True, label="Virtual Machine Type" - ) - - virtual_machine_type_assignment_desc = forms.CharField( - max_length=50, min_length=1, required=False, label="Description" - ) - def __init__(self, *args, **kwargs): # Initialize helper selectors @@ -43,54 +34,42 @@ class VmAssignedVmTypeForm(NetBoxModelForm): super().__init__(*args, **kwargs) if instance: - current_virtual_machine_id = instance.assigned_object.id if instance.assigned_object else None + current_vm_id = instance.assigned_object.id if instance.assigned_object else None else: - current_virtual_machine_id = None + current_vm_id = None - assigned_virtual_machines = VmAssignedVirtualMachineType.objects.filter( + assigned_vms = VmAssignedVirtualMachineType.objects.filter( assigned_object_type=ContentType.objects.get_for_model(VirtualMachine) - ).exclude(assigned_object_id=current_virtual_machine_id).values_list('assigned_object_id', flat=True) - self.fields['virtual_machine'].queryset = VirtualMachine.objects.exclude(id__in=assigned_virtual_machines) + ).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 = VmAssignedVirtualMachineType fields = ('virtual_machine','virtual_machine_type_name', 'virtual_machine_type_assignment_desc','tags') - def clean_virtual_machine(self): - - virtual_machine = self.cleaned_data.get("virtual_machine") - - virtual_machine_ct = ContentType.objects.get_for_model(VirtualMachine) - - if VmAssignedVirtualMachineType.objects.filter( - assigned_object_type=virtual_machine_ct, - assigned_object_id=virtual_machine.id - ).exclude(pk=self.instance.pk).exists(): - raise ValidationError() - return virtual_machine - def clean(self): """ Validates form inputs before submitting: """ super().clean() - - if self.errors.get(f"virtual_machine_type_name"): - return - virtual_machine = self.cleaned_data.get("virtual_machine") + + vm = self.cleaned_data.get("virtual_machine") - #Check if VM is assigned corretly - if (not virtual_machine): + #Check if Virtual Machine is assigned corretly + if (not vm): raise ValidationError( - {"__all__": "The virtual machine you picked already has a Type assigned"}, + {"__all__": "Can't assign more than one Type 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") + self.cleaned_data.get("virtual_machine") ) return super().save(*args, **kwargs) @@ -137,22 +116,23 @@ class VmTypeForm(NetBoxModelForm): """ super().clean() - if self.errors.get(f"virtual_machine_type_name"): - return - + virtual_machine_type_name = self.cleaned_data.get("virtual_machine_type_name") cluster_type = self.cleaned_data.get("cluster_type") + cluster_type_ct = ContentType.objects.get_for_model(ClusterType) - #Check if cluster is assigned corretly - if (not cluster_type): + if VirtualMachineType.objects.filter( + virtual_machine_type_name =virtual_machine_type_name, + assigned_object_type=cluster_type_ct, + assigned_object_id=cluster_type.id + ).exclude(pk=self.instance.pk).exists(): raise ValidationError( - {"__all__": "A Virtual Machine Type needs to be associated with the Cluster Type"}, + {"__all__":"A Type with this name and cluster type already exists"} ) + def save(self, *args, **kwargs): # Set assigned object - self.instance.assigned_object = ( - self.cleaned_data.get("cluster_type") - ) + self.instance.assigned_object = self.cleaned_data.get("cluster_type") return super().save(*args, **kwargs) class VmTypeFilterForm(NetBoxModelFilterSetForm): @@ -199,37 +179,24 @@ class VmMaitenanceForm(NetBoxModelForm): model = VirtualMachineMaintenance fields = ( 'virtual_machine','maintenance_window','tags') - def clean_virtual_machine(self): - - virtual_machine = self.cleaned_data.get("virtual_machine") - - virtual_machine_ct = ContentType.objects.get_for_model(VirtualMachine) - - if VirtualMachineMaintenance.objects.filter( - assigned_object_type=virtual_machine_ct, - assigned_object_id=virtual_machine.id - ).exclude(pk=self.instance.pk).exists(): - raise ValidationError() - return virtual_machine - - def clean(self): """ Validates form inputs before submitting: """ super().clean() + + + vm = self.cleaned_data.get("virtual_machine") - if self.errors.get("maintenance_window"): - return - - virtual_machine = self.cleaned_data.get("virtual_machine") - - #Check if VM is assigned corretly - if (not virtual_machine): + #Check if Virtual Machine is assigned corretly + if (not vm): raise ValidationError( - {"__all__": "A Virtual Machine needs to be associated with the maintenance window"}, + {"__all__": "Can't assign more than one Maintenance Window to the same Virtual Machine"}, ) + + if self.errors.get("virtual_machine"): + return diff --git a/netbox_sys_plugin/forms/provider.py b/netbox_sys_plugin/forms/provider.py index 1909d38..ffd747c 100644 --- a/netbox_sys_plugin/forms/provider.py +++ b/netbox_sys_plugin/forms/provider.py @@ -55,18 +55,6 @@ class ProviderCredentialsForm(NetBoxModelForm): model = ProviderCredentials fields = ('cluster','provider_url', 'provider_username', 'provider_password_vault_url','tags') - def clean_cluster(self): - - cluster = self.cleaned_data.get("cluster") - - cluster_ct = ContentType.objects.get_for_model(Cluster) - - if ProviderCredentials.objects.filter( - assigned_object_type=cluster_ct, - assigned_object_id=cluster.id - ).exclude(pk=self.instance.pk).exists(): - raise ValidationError() - return cluster def clean(self): """ @@ -74,16 +62,18 @@ class ProviderCredentialsForm(NetBoxModelForm): """ super().clean() - if self.errors.get(f"provider_url"): - return + cluster = self.cleaned_data.get("cluster") #Check if cluster is assigned corretly if (not cluster): raise ValidationError( - {"__all__": "A Virtual Machine needs to be associated with the maintenance window"}, + {"__all__": "Can't assign more than one Credential to the same Cluster"}, ) + + if self.errors.get(f"provider_url"): + return def save(self, *args, **kwargs): # Set assigned object diff --git a/netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py b/netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py new file mode 100644 index 0000000..c70b7a7 --- /dev/null +++ b/netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.16 on 2024-11-21 12:24 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a'), + ] + + operations = [ + migrations.AlterField( + model_name='virtualmachinetype', + name='virtual_machine_type_name', + field=models.CharField(default=None, max_length=50), + ), + migrations.AlterField( + model_name='vmassignedvirtualmachinetype', + name='virtual_machine_type_name', + field=models.ForeignKey(blank=True, default=1, on_delete=django.db.models.deletion.CASCADE, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype'), + preserve_default=False, + ), + ] diff --git a/netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py b/netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py new file mode 100644 index 0000000..6dbc855 --- /dev/null +++ b/netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.16 on 2024-11-21 12:38 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0009_alter_virtualmachinetype_virtual_machine_type_name_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='vmassignedvirtualmachinetype', + name='virtual_machine_type_name', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype'), + ), + ] diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index 66aef0c..fb137ac 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -21,7 +21,7 @@ class VirtualMachineType(NetBoxModel): """Cluster ProviderInfo definition class""" virtual_machine_type_name = models.CharField( - default=None, blank=True, null=True, + default=None, blank=False, null=False, max_length=50, ) @@ -46,12 +46,12 @@ class VirtualMachineType(NetBoxModel): """Meta class""" unique_together = ["assigned_object_id","virtual_machine_type_name"] ordering = ["assigned_object_id"] - verbose_name = "Machine Type" - verbose_name_plural = "Machine Types" + verbose_name = "Virtual Machine Type" + verbose_name_plural = "Virtual Machine Types" def __str__(self): - return self.virtual_machine_type_name or f"for Cluster Type ID {self.assigned_object_id}" + return self.virtual_machine_type_name def get_absolute_url(self): """override""" @@ -70,9 +70,9 @@ class VmAssignedVirtualMachineType(NetBoxModel): virtual_machine_type_name = models.ForeignKey( to="VirtualMachineType", - on_delete=models.SET_NULL, - null=True, - blank=True, + on_delete=models.PROTECT, + null=False, + blank=False, related_name="assigned_vm_type" ) @@ -102,7 +102,7 @@ class VmAssignedVirtualMachineType(NetBoxModel): def __str__(self): - return f"For Virtual machine ID {self.assigned_object_id}" + return f"Virtual machine ID {self.assigned_object_id}" def get_absolute_url(self): """override""" -- GitLab From 92b3502da18ffcae2cfdb4ab9fc859dc2d0bb3bc Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 21 Nov 2024 16:10:52 +0000 Subject: [PATCH 09/11] =?UTF-8?q?=F0=9F=92=84=20Add=20filters=20to=20VM=20?= =?UTF-8?q?Types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/filtersets.py | 29 ++++++++++++++++++++++++++--- netbox_sys_plugin/views.py | 4 ++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/netbox_sys_plugin/filtersets.py b/netbox_sys_plugin/filtersets.py index 6574a70..07edfc5 100644 --- a/netbox_sys_plugin/filtersets.py +++ b/netbox_sys_plugin/filtersets.py @@ -2,9 +2,9 @@ import django_filters from netbox.filtersets import NetBoxModelFilterSet -from virtualization.models import VirtualMachine, Cluster +from virtualization.models import VirtualMachine, Cluster, ClusterType from django.db.models import Q -from .models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType +from .models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType class VmMaintenanceFilterSet(NetBoxModelFilterSet): @@ -30,7 +30,7 @@ class VmMaintenanceFilterSet(NetBoxModelFilterSet): return queryset.filter(Q(maintenance_window__icontains=value)) class VmAssignedVmTypeFilterSet(NetBoxModelFilterSet): - """VirtualMachineType filterset definition class""" + """VirtualMachineAssignType filterset definition class""" virtualmachine = django_filters.ModelMultipleChoiceFilter( field_name="VirtualMachine__name", @@ -51,6 +51,29 @@ class VmAssignedVmTypeFilterSet(NetBoxModelFilterSet): return queryset return queryset.filter(Q(virtual_machine_type_name__icontains=value)|Q(virtual_machine_type_desc__icontains=value)) +class VmTypeFilterSet(NetBoxModelFilterSet): + """VirtualMachineType filterset definition class""" + + cluster_type = django_filters.ModelMultipleChoiceFilter( + field_name="ClusterType__name", + queryset=ClusterType.objects.all(), + to_field_name="name", + label="Cluster Type (name)", + ) + + class Meta: + """Meta class""" + model = VirtualMachineType + fields = ('virtual_machine_type_name','virtual_machine_type_desc', 'cluster_type') + + # pylint: disable=W0613 + def search(self, queryset, name, value): + """override""" + if not value.strip(): + return queryset + return queryset.filter(Q(virtual_machine_type_name__icontains=value)|Q(virtual_machine_type_desc__icontains=value)) + + class ProviderCredentialsFilterSet(NetBoxModelFilterSet): """ProviderCredentials filterset definition class""" diff --git a/netbox_sys_plugin/views.py b/netbox_sys_plugin/views.py index 123e31e..f93e69d 100644 --- a/netbox_sys_plugin/views.py +++ b/netbox_sys_plugin/views.py @@ -101,8 +101,8 @@ class VmTypeListView(generic.ObjectListView): queryset = models.VirtualMachineType.objects.all() table = tables.VmTypeTable - #filterset = filtersets.VmTypeFilterSet - #filterset_form = forms.VmTypeFilterForm + filterset = filtersets.VmTypeFilterSet + filterset_form = forms.VmTypeFilterForm class VmTypeDeleteView(generic.ObjectDeleteView): """Vm maintenance delete view definition""" -- GitLab From e2267072c56023cd14f93ba7ca62313acdc00d26 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 21 Nov 2024 17:04:13 +0000 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=92=84=20Add=20filtersets=20and=20U?= =?UTF-8?q?I=20objects?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/filtersets.py | 4 +- netbox_sys_plugin/forms/machine.py | 2 +- ...virtualmachinetype_virtual_machine_type.py | 18 +++++++++ netbox_sys_plugin/models/machine.py | 2 +- netbox_sys_plugin/tables.py | 6 +-- netbox_sys_plugin/template_content.py | 17 ++++++-- .../clustertype_virtualmachinetype.html | 39 +++++++++++++++++++ .../vm_vmassignedvirtualmachinetype.html | 12 +++--- .../vmassignedvirtualmachinetype.html | 6 +-- 9 files changed, 86 insertions(+), 20 deletions(-) create mode 100644 netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py create mode 100644 netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html diff --git a/netbox_sys_plugin/filtersets.py b/netbox_sys_plugin/filtersets.py index 07edfc5..3c031b6 100644 --- a/netbox_sys_plugin/filtersets.py +++ b/netbox_sys_plugin/filtersets.py @@ -42,14 +42,14 @@ class VmAssignedVmTypeFilterSet(NetBoxModelFilterSet): class Meta: """Meta class""" model = VmAssignedVirtualMachineType - fields = ('virtual_machine_type_name','virtual_machine_type_assignment_desc', 'virtualmachine') + fields = ('virtual_machine_type','virtual_machine_type_assignment_desc', 'virtualmachine') # pylint: disable=W0613 def search(self, queryset, name, value): """override""" if not value.strip(): return queryset - return queryset.filter(Q(virtual_machine_type_name__icontains=value)|Q(virtual_machine_type_desc__icontains=value)) + return queryset.filter(Q(virtual_machine_type__icontains=value)|Q(virtual_machine_type_desc__icontains=value)) class VmTypeFilterSet(NetBoxModelFilterSet): """VirtualMachineType filterset definition class""" diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py index d90b2f7..7dbb437 100644 --- a/netbox_sys_plugin/forms/machine.py +++ b/netbox_sys_plugin/forms/machine.py @@ -46,7 +46,7 @@ class VmAssignedVmTypeForm(NetBoxModelForm): class Meta: """Meta class""" model = VmAssignedVirtualMachineType - fields = ('virtual_machine','virtual_machine_type_name', 'virtual_machine_type_assignment_desc','tags') + fields = ('virtual_machine','virtual_machine_type', 'virtual_machine_type_assignment_desc','tags') def clean(self): """ diff --git a/netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py b/netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py new file mode 100644 index 0000000..be74bb5 --- /dev/null +++ b/netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.16 on 2024-11-21 16:38 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('netbox_sys_plugin', '0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name'), + ] + + operations = [ + migrations.RenameField( + model_name='vmassignedvirtualmachinetype', + old_name='virtual_machine_type_name', + new_name='virtual_machine_type', + ), + ] diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index fb137ac..690faa7 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -68,7 +68,7 @@ GenericRelation( class VmAssignedVirtualMachineType(NetBoxModel): """Virtual Machine Type Info definition class""" - virtual_machine_type_name = models.ForeignKey( + virtual_machine_type = models.ForeignKey( to="VirtualMachineType", on_delete=models.PROTECT, null=False, diff --git a/netbox_sys_plugin/tables.py b/netbox_sys_plugin/tables.py index bb9049b..001f223 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -94,7 +94,7 @@ class VmAssignedVmTypeTable(NetBoxTable): orderable=False, verbose_name="Virtual Machine", ) - virtual_machine_type_name = tables.Column( + virtual_machine_type = tables.Column( linkify=True, verbose_name="Virtual Machine Type", ) @@ -109,11 +109,11 @@ class VmAssignedVmTypeTable(NetBoxTable): fields = ( "pk", "id", - "virtual_machine_type_name", + "virtual_machine_type", "virtual_machine_type_assignment_desc", ) - default_columns = ('id','assigned_object','virtual_machine_type_name','virtual_machine_type_assignment_desc') + default_columns = ('id','assigned_object','virtual_machine_type','virtual_machine_type_assignment_desc') #VmType class VmTypeTable(NetBoxTable): diff --git a/netbox_sys_plugin/template_content.py b/netbox_sys_plugin/template_content.py index f390d53..4400d88 100644 --- a/netbox_sys_plugin/template_content.py +++ b/netbox_sys_plugin/template_content.py @@ -5,7 +5,7 @@ from extras.plugins import PluginTemplateExtension from netbox_sys_plugin import models class VmTable(PluginTemplateExtension): - """VM Maintenance object template""" + """VM object template""" model = 'virtualization.virtualmachine' @@ -13,8 +13,17 @@ class VmTable(PluginTemplateExtension): return self.render('netbox_sys_plugin/vm_vmmaintenance.html', extra_context={'vmmaintenanceinfo': models.VirtualMachineMaintenance.objects.filter(VirtualMachine=self.context['object'])}) def right_page(self): - return self.render('netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html', extra_context={'vmtypeinfo': models.VmAssignedVirtualMachineType.objects.filter(VirtualMachine=self.context['object'])}) - + return self.render('netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html', extra_context={'vmassigntypeinfo': models.VmAssignedVirtualMachineType.objects.filter(VirtualMachine=self.context['object'])}) + +class VmTypeTable(PluginTemplateExtension): + """Cluster object template""" + + model = 'virtualization.clustertype' + + def right_page(self): + return self.render('netbox_sys_plugin/clustertype_virtualmachinetype.html', extra_context={'vmtypesinfo': models.VirtualMachineType.objects.filter(ClusterType=self.context['object'])}) + + class ProviderCredentialsTable(PluginTemplateExtension): """Provider Credentials object template""" @@ -24,4 +33,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] +template_extensions = [VmTable,ProviderCredentialsTable,VmTypeTable] diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html new file mode 100644 index 0000000..cd3a25c --- /dev/null +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html @@ -0,0 +1,39 @@ +{% block content %} + <div class="row mb-3"> + <div class="col col-md-12"> + <div class="card"> + <h5 class="card-header">Provider Credentials</h5> + <div class="card-body"> + <table class="table table-responsive"> + <th scope="row">Virtual Machine Type</th> + <th scope="row">Description</th> + {% for vmtypes in vmtypesinfo %} + <tr> + <td> + {% if vmtypes.virtual_machine_type_name %} + <a href="{{ vmtypes.get_absolute_url }}">{{ vmtypes.virtual_machine_type_name }}</a> + {% else %} + {{ ''|placeholder }} + {% endif %} + </td> + <td> + {% if vmtypes.virtual_machine_type_desc %} + {{ vmtypes.virtual_machine_type_desc }} + {% else %} + {{ ''|placeholder }} + {% endif %} + </td> + </tr> + {% empty %} + <tr> + <td colspan="3">No Virtual Machine Types 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/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html index 4154da8..bdebafb 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html @@ -8,19 +8,19 @@ <th scope="row">ID</th> <th scope="row">Type</th> <th scope="row">Description</th> - {% for vmtype in vmtypeinfo %} + {% for vmassigntype in vmassigntypeinfo %} <tr> - <td>{{ vmtype.id }}</td> + <td>{{ vmassigntype.id }}</td> <td> - {% if vmtype.virtual_machine_type_name %} - <a href="{{ vmtype.get_absolute_url }}">{{ vmtype.virtual_machine_type_name }}</a> + {% if vmassigntype.virtual_machine_type %} + <a href="{{ vmassigntype.get_absolute_url }}">{{ vmassigntype.virtual_machine_type }}</a> {% else %} {{ ''|placeholder }} {% endif %} </td> <td> - {% if vmtype.virtual_machine_type_assignment_desc %} - {{ vmtype.virtual_machine_type_assignment_desc }} + {% if vmassigntype.virtual_machine_type_assignment_desc %} + {{ vmassigntype.virtual_machine_type_assignment_desc }} {% else %} {{ ''|placeholder }} {% endif %} diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html index aadce1c..5fa41ae 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/vmassignedvirtualmachinetype.html @@ -8,14 +8,14 @@ Virtual Machine Type for {{ object.assigned_object }} <div class="row mb-3"> <div class="col col-md-6"> <div class="card"> - <h5 class="card-header">Virtual Machine Type Assignedment </h5> + <h5 class="card-header">Virtual Machine Type Assignement </h5> <div class="card-body"> <table class="table table-hover attr-table"> <tr> <th scope="row">Name</th> <td> - {% if object.virtual_machine_type_name %} - <a href="{{ object.virtual_machine_type_name.get_absolute_url }}">{{ object.virtual_machine_type_name }}</a> + {% if object.virtual_machine_type %} + <a href="{{ object.virtual_machine_type.get_absolute_url }}">{{ object.virtual_machine_type }}</a> {% else %} {{ ''|placeholder }} {% endif %} -- GitLab From ad5d87f508a67586d73c7d34d11512c05430d4ac Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 21 Nov 2024 17:11:29 +0000 Subject: [PATCH 11/11] =?UTF-8?q?=F0=9F=94=A5=20squash=20migrations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...chinetype_vmassignedvirtualmachinetype.py} | 28 +++++++++---------- ...lter_virtualmachinetype_unique_together.py | 17 ----------- ...005_vmassignedvirtualmachinetype_vmtype.py | 20 ------------- ...ignedvirtualmachinetype_vmtype_and_more.py | 24 ---------------- ...machinetype_virtualmachinetype_and_more.py | 23 --------------- ..._virtual_machine_type_assignment_desc_a.py | 28 ------------------- ...type_virtual_machine_type_name_and_more.py | 25 ----------------- ...almachinetype_virtual_machine_type_name.py | 19 ------------- ...virtualmachinetype_virtual_machine_type.py | 18 ------------ 9 files changed, 14 insertions(+), 188 deletions(-) rename netbox_sys_plugin/migrations/{0003_vmassignedvirtualmachinetype_virtualmachinetype.py => 0003_virtualmachinetype_vmassignedvirtualmachinetype.py} (81%) delete mode 100644 netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py delete mode 100644 netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py delete mode 100644 netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py delete mode 100644 netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py delete mode 100644 netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py delete mode 100644 netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py delete mode 100644 netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py delete mode 100644 netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py diff --git a/netbox_sys_plugin/migrations/0003_vmassignedvirtualmachinetype_virtualmachinetype.py b/netbox_sys_plugin/migrations/0003_virtualmachinetype_vmassignedvirtualmachinetype.py similarity index 81% rename from netbox_sys_plugin/migrations/0003_vmassignedvirtualmachinetype_virtualmachinetype.py rename to netbox_sys_plugin/migrations/0003_virtualmachinetype_vmassignedvirtualmachinetype.py index c35fd43..cad573f 100644 --- a/netbox_sys_plugin/migrations/0003_vmassignedvirtualmachinetype_virtualmachinetype.py +++ b/netbox_sys_plugin/migrations/0003_virtualmachinetype_vmassignedvirtualmachinetype.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2024-11-20 14:43 +# Generated by Django 4.2.16 on 2024-11-21 17:06 from django.db import migrations, models import django.db.models.deletion @@ -9,48 +9,48 @@ import utilities.json class Migration(migrations.Migration): dependencies = [ - ('extras', '0098_webhook_custom_field_data_webhook_tags'), ('contenttypes', '0002_remove_content_type_name'), + ('extras', '0098_webhook_custom_field_data_webhook_tags'), ('netbox_sys_plugin', '0002_alter_virtualmachinemaintenance_maintenance_window_and_more'), ] operations = [ migrations.CreateModel( - name='VmAssignedVirtualMachineType', + name='VirtualMachineType', 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)), - ('virtual_machine_type_name', models.CharField(blank=True, default=None, max_length=50, null=True)), + ('virtual_machine_type_name', models.CharField(default=None, max_length=50)), ('virtual_machine_type_desc', models.CharField(blank=True, default=None, max_length=100, 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', 'virtualization'), ('model', 'VirtualMachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), + ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'ClusterType'))), 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': 'Assigned Machine Type', - 'verbose_name_plural': 'Assigned Machine Types', + 'verbose_name': 'Virtual Machine Type', + 'verbose_name_plural': 'Virtual Machine Types', 'ordering': ['assigned_object_id'], - 'unique_together': {('assigned_object_id',)}, + 'unique_together': {('assigned_object_id', 'virtual_machine_type_name')}, }, ), migrations.CreateModel( - name='VirtualMachineType', + name='VmAssignedVirtualMachineType', 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)), - ('virtual_machine_type_name', models.CharField(blank=True, default=None, max_length=50, null=True)), - ('virtual_machine_type_desc', models.CharField(blank=True, default=None, max_length=100, null=True)), + ('virtual_machine_type_assignment_desc', models.CharField(blank=True, default=None, max_length=100, 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', 'virtualization'), ('model', 'ClusterType'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')), + ('assigned_object_type', 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')), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ('virtual_machine_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype')), ], options={ - 'verbose_name': 'Machine Type', - 'verbose_name_plural': 'Machine Types', + 'verbose_name': 'Assigned Machine Type', + 'verbose_name_plural': 'Assigned Machine Types', 'ordering': ['assigned_object_id'], 'unique_together': {('assigned_object_id',)}, }, diff --git a/netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py b/netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py deleted file mode 100644 index 1d662ad..0000000 --- a/netbox_sys_plugin/migrations/0004_alter_virtualmachinetype_unique_together.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-20 14:54 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0003_vmassignedvirtualmachinetype_virtualmachinetype'), - ] - - operations = [ - migrations.AlterUniqueTogether( - name='virtualmachinetype', - unique_together={('assigned_object_id', 'virtual_machine_type_name')}, - ), - ] diff --git a/netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py b/netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py deleted file mode 100644 index de15b2e..0000000 --- a/netbox_sys_plugin/migrations/0005_vmassignedvirtualmachinetype_vmtype.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-20 15:07 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0004_alter_virtualmachinetype_unique_together'), - ] - - operations = [ - migrations.AddField( - model_name='vmassignedvirtualmachinetype', - name='vmtype', - field=models.OneToOneField(db_column='vm_type_id', default=0, on_delete=django.db.models.deletion.CASCADE, related_name='vmtype', to='netbox_sys_plugin.virtualmachinetype'), - preserve_default=False, - ), - ] diff --git a/netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py b/netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py deleted file mode 100644 index c038afe..0000000 --- a/netbox_sys_plugin/migrations/0006_remove_vmassignedvirtualmachinetype_vmtype_and_more.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-20 15:19 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0005_vmassignedvirtualmachinetype_vmtype'), - ] - - operations = [ - migrations.RemoveField( - model_name='vmassignedvirtualmachinetype', - name='vmtype', - ), - migrations.AddField( - model_name='vmassignedvirtualmachinetype', - name='VirtualMachineType', - field=models.OneToOneField(db_column='virtual_machine_type_id', default=0, on_delete=django.db.models.deletion.CASCADE, related_name='VirtualMachineType', to='netbox_sys_plugin.virtualmachinetype'), - preserve_default=False, - ), - ] diff --git a/netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py b/netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py deleted file mode 100644 index cc3e70f..0000000 --- a/netbox_sys_plugin/migrations/0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-20 15:30 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0006_remove_vmassignedvirtualmachinetype_vmtype_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='vmassignedvirtualmachinetype', - name='VirtualMachineType', - ), - migrations.AddField( - model_name='vmassignedvirtualmachinetype', - name='virtual_machine_type_id', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_vm_types', to='netbox_sys_plugin.virtualmachinetype'), - ), - ] diff --git a/netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py b/netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py deleted file mode 100644 index bd812dd..0000000 --- a/netbox_sys_plugin/migrations/0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-20 16:16 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0007_remove_vmassignedvirtualmachinetype_virtualmachinetype_and_more'), - ] - - operations = [ - migrations.RenameField( - model_name='vmassignedvirtualmachinetype', - old_name='virtual_machine_type_desc', - new_name='virtual_machine_type_assignment_desc', - ), - migrations.RemoveField( - model_name='vmassignedvirtualmachinetype', - name='virtual_machine_type_id', - ), - migrations.AlterField( - model_name='vmassignedvirtualmachinetype', - name='virtual_machine_type_name', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype'), - ), - ] diff --git a/netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py b/netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py deleted file mode 100644 index c70b7a7..0000000 --- a/netbox_sys_plugin/migrations/0009_alter_virtualmachinetype_virtual_machine_type_name_and_more.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-21 12:24 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0008_rename_virtual_machine_type_desc_vmassignedvirtualmachinetype_virtual_machine_type_assignment_desc_a'), - ] - - operations = [ - migrations.AlterField( - model_name='virtualmachinetype', - name='virtual_machine_type_name', - field=models.CharField(default=None, max_length=50), - ), - migrations.AlterField( - model_name='vmassignedvirtualmachinetype', - name='virtual_machine_type_name', - field=models.ForeignKey(blank=True, default=1, on_delete=django.db.models.deletion.CASCADE, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype'), - preserve_default=False, - ), - ] diff --git a/netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py b/netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py deleted file mode 100644 index 6dbc855..0000000 --- a/netbox_sys_plugin/migrations/0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-21 12:38 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0009_alter_virtualmachinetype_virtual_machine_type_name_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='vmassignedvirtualmachinetype', - name='virtual_machine_type_name', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype'), - ), - ] diff --git a/netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py b/netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py deleted file mode 100644 index be74bb5..0000000 --- a/netbox_sys_plugin/migrations/0011_rename_virtual_machine_type_name_vmassignedvirtualmachinetype_virtual_machine_type.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2.16 on 2024-11-21 16:38 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('netbox_sys_plugin', '0010_alter_vmassignedvirtualmachinetype_virtual_machine_type_name'), - ] - - operations = [ - migrations.RenameField( - model_name='vmassignedvirtualmachinetype', - old_name='virtual_machine_type_name', - new_name='virtual_machine_type', - ), - ] -- GitLab