From 592736f2d5f88b6aed3400604c721377c90d831e Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 17 Dec 2024 09:47:42 +0000 Subject: [PATCH 01/12] =?UTF-8?q?=E2=9C=A8=20Add=20webhook=20to=20vm=20cre?= =?UTF-8?q?ation=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 64 ++++++++++++++++++++++++++--- netbox_sys_plugin/utils.py | 14 +++++++ 2 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 netbox_sys_plugin/utils.py diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index 6b71a49..5d4e99b 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -6,14 +6,12 @@ from utilities.forms.fields import DynamicModelChoiceField from netbox.forms import NetBoxModelForm from virtualization.models import ClusterType, Cluster, VirtualMachine, VMInterface from ipam.models import IPAddress, Service -from dcim.models import DeviceRole,Site, Platform +from dcim.models import DeviceRole, Platform from extras.models import Tag, TaggedItem +from . . utils import send_webhook import netaddr - - - class ClusterForm(NetBoxModelForm): """Form for Clusters.""" @@ -108,8 +106,6 @@ class TagsForm(NetBoxModelForm): self.fields.pop('tags',None) - - # Inline formsets for managing relationships ClusterFormSet = inlineformset_factory( ClusterType, Cluster, form=ClusterForm, extra=1, can_delete=False @@ -340,6 +336,62 @@ class CreateVmForm(NetBoxModelForm): vmi = self.create_vm_interface(data, vm) self.create_all_services(data, vm) self.create_all_ip_adresses(data, vmi) + + + # Gather related data for webhook payload + + interfaces = VMInterface.objects.filter(virtual_machine=vm) + services = Service.objects.filter(virtual_machine=vm) + vm_interface_content_type = ContentType.objects.get_for_model(VMInterface) + ip_addresses = IPAddress.objects.filter( + assigned_object_id__in=interfaces.values_list('id', flat=True), + assigned_object_type=vm_interface_content_type + ) + + payload = { + "virtual_machine": { + "id": vm.id, + "name": vm.name, + "status": vm.status, + "role": vm.role.name if vm.role else None, + "platform": vm.platform.name if vm.platform else None, + "description": vm.description, + }, + "cluster": { + "id": cluster.id if cluster else None, + "name": cluster.name if cluster else None, + "type": { + "id": cluster.type.id if cluster.type else None, + "name": cluster.type.name if cluster.type else None, + }, + }, + "interfaces": [ + { + "id": interface.id, + "name": interface.name} + for interface in interfaces + ], + "ip_addresses": [ + { + "id": ip.id, + "address": str(ip.address), + "status": ip.status, + } + for ip in ip_addresses + ], + "services": [ + { + "id": service.id, + "name": service.name, + "description": service.description, + } + for service in services + ], + } + print("payload",payload) + + # Send webhook + send_webhook(payload) return vm except ValueError as e: diff --git a/netbox_sys_plugin/utils.py b/netbox_sys_plugin/utils.py new file mode 100644 index 0000000..4138c27 --- /dev/null +++ b/netbox_sys_plugin/utils.py @@ -0,0 +1,14 @@ +import requests +from django.conf import settings + +WEBHOOK_URL = " http://127.0.0.1:9000/" + +def send_webhook(payload): + """Send a webhook to the specified endpoint.""" + try: + headers = {'Content-Type': 'application/json'} + response = requests.post(WEBHOOK_URL, json=payload, headers=headers) + response.raise_for_status() + print(f"Webhook sent successfully: {response.status_code}") + except requests.RequestException as e: + print(f"Error sending webhook: {e}") \ No newline at end of file -- GitLab From 253ea1b6e718bce4fd86ba13eb6bae78d3180544 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 17 Dec 2024 15:33:53 +0000 Subject: [PATCH 02/12] =?UTF-8?q?=F0=9F=97=83=EF=B8=8F=20Add=20model=20and?= =?UTF-8?q?=20form=20to=20manage=20plugin=20webhook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 10 ++++- netbox_sys_plugin/api/urls.py | 1 + netbox_sys_plugin/api/views.py | 9 +++-- netbox_sys_plugin/forms/__init__.py | 3 +- netbox_sys_plugin/forms/operation.py | 22 +++++++++++ .../migrations/0008_webhooksettings.py | 34 +++++++++++++++++ netbox_sys_plugin/models/__init__.py | 3 +- netbox_sys_plugin/models/operation.py | 38 +++++++++++++++++++ netbox_sys_plugin/navigation.py | 19 ++++------ netbox_sys_plugin/tables.py | 36 +++++++++++++++++- .../netbox_sys_plugin/webhooksettings.html | 27 +++++++++++++ netbox_sys_plugin/urls.py | 8 ++++ netbox_sys_plugin/views.py | 29 +++++++++++++- 13 files changed, 218 insertions(+), 21 deletions(-) create mode 100644 netbox_sys_plugin/forms/operation.py create mode 100644 netbox_sys_plugin/migrations/0008_webhooksettings.py create mode 100644 netbox_sys_plugin/models/operation.py create mode 100644 netbox_sys_plugin/templates/netbox_sys_plugin/webhooksettings.html diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index afba76e..9715643 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -8,7 +8,7 @@ from dcim.api.nested_serializers import ( from ipam.api.nested_serializers import ( NestedIPAddressSerializer, NestedServiceSerializer ) -from .. models import VirtualMachineMaintenance, ProviderCredentials,VmAssignedVirtualMachineType, VirtualMachineType,DomainNames +from .. models import VirtualMachineMaintenance, ProviderCredentials,VmAssignedVirtualMachineType, VirtualMachineType,DomainNames, WebhookSettings from django.contrib.contenttypes.models import ContentType from .nested_serializers import * from virtualization.choices import * @@ -96,6 +96,14 @@ class DomainNamesSerializer(serializers.ModelSerializer): #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' +class WebhookSettingsSerializer(serializers.ModelSerializer): + id = serializers.IntegerField(read_only=True) + + class Meta: + model = WebhookSettings + fields = '__all__' + + class VirtualMachineSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:virtualmachine-detail') status = ChoiceField(choices=VirtualMachineStatusChoices, required=False) diff --git a/netbox_sys_plugin/api/urls.py b/netbox_sys_plugin/api/urls.py index 51e074e..ee39bf0 100644 --- a/netbox_sys_plugin/api/urls.py +++ b/netbox_sys_plugin/api/urls.py @@ -7,6 +7,7 @@ router.register(r'ProviderCredentials', ProviderCredentialsViewSet) router.register(r'AssignedVmType', VmAssignedVirtualMachineTypeViewSet) router.register(r'VmType', VirtualMachineTypeViewSet) router.register(r'DomainNames', VirtualMachineTypeViewSet) +router.register(r'WebhookSettings', WebhookSettingsViewSet) router.register(r'VirtualMachine', VirtualMachineViewSet) app_name = "netbox_sys_plugin" diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index 64e5e7f..aca55ba 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -4,7 +4,7 @@ from rest_framework.response import Response from django.db.models import Prefetch from netbox.api.viewsets import NetBoxModelViewSet from virtualization import filtersets -from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType,DomainNames +from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType,DomainNames, WebhookSettings from . serializers import * class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): @@ -13,7 +13,7 @@ class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): http_method_names = ["get", "post", "patch", "delete", "options"] class DomainNamesViewSet(viewsets.ModelViewSet): - queryset = VirtualMachineMaintenance.objects.all() + queryset = DomainNames.objects.all() serializer_class = DomainNamesSerializer http_method_names = ["get", "post", "patch", "delete", "options"] @@ -22,7 +22,6 @@ class ProviderCredentialsViewSet(viewsets.ModelViewSet): serializer_class = ProviderCredentialsSerializer http_method_names = ["get", "post", "patch", "delete", "options"] - class VmAssignedVirtualMachineTypeViewSet(viewsets.ModelViewSet): queryset = VmAssignedVirtualMachineType.objects.prefetch_related(Prefetch( 'virtual_machine_type', queryset=VirtualMachineType.objects.all(), @@ -43,3 +42,7 @@ class VirtualMachineViewSet(NetBoxModelViewSet): serializer_class = VirtualMachineSerializer http_method_names = ["get"] +class WebhookSettingsViewSet(viewsets.ModelViewSet): + queryset = WebhookSettings.objects.all() + serializer_class = WebhookSettingsSerializer + 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 b26bccd..8b1460c 100644 --- a/netbox_sys_plugin/forms/__init__.py +++ b/netbox_sys_plugin/forms/__init__.py @@ -2,4 +2,5 @@ from .provider import * from .machine import * -from .createvm import * \ No newline at end of file +from .createvm import * +from .operation import * \ No newline at end of file diff --git a/netbox_sys_plugin/forms/operation.py b/netbox_sys_plugin/forms/operation.py new file mode 100644 index 0000000..b65ff2e --- /dev/null +++ b/netbox_sys_plugin/forms/operation.py @@ -0,0 +1,22 @@ +from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm +from ..models import WebhookSettings + + + +class WebhookSettingsForm(NetBoxModelForm): + """Webhook Settings form definition class""" + + class Meta: + """Meta class""" + + model = WebhookSettings + fields = ('payload_url','http_content_type','tags') + labels = { + "payload_url": "Payload URL", + "http_content_type": "HTTP Content Type", + } + +class WebhookSettingsFilterForm(NetBoxModelFilterSetForm): + """Webhook Settings filter form definition class""" + + model = WebhookSettings \ No newline at end of file diff --git a/netbox_sys_plugin/migrations/0008_webhooksettings.py b/netbox_sys_plugin/migrations/0008_webhooksettings.py new file mode 100644 index 0000000..e00f7a3 --- /dev/null +++ b/netbox_sys_plugin/migrations/0008_webhooksettings.py @@ -0,0 +1,34 @@ +# Generated by Django 4.2.16 on 2024-12-17 12:29 + +from django.db import migrations, models +import taggit.managers +import utilities.json + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0098_webhook_custom_field_data_webhook_tags'), + ('netbox_sys_plugin', '0007_alter_domainnames_assigned_object_type'), + ] + + operations = [ + migrations.CreateModel( + name='WebhookSettings', + 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)), + ('payload_url', models.CharField(max_length=500)), + ('http_content_type', models.CharField(default='application/json', editable=False, max_length=100)), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ], + options={ + 'verbose_name': 'Webhook Settings', + 'verbose_name_plural': 'Webhook Settings', + 'ordering': ['payload_url'], + 'unique_together': {('payload_url',)}, + }, + ), + ] diff --git a/netbox_sys_plugin/models/__init__.py b/netbox_sys_plugin/models/__init__.py index bf52380..3cbc7b5 100644 --- a/netbox_sys_plugin/models/__init__.py +++ b/netbox_sys_plugin/models/__init__.py @@ -1,4 +1,5 @@ """Models definitions""" from .provider import * -from .machine import * \ No newline at end of file +from .machine import * +from .operation import * \ No newline at end of file diff --git a/netbox_sys_plugin/models/operation.py b/netbox_sys_plugin/models/operation.py new file mode 100644 index 0000000..9c4aa19 --- /dev/null +++ b/netbox_sys_plugin/models/operation.py @@ -0,0 +1,38 @@ +from django.core.validators import ( + URLValidator, +) # pylint: disable=import-error +from django.db import models +from django.urls import reverse +from netbox.models import NetBoxModel +from django.db import models +from django.utils.translation import gettext_lazy as _ + + + +class WebhookSettings(NetBoxModel): + """Webhook settings config definition class""" + + payload_url = models.CharField( + max_length=500, + verbose_name=_('URL'), + help_text=_( + "This URL will be called using the HTTP method defined when the webhook is called." + ) + ) + + http_content_type = models.CharField( + max_length=100, + default='application/json', + verbose_name=_('HTTP content type') + ) + + class Meta: + """Meta class""" + unique_together = ["payload_url"] + ordering = ["payload_url"] + verbose_name = "Webhook Settings" + verbose_name_plural = "Webhook Settings" + + def get_absolute_url(self): + """override""" + return reverse("plugins:netbox_sys_plugin:webhooksettings", args=[self.pk]) \ No newline at end of file diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index ca9245d..c9df8ff 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -47,15 +47,6 @@ vm_machine_type_buttons = [ ), ] -create_vm_buttons = [ - PluginMenuButton( - link="plugins:netbox_sys_plugin:creatvm_add", - title="Add", - icon_class="mdi mdi-plus-thick", - color=ButtonColorChoices.GREEN, - permissions=["netbox_sys_plugin.add_createvm"], - ), -] create_domainnames_buttons = [ PluginMenuButton( @@ -107,21 +98,25 @@ vmMachineItem = [ PluginMenuItem( link="plugins:netbox_sys_plugin:creatvm_add", link_text="Create VM", - buttons=create_vm_buttons, permissions=["netbox_sys_plugin.add_createvm"], ), ] operItem =[ - + PluginMenuItem( + link="plugins:netbox_sys_plugin:webhooksettings_list", + link_text="Webhook", + permissions=["netbox_sys_plugin.list_webhooksettings"], + ), ] #Menu menu = PluginMenu( - label="Sys", + label="System Squad", groups=( ("Provider", clusterProviderCredentialsItem), ("Virtual Machine", (vmMachineItem)), + ("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 a922227..cac807e 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, VmAssignedVirtualMachineType, VirtualMachineType +from .models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType, WebhookSettings #VmMaintenance class VmMaintenanceTable(NetBoxTable): @@ -175,4 +175,36 @@ class DomainNamesTable(NetBoxTable): "domain_names", ) - default_columns = ('id','domain_names','assigned_object') \ No newline at end of file + default_columns = ('id','domain_names','assigned_object') + +#WebhookSettings +class WebhookSettingsTable(NetBoxTable): + """webhook Settings Table definition class""" + + pk = columns.ToggleColumn() + id = tables.Column( + linkify=True, + ) + + payload_url = tables.Column( + linkify=True, + verbose_name="Payload Url", + ) + + http_content_type = tables.Column( + linkify=True, + verbose_name="Http Content Type", + ) + + class Meta(NetBoxTable.Meta): + """Meta class""" + model = WebhookSettings + fields = ( + "pk", + "id", + "payload_url", + "http_content_type", + ) + + default_columns = ('id','payload_url','http_content_type') + diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/webhooksettings.html b/netbox_sys_plugin/templates/netbox_sys_plugin/webhooksettings.html new file mode 100644 index 0000000..4d74ad1 --- /dev/null +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/webhooksettings.html @@ -0,0 +1,27 @@ +{% extends 'generic/object.html' %} +{% block title%} +Webhook for Create VM Form +{% endblock title%} +{% block content %} +<div class="row mb-3"> + <div class="col col-md-12"> + <div class="card"> + <h5 class="card-header">Webhook Information</h5> + <div class="card-body"> + <table class="table table-hover attr-table"> + <tr> + <th scope="row">Payload URL</th> + <td>{{ object.payload_url }}</td> + </tr> + <tr> + <th scope="row">HTTP Content Type</th> + <td>{{ object.http_content_type }}</td> + </tr> + </table> + </div> + </div> + {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/tags.html' %} + </div> +</div> +{% endblock content %} diff --git a/netbox_sys_plugin/urls.py b/netbox_sys_plugin/urls.py index c43d9b1..2d281af 100644 --- a/netbox_sys_plugin/urls.py +++ b/netbox_sys_plugin/urls.py @@ -48,5 +48,13 @@ urlpatterns = ( path('domain-names/<int:pk>/journal/', ObjectJournalView.as_view(), name='domainnames_journal', kwargs={'model': models.DomainNames}), #CreateVM path('create-vm/', CreateVmView.as_view(), name='creatvm_add'), + #WebhookSettings + path('webhook-settings/<int:pk>/', views.WebhookSettingsView.as_view(), name='webhooksettings'), + path('webhook-settings/', views.WebhookSettingsListView.as_view(), name='webhooksettings_list'), + path('webhook-settings/add/', views.WebhookSettingsEditView.as_view(), name='webhooksettings_add'), + path('webhook-settings/<int:pk>/edit/', views.WebhookSettingsEditView.as_view(), name='webhooksettings_edit'), + path('webhook-settings/<int:pk>/delete/', views.WebhookSettingsDeleteView.as_view(), name='webhooksettings_delete'), + path('webhook-settings/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='webhooksettings_changelog', kwargs={'model': models.WebhookSettings}), + path('webhook-settings/<int:pk>/journal/', ObjectJournalView.as_view(), name='webhooksettings_journal', kwargs={'model': models.WebhookSettings}), ) diff --git a/netbox_sys_plugin/views.py b/netbox_sys_plugin/views.py index 0b1f59b..59ddfd7 100644 --- a/netbox_sys_plugin/views.py +++ b/netbox_sys_plugin/views.py @@ -170,4 +170,31 @@ class DomainNamesEditView(generic.ObjectEditView): class DomainNamesDeleteView(generic.ObjectDeleteView): """Domain Names delete view definition""" - queryset = models.DomainNames.objects.all() \ No newline at end of file + queryset = models.DomainNames.objects.all() + +#Webhook Settings +class WebhookSettingsView(generic.ObjectView): + + """ Webhook Settings view definition""" + + queryset = ( + models.WebhookSettings.objects.all() + ) + +class WebhookSettingsListView(generic.ObjectListView): + """Webhook Settings list view definition""" + + queryset = models.WebhookSettings.objects.all() + table = tables.WebhookSettingsTable + filterset_form = forms.WebhookSettingsFilterForm + +class WebhookSettingsEditView(generic.ObjectEditView): + """ + Defines the edit view for the Webhook Settings django model. + """ + queryset = models.WebhookSettings.objects.all() + form = forms.WebhookSettingsForm + +class WebhookSettingsDeleteView(generic.ObjectDeleteView): + + queryset = models.WebhookSettings.objects.all() \ No newline at end of file -- GitLab From 81fc1efacaa94616e91118d0694822d601779e94 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 17 Dec 2024 16:28:40 +0000 Subject: [PATCH 03/12] =?UTF-8?q?=F0=9F=A6=BA=20Add=20retrive=20values=20f?= =?UTF-8?q?rom=20database=20and=20form=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/operation.py | 11 +++++++++++ netbox_sys_plugin/utils.py | 23 ++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/netbox_sys_plugin/forms/operation.py b/netbox_sys_plugin/forms/operation.py index b65ff2e..041d6f7 100644 --- a/netbox_sys_plugin/forms/operation.py +++ b/netbox_sys_plugin/forms/operation.py @@ -1,3 +1,4 @@ +from django.core.exceptions import ValidationError from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm from ..models import WebhookSettings @@ -16,6 +17,16 @@ class WebhookSettingsForm(NetBoxModelForm): "http_content_type": "HTTP Content Type", } + def clean(self): + cleaned_data = super().clean() + + if self.instance.pk: + return cleaned_data + + if WebhookSettings.objects.exists(): + raise ValidationError("You can only have one webbook setting") + + class WebhookSettingsFilterForm(NetBoxModelFilterSetForm): """Webhook Settings filter form definition class""" diff --git a/netbox_sys_plugin/utils.py b/netbox_sys_plugin/utils.py index 4138c27..82c3136 100644 --- a/netbox_sys_plugin/utils.py +++ b/netbox_sys_plugin/utils.py @@ -1,13 +1,30 @@ import requests from django.conf import settings +from .models import WebhookSettings -WEBHOOK_URL = " http://127.0.0.1:9000/" +def get_webhook_settings(): + try: + webhook_settings = WebhookSettings.objects.first() + if not webhook_settings: + raise ValueError("No webhook configured") + + return { + "url":webhook_settings.payload_url, + "content_type":webhook_settings.http_content_type + } + except Exception as e: + print(f"Error Fetching webhook settings: {e}") + return None def send_webhook(payload): """Send a webhook to the specified endpoint.""" + settings = get_webhook_settings() + if not settings: + print("Cannot send webhook, missing configurations") + return try: - headers = {'Content-Type': 'application/json'} - response = requests.post(WEBHOOK_URL, json=payload, headers=headers) + headers = {'Content-Type': settings['content_type']} + response = requests.post(settings['url'], json=payload, headers=headers) response.raise_for_status() print(f"Webhook sent successfully: {response.status_code}") except requests.RequestException as e: -- GitLab From 067d9571200a4586b2a4376758746c130a76fd5d Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Wed, 18 Dec 2024 11:27:50 +0000 Subject: [PATCH 04/12] =?UTF-8?q?=F0=9F=92=84=20Add=20NB=20DM=20extention?= =?UTF-8?q?=20elements=20to=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 53 ++++++++++++++++++- netbox_sys_plugin/models/machine.py | 5 +- .../netbox_sys_plugin/create_vm.html | 18 ++++++- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index 5d4e99b..0bca3c9 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -1,13 +1,15 @@ from django import forms from django.forms import inlineformset_factory from django.contrib.contenttypes.models import ContentType +from django.utils.translation import gettext_lazy as _ from django.db import transaction -from utilities.forms.fields import DynamicModelChoiceField +from utilities.forms.fields import DynamicModelChoiceField, JSONField from netbox.forms import NetBoxModelForm from virtualization.models import ClusterType, Cluster, VirtualMachine, VMInterface from ipam.models import IPAddress, Service from dcim.models import DeviceRole, Platform from extras.models import Tag, TaggedItem +from .. models import DomainNames, VmAssignedVirtualMachineType, VirtualMachineType from . . utils import send_webhook import netaddr @@ -92,6 +94,39 @@ class IPAddressForm(NetBoxModelForm): super().__init__(*args, **kwargs) self.fields.pop('tags',None) +class DomainNamesForm(NetBoxModelForm): + """Form for Domain Names.""" + + domain_names = JSONField( + label=_(''), + required=True, + initial=({'domain_name': 'domain1'}) + ) + + class Meta: + model = DomainNames + fields = ('domain_names','tags') + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields.pop('tags',None) + +class VmAssignedVirtualMachineTypeForm(NetBoxModelForm): + """Form for Domain Names.""" + + #virtual_machine_type = DynamicModelChoiceField( + # queryset=VirtualMachineType.objects.all(), + # query_params={'assigned_object_id': '$cl_list_new-cluster_type',}, + #) + + class Meta: + model = VmAssignedVirtualMachineType + fields = ('virtual_machine_type','tags') + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields.pop('tags',None) + class TagsForm(NetBoxModelForm): """Form for IP Addresses.""" tag = DynamicModelChoiceField( @@ -139,6 +174,14 @@ ClusterListFormSet = forms.modelformset_factory( Cluster, form=ClusterFormList, formset=ClusterFormList, extra=1, can_delete=False ) +DomainNamesFormSet = forms.modelformset_factory( + DomainNames, form=DomainNamesForm, formset=DomainNamesForm, extra=1, can_delete=False +) + +VmAssignedVirtualMachineTypeFormSet = forms.modelformset_factory( + VmAssignedVirtualMachineType, form=VmAssignedVirtualMachineTypeForm, formset=VmAssignedVirtualMachineTypeForm, extra=1, can_delete=False +) + TagFormSet = forms.modelformset_factory( Tag, form=TagsForm, formset=TagsForm, extra=1, can_delete=False ) @@ -193,6 +236,14 @@ class CreateVmForm(NetBoxModelForm): self.cl_list_formsets = [] empty_cl_list_formset = ClusterListFormSet(data=data, prefix='cl_list_new') self.cl_list_formsets.append(('new', empty_cl_list_formset)) + # Domain Names + self.domainnames_formsets = [] + empty_domainnames_formset = DomainNamesFormSet(data=data, prefix='domainnames_new') + self.domainnames_formsets.append(('new', empty_domainnames_formset)) + # VM Assigned VM Type + self.vmassignedvmtype_formsets = [] + empty_vmassignedvmtype_formset = VmAssignedVirtualMachineTypeFormSet(data=data, prefix='vmassignedvmtype_new') + self.vmassignedvmtype_formsets.append(('new', empty_vmassignedvmtype_formset)) # Tags self.tagformsets = [] empty_tagformset = TagFormSet(data=data, prefix='tag_new') diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index f1e195b..25098d0 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -26,7 +26,7 @@ class VirtualMachineType(NetBoxModel): ) virtual_machine_type_desc = models.CharField( - default=None, blank=True, null=True, + default=None, blank=False, null=False, max_length=100) assigned_object_type = models.ForeignKey( @@ -73,7 +73,8 @@ class VmAssignedVirtualMachineType(NetBoxModel): on_delete=models.PROTECT, null=False, blank=False, - related_name="assigned_vm_type" + related_name="assigned_vm_type", + name='virtual_machine_type' ) virtual_machine_type_assignment_desc = models.CharField( diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html b/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html index 3e562fd..fd8f6ec 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html @@ -55,13 +55,19 @@ SYS - Virtual Machine {% if vm_form.non_field_errors %} <h1> {{ vm_form.non_field_errors }}</h1> {% endif %} - + </div> + {% endfor %} + {% endfor %} + {% for vmassignedvmtype_formset in form.vmassignedvmtype_formsets %} + {% for vmassignedvmtype_form in vmassignedvmtype_formset %} + <div class="form-group" class="field-group mb-5"> + {{ vmassignedvmtype_form.as_p }} </div> {% endfor %} {% endfor %} </div> <div class="field-group my-5"> - <h5>Network Name</h5> + <h5>Network</h5> {% for vmi_formset in form.virtual_machine_interface_formsets %} {% for vmi_form in vmi_formset %} <div class="form-group" class="field-group mb-5"> @@ -85,6 +91,14 @@ SYS - Virtual Machine </div> {% endfor %} {% endfor %} + <h5>Domain Names</h5> + {% for domainnames_formset in form.domainnames_formsets %} + {% for domainnames_form in domainnames_formset %} + <div class="form-group" class="field-group mb-5"> + {{ domainnames_form.as_p }} + </div> + {% endfor %} + {% endfor %} </div> <div class="field-group my-5"> <h5>Dependencies</h5> -- GitLab From fc8244f26831ef38d06f2b5167a4b4be25f16078 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 19 Dec 2024 10:03:09 +0000 Subject: [PATCH 05/12] =?UTF-8?q?=F0=9F=90=9B=20Add=20filters=20and=20fix?= =?UTF-8?q?=20bug=20with=20droplist=20rendering?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 21 ++++++++++----------- netbox_sys_plugin/api/urls.py | 2 +- netbox_sys_plugin/api/views.py | 2 ++ netbox_sys_plugin/filtersets.py | 12 +++++++++--- netbox_sys_plugin/forms/createvm.py | 18 +++++++++--------- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index 9715643..a09b18a 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -40,29 +40,29 @@ class ClusterTypeSerializer(serializers.ModelSerializer): fields = ['id', 'name'] #Plugin Data Serializer -class VirtualMachineMaintenanceSerializer(serializers.ModelSerializer): +class VirtualMachineMaintenanceSerializer(NetBoxModelSerializer): 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) + display = serializers.CharField(source="__str__") class Meta: model = VirtualMachineMaintenance - #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' -class ProviderCredentialsSerializer(serializers.ModelSerializer): +class ProviderCredentialsSerializer(NetBoxModelSerializer): id = serializers.IntegerField(read_only=True) cluster = ClusterSerializer(source='assigned_object', read_only=True) assigned_object_id = serializers.IntegerField(write_only=True) assigned_object_type = serializers.CharField(write_only=True) + display = serializers.CharField(source="__str__") 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): +class VirtualMachineTypeSerializer(NetBoxModelSerializer): id = serializers.IntegerField(read_only=True) cluster_type = ClusterTypeSerializer(source='assigned_object', read_only=True) assigned_object_id = serializers.IntegerField(write_only=True) @@ -70,33 +70,32 @@ class VirtualMachineTypeSerializer(serializers.ModelSerializer): class Meta: model = VirtualMachineType - #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' -class VmAssignedVirtualMachineTypeSerializer(serializers.ModelSerializer): +class VmAssignedVirtualMachineTypeSerializer(NetBoxModelSerializer): id = serializers.IntegerField(read_only=True) virtual_machine = VirtualMachineSerializer(source='assigned_object', read_only=True) virtual_machine_type = VirtualMachineTypeSerializer() assigned_object_id = serializers.IntegerField(write_only=True) assigned_object_type = serializers.CharField(write_only=True) + display = serializers.CharField(source="__str__") class Meta: model = VmAssignedVirtualMachineType - #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' -class DomainNamesSerializer(serializers.ModelSerializer): +class DomainNamesSerializer(NetBoxModelSerializer): 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) + display = serializers.CharField(source="__str__") class Meta: model = DomainNames - #fields = ['id','maintenance_window','assigned_object_type','assigned_object_id','assigned_object_type','virtual_machine'] fields = '__all__' -class WebhookSettingsSerializer(serializers.ModelSerializer): +class WebhookSettingsSerializer(NetBoxModelSerializer): id = serializers.IntegerField(read_only=True) class Meta: diff --git a/netbox_sys_plugin/api/urls.py b/netbox_sys_plugin/api/urls.py index ee39bf0..3c43e5e 100644 --- a/netbox_sys_plugin/api/urls.py +++ b/netbox_sys_plugin/api/urls.py @@ -6,7 +6,7 @@ router.register(r'MaintenanceWindow', VirtualMachineMaintenanceViewSet) router.register(r'ProviderCredentials', ProviderCredentialsViewSet) router.register(r'AssignedVmType', VmAssignedVirtualMachineTypeViewSet) router.register(r'VmType', VirtualMachineTypeViewSet) -router.register(r'DomainNames', VirtualMachineTypeViewSet) +router.register(r'DomainNames', DomainNamesViewSet) router.register(r'WebhookSettings', WebhookSettingsViewSet) router.register(r'VirtualMachine', VirtualMachineViewSet) diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index aca55ba..ed9e993 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -4,6 +4,7 @@ from rest_framework.response import Response from django.db.models import Prefetch from netbox.api.viewsets import NetBoxModelViewSet from virtualization import filtersets +from .. filtersets import VmTypeFilterSet from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType,DomainNames, WebhookSettings from . serializers import * @@ -32,6 +33,7 @@ class VmAssignedVirtualMachineTypeViewSet(viewsets.ModelViewSet): class VirtualMachineTypeViewSet(viewsets.ModelViewSet): queryset = VirtualMachineType.objects.all() serializer_class = VirtualMachineTypeSerializer + filterset_class = VmTypeFilterSet http_method_names = ["get", "post", "patch", "delete", "options"] class VirtualMachineViewSet(NetBoxModelViewSet): diff --git a/netbox_sys_plugin/filtersets.py b/netbox_sys_plugin/filtersets.py index a934a31..5b44013 100644 --- a/netbox_sys_plugin/filtersets.py +++ b/netbox_sys_plugin/filtersets.py @@ -54,17 +54,24 @@ class VmAssignedVmTypeFilterSet(NetBoxModelFilterSet): class VmTypeFilterSet(NetBoxModelFilterSet): """VirtualMachineType filterset definition class""" - cluster_type = django_filters.ModelMultipleChoiceFilter( + cluster_type_name = django_filters.ModelMultipleChoiceFilter( field_name="ClusterType__name", queryset=ClusterType.objects.all(), to_field_name="name", label="Cluster Type (name)", ) + cluster_type_id = django_filters.ModelMultipleChoiceFilter( + field_name="ClusterType__id", + queryset=ClusterType.objects.all(), + to_field_name="id", + label="Cluster Type (id)", + ) + class Meta: """Meta class""" model = VirtualMachineType - fields = ('virtual_machine_type_name','virtual_machine_type_desc', 'cluster_type') + fields = ('virtual_machine_type_name','virtual_machine_type_desc', 'cluster_type_name','cluster_type_id') # pylint: disable=W0613 def search(self, queryset, name, value): @@ -73,7 +80,6 @@ class VmTypeFilterSet(NetBoxModelFilterSet): 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/createvm.py b/netbox_sys_plugin/forms/createvm.py index 0bca3c9..cbd46b8 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -111,16 +111,16 @@ class DomainNamesForm(NetBoxModelForm): super().__init__(*args, **kwargs) self.fields.pop('tags',None) -class VmAssignedVirtualMachineTypeForm(NetBoxModelForm): - """Form for Domain Names.""" +class VmAssignedVirtualMachineTypeForm(NetBoxModelForm, forms.Form): + """Form for Type Assignment.""" - #virtual_machine_type = DynamicModelChoiceField( - # queryset=VirtualMachineType.objects.all(), - # query_params={'assigned_object_id': '$cl_list_new-cluster_type',}, - #) + virtual_machine_type = DynamicModelChoiceField( + queryset=VirtualMachineType.objects.all(), + query_params={'cluster_type_id': '$cl_list_new-cluster_type',}, + ) class Meta: - model = VmAssignedVirtualMachineType + model = VirtualMachineType fields = ('virtual_machine_type','tags') def __init__(self, *args, **kwargs): @@ -179,7 +179,7 @@ DomainNamesFormSet = forms.modelformset_factory( ) VmAssignedVirtualMachineTypeFormSet = forms.modelformset_factory( - VmAssignedVirtualMachineType, form=VmAssignedVirtualMachineTypeForm, formset=VmAssignedVirtualMachineTypeForm, extra=1, can_delete=False + VirtualMachineType, form=VmAssignedVirtualMachineTypeForm, formset=VmAssignedVirtualMachineTypeForm, extra=1, can_delete=False ) TagFormSet = forms.modelformset_factory( @@ -416,7 +416,7 @@ class CreateVmForm(NetBoxModelForm): "name": cluster.type.name if cluster.type else None, }, }, - "interfaces": [ + "interface": [ { "id": interface.id, "name": interface.name} -- GitLab From 5e43eff70da8528d2c39f51681ee81aade2f3be8 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 19 Dec 2024 10:15:58 +0000 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=93=9D=20Add=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/model/netbox_sys_webhook_settings.md | 11 +++++++++++ netbox_sys_plugin/forms/createvm.py | 1 + netbox_sys_plugin/models/operation.py | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 docs/model/netbox_sys_webhook_settings.md diff --git a/docs/model/netbox_sys_webhook_settings.md b/docs/model/netbox_sys_webhook_settings.md new file mode 100644 index 0000000..680b800 --- /dev/null +++ b/docs/model/netbox_sys_webhook_settings.md @@ -0,0 +1,11 @@ +## netbox_sys_webhook_settings + +**Webhook Settings definition class** + +| FIELD | TYPE | DESCRIPTION | +|----------------------------------------------------|----------------------------------|---------------------------------------------------------------------------| +| id | Big (8 byte) integer | Unique ID | +| payload_url | String (URL ) | URL will be called using the POST method when the webhook is called | +| http_content_type | String (100) | Http content type used in the webhook. Default value "application/json" | + + diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index cbd46b8..4a6e69f 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -116,6 +116,7 @@ class VmAssignedVirtualMachineTypeForm(NetBoxModelForm, forms.Form): virtual_machine_type = DynamicModelChoiceField( queryset=VirtualMachineType.objects.all(), + required=True, query_params={'cluster_type_id': '$cl_list_new-cluster_type',}, ) diff --git a/netbox_sys_plugin/models/operation.py b/netbox_sys_plugin/models/operation.py index 9c4aa19..6b35db7 100644 --- a/netbox_sys_plugin/models/operation.py +++ b/netbox_sys_plugin/models/operation.py @@ -16,7 +16,7 @@ class WebhookSettings(NetBoxModel): max_length=500, verbose_name=_('URL'), help_text=_( - "This URL will be called using the HTTP method defined when the webhook is called." + "This URL will be called using the HTTP POST when the webhook is called." ) ) -- GitLab From 68d8b2e3a4d68c9920529514526f32f1df942077 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Thu, 19 Dec 2024 13:02:29 +0000 Subject: [PATCH 07/12] =?UTF-8?q?=E2=9C=A8=20Insert=20data=20into=20vm=20t?= =?UTF-8?q?ype=20assignment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index 4a6e69f..5a3bf83 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -100,7 +100,7 @@ class DomainNamesForm(NetBoxModelForm): domain_names = JSONField( label=_(''), required=True, - initial=({'domain_name': 'domain1'}) + initial=({'example_domain_name': 'example_domain1','example_domain_name2': 'example_domain2'}) ) class Meta: @@ -379,13 +379,32 @@ class CreateVmForm(NetBoxModelForm): self.create_ip_address(data,vm_interface,'ip_new','Network IP Address') self.create_ip_address(data,vm_interface,'gateway_new','Network Gateway') + @staticmethod + def create_vmtype_assignment(data, vm): + vmtype_id =data.get('vmassignedvmtype_new-virtual_machine_type', '') + try: + vmtype = VirtualMachineType.objects.get(pk=vmtype_id) + except VirtualMachineType.DoesNotExist: + raise ValueError(f"Invalid VM Type ID: {vmtype}") + + vm_assignment = VmAssignedVirtualMachineType( + virtual_machine_type=vmtype, + assigned_object=vm + ) + vm_assignment.full_clean() + vm_assignment.save() + CreateVmForm.assign_tags(vm_assignment,data) + return vm_assignment + def process_creation(self, data): """Object creation""" try: with transaction.atomic(): + print(data) cluster = Cluster.objects.get(pk=data.get('cl_list_new-cluster', '')) vm = self.create_virtual_machine(data, cluster) vmi = self.create_vm_interface(data, vm) + self.create_vmtype_assignment(data,vm) self.create_all_services(data, vm) self.create_all_ip_adresses(data, vmi) -- GitLab From 13ed2f7d3209b9b3a72e1e7e0278556112d7043b Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Fri, 20 Dec 2024 09:50:11 +0000 Subject: [PATCH 08/12] =?UTF-8?q?=E2=9C=A8=20Add=20domain=20names=20and=20?= =?UTF-8?q?fix=20VM=20type=20object=20creation=20and=20payload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 55 ++++++++++++++++++++++++++--- netbox_sys_plugin/models/machine.py | 2 +- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index 5a3bf83..674052e 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -381,43 +381,72 @@ class CreateVmForm(NetBoxModelForm): @staticmethod def create_vmtype_assignment(data, vm): + """Assign a Type to the virtual machine.""" vmtype_id =data.get('vmassignedvmtype_new-virtual_machine_type', '') try: vmtype = VirtualMachineType.objects.get(pk=vmtype_id) except VirtualMachineType.DoesNotExist: - raise ValueError(f"Invalid VM Type ID: {vmtype}") + raise ValueError(f"Invalid VM Type ID: {vmtype_id}") vm_assignment = VmAssignedVirtualMachineType( virtual_machine_type=vmtype, - assigned_object=vm + assigned_object=vm, + virtual_machine_type_assignment_desc=f"Type {vmtype.virtual_machine_type_name} {vmtype.virtual_machine_type_desc} assigned to {vm.name}" ) vm_assignment.full_clean() vm_assignment.save() CreateVmForm.assign_tags(vm_assignment,data) return vm_assignment - + + @staticmethod + def create_domain_names(data, vm): + """Create and save DomainNames objects for the virtual machine.""" + domain_names_data = data.get('domainnames_new-domain_names', None) + + if not domain_names_data: + return None + + domain_names_object = DomainNames( + domain_names=domain_names_data, + assigned_object_type=ContentType.objects.get_for_model(vm), + assigned_object_id=vm.id, + ) + domain_names_object.full_clean() + domain_names_object.save() + CreateVmForm.assign_tags(domain_names_object, data) + return domain_names_object + def process_creation(self, data): """Object creation""" try: with transaction.atomic(): - print(data) cluster = Cluster.objects.get(pk=data.get('cl_list_new-cluster', '')) vm = self.create_virtual_machine(data, cluster) vmi = self.create_vm_interface(data, vm) self.create_vmtype_assignment(data,vm) + self.create_domain_names(data,vm) self.create_all_services(data, vm) self.create_all_ip_adresses(data, vmi) # Gather related data for webhook payload - interfaces = VMInterface.objects.filter(virtual_machine=vm) services = Service.objects.filter(virtual_machine=vm) vm_interface_content_type = ContentType.objects.get_for_model(VMInterface) + vm_content_type = ContentType.objects.get_for_model(VirtualMachine) ip_addresses = IPAddress.objects.filter( assigned_object_id__in=interfaces.values_list('id', flat=True), assigned_object_type=vm_interface_content_type ) + types = VmAssignedVirtualMachineType.objects.filter( + assigned_object_id=vm.id, + assigned_object_type=vm_content_type + ).select_related('virtual_machine_type') + + domain_names = DomainNames.objects.filter( + assigned_object_id=vm.id, + assigned_object_type=ContentType.objects.get_for_model(VirtualMachine) + ) payload = { "virtual_machine": { @@ -436,6 +465,15 @@ class CreateVmForm(NetBoxModelForm): "name": cluster.type.name if cluster.type else None, }, }, + "Virtual Machine Type": [ + { + "id": type.id, + "name": type.virtual_machine_type.virtual_machine_type_name, + "description": type.virtual_machine_type.virtual_machine_type_desc + + } + for type in types + ], "interface": [ { "id": interface.id, @@ -458,6 +496,13 @@ class CreateVmForm(NetBoxModelForm): } for service in services ], + "domain_names": [ + { + "id": domain.id, + "names": domain.domain_names, + } + for domain in domain_names + ], } print("payload",payload) diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py index 25098d0..8ccb800 100644 --- a/netbox_sys_plugin/models/machine.py +++ b/netbox_sys_plugin/models/machine.py @@ -13,7 +13,7 @@ from django.db import models from virtualization.models import VirtualMachine, ClusterType from netbox.models import NetBoxModel -VM_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="VirtualMachine")) +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 -- GitLab From 15f6ccd17c43225c899ce5b7ad09cc19b1962e94 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Fri, 20 Dec 2024 09:56:50 +0000 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=94=87=20Remove=20logs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index 674052e..829acbc 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -504,7 +504,6 @@ class CreateVmForm(NetBoxModelForm): for domain in domain_names ], } - print("payload",payload) # Send webhook send_webhook(payload) -- GitLab From b0f64009ba8d763a60178694046749b77ffaac64 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Fri, 20 Dec 2024 10:28:29 +0000 Subject: [PATCH 10/12] =?UTF-8?q?=F0=9F=92=84=20Change=20navigation=20labe?= =?UTF-8?q?ls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/navigation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index c9df8ff..e92953a 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -73,31 +73,31 @@ clusterProviderCredentialsItem = [ vmMachineItem = [ PluginMenuItem( link="plugins:netbox_sys_plugin:virtualmachinetype_list", - link_text="VM Type", + link_text="Type", buttons=vm_machine_type_buttons, permissions=["netbox_sys_plugin.list_vmmachinetype"], ), PluginMenuItem( link="plugins:netbox_sys_plugin:vmassignedvirtualmachinetype_list", - link_text="VM Type Assignment", + link_text="Type Assignment", buttons=vm_assigned_machine_type_buttons, permissions=["netbox_sys_plugin.list_vmassignedmachinetype"], ), PluginMenuItem( link="plugins:netbox_sys_plugin:virtualmachinemaintenance_list", - link_text="VM Maintenance", + link_text="Maintenance", buttons=vm_maintenance_buttons, permissions=["netbox_sys_plugin.list_maintenance"], ), PluginMenuItem( link="plugins:netbox_sys_plugin:domainnames_list", - link_text="VM Domain Names", + link_text="Domain Names", buttons=create_domainnames_buttons, permissions=["netbox_sys_plugin.add_domainnames"], ), PluginMenuItem( link="plugins:netbox_sys_plugin:creatvm_add", - link_text="Create VM", + link_text="Create Virtual Machine", permissions=["netbox_sys_plugin.add_createvm"], ), ] -- GitLab From a1a61e90278c689f993343a00e9e11e43a84153a Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Fri, 20 Dec 2024 10:52:07 +0000 Subject: [PATCH 11/12] =?UTF-8?q?=F0=9F=97=83=EF=B8=8F=20add=20missing=20m?= =?UTF-8?q?igrations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...mainnames_assigned_object_type_and_more.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 netbox_sys_plugin/migrations/0009_alter_domainnames_assigned_object_type_and_more.py diff --git a/netbox_sys_plugin/migrations/0009_alter_domainnames_assigned_object_type_and_more.py b/netbox_sys_plugin/migrations/0009_alter_domainnames_assigned_object_type_and_more.py new file mode 100644 index 0000000..7dc9a61 --- /dev/null +++ b/netbox_sys_plugin/migrations/0009_alter_domainnames_assigned_object_type_and_more.py @@ -0,0 +1,40 @@ +# Generated by Django 4.2.16 on 2024-12-20 10:51 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('netbox_sys_plugin', '0008_webhooksettings'), + ] + + operations = [ + migrations.AlterField( + model_name='domainnames', + name='assigned_object_type', + field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='virtualmachinemaintenance', + name='assigned_object_type', + field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='virtualmachinetype', + name='virtual_machine_type_desc', + field=models.CharField(default=None, max_length=100), + ), + migrations.AlterField( + model_name='vmassignedvirtualmachinetype', + name='assigned_object_type', + field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'), + ), + migrations.AlterField( + model_name='webhooksettings', + name='http_content_type', + field=models.CharField(default='application/json', max_length=100), + ), + ] -- GitLab From 8e0a9f5e5618510be560b78ca1c69130cf3a2a17 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Fri, 20 Dec 2024 12:06:51 +0000 Subject: [PATCH 12/12] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20Typo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../netbox_sys_plugin/clustertype_virtualmachinetype.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html b/netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html index cd3a25c..fb72b29 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/clustertype_virtualmachinetype.html @@ -2,7 +2,7 @@ <div class="row mb-3"> <div class="col col-md-12"> <div class="card"> - <h5 class="card-header">Provider Credentials</h5> + <h5 class="card-header">Virtual Machine Types</h5> <div class="card-body"> <table class="table table-responsive"> <th scope="row">Virtual Machine Type</th> -- GitLab