From 302a4052d6849b2aeee03ff46ad4d86403de5442 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Mon, 10 Feb 2025 15:15:06 +0000 Subject: [PATCH 1/9] =?UTF-8?q?=F0=9F=91=BD=EF=B8=8F=20=E2=9C=A8=20Add=20n?= =?UTF-8?q?ew=20POST=20endpoint=20to=20create=20a=20VM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 125 ++++++++++++++++++++++++++- netbox_sys_plugin/api/urls.py | 1 + netbox_sys_plugin/api/views.py | 35 +++++++- 3 files changed, 159 insertions(+), 2 deletions(-) diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index 9f059af..8691831 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -1,5 +1,6 @@ from rest_framework import serializers from virtualization.models import VirtualMachine, Cluster, ClusterType +from dcim.models import DeviceRole, Platform from netbox.api.fields import ChoiceField from dcim.api.nested_serializers import ( NestedDeviceSerializer, NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer, @@ -14,6 +15,8 @@ from virtualization.choices import * from netbox.api.serializers import NetBoxModelSerializer from ..utils import validate_extra_config_values from ..validators import validate_extra_config_structure +from ..forms import CreateVmForm +import json #Netbox Data Serializer @@ -396,4 +399,124 @@ class VirtualMachineSerializer(NetBoxModelSerializer): vm_assigned_extra_config = VmAssignedExtraConfig.objects.filter(assigned_object_type=ContentType.objects.get_for_model(VirtualMachine), assigned_object_id=obj.id) return NestedVmAssignedExtraConfigSerializer(vm_assigned_extra_config, many=True).data - \ No newline at end of file + +class CreateVmSerializer(serializers.Serializer): + """Serializer to handle Create VM requests.""" + cluster_type = serializers.CharField(required=True) + cluster = serializers.CharField(required=True) + name = serializers.CharField(required=True, max_length=50) + status = serializers.CharField(required=True, max_length=50) + role = serializers.CharField(required=True) + platform = serializers.CharField(required=True) + description = serializers.CharField(required=False, allow_blank=True) + virtual_machine_type = serializers.CharField(required=True) + interface_name = serializers.CharField(required=True, max_length=50) + ip_addresses = serializers.CharField(required=True, max_length=50) + ip_addresses_status = serializers.CharField(required=True, max_length=50) + gateway = serializers.CharField(required=True, max_length=50) + gateway_status = serializers.CharField(required=True, max_length=50) + domain_names = serializers.JSONField(required=False) + extra_config_structure = serializers.CharField(required=True) + extra_config_values = serializers.JSONField(required=False) + ntp_service_name = serializers.CharField(required=True, max_length=50) + ntp_service_protocol = serializers.CharField(required=True, max_length=50) + ntp_service_ports = serializers.CharField(required=True, max_length=50) + dns_service_name = serializers.CharField(required=True, max_length=50) + dns_service_protocol = serializers.CharField(required=True, max_length=50) + dns_service_ports = serializers.CharField(required=True, max_length=50) + syslog_service_name = serializers.CharField(required=True, max_length=50) + syslog_service_protocol = serializers.CharField(required=True, max_length=50) + syslog_service_ports = serializers.CharField(required=True, max_length=50) + #tags = serializers.ListField(child=serializers.IntegerField(), required=False) + + class Meta: + fields = '__all__' + + def validate(self, data): + request = self.context.get("request") + if not request or not request.user.has_perm("virtualization.add_virutal_machine"): + raise serializers.ValidationError("You dont have permission to create a VM") + + cluster_type = data.pop('cluster_type', None) + data['cl_list_new-cluster_type']=cluster_type + + cluster = data.pop('cluster', None) + data['cl_list_new-cluster']=cluster + + name = data.pop('name', None) + data['vms_new-0-name']=name + + status = data.pop('status', None) + data['vms_new-0-status']=status + + role = data.pop('role', None) + data['vms_new-0-role']=role + + platform = data.pop('platform', None) + data['vms_new-0-platform']=platform + + description = data.pop('description', None) + data['vms_new-0-description']=description + + virtual_machine_type = data.pop('virtual_machine_type', None) + data['vmassignedvmtype_new-virtual_machine_type']=virtual_machine_type + + interface_name = data.pop('interface_name', None) + data['vmis_new-0-name']=interface_name + + ip_addresses = data.pop('ip_addresses', None) + data['ip_new-address']=ip_addresses + + ip_addresses_status = data.pop('ip_addresses_status', None) + data['ip_new-status']=ip_addresses_status + + gateway = data.pop('gateway', None) + data['gateway_new-address']=gateway + + gateway_status = data.pop('gateway_status', None) + data['gateway_new-status']=gateway_status + + domain_names = data.pop('domain_names', None) + data['domainnames_new-domain_names']=json.dumps(domain_names) + + extra_config_structure = data.pop('extra_config_structure', None) + data['vmassignedextraconfig_new-provider_type_extra_config']=extra_config_structure + + extra_config_values = data.pop('extra_config_values', None) + data['vmassignedextraconfig_new-extra_config_values']=json.dumps(extra_config_values) + + ntp_service_name = data.pop('ntp_service_name', None) + data['service_ntp-0-name']=ntp_service_name + + ntp_service_protocol = data.pop('ntp_service_protocol', None) + data['service_ntp-0-protocol']=ntp_service_protocol + + ntp_service_ports = data.pop('ntp_service_ports', None) + data['service_ntp-0-ports']=ntp_service_ports + + dns_service_name = data.pop('dns_service_name', None) + data['service_dns-0-name']=dns_service_name + + dns_service_protocol = data.pop('dns_service_protocol', None) + data['service_dns-0-protocol']=dns_service_protocol + + dns_service_ports = data.pop('dns_service_ports', None) + data['service_dns-0-ports']=dns_service_ports + + syslog_service_name = data.pop('syslog_service_name', None) + data['service_syslog-0-name']=syslog_service_name + + syslog_service_protocol = data.pop('syslog_service_protocol', None) + data['service_syslog-0-protocol']=syslog_service_protocol + + syslog_service_ports = data.pop('syslog_service_ports', None) + data['service_syslog-0-ports']=syslog_service_ports + data = super().validate(data) + return data + + def create(self, data): + """Process VM creation using CreateVmForm.""" + form_data = data + form = CreateVmForm(data=form_data) + vm = form.process_creation(form_data) + return vm \ No newline at end of file diff --git a/netbox_sys_plugin/api/urls.py b/netbox_sys_plugin/api/urls.py index b6d7df9..67c639c 100644 --- a/netbox_sys_plugin/api/urls.py +++ b/netbox_sys_plugin/api/urls.py @@ -12,6 +12,7 @@ router.register(r'ProviderTypeExtraConfig', ProviderTypeExtraConfigViewSet) router.register(r'VirtualMachine', VirtualMachineViewSet, basename='virtualmachine') router.register(r'ExtraConfig', ProviderTypeExtraConfigViewSet) router.register(r'AssignedExtraConfig', VmAssignedExtraConfigViewSet) +router.register(r'CreateVM', CreateVmViewSet) app_name = 'netbox_sys_plugin' diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index c407a54..c209153 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -1,9 +1,10 @@ from rest_framework import viewsets, status -from rest_framework.decorators import action +from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from django.db.models import Prefetch from netbox.api.viewsets import NetBoxModelViewSet from virtualization import filtersets +from django.db import transaction from .. filtersets import VmTypeFilterSet, ProviderTypeExtraConfigFilterSet from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType,DomainNames, ProviderTypeExtraConfig, WebhookPayload from . serializers import * @@ -66,3 +67,35 @@ class VmAssignedExtraConfigViewSet(viewsets.ModelViewSet): serializer_class = VmAssignedExtraConfigSerializer http_method_names = ["get", "post", "patch", "delete", "options"] +class CreateVmViewSet(NetBoxModelViewSet): + """API ViewSet to handle VM creation.""" + queryset = WebhookPayload.objects.all() + serializer_class = CreateVmSerializer + permission_classes = [IsAuthenticated] + http_method_names = ["post"] + + def create_vm(self, request): + serializer = self.get_serializer(data=request.data) + if serializer.is_valid(): + try: + with transaction.atomic(): + vm = serializer.save() + return Response({ + "message": "VM created successfully!", + "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, + "domain_names": vm.domain_names, + "extra_config_values": vm.extra_config_values, + "virtual_machine_type": vm.virtual_machine_type.id if vm.virtual_machine_type else None, + "services": vm.services, + "ip_addresses": vm.ip_addresses, + }, + }, status=status.HTTP_201_CREATED) + except ValueError as e: + return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -- GitLab From 1cb1deb9375da34afcb64721309397510c157376 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Mon, 10 Feb 2025 15:39:37 +0000 Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=90=9B=20Fix=20naming=20and=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 2 +- netbox_sys_plugin/api/urls.py | 2 +- netbox_sys_plugin/api/views.py | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index 8691831..a2b5592 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -400,7 +400,7 @@ class VirtualMachineSerializer(NetBoxModelSerializer): assigned_object_id=obj.id) return NestedVmAssignedExtraConfigSerializer(vm_assigned_extra_config, many=True).data -class CreateVmSerializer(serializers.Serializer): +class CreateVirtualMachineSerializer(serializers.Serializer): """Serializer to handle Create VM requests.""" cluster_type = serializers.CharField(required=True) cluster = serializers.CharField(required=True) diff --git a/netbox_sys_plugin/api/urls.py b/netbox_sys_plugin/api/urls.py index 67c639c..67be6be 100644 --- a/netbox_sys_plugin/api/urls.py +++ b/netbox_sys_plugin/api/urls.py @@ -12,7 +12,7 @@ router.register(r'ProviderTypeExtraConfig', ProviderTypeExtraConfigViewSet) router.register(r'VirtualMachine', VirtualMachineViewSet, basename='virtualmachine') router.register(r'ExtraConfig', ProviderTypeExtraConfigViewSet) router.register(r'AssignedExtraConfig', VmAssignedExtraConfigViewSet) -router.register(r'CreateVM', CreateVmViewSet) +router.register(r'CreateVirtualMachine', CreateVirtualMachineViewSet,basename='CreteVirtualMachine') app_name = 'netbox_sys_plugin' diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index c209153..6984939 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -67,14 +67,13 @@ class VmAssignedExtraConfigViewSet(viewsets.ModelViewSet): serializer_class = VmAssignedExtraConfigSerializer http_method_names = ["get", "post", "patch", "delete", "options"] -class CreateVmViewSet(NetBoxModelViewSet): +class CreateVirtualMachineViewSet(NetBoxModelViewSet): """API ViewSet to handle VM creation.""" - queryset = WebhookPayload.objects.all() - serializer_class = CreateVmSerializer + serializer_class = CreateVirtualMachineSerializer permission_classes = [IsAuthenticated] http_method_names = ["post"] - def create_vm(self, request): + def create_virtual_machine(self, request): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): try: -- GitLab From e15c66222e9c2ef45bef30e349a0d104d2206ad2 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Mon, 10 Feb 2025 17:06:45 +0000 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=90=9B=20Fix=20permission=20bug?= 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/views.py | 22 ++++++---------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index a2b5592..63455c7 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 django.contrib.auth.models import User from virtualization.models import VirtualMachine, Cluster, ClusterType -from dcim.models import DeviceRole, Platform from netbox.api.fields import ChoiceField from dcim.api.nested_serializers import ( NestedDeviceSerializer, NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer, @@ -430,13 +430,19 @@ class CreateVirtualMachineSerializer(serializers.Serializer): #tags = serializers.ListField(child=serializers.IntegerField(), required=False) class Meta: - fields = '__all__' + fields = ['cluster_type','cluster','name','status','role','platform' + ,'description','virtual_machine_type','interface_name','ip_addresses','ip_addresses_status' + ,'gateway','gateway_status','domain_names','extra_config_structure','extra_config_values' + ,'ntp_service_name','ntp_service_protocol','ntp_service_ports' + ,'dns_service_name','dns_service_protocol','dns_service_ports' + ,'syslog_service_name','syslog_service_protocol','syslog_service_ports' + ] def validate(self, data): request = self.context.get("request") - if not request or not request.user.has_perm("virtualization.add_virutal_machine"): + if not request or not request.user.has_perm("virtualization.add_virtualmachine"): raise serializers.ValidationError("You dont have permission to create a VM") - + cluster_type = data.pop('cluster_type', None) data['cl_list_new-cluster_type']=cluster_type @@ -511,12 +517,11 @@ class CreateVirtualMachineSerializer(serializers.Serializer): syslog_service_ports = data.pop('syslog_service_ports', None) data['service_syslog-0-ports']=syslog_service_ports + data = super().validate(data) return data def create(self, data): """Process VM creation using CreateVmForm.""" - form_data = data - form = CreateVmForm(data=form_data) - vm = form.process_creation(form_data) - return vm \ No newline at end of file + + return data \ No newline at end of file diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index 6984939..fd91921 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -1,5 +1,5 @@ from rest_framework import viewsets, status -from rest_framework.permissions import IsAuthenticated +from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions from rest_framework.response import Response from django.db.models import Prefetch from netbox.api.viewsets import NetBoxModelViewSet @@ -69,31 +69,21 @@ class VmAssignedExtraConfigViewSet(viewsets.ModelViewSet): class CreateVirtualMachineViewSet(NetBoxModelViewSet): """API ViewSet to handle VM creation.""" + queryset = Cluster.objects.all() serializer_class = CreateVirtualMachineSerializer - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, DjangoModelPermissions] http_method_names = ["post"] - def create_virtual_machine(self, request): + def create(self, request): serializer = self.get_serializer(data=request.data) if serializer.is_valid(): try: with transaction.atomic(): vm = serializer.save() + form = CreateVmForm(data=vm) + vm = form.process_creation(vm) return Response({ "message": "VM created successfully!", - "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, - "domain_names": vm.domain_names, - "extra_config_values": vm.extra_config_values, - "virtual_machine_type": vm.virtual_machine_type.id if vm.virtual_machine_type else None, - "services": vm.services, - "ip_addresses": vm.ip_addresses, - }, }, status=status.HTTP_201_CREATED) except ValueError as e: return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) -- GitLab From 09f25640b27c672f61ad865092afea7ecd1f287b Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 11 Feb 2025 09:36:55 +0000 Subject: [PATCH 4/9] =?UTF-8?q?=F0=9F=91=BD=EF=B8=8F=20Add=20tag=20to=20AP?= =?UTF-8?q?I=20endpoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 35 +++++++++++++++------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index 63455c7..b9bcfb4 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -402,21 +402,21 @@ class VirtualMachineSerializer(NetBoxModelSerializer): class CreateVirtualMachineSerializer(serializers.Serializer): """Serializer to handle Create VM requests.""" - cluster_type = serializers.CharField(required=True) - cluster = serializers.CharField(required=True) + cluster_type = serializers.IntegerField(required=True) + cluster = serializers.IntegerField(required=True) name = serializers.CharField(required=True, max_length=50) status = serializers.CharField(required=True, max_length=50) - role = serializers.CharField(required=True) - platform = serializers.CharField(required=True) - description = serializers.CharField(required=False, allow_blank=True) - virtual_machine_type = serializers.CharField(required=True) + role = serializers.IntegerField(required=True) + platform = serializers.IntegerField(required=True) + description = serializers.CharField(required=True) + virtual_machine_type = serializers.IntegerField(required=True) interface_name = serializers.CharField(required=True, max_length=50) ip_addresses = serializers.CharField(required=True, max_length=50) ip_addresses_status = serializers.CharField(required=True, max_length=50) gateway = serializers.CharField(required=True, max_length=50) gateway_status = serializers.CharField(required=True, max_length=50) domain_names = serializers.JSONField(required=False) - extra_config_structure = serializers.CharField(required=True) + extra_config_structure = serializers.IntegerField(required=True) extra_config_values = serializers.JSONField(required=False) ntp_service_name = serializers.CharField(required=True, max_length=50) ntp_service_protocol = serializers.CharField(required=True, max_length=50) @@ -427,7 +427,7 @@ class CreateVirtualMachineSerializer(serializers.Serializer): syslog_service_name = serializers.CharField(required=True, max_length=50) syslog_service_protocol = serializers.CharField(required=True, max_length=50) syslog_service_ports = serializers.CharField(required=True, max_length=50) - #tags = serializers.ListField(child=serializers.IntegerField(), required=False) + tag = serializers.IntegerField(required=False) class Meta: fields = ['cluster_type','cluster','name','status','role','platform' @@ -436,6 +436,7 @@ class CreateVirtualMachineSerializer(serializers.Serializer): ,'ntp_service_name','ntp_service_protocol','ntp_service_ports' ,'dns_service_name','dns_service_protocol','dns_service_ports' ,'syslog_service_name','syslog_service_protocol','syslog_service_ports' + ,'tag' ] def validate(self, data): @@ -444,10 +445,10 @@ class CreateVirtualMachineSerializer(serializers.Serializer): raise serializers.ValidationError("You dont have permission to create a VM") cluster_type = data.pop('cluster_type', None) - data['cl_list_new-cluster_type']=cluster_type + data['cl_list_new-cluster_type']= str(cluster_type) cluster = data.pop('cluster', None) - data['cl_list_new-cluster']=cluster + data['cl_list_new-cluster']= str(cluster) name = data.pop('name', None) data['vms_new-0-name']=name @@ -456,16 +457,16 @@ class CreateVirtualMachineSerializer(serializers.Serializer): data['vms_new-0-status']=status role = data.pop('role', None) - data['vms_new-0-role']=role + data['vms_new-0-role']=str(role) platform = data.pop('platform', None) - data['vms_new-0-platform']=platform + data['vms_new-0-platform']=str(platform) description = data.pop('description', None) data['vms_new-0-description']=description virtual_machine_type = data.pop('virtual_machine_type', None) - data['vmassignedvmtype_new-virtual_machine_type']=virtual_machine_type + data['vmassignedvmtype_new-virtual_machine_type']=str(virtual_machine_type) interface_name = data.pop('interface_name', None) data['vmis_new-0-name']=interface_name @@ -486,7 +487,7 @@ class CreateVirtualMachineSerializer(serializers.Serializer): data['domainnames_new-domain_names']=json.dumps(domain_names) extra_config_structure = data.pop('extra_config_structure', None) - data['vmassignedextraconfig_new-provider_type_extra_config']=extra_config_structure + data['vmassignedextraconfig_new-provider_type_extra_config']=str(extra_config_structure) extra_config_values = data.pop('extra_config_values', None) data['vmassignedextraconfig_new-extra_config_values']=json.dumps(extra_config_values) @@ -507,7 +508,7 @@ class CreateVirtualMachineSerializer(serializers.Serializer): data['service_dns-0-protocol']=dns_service_protocol dns_service_ports = data.pop('dns_service_ports', None) - data['service_dns-0-ports']=dns_service_ports + data['service_dns-0-ports']= dns_service_ports syslog_service_name = data.pop('syslog_service_name', None) data['service_syslog-0-name']=syslog_service_name @@ -518,10 +519,12 @@ class CreateVirtualMachineSerializer(serializers.Serializer): syslog_service_ports = data.pop('syslog_service_ports', None) data['service_syslog-0-ports']=syslog_service_ports + tag = data.pop('tag', None) + data['tag_new-tag']=str(tag) + data = super().validate(data) return data def create(self, data): """Process VM creation using CreateVmForm.""" - return data \ No newline at end of file -- GitLab From c84fa015a61a79af14d95104e5c4a6378a5b404b Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 11 Feb 2025 17:23:42 +0000 Subject: [PATCH 5/9] =?UTF-8?q?=E2=9C=85=20Add=20tests=20for=20the=20Creat?= =?UTF-8?q?eVM=20API=20endpoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 14 +-- netbox_sys_plugin/api/views.py | 1 + .../tests/createvm/test_createvm_api.py | 109 ++++++++++++++++++ netbox_sys_plugin/tests/test_init.py | 2 +- 4 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 netbox_sys_plugin/tests/createvm/test_createvm_api.py diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index b9bcfb4..ca8b1ee 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -1,5 +1,4 @@ from rest_framework import serializers -from django.contrib.auth.models import User from virtualization.models import VirtualMachine, Cluster, ClusterType from netbox.api.fields import ChoiceField from dcim.api.nested_serializers import ( @@ -15,7 +14,6 @@ from virtualization.choices import * from netbox.api.serializers import NetBoxModelSerializer from ..utils import validate_extra_config_values from ..validators import validate_extra_config_structure -from ..forms import CreateVmForm import json #Netbox Data Serializer @@ -402,11 +400,11 @@ class VirtualMachineSerializer(NetBoxModelSerializer): class CreateVirtualMachineSerializer(serializers.Serializer): """Serializer to handle Create VM requests.""" - cluster_type = serializers.IntegerField(required=True) - cluster = serializers.IntegerField(required=True) + provider_type = serializers.IntegerField(required=True) + provider = serializers.IntegerField(required=True) name = serializers.CharField(required=True, max_length=50) status = serializers.CharField(required=True, max_length=50) - role = serializers.IntegerField(required=True) + owner = serializers.IntegerField(required=True) platform = serializers.IntegerField(required=True) description = serializers.CharField(required=True) virtual_machine_type = serializers.IntegerField(required=True) @@ -444,10 +442,10 @@ class CreateVirtualMachineSerializer(serializers.Serializer): if not request or not request.user.has_perm("virtualization.add_virtualmachine"): raise serializers.ValidationError("You dont have permission to create a VM") - cluster_type = data.pop('cluster_type', None) + cluster_type = data.pop('provider_type', None) data['cl_list_new-cluster_type']= str(cluster_type) - cluster = data.pop('cluster', None) + cluster = data.pop('provider', None) data['cl_list_new-cluster']= str(cluster) name = data.pop('name', None) @@ -456,7 +454,7 @@ class CreateVirtualMachineSerializer(serializers.Serializer): status = data.pop('status', None) data['vms_new-0-status']=status - role = data.pop('role', None) + role = data.pop('owner', None) data['vms_new-0-role']=str(role) platform = data.pop('platform', None) diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index fd91921..285ae72 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -8,6 +8,7 @@ from django.db import transaction from .. filtersets import VmTypeFilterSet, ProviderTypeExtraConfigFilterSet from .. models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType,DomainNames, ProviderTypeExtraConfig, WebhookPayload from . serializers import * +from ..forms import CreateVmForm class VirtualMachineMaintenanceViewSet(viewsets.ModelViewSet): queryset = VirtualMachineMaintenance.objects.all() diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_api.py b/netbox_sys_plugin/tests/createvm/test_createvm_api.py new file mode 100644 index 0000000..1bf4a52 --- /dev/null +++ b/netbox_sys_plugin/tests/createvm/test_createvm_api.py @@ -0,0 +1,109 @@ +"""SYS Plugin CreateVirtualMachine API Test Case Class""" + +from users.models import ObjectPermission +from django.contrib.contenttypes.models import ContentType +from rest_framework import status +from virtualization.models import Cluster, ClusterType, VMInterface, VirtualMachine +from dcim.models import DeviceRole, Platform +from ipam.models import IPAddress, Service +from extras.models import Tag +from ... models import DomainNames, VmAssignedVirtualMachineType, VirtualMachineType, VmAssignedExtraConfig, ProviderTypeExtraConfig, WebhookPayload +from ..base import BaseAPITestCase + +class CreateVmAPITestCase(BaseAPITestCase): + """Test suite for Create Virtual Machine API""" + brief_fields = [ +"cluster_type","cluster","name","status","role","platform","description","virtual_machine_type","interface_name","ip_addresses" + "ip_addresses_status","gateway","gateway_status","domain_names","extra_config_structure","extra_config_values","ntp_service_name", + "ntp_service_protocol","ntp_service_ports","dns_service_name","dns_service_protocol","dns_service_ports","syslog_service_name", + "syslog_service_protocol","syslog_service_ports","tag" + ] + + + @classmethod + def setUpTestData(cls): + + """Set up test data for Create Virtual Machine API""" + #Create Tag + cls.tag = Tag.objects.create(name="test_tag",slug="testtag") + #Create Device Role + cls.devicerole = DeviceRole.objects.create(name="Test Device", slug="TestRole") + #Create Platform + cls.platform = Platform.objects.create(name="Test platform", slug="TestPlatform") + # Create a ClusterType + cls.cluster_type = ClusterType.objects.create(name="Test ClusterType1", slug="ClusterType1") + # Create Cluster + cls.cluster = Cluster.objects.create(name="Test Cluster", type=cls.cluster_type) + # Create VM Type + cls.vmtype = VirtualMachineType.objects.create( + virtual_machine_type_name='vm_type_name1', + virtual_machine_type_desc='vm_type_desc_1', + assigned_object=cls.cluster_type + ) + cls.extra_config_structure = ProviderTypeExtraConfig.objects.create( + extra_config_name="TEST", + extra_config_structure={'test_extra': [{'id': {'required': 'true','type': 'String'}}]}, + extra_config_description="Test Extra", + assigned_object=cls.cluster_type + ) + + # Data for valid creation + cls.valid_create_data = [ + { + "provider_type": cls.cluster_type.id, + "provider": cls.cluster.id, + "name": "vm_test", + "status": "active", + "owner": cls.devicerole.id, + "platform": cls.platform.id, + "description": "test", + "virtual_machine_type": cls.vmtype.id, + "interface_name": "interface_test", + "ip_addresses": "192.168.1.10/24", + "ip_addresses_status": "active", + "gateway": "193.168.1.10/24", + "gateway_status": "active", + "domain_names": {"example_domain_name": "vm.example.com"}, + "extra_config_structure": cls.extra_config_structure.id, + "extra_config_values": {"id": "id"}, + "ntp_service_name": "ntp_test", + "ntp_service_protocol": "tcp", + "ntp_service_ports": "44", + "dns_service_name": "dns_test", + "dns_service_protocol": "tcp", + "dns_service_ports": "44", + "syslog_service_name": "syslog_test", + "syslog_service_protocol": "tcp", + "syslog_service_ports": "44", + "tag":str(cls.tag.id) + } + ] + + def test_valid_createVM(self): + """Test creating a valid CreateVM""" + + obj_perm = ObjectPermission( + name="Create CreateVM Permission", + actions=["add", "view"], + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(DeviceRole)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Platform)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ClusterType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Cluster)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VMInterface)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachine)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Service)) + obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress)) + obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedVirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ProviderTypeExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(WebhookPayload)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Tag)) + + api_data = self.valid_create_data[0] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_201_CREATED) diff --git a/netbox_sys_plugin/tests/test_init.py b/netbox_sys_plugin/tests/test_init.py index 8a0c2e0..b0b0bb7 100644 --- a/netbox_sys_plugin/tests/test_init.py +++ b/netbox_sys_plugin/tests/test_init.py @@ -24,5 +24,5 @@ class InitTestCase(APITestCase): self.assertTrue("VirtualMachine" in content) self.assertTrue("ExtraConfig" in content) self.assertTrue("AssignedExtraConfig" in content) - self.assertTrue("VirtualMachine" in content) + self.assertTrue("CreateVirtualMachine" in content) self.assertEqual(response.status_code, 200) -- GitLab From 21112b5b44d40876e73f5a3653639963475f68a1 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 11 Feb 2025 17:35:47 +0000 Subject: [PATCH 6/9] =?UTF-8?q?=F0=9F=90=9B=20Fix=20bug=20in=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/tests/createvm/test_createvm_view.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_view.py b/netbox_sys_plugin/tests/createvm/test_createvm_view.py index 5c09480..79df3d9 100644 --- a/netbox_sys_plugin/tests/createvm/test_createvm_view.py +++ b/netbox_sys_plugin/tests/createvm/test_createvm_view.py @@ -136,7 +136,7 @@ class CreateVmFormTestCase(TestCase): #invalid role/owner self.invalid_ports_form_data = self.form_data_template.copy() - self.invalid_ports_form_data["vms_new-0-role"] = "2" # Invalid format + self.invalid_ports_form_data["vms_new-0-role"] = "999" # Invalid Number form_data = self.invalid_ports_form_data form = CreateVmForm(data=form_data) with self.assertRaises(ValueError) as context: @@ -156,7 +156,7 @@ class CreateVmFormTestCase(TestCase): #invalid platform self.invalid_ports_form_data = self.form_data_template.copy() - self.invalid_ports_form_data["vms_new-0-platform"] = "2" # Invalid id + self.invalid_ports_form_data["vms_new-0-platform"] = "999" # Invalid id form_data = self.invalid_ports_form_data form = CreateVmForm(data=form_data) with self.assertRaises(ValueError) as context: @@ -176,7 +176,7 @@ class CreateVmFormTestCase(TestCase): #invalid Extra Config self.invalid_ports_form_data = self.form_data_template.copy() - self.invalid_ports_form_data["vmassignedextraconfig_new-provider_type_extra_config"] = "2" # Invalid id + self.invalid_ports_form_data["vmassignedextraconfig_new-provider_type_extra_config"] = "999" # Invalid id form_data = self.invalid_ports_form_data form = CreateVmForm(data=form_data) with self.assertRaises(ValueError) as context: -- GitLab From f6230789e1b8896c4af828efe61e29559008951d Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Wed, 12 Feb 2025 11:06:19 +0000 Subject: [PATCH 7/9] =?UTF-8?q?=E2=9C=85=20Add=20test=20GET=20virtualmachi?= =?UTF-8?q?ne=20info=20and=20create=20invalid=20info?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/views.py | 3 +- .../tests/createvm/test_createvm_api.py | 287 +++++++++++++++++- 2 files changed, 287 insertions(+), 3 deletions(-) diff --git a/netbox_sys_plugin/api/views.py b/netbox_sys_plugin/api/views.py index 285ae72..ea8e963 100644 --- a/netbox_sys_plugin/api/views.py +++ b/netbox_sys_plugin/api/views.py @@ -1,6 +1,7 @@ from rest_framework import viewsets, status from rest_framework.permissions import IsAuthenticated, DjangoModelPermissions from rest_framework.response import Response +from django.core.exceptions import ValidationError from django.db.models import Prefetch from netbox.api.viewsets import NetBoxModelViewSet from virtualization import filtersets @@ -86,6 +87,6 @@ class CreateVirtualMachineViewSet(NetBoxModelViewSet): return Response({ "message": "VM created successfully!", }, status=status.HTTP_201_CREATED) - except ValueError as e: + except (ValueError, ValidationError) as e: return Response({"error": str(e)}, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_api.py b/netbox_sys_plugin/tests/createvm/test_createvm_api.py index 1bf4a52..9bd45c9 100644 --- a/netbox_sys_plugin/tests/createvm/test_createvm_api.py +++ b/netbox_sys_plugin/tests/createvm/test_createvm_api.py @@ -48,8 +48,7 @@ class CreateVmAPITestCase(BaseAPITestCase): ) # Data for valid creation - cls.valid_create_data = [ - { + cls.valid_create_data = [{ "provider_type": cls.cluster_type.id, "provider": cls.cluster.id, "name": "vm_test", @@ -76,8 +75,126 @@ class CreateVmAPITestCase(BaseAPITestCase): "syslog_service_protocol": "tcp", "syslog_service_ports": "44", "tag":str(cls.tag.id) + }, + { + "provider_type": cls.cluster_type.id, + "provider": cls.cluster.id, + "name": "vm_test2", + "status": "active", + "owner": cls.devicerole.id, + "platform": cls.platform.id, + "description": "test", + "virtual_machine_type": cls.vmtype.id, + "interface_name": "interface_test", + "ip_addresses": "192.168.1.10/24", + "ip_addresses_status": "active", + "gateway": "193.168.1.10/24", + "gateway_status": "active", + "domain_names": {"example_domain_name": "vm.example.com"}, + "extra_config_structure": cls.extra_config_structure.id, + "extra_config_values": {"id": "id"}, + "ntp_service_name": "ntp_test", + "ntp_service_protocol": "tcp", + "ntp_service_ports": "44", + "dns_service_name": "dns_test", + "dns_service_protocol": "tcp", + "dns_service_ports": "44", + "syslog_service_name": "syslog_test", + "syslog_service_protocol": "tcp", + "syslog_service_ports": "44", + "tag":str(cls.tag.id) + }] + + # Data for invalid creation + cls.invalid_create_data = [ + #Check unique + { + "provider_type": cls.cluster_type.id, + "provider": cls.cluster.id, + "name": "vm_test", + "status": "active", + "owner": cls.devicerole.id, + "platform": cls.platform.id, + "description": "test_unique", + "virtual_machine_type": cls.vmtype.id, + "interface_name": "interface_test", + "ip_addresses": "192.168.1.10/24", + "ip_addresses_status": "active", + "gateway": "193.168.1.10/24", + "gateway_status": "active", + "domain_names": {"example_domain_name": "vm.example.com"}, + "extra_config_structure": cls.extra_config_structure.id, + "extra_config_values": {"id": "id"}, + "ntp_service_name": "ntp_test", + "ntp_service_protocol": "tcp", + "ntp_service_ports": "44", + "dns_service_name": "dns_test", + "dns_service_protocol": "tcp", + "dns_service_ports": "44", + "syslog_service_name": "syslog_test", + "syslog_service_protocol": "tcp", + "syslog_service_ports": "44", + "tag":str(cls.tag.id) + }, + #Invalid port + { + "provider_type": cls.cluster_type.id, + "provider": cls.cluster.id, + "name": "vm_test", + "status": "active", + "owner": cls.devicerole.id, + "platform": cls.platform.id, + "description": "test_invalid", + "virtual_machine_type": cls.vmtype.id, + "interface_name": "interface_test", + "ip_addresses": "192.168.1.10/24", + "ip_addresses_status": "active", + "gateway": "193.168.1.10/24", + "gateway_status": "active", + "domain_names": {"example_domain_name": "vm.example.com"}, + "extra_config_structure": cls.extra_config_structure.id, + "extra_config_values": {"id": "id"}, + "ntp_service_name": "ntp_test", + "ntp_service_protocol": "tcp", + "ntp_service_ports": "44", + "dns_service_name": "dns_test", + "dns_service_protocol": "tcp", + "dns_service_ports": "AA", + "syslog_service_name": "syslog_test", + "syslog_service_protocol": "tcp", + "syslog_service_ports": "44", + "tag":str(cls.tag.id) + }, + #Missing field + { + "provider_type": cls.cluster_type.id, + "provider": cls.cluster.id, + "name": "vm_test", + "status": "active", + "owner": cls.devicerole.id, + "platform": cls.platform.id, + "virtual_machine_type": cls.vmtype.id, + "interface_name": "interface_test", + "ip_addresses": "192.168.1.10/24", + "ip_addresses_status": "active", + "gateway": "193.168.1.10/24", + "gateway_status": "active", + "domain_names": {"example_domain_name": "vm.example.com"}, + "extra_config_structure": cls.extra_config_structure.id, + "extra_config_values": {"id": "id"}, + "ntp_service_name": "ntp_test", + "ntp_service_protocol": "tcp", + "ntp_service_ports": "44", + "dns_service_name": "dns_test", + "dns_service_protocol": "tcp", + "dns_service_ports": "AA", + "syslog_service_name": "syslog_test", + "syslog_service_protocol": "tcp", + "syslog_service_ports": "44", + "tag":str(cls.tag.id) } ] + def test_valid_createVM(self): """Test creating a valid CreateVM""" @@ -107,3 +224,169 @@ class CreateVmAPITestCase(BaseAPITestCase): api_data = self.valid_create_data[0] response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) self.assertHttpStatus(response, status.HTTP_201_CREATED) + + def test_unique_key_createVM(self): + """Test unique vm key of CreateVM""" + + obj_perm = ObjectPermission( + name="Create test unique CreateVM Permission", + actions=["add", "view"], + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(DeviceRole)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Platform)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ClusterType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Cluster)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VMInterface)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachine)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Service)) + obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress)) + obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedVirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ProviderTypeExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(WebhookPayload)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Tag)) + + #1st VM + api_data = self.invalid_create_data[0] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_201_CREATED) + #2nd VM + api_data = self.invalid_create_data[0] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) + self.assertIn('Virtual machine name must be unique per cluster.',str(response.data)) + + def test_invalid_value_createVM(self): + """Test creating an invalid CreateVM""" + + obj_perm = ObjectPermission( + name="Create invalid CreateVM Permission", + actions=["add", "view"], + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(DeviceRole)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Platform)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ClusterType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Cluster)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VMInterface)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachine)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Service)) + obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress)) + obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedVirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ProviderTypeExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(WebhookPayload)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Tag)) + + api_data = self.invalid_create_data[1] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) + self.assertIn('Error during creation: Invalid ports value: AA',str(response.data)) + + def test_invalid_missing_value_createVM(self): + """Test creating an invalid CreateVM""" + + obj_perm = ObjectPermission( + name="Create invalid CreateVM Permission", + actions=["add", "view"], + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(DeviceRole)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Platform)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ClusterType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Cluster)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VMInterface)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachine)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Service)) + obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress)) + obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedVirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ProviderTypeExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(WebhookPayload)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Tag)) + + api_data = self.invalid_create_data[2] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) + self.assertIn('This field is required.',str(response.data)) + + + def test_get_all_created_virtual_machines(self): + """Test fetching all VMs""" + obj_perm = ObjectPermission( + name="View all VMs Permission", + actions=["view","add"], + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(DeviceRole)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Platform)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ClusterType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Cluster)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VMInterface)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachine)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Service)) + obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress)) + obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedVirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ProviderTypeExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(WebhookPayload)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Tag)) + + #1st VM + api_data = self.valid_create_data[0] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_201_CREATED) + #2nd VM + api_data = self.valid_create_data[1] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_201_CREATED) + + response = self.client.get("/api/plugins/sys/VirtualMachine/", **self.header) + self.assertHttpStatus(response, status.HTTP_200_OK) + self.assertGreaterEqual(len(response.data), 2) + + def test_get_single_created_virtual_machine(self): + """Test fetching a single VM""" + obj_perm = ObjectPermission( + name="View single VM Permission", + actions=["view","add"], + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(DeviceRole)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Platform)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ClusterType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Cluster)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VMInterface)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachine)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Service)) + obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress)) + obj_perm.object_types.add(ContentType.objects.get_for_model(DomainNames)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedVirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VirtualMachineType)) + obj_perm.object_types.add(ContentType.objects.get_for_model(VmAssignedExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(ProviderTypeExtraConfig)) + obj_perm.object_types.add(ContentType.objects.get_for_model(WebhookPayload)) + obj_perm.object_types.add(ContentType.objects.get_for_model(Tag)) + + #1st VM + api_data = self.valid_create_data[0] + response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) + self.assertHttpStatus(response, status.HTTP_201_CREATED) + + VM = VirtualMachine.objects.first() + response = self.client.get((f'/api/plugins/sys/VirtualMachine/{VM.id}/'), **self.header) + self.assertHttpStatus(response, status.HTTP_200_OK) \ No newline at end of file -- GitLab From 08e181f267374806c52445b2bce069cf98df4700 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Wed, 12 Feb 2025 11:11:49 +0000 Subject: [PATCH 8/9] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20lint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/tests/createvm/test_createvm_api.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/netbox_sys_plugin/tests/createvm/test_createvm_api.py b/netbox_sys_plugin/tests/createvm/test_createvm_api.py index 9bd45c9..eaa1d55 100644 --- a/netbox_sys_plugin/tests/createvm/test_createvm_api.py +++ b/netbox_sys_plugin/tests/createvm/test_createvm_api.py @@ -104,7 +104,7 @@ class CreateVmAPITestCase(BaseAPITestCase): "syslog_service_ports": "44", "tag":str(cls.tag.id) }] - + # Data for invalid creation cls.invalid_create_data = [ #Check unique @@ -194,7 +194,6 @@ class CreateVmAPITestCase(BaseAPITestCase): "tag":str(cls.tag.id) } ] - def test_valid_createVM(self): """Test creating a valid CreateVM""" @@ -259,7 +258,7 @@ class CreateVmAPITestCase(BaseAPITestCase): response = self.client.post("/api/plugins/sys/CreateVirtualMachine/", api_data, format="json", **self.header) self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST) self.assertIn('Virtual machine name must be unique per cluster.',str(response.data)) - + def test_invalid_value_createVM(self): """Test creating an invalid CreateVM""" @@ -389,4 +388,4 @@ class CreateVmAPITestCase(BaseAPITestCase): VM = VirtualMachine.objects.first() response = self.client.get((f'/api/plugins/sys/VirtualMachine/{VM.id}/'), **self.header) - self.assertHttpStatus(response, status.HTTP_200_OK) \ No newline at end of file + self.assertHttpStatus(response, status.HTTP_200_OK) -- GitLab From f9fc488c6ce2d88d6f71cd7a06b93f81eb879a94 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Wed, 12 Feb 2025 11:19:26 +0000 Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20lint=20missing=20new?= =?UTF-8?q?=20line?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/api/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox_sys_plugin/api/serializers.py b/netbox_sys_plugin/api/serializers.py index ca8b1ee..7dd60b3 100644 --- a/netbox_sys_plugin/api/serializers.py +++ b/netbox_sys_plugin/api/serializers.py @@ -525,4 +525,4 @@ class CreateVirtualMachineSerializer(serializers.Serializer): def create(self, data): """Process VM creation using CreateVmForm.""" - return data \ No newline at end of file + return data -- GitLab