From 498753ff78acd5c5bffe5125cc0bb11452e6a97d Mon Sep 17 00:00:00 2001
From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu>
Date: Fri, 3 Jan 2025 17:12:10 +0000
Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A8=20Add=20lint=20and=20squash=20comm?=
 =?UTF-8?q?its?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .pylintrc                                     |  20 +++
 netbox_sys_plugin/filtersets.py               |   6 +-
 netbox_sys_plugin/forms/__init__.py           |   2 +-
 netbox_sys_plugin/forms/createvm.py           |  95 ++++++------
 netbox_sys_plugin/forms/machine.py            |  70 +++------
 netbox_sys_plugin/forms/operation.py          |   9 +-
 netbox_sys_plugin/forms/provider.py           |  22 ++-
 netbox_sys_plugin/migrations/0001_initial.py  | 145 +++++++++++++++++-
 ...maintenance_maintenance_window_and_more.py |  45 ------
 ...achinetype_vmassignedvirtualmachinetype.py |  58 -------
 ...redentials_provider_password_vault_path.py |  18 ---
 ...ovidercredentials_provider_url_and_more.py |  22 ---
 .../migrations/0006_domainnames.py            |  37 -----
 ..._alter_domainnames_assigned_object_type.py |  20 ---
 .../migrations/0008_webhooksettings.py        |  34 ----
 ...mainnames_assigned_object_type_and_more.py |  40 -----
 .../0010_providertypeextraconfig.py           |  37 -----
 ...ypeextraconfig_extra_config_description.py |  18 ---
 .../migrations/0012_vmassignedextraconfig.py  |  38 -----
 ...aconfig_extra_config_structure_and_more.py |  23 ---
 ...assignedextraconfig_extra_config_values.py |  18 ---
 ...dextraconfig_provider_type_extra_config.py |  19 ---
 netbox_sys_plugin/models/__init__.py          |   2 +-
 netbox_sys_plugin/models/machine.py           |  16 +-
 netbox_sys_plugin/models/operation.py         |  12 +-
 netbox_sys_plugin/models/provider.py          |  12 +-
 netbox_sys_plugin/navigation.py               |   6 +-
 netbox_sys_plugin/tables.py                   |  30 ++--
 netbox_sys_plugin/template_content.py         |  43 ++++--
 netbox_sys_plugin/urls.py                     |  48 ++++--
 netbox_sys_plugin/utils.py                    |  17 +-
 netbox_sys_plugin/views.py                    |  24 +--
 32 files changed, 380 insertions(+), 626 deletions(-)
 create mode 100644 .pylintrc
 delete mode 100644 netbox_sys_plugin/migrations/0002_alter_virtualmachinemaintenance_maintenance_window_and_more.py
 delete mode 100644 netbox_sys_plugin/migrations/0003_virtualmachinetype_vmassignedvirtualmachinetype.py
 delete mode 100644 netbox_sys_plugin/migrations/0004_rename_provider_password_vault_url_providercredentials_provider_password_vault_path.py
 delete mode 100644 netbox_sys_plugin/migrations/0005_remove_providercredentials_provider_url_and_more.py
 delete mode 100644 netbox_sys_plugin/migrations/0006_domainnames.py
 delete mode 100644 netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py
 delete mode 100644 netbox_sys_plugin/migrations/0008_webhooksettings.py
 delete mode 100644 netbox_sys_plugin/migrations/0009_alter_domainnames_assigned_object_type_and_more.py
 delete mode 100644 netbox_sys_plugin/migrations/0010_providertypeextraconfig.py
 delete mode 100644 netbox_sys_plugin/migrations/0011_providertypeextraconfig_extra_config_description.py
 delete mode 100644 netbox_sys_plugin/migrations/0012_vmassignedextraconfig.py
 delete mode 100644 netbox_sys_plugin/migrations/0013_rename_extra_config_providertypeextraconfig_extra_config_structure_and_more.py
 delete mode 100644 netbox_sys_plugin/migrations/0014_vmassignedextraconfig_extra_config_values.py
 delete mode 100644 netbox_sys_plugin/migrations/0015_alter_vmassignedextraconfig_provider_type_extra_config.py

diff --git a/.pylintrc b/.pylintrc
new file mode 100644
index 0000000..4f39def
--- /dev/null
+++ b/.pylintrc
@@ -0,0 +1,20 @@
+[MASTER]
+disable=R0903,R0901,C0103,C0114,C0115
+min-similarity-lines=10
+exclude-protected=_meta,_asdict,_fields,_replace,_source,_make,os._exit
+ignore=migrations
+
+# Maximum number of characters on a single line.
+max-line-length=180
+
+[FORMAT]
+max-line-length=180
+
+
+[MESSAGES CONTROL]
+
+# import-error works badly on most DEV setup.
+# If you want this to be enabled, please organize a troubleshoot session with the whole SQUAD.
+disable=
+    import-error,
+    R0801,
\ No newline at end of file
diff --git a/netbox_sys_plugin/filtersets.py b/netbox_sys_plugin/filtersets.py
index 45dcbae..5d6f964 100644
--- a/netbox_sys_plugin/filtersets.py
+++ b/netbox_sys_plugin/filtersets.py
@@ -28,7 +28,7 @@ class VmMaintenanceFilterSet(NetBoxModelFilterSet):
         if not value.strip():
             return queryset
         return queryset.filter(Q(maintenance_window__icontains=value))
-    
+
 class VmAssignedVmTypeFilterSet(NetBoxModelFilterSet):
     """VirtualMachineAssignType filterset definition class"""
 
@@ -101,7 +101,7 @@ class ProviderCredentialsFilterSet(NetBoxModelFilterSet):
         if not value.strip():
             return queryset
         return queryset.filter(Q(provider_username__icontains=value)|Q(provider_password_vault_url__icontains=value))
-    
+
 class ProviderTypeExtraConfigFilterSet(NetBoxModelFilterSet):
     """Provider Type Extra Config filterset definition class"""
 
@@ -132,5 +132,3 @@ class VmAssignedExtraConfigFilterSet(NetBoxModelFilterSet):
         """Meta class"""     
         model = VmAssignedExtraConfig
         fields = ('assigned_object_type','provider_type_extra_config_assignment_desc', 'provider_type_extra_config')
-
-
diff --git a/netbox_sys_plugin/forms/__init__.py b/netbox_sys_plugin/forms/__init__.py
index 8b1460c..099a164 100644
--- a/netbox_sys_plugin/forms/__init__.py
+++ b/netbox_sys_plugin/forms/__init__.py
@@ -3,4 +3,4 @@
 from .provider import *
 from .machine import *
 from .createvm import *
-from .operation import *
\ No newline at end of file
+from .operation import *
diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py
index 954ba44..69d4d3a 100644
--- a/netbox_sys_plugin/forms/createvm.py
+++ b/netbox_sys_plugin/forms/createvm.py
@@ -1,8 +1,11 @@
+"""Create VM Custom Form definitions"""
+
+import json
+import netaddr
 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.core.exceptions import ValidationError
 from django.db import transaction
 from utilities.forms.fields import DynamicModelChoiceField, JSONField
 from netbox.forms import NetBoxModelForm
@@ -12,7 +15,7 @@ from dcim.models import DeviceRole, Platform
 from extras.models import Tag, TaggedItem
 from .. models import DomainNames, VmAssignedVirtualMachineType, VirtualMachineType, VmAssignedExtraConfig, ProviderTypeExtraConfig
 from . . utils import send_webhook, validate_extra_config_values
-import netaddr
+
 
 
 class ClusterForm(NetBoxModelForm):
@@ -40,7 +43,7 @@ class ClusterFormList(NetBoxModelForm, forms.Form):
         queryset=Cluster.objects.all(), required=True, label="Provider",
         query_params={'type_id': '$cl_list_new-cluster_type',},
     )
-    
+
     class Meta:
         model = Cluster
         fields = ('cluster_type','cluster','tags')
@@ -59,7 +62,7 @@ class VirtualMachineForm(NetBoxModelForm):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.fields.pop('tags',None)
-    
+
 class VirtualMachineInterfaceForm(NetBoxModelForm):
     """Form for Virtual Machine Interfaces."""
 
@@ -134,7 +137,7 @@ class VmAssignedExtraConfigurationsForm(NetBoxModelForm, forms.Form):
 
     provider_type_extra_config = DynamicModelChoiceField(
         queryset=ProviderTypeExtraConfig.objects.all(),
-        required=True, 
+        required=True,
         label="Provider Type Extra Config",
         query_params={
             'cluster_type_id': '$cl_list_new-cluster_type',  # Example: Filter configs with non-null structures
@@ -156,7 +159,7 @@ class VmAssignedExtraConfigurationsForm(NetBoxModelForm, forms.Form):
         self.fields.pop('tags',None)
 
 class TagsForm(NetBoxModelForm):
-    """Form for IP Addresses."""
+    """Form for Tags Addresses."""
     tag = DynamicModelChoiceField(
         queryset=Tag.objects.all(), required=False, label="Tag"
     )
@@ -167,7 +170,7 @@ class TagsForm(NetBoxModelForm):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.fields.pop('tags',None)
-    
+
 
 # Inline formsets for managing relationships
 ClusterFormSet = inlineformset_factory(
@@ -219,7 +222,8 @@ TagFormSet = forms.modelformset_factory(
 )
 
 
-# Combined form
+# pylint: disable=R0902
+# All of these instances are needed to combine all the data into one single form
 class CreateVmForm(NetBoxModelForm):
     """Combined form for managing ClusterType, Cluster, and VirtualMachine, etc"""
 
@@ -230,13 +234,15 @@ class CreateVmForm(NetBoxModelForm):
         model = ClusterType
         fields = ('name', 'slug', 'description', 'tags')
 
+    # pylint: disable=R0914
+    # All of these variables are needed to create the forms
     def __init__(self, *args, **kwargs):
         data = kwargs.pop('data', None)
         super().__init__(*args, **kwargs)
         self.fields.pop('tags', None)
 
         # Initialize formsets
-        # Virtual Machine 
+        # Virtual Machine
         self.virtual_machine_formsets = []
         empty_vm_formset = VirtualMachineFormSet(data=data, prefix='vms_new')
         self.virtual_machine_formsets.append(('new', empty_vm_formset))
@@ -291,21 +297,22 @@ class CreateVmForm(NetBoxModelForm):
         try:
             ports = [int(port.strip()) for port in ports_field.split(',') if port.strip().isdigit()]
             return ports
-        except ValueError:
-            raise ValueError(f"Invalid ports value: {ports_field}")
-   
+        except ValueError as e:
+            raise ValueError(f"Invalid ports value: {ports_field}") from e
+
     @staticmethod
     def get_parse_tags(data):
+        """Parse Tags"""
         tag_id = data.get('tag_new-tag', '')
-        
+
         if not tag_id:
             return []
         try:
             tags_field = Tag.objects.get(pk=tag_id)
             return [tags_field]
-        except Tag.DoesNotExist:
-            raise ValueError (f"Invalid tag: {tags_field}")
-    
+        except Tag.DoesNotExist as e:
+            raise ValueError (f"Invalid tag: {tags_field}") from e
+
     @staticmethod
     def assign_tags(obj,data):
         """Assign Tags to the created objects"""
@@ -323,11 +330,10 @@ class CreateVmForm(NetBoxModelForm):
     def clean_json(json_data):
         """Clean JSON field"""
         try:
-            import json
             data = json.loads(json_data)
         except (TypeError,ValueError) as e:
-            raise ValueError("Invalid JSON format: Please provide a valid JSON object")
-        
+            raise ValueError(f"Invalid JSON format: Please provide a valid JSON object. {str(e)}") from e
+
         cleaned_data = {k.strip(): v.strip() for k, v in data.items() if isinstance(v,str)}
         return cleaned_data
 
@@ -337,14 +343,14 @@ class CreateVmForm(NetBoxModelForm):
         role_id = data.get('vms_new-0-role', '')
         try:
             role = DeviceRole.objects.get(pk=role_id)
-        except DeviceRole.DoesNotExist:
-            raise ValueError(f"Invalid Device Role ID: {role_id}")
+        except DeviceRole.DoesNotExist as e:
+            raise ValueError(f"Invalid Device Role ID: {role_id}") from e
 
         platform_id = data.get('vms_new-0-platform', '')
         try:
             platform = Platform.objects.get(pk=platform_id)
-        except Platform.DoesNotExist:
-            raise ValueError(f"Invalid Platform ID: {platform_id}")
+        except Platform.DoesNotExist as e:
+            raise ValueError(f"Invalid Platform ID: {platform_id}") from e
 
         vm = VirtualMachine(
             name=data.get('vms_new-0-name', ''),
@@ -372,7 +378,7 @@ class CreateVmForm(NetBoxModelForm):
         vmi.save()
         CreateVmForm.assign_tags(vmi,data)
         return vmi
-    
+
     @staticmethod
     def create_service(data, vm, prefix, description):
         """Create and save a Service object."""
@@ -406,9 +412,9 @@ class CreateVmForm(NetBoxModelForm):
             raise ValueError("IP Address cannot be empty")
         try:
             ipaddress_raw = netaddr.IPNetwork(ipaddress_raw)
-        except:
-            raise ValueError("Invalid IP Address")
-            
+        except Exception as e:
+            raise ValueError("Invalid IP Address") from e
+
         ip_address = IPAddress(
             address=ipaddress_raw,
             status=data.get(f'{prefix}-status', ''),
@@ -420,8 +426,9 @@ class CreateVmForm(NetBoxModelForm):
         ip_address.save()
         CreateVmForm.assign_tags(ip_address,data)
         return ip_address
-    
+
     def create_all_ip_adresses(self, data, vm_interface):
+        """Create all IP addresses"""
         self.create_ip_address(data,vm_interface,'ip_new','Network IP Address')
         self.create_ip_address(data,vm_interface,'gateway_new','Network Gateway')
 
@@ -431,8 +438,8 @@ class CreateVmForm(NetBoxModelForm):
         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_id}")
+        except VirtualMachineType.DoesNotExist as e:
+            raise ValueError(f"Invalid VM Type ID: {vmtype_id}") from e
 
         vm_assignment = VmAssignedVirtualMachineType(
             virtual_machine_type=vmtype,
@@ -443,17 +450,17 @@ class CreateVmForm(NetBoxModelForm):
         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)
 
         cleaned_domain_names_data = CreateVmForm.clean_json(domain_names_data)
-        
+
         if not cleaned_domain_names_data:
             return None
-    
+
         domain_names_object = DomainNames(
             domain_names=cleaned_domain_names_data,
             assigned_object_type=ContentType.objects.get_for_model(vm),
@@ -463,7 +470,7 @@ class CreateVmForm(NetBoxModelForm):
         domain_names_object.save()
         CreateVmForm.assign_tags(domain_names_object, data)
         return domain_names_object
-    
+
     @staticmethod
     def create_extraconfig_assignment(data, vm):
         """Assign Extra COnfig to the virtual machine."""
@@ -471,15 +478,14 @@ class CreateVmForm(NetBoxModelForm):
 
         extra_config_values =data.get('vmassignedextraconfig_new-extra_config_values', '')
 
-        
         extra_config_estructure_id =data.get('vmassignedextraconfig_new-provider_type_extra_config', '')
         try:
             extra_config_estructure = ProviderTypeExtraConfig.objects.get(pk=extra_config_estructure_id)
-        except ProviderTypeExtraConfig.DoesNotExist:
-            raise ValueError(f"Invalid Extra Config Structure: {extra_config_estructure_id}")
-        
+        except ProviderTypeExtraConfig.DoesNotExist as e:
+            raise ValueError(f"Invalid Extra Config Structure: {extra_config_estructure_id}") from e
+
         cleaned_extra_config_data = CreateVmForm.clean_json(extra_config_values)
-        
+
         #Validation of structure
         provider_config = extra_config_estructure
         extra_config_values= cleaned_extra_config_data
@@ -520,7 +526,7 @@ class CreateVmForm(NetBoxModelForm):
                 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)
@@ -539,7 +545,7 @@ class CreateVmForm(NetBoxModelForm):
                     assigned_object_id=vm.id,
                     assigned_object_type=vm_content_type
                 )
-                
+
                 domain_names = DomainNames.objects.filter(
                 assigned_object_id=vm.id,
                 assigned_object_type=ContentType.objects.get_for_model(VirtualMachine)
@@ -567,8 +573,7 @@ class CreateVmForm(NetBoxModelForm):
                             "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
                     ],
                     "network_interface": [
@@ -609,10 +614,10 @@ class CreateVmForm(NetBoxModelForm):
                         for domain in domain_names
                 ],
                     }
-    
+
                 # Send webhook
                 send_webhook(payload)
                 return vm
 
         except ValueError as e:
-            raise ValueError(f"Error during creation: {str(e)}")
\ No newline at end of file
+            raise ValueError(f"Error during creation: {str(e)}") from e
diff --git a/netbox_sys_plugin/forms/machine.py b/netbox_sys_plugin/forms/machine.py
index 8f424dc..03f2b09 100644
--- a/netbox_sys_plugin/forms/machine.py
+++ b/netbox_sys_plugin/forms/machine.py
@@ -1,6 +1,6 @@
-"""Forms definitions"""
+"""Virtual Machine Forms definitions"""
 
-from virtualization.models import VirtualMachine, ClusterType
+from virtualization.models import VirtualMachine
 from django.contrib.contenttypes.models import ContentType
 from django.utils.translation import gettext_lazy as _
 from django.core.exceptions import ValidationError
@@ -15,9 +15,7 @@ from . . utils import validate_extra_config_values
 from ..models import VmAssignedVirtualMachineType, VirtualMachineMaintenance, DomainNames, VmAssignedExtraConfig, ProviderTypeExtraConfig
 
 class VmAssignedVmTypeForm(NetBoxModelForm):
-    """
-    GUI form to add or edit a Virtual Machine Type.
-    """
+    """GUI form to add or edit a Virtual Machine Type."""
 
     virtual_machine = DynamicModelChoiceField(
         queryset=VirtualMachine.objects.all(), required=True, label="Virtual Machine"
@@ -54,27 +52,22 @@ class VmAssignedVmTypeForm(NetBoxModelForm):
         fields = ('virtual_machine','virtual_machine_type', 'virtual_machine_type_assignment_desc','tags')
 
     def clean(self):
-        """
-        Validates form inputs before submitting:
-        """
+        """Validates form inputs before submitting:"""
         super().clean()
-        
-        
+
         vm = self.cleaned_data.get("virtual_machine")
 
         #Check if Virtual Machine is assigned corretly
-        if (not vm):
+        if not vm:
             raise ValidationError(
                 {"__all__": "Can't assign more than one Type to the same Virtual Machine"},
             )
-        
-        if self.errors.get("virtual_machine"):
-            return
 
     def save(self, *args, **kwargs):
+        """Set assigned object and save"""
         # Set assigned object
         self.instance.assigned_object = (
-            self.cleaned_data.get("virtual_machine") 
+            self.cleaned_data.get("virtual_machine")
         )
         return super().save(*args, **kwargs)
 
@@ -128,25 +121,20 @@ class VmMaitenanceForm(NetBoxModelForm):
         Validates form inputs before submitting:
         """
         super().clean()
-        
-        
+
         vm = self.cleaned_data.get("virtual_machine")
 
         #Check if Virtual Machine is assigned corretly
-        if (not vm):
+        if not vm:
             raise ValidationError(
                 {"__all__": "Can't assign more than one Maintenance Window to the same Virtual Machine"},
             )
-        
-        if self.errors.get("virtual_machine"):
-            return
-
-
 
     def save(self, *args, **kwargs):
+        """Set assigned object and save"""
         # Set assigned object
         self.instance.assigned_object = (
-            self.cleaned_data.get("virtual_machine") 
+            self.cleaned_data.get("virtual_machine")
         )
         return super().save(*args, **kwargs)
 
@@ -194,29 +182,22 @@ class DomainNamesForm(NetBoxModelForm):
 
 
     def clean(self):
-        """
-        Validates form inputs before submitting:
-        """
+        """Validates form inputs before submitting:"""
         super().clean()
-        
-        
+
         vm = self.cleaned_data.get("virtual_machine")
 
         #Check if Virtual Machine is assigned corretly
-        if (not vm):
+        if not vm:
             raise ValidationError(
                 {"__all__": "Can't assign more than one Maintenance Window to the same Virtual Machine"},
             )
-        
-        if self.errors.get("virtual_machine"):
-            return
-
-
 
     def save(self, *args, **kwargs):
+        """Set assigned object and save"""
         # Set assigned object
         self.instance.assigned_object = (
-            self.cleaned_data.get("virtual_machine") 
+            self.cleaned_data.get("virtual_machine")
         )
         return super().save(*args, **kwargs)
 
@@ -296,31 +277,26 @@ class VmAssignedExtraConfigForm(NetBoxModelForm):
         return extra_config_values
 
     def clean(self):
-        """
-        Validates form inputs before submitting:
-        """
+        """Validates form inputs before submitting:"""
         super().clean()
-        
-        
+
         vm = self.cleaned_data.get("virtual_machine")
 
         #Check if Virtual Machine is assigned corretly
-        if (not vm):
+        if not vm:
             raise ValidationError(
                 {"__all__": "Can't assign more than one Extra Config to the same Virtual Machine"},
             )
-        
-        if self.errors.get("virtual_machine"):
-            return
 
     def save(self, *args, **kwargs):
+        """Set assigned object and save"""
         # Set assigned object
         self.instance.assigned_object = (
-            self.cleaned_data.get("virtual_machine") 
+            self.cleaned_data.get("virtual_machine")
         )
         return super().save(*args, **kwargs)
 
 class VmAssignedExtraConfigFilterForm(NetBoxModelFilterSetForm):
     """Virtual Machine Type filter form definition class"""
 
-    model = VmAssignedExtraConfig
\ No newline at end of file
+    model = VmAssignedExtraConfig
diff --git a/netbox_sys_plugin/forms/operation.py b/netbox_sys_plugin/forms/operation.py
index 041d6f7..40a70c4 100644
--- a/netbox_sys_plugin/forms/operation.py
+++ b/netbox_sys_plugin/forms/operation.py
@@ -1,3 +1,5 @@
+"""Operational Forms definitions"""
+
 from django.core.exceptions import ValidationError
 from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm
 from ..models import WebhookSettings
@@ -18,16 +20,19 @@ class WebhookSettingsForm(NetBoxModelForm):
         }
 
     def clean(self):
+        """Clean for Webhook Setting Form"""
         cleaned_data = super().clean()
 
         if self.instance.pk:
             return cleaned_data
-        
+
         if WebhookSettings.objects.exists():
             raise ValidationError("You can only have one webbook setting")
 
+        return None
+
 
 class WebhookSettingsFilterForm(NetBoxModelFilterSetForm):
     """Webhook Settings filter form definition class"""
 
-    model = WebhookSettings
\ No newline at end of file
+    model = WebhookSettings
diff --git a/netbox_sys_plugin/forms/provider.py b/netbox_sys_plugin/forms/provider.py
index e966127..27bff58 100644
--- a/netbox_sys_plugin/forms/provider.py
+++ b/netbox_sys_plugin/forms/provider.py
@@ -1,6 +1,5 @@
-"""Forms definitions"""
+"""Provider Forms definitions"""
 
-import json
 from virtualization.models import Cluster,ClusterType
 from django.contrib.contenttypes.models import ContentType
 from django.utils.translation import gettext_lazy as _
@@ -60,20 +59,17 @@ class ProviderCredentialsForm(NetBoxModelForm):
         """
         super().clean()
 
-
-        
         cluster = self.cleaned_data.get("cluster")
 
         #Check if cluster is assigned corretly
-        if (not cluster):
+        if not cluster:
             raise ValidationError(
                 {"__all__": "Can't assign more than one Credential to the same Provider"},
             )
-        
-        if self.errors.get(f"provider_username"):
-            return
+
 
     def save(self, *args, **kwargs):
+        """Set assigned object and save"""
         # Set assigned object
         self.instance.assigned_object = (
             self.cleaned_data.get("cluster")
@@ -138,7 +134,7 @@ class VmTypeForm(NetBoxModelForm):
 
 
     def save(self, *args, **kwargs):
-        # Set assigned object
+        """Set assigned object and save"""
         self.instance.assigned_object = self.cleaned_data.get("cluster_type")
         return super().save(*args, **kwargs)
 
@@ -212,15 +208,15 @@ class ProviderTypeExtraConfigForm(NetBoxModelForm):
             raise ValidationError(
                 {"__all__":"A Provider Type can only have one extra configuration"}
             )
-        
+
     def save(self, *args, **kwargs):
-        # Set assigned object
+        """Set assigned object and save"""
         self.instance.assigned_object = (
             self.cleaned_data.get("cluster_type")
         )
         return super().save(*args, **kwargs)
-    
+
 class ProviderTypeExtraConfigFilterForm(NetBoxModelFilterSetForm):
     """Provider Credentials filter form definition class"""
 
-    model = ProviderTypeExtraConfig
\ No newline at end of file
+    model = ProviderTypeExtraConfig
diff --git a/netbox_sys_plugin/migrations/0001_initial.py b/netbox_sys_plugin/migrations/0001_initial.py
index 90f9ca3..8d4fadf 100644
--- a/netbox_sys_plugin/migrations/0001_initial.py
+++ b/netbox_sys_plugin/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 4.2.16 on 2024-11-14 13:24
+# Generated by Django 4.2.16 on 2025-01-03 15:28
 
 import django.core.validators
 from django.db import migrations, models
@@ -17,6 +17,106 @@ class Migration(migrations.Migration):
     ]
 
     operations = [
+        migrations.CreateModel(
+            name='ProviderTypeExtraConfig',
+            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)),
+                ('extra_config_name', models.CharField(blank=True, default=None, max_length=50, null=True)),
+                ('extra_config_structure', models.JSONField(blank=True, null=True)),
+                ('extra_config_description', models.CharField(default=None, max_length=100)),
+                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
+                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'ClusterType'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
+                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
+            ],
+            options={
+                'verbose_name': 'Provider Extra Configuration',
+                'verbose_name_plural': 'Provider Extra Configurations',
+                'ordering': ['assigned_object_id'],
+                'unique_together': {('assigned_object_id',)},
+            },
+        ),
+        migrations.CreateModel(
+            name='VirtualMachineType',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
+                ('created', models.DateTimeField(auto_now_add=True, null=True)),
+                ('last_updated', models.DateTimeField(auto_now=True, null=True)),
+                ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
+                ('virtual_machine_type_name', models.CharField(default=None, max_length=50)),
+                ('virtual_machine_type_desc', models.CharField(default=None, max_length=100)),
+                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
+                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'ClusterType'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
+                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
+            ],
+            options={
+                'verbose_name': 'Virtual Machine Type',
+                'verbose_name_plural': 'Virtual Machine Types',
+                'ordering': ['assigned_object_id'],
+                'unique_together': {('assigned_object_id', 'virtual_machine_type_name')},
+            },
+        ),
+        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', 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',)},
+            },
+        ),
+        migrations.CreateModel(
+            name='VmAssignedVirtualMachineType',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
+                ('created', models.DateTimeField(auto_now_add=True, null=True)),
+                ('last_updated', models.DateTimeField(auto_now=True, null=True)),
+                ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
+                ('virtual_machine_type_assignment_desc', models.CharField(blank=True, default=None, max_length=100, null=True)),
+                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
+                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
+                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
+                ('virtual_machine_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype')),
+            ],
+            options={
+                'verbose_name': 'Assigned Machine Type',
+                'verbose_name_plural': 'Assigned Machine Types',
+                'ordering': ['assigned_object_id'],
+                'unique_together': {('assigned_object_id',)},
+            },
+        ),
+        migrations.CreateModel(
+            name='VmAssignedExtraConfig',
+            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)),
+                ('extra_config_values', models.JSONField(null=True)),
+                ('provider_type_extra_config_assignment_desc', models.CharField(blank=True, default=None, max_length=100, null=True)),
+                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
+                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
+                ('provider_type_extra_config', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='provider_type_extra_config', to='netbox_sys_plugin.providertypeextraconfig')),
+                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
+            ],
+            options={
+                'verbose_name': 'Assigned Extra Config',
+                'verbose_name_plural': 'Assigned Extra Configs',
+                'ordering': ['assigned_object_id'],
+                'unique_together': {('assigned_object_id',)},
+            },
+        ),
         migrations.CreateModel(
             name='VirtualMachineMaintenance',
             fields=[
@@ -24,9 +124,9 @@ class Migration(migrations.Migration):
                 ('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)),
-                ('maintenance_window', models.CharField(blank=True, default=None, max_length=200, null=True, validators=[django.core.validators.RegexValidator(message='Incorrect maintenance window format', regex='(^([0-1])-[0-1]?[0-9]|2[0-3]):[0-5][0-9]$')])),
+                ('maintenance_window', models.CharField(blank=True, default=None, max_length=200, null=True, validators=[django.core.validators.RegexValidator(message='Incorrect maintenance window format', regex='(^([0-6])-[0-1]?[0-9]|2[0-3]):[0-5][0-9]$')])),
                 ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
-                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'VirtualMachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
+                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
                 ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
             ],
             options={
@@ -36,4 +136,43 @@ class Migration(migrations.Migration):
                 'unique_together': {('assigned_object_id',)},
             },
         ),
+        migrations.CreateModel(
+            name='ProviderCredentials',
+            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)),
+                ('provider_username', models.CharField(blank=True, default=None, max_length=50, null=True)),
+                ('provider_password_vault_path', models.CharField(blank=True, default=None, max_length=200, null=True)),
+                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
+                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'Cluster'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
+                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
+            ],
+            options={
+                'verbose_name': 'Provider Credential',
+                'verbose_name_plural': 'Provider Credentials',
+                'ordering': ['assigned_object_id'],
+                'unique_together': {('assigned_object_id',)},
+            },
+        ),
+        migrations.CreateModel(
+            name='DomainNames',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
+                ('created', models.DateTimeField(auto_now_add=True, null=True)),
+                ('last_updated', models.DateTimeField(auto_now=True, null=True)),
+                ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
+                ('domain_names', models.JSONField(blank=True, null=True)),
+                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
+                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
+                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
+            ],
+            options={
+                'verbose_name': 'Domain Name',
+                'verbose_name_plural': 'Domain Names',
+                'ordering': ['assigned_object_id'],
+                'unique_together': {('assigned_object_id',)},
+            },
+        ),
     ]
diff --git a/netbox_sys_plugin/migrations/0002_alter_virtualmachinemaintenance_maintenance_window_and_more.py b/netbox_sys_plugin/migrations/0002_alter_virtualmachinemaintenance_maintenance_window_and_more.py
deleted file mode 100644
index 64b5bde..0000000
--- a/netbox_sys_plugin/migrations/0002_alter_virtualmachinemaintenance_maintenance_window_and_more.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Generated by Django 4.2.16 on 2024-11-18 15:20
-
-import django.core.validators
-from django.db import migrations, models
-import django.db.models.deletion
-import taggit.managers
-import utilities.json
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('contenttypes', '0002_remove_content_type_name'),
-        ('extras', '0098_webhook_custom_field_data_webhook_tags'),
-        ('netbox_sys_plugin', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='virtualmachinemaintenance',
-            name='maintenance_window',
-            field=models.CharField(blank=True, default=None, max_length=200, null=True, validators=[django.core.validators.RegexValidator(message='Incorrect maintenance window format', regex='(^([0-6])-[0-1]?[0-9]|2[0-3]):[0-5][0-9]$')]),
-        ),
-        migrations.CreateModel(
-            name='ProviderCredentials',
-            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)),
-                ('provider_url', models.CharField(blank=True, default=None, max_length=100, null=True, validators=[django.core.validators.URLValidator(schemes=['http', 'https'])])),
-                ('provider_username', models.CharField(blank=True, default=None, max_length=50, null=True)),
-                ('provider_password_vault_url', models.CharField(blank=True, default=None, max_length=200, null=True, validators=[django.core.validators.URLValidator(schemes=['http', 'https'])])),
-                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
-                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'Cluster'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
-                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
-            ],
-            options={
-                'verbose_name': 'Provider Credential',
-                'verbose_name_plural': 'Provider Credentials',
-                'ordering': ['assigned_object_id'],
-                'unique_together': {('assigned_object_id',)},
-            },
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0003_virtualmachinetype_vmassignedvirtualmachinetype.py b/netbox_sys_plugin/migrations/0003_virtualmachinetype_vmassignedvirtualmachinetype.py
deleted file mode 100644
index cad573f..0000000
--- a/netbox_sys_plugin/migrations/0003_virtualmachinetype_vmassignedvirtualmachinetype.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Generated by Django 4.2.16 on 2024-11-21 17:06
-
-from django.db import migrations, models
-import django.db.models.deletion
-import taggit.managers
-import utilities.json
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('contenttypes', '0002_remove_content_type_name'),
-        ('extras', '0098_webhook_custom_field_data_webhook_tags'),
-        ('netbox_sys_plugin', '0002_alter_virtualmachinemaintenance_maintenance_window_and_more'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='VirtualMachineType',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
-                ('created', models.DateTimeField(auto_now_add=True, null=True)),
-                ('last_updated', models.DateTimeField(auto_now=True, null=True)),
-                ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
-                ('virtual_machine_type_name', models.CharField(default=None, max_length=50)),
-                ('virtual_machine_type_desc', models.CharField(blank=True, default=None, max_length=100, null=True)),
-                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
-                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'ClusterType'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
-                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
-            ],
-            options={
-                'verbose_name': 'Virtual Machine Type',
-                'verbose_name_plural': 'Virtual Machine Types',
-                'ordering': ['assigned_object_id'],
-                'unique_together': {('assigned_object_id', 'virtual_machine_type_name')},
-            },
-        ),
-        migrations.CreateModel(
-            name='VmAssignedVirtualMachineType',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
-                ('created', models.DateTimeField(auto_now_add=True, null=True)),
-                ('last_updated', models.DateTimeField(auto_now=True, null=True)),
-                ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
-                ('virtual_machine_type_assignment_desc', models.CharField(blank=True, default=None, max_length=100, null=True)),
-                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
-                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'VirtualMachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
-                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
-                ('virtual_machine_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assigned_vm_type', to='netbox_sys_plugin.virtualmachinetype')),
-            ],
-            options={
-                'verbose_name': 'Assigned Machine Type',
-                'verbose_name_plural': 'Assigned Machine Types',
-                'ordering': ['assigned_object_id'],
-                'unique_together': {('assigned_object_id',)},
-            },
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0004_rename_provider_password_vault_url_providercredentials_provider_password_vault_path.py b/netbox_sys_plugin/migrations/0004_rename_provider_password_vault_url_providercredentials_provider_password_vault_path.py
deleted file mode 100644
index 2f21dc6..0000000
--- a/netbox_sys_plugin/migrations/0004_rename_provider_password_vault_url_providercredentials_provider_password_vault_path.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-02 09:44
-
-from django.db import migrations
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('netbox_sys_plugin', '0003_virtualmachinetype_vmassignedvirtualmachinetype'),
-    ]
-
-    operations = [
-        migrations.RenameField(
-            model_name='providercredentials',
-            old_name='provider_password_vault_url',
-            new_name='provider_password_vault_path',
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0005_remove_providercredentials_provider_url_and_more.py b/netbox_sys_plugin/migrations/0005_remove_providercredentials_provider_url_and_more.py
deleted file mode 100644
index 17ee435..0000000
--- a/netbox_sys_plugin/migrations/0005_remove_providercredentials_provider_url_and_more.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-02 09:47
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('netbox_sys_plugin', '0004_rename_provider_password_vault_url_providercredentials_provider_password_vault_path'),
-    ]
-
-    operations = [
-        migrations.RemoveField(
-            model_name='providercredentials',
-            name='provider_url',
-        ),
-        migrations.AlterField(
-            model_name='providercredentials',
-            name='provider_password_vault_path',
-            field=models.CharField(blank=True, default=None, max_length=200, null=True),
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0006_domainnames.py b/netbox_sys_plugin/migrations/0006_domainnames.py
deleted file mode 100644
index b0fbbf9..0000000
--- a/netbox_sys_plugin/migrations/0006_domainnames.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-06 12:19
-
-from django.db import migrations, models
-import django.db.models.deletion
-import taggit.managers
-import utilities.json
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('extras', '0098_webhook_custom_field_data_webhook_tags'),
-        ('contenttypes', '0002_remove_content_type_name'),
-        ('netbox_sys_plugin', '0005_remove_providercredentials_provider_url_and_more'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='DomainNames',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
-                ('created', models.DateTimeField(auto_now_add=True, null=True)),
-                ('last_updated', models.DateTimeField(auto_now=True, null=True)),
-                ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)),
-                ('domain_names', models.JSONField(blank=True, null=True)),
-                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
-                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'ipam'), ('model', 'IPAddress'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
-                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
-            ],
-            options={
-                'verbose_name': 'Domain Name',
-                'verbose_name_plural': 'Domain Names',
-                'ordering': ['assigned_object_id'],
-                'unique_together': {('assigned_object_id',)},
-            },
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py b/netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py
deleted file mode 100644
index 2d74afe..0000000
--- a/netbox_sys_plugin/migrations/0007_alter_domainnames_assigned_object_type.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-06 14:58
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('contenttypes', '0002_remove_content_type_name'),
-        ('netbox_sys_plugin', '0006_domainnames'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='domainnames',
-            name='assigned_object_type',
-            field=models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'VirtualMachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype'),
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0008_webhooksettings.py b/netbox_sys_plugin/migrations/0008_webhooksettings.py
deleted file mode 100644
index e00f7a3..0000000
--- a/netbox_sys_plugin/migrations/0008_webhooksettings.py
+++ /dev/null
@@ -1,34 +0,0 @@
-# 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/migrations/0009_alter_domainnames_assigned_object_type_and_more.py b/netbox_sys_plugin/migrations/0009_alter_domainnames_assigned_object_type_and_more.py
deleted file mode 100644
index 7dc9a61..0000000
--- a/netbox_sys_plugin/migrations/0009_alter_domainnames_assigned_object_type_and_more.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# 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),
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0010_providertypeextraconfig.py b/netbox_sys_plugin/migrations/0010_providertypeextraconfig.py
deleted file mode 100644
index c2b159c..0000000
--- a/netbox_sys_plugin/migrations/0010_providertypeextraconfig.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-23 14:46
-
-from django.db import migrations, models
-import django.db.models.deletion
-import taggit.managers
-import utilities.json
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('extras', '0098_webhook_custom_field_data_webhook_tags'),
-        ('contenttypes', '0002_remove_content_type_name'),
-        ('netbox_sys_plugin', '0009_alter_domainnames_assigned_object_type_and_more'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='ProviderTypeExtraConfig',
-            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)),
-                ('extra_config', models.JSONField(blank=True, null=True)),
-                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
-                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'ClusterType'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
-                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
-            ],
-            options={
-                'verbose_name': 'Provider Extra Configuration',
-                'verbose_name_plural': 'Provider Extra Configurations',
-                'ordering': ['assigned_object_id'],
-                'unique_together': {('assigned_object_id',)},
-            },
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0011_providertypeextraconfig_extra_config_description.py b/netbox_sys_plugin/migrations/0011_providertypeextraconfig_extra_config_description.py
deleted file mode 100644
index c5819cb..0000000
--- a/netbox_sys_plugin/migrations/0011_providertypeextraconfig_extra_config_description.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-23 15:25
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('netbox_sys_plugin', '0010_providertypeextraconfig'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='providertypeextraconfig',
-            name='extra_config_description',
-            field=models.CharField(default=None, max_length=100),
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0012_vmassignedextraconfig.py b/netbox_sys_plugin/migrations/0012_vmassignedextraconfig.py
deleted file mode 100644
index 8bb9b79..0000000
--- a/netbox_sys_plugin/migrations/0012_vmassignedextraconfig.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-27 12:45
-
-from django.db import migrations, models
-import django.db.models.deletion
-import taggit.managers
-import utilities.json
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('contenttypes', '0002_remove_content_type_name'),
-        ('extras', '0098_webhook_custom_field_data_webhook_tags'),
-        ('netbox_sys_plugin', '0011_providertypeextraconfig_extra_config_description'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='VmAssignedExtraConfig',
-            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)),
-                ('provider_type_extra_config_assignment_desc', models.CharField(blank=True, default=None, max_length=100, null=True)),
-                ('assigned_object_id', models.PositiveBigIntegerField(blank=True, null=True)),
-                ('assigned_object_type', models.ForeignKey(blank=True, limit_choices_to=models.Q(models.Q(('app_label', 'virtualization'), ('model', 'virtualmachine'))), null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.contenttype')),
-                ('provider_type_extra_config', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='assigned_vm_type', to='netbox_sys_plugin.providertypeextraconfig')),
-                ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
-            ],
-            options={
-                'verbose_name': 'Assigned Extra Config',
-                'verbose_name_plural': 'Assigned Extra Configs',
-                'ordering': ['assigned_object_id'],
-                'unique_together': {('assigned_object_id',)},
-            },
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0013_rename_extra_config_providertypeextraconfig_extra_config_structure_and_more.py b/netbox_sys_plugin/migrations/0013_rename_extra_config_providertypeextraconfig_extra_config_structure_and_more.py
deleted file mode 100644
index 4de7a83..0000000
--- a/netbox_sys_plugin/migrations/0013_rename_extra_config_providertypeextraconfig_extra_config_structure_and_more.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-27 16:33
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('netbox_sys_plugin', '0012_vmassignedextraconfig'),
-    ]
-
-    operations = [
-        migrations.RenameField(
-            model_name='providertypeextraconfig',
-            old_name='extra_config',
-            new_name='extra_config_structure',
-        ),
-        migrations.AddField(
-            model_name='providertypeextraconfig',
-            name='extra_config_name',
-            field=models.CharField(blank=True, default=None, max_length=50, null=True),
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0014_vmassignedextraconfig_extra_config_values.py b/netbox_sys_plugin/migrations/0014_vmassignedextraconfig_extra_config_values.py
deleted file mode 100644
index d55ed6a..0000000
--- a/netbox_sys_plugin/migrations/0014_vmassignedextraconfig_extra_config_values.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-30 10:10
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('netbox_sys_plugin', '0013_rename_extra_config_providertypeextraconfig_extra_config_structure_and_more'),
-    ]
-
-    operations = [
-        migrations.AddField(
-            model_name='vmassignedextraconfig',
-            name='extra_config_values',
-            field=models.JSONField(null=True),
-        ),
-    ]
diff --git a/netbox_sys_plugin/migrations/0015_alter_vmassignedextraconfig_provider_type_extra_config.py b/netbox_sys_plugin/migrations/0015_alter_vmassignedextraconfig_provider_type_extra_config.py
deleted file mode 100644
index 81d305c..0000000
--- a/netbox_sys_plugin/migrations/0015_alter_vmassignedextraconfig_provider_type_extra_config.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Generated by Django 4.2.16 on 2024-12-30 12:16
-
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('netbox_sys_plugin', '0014_vmassignedextraconfig_extra_config_values'),
-    ]
-
-    operations = [
-        migrations.AlterField(
-            model_name='vmassignedextraconfig',
-            name='provider_type_extra_config',
-            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='provider_type_extra_config', to='netbox_sys_plugin.providertypeextraconfig'),
-        ),
-    ]
diff --git a/netbox_sys_plugin/models/__init__.py b/netbox_sys_plugin/models/__init__.py
index 3cbc7b5..026b329 100644
--- a/netbox_sys_plugin/models/__init__.py
+++ b/netbox_sys_plugin/models/__init__.py
@@ -2,4 +2,4 @@
 
 from .provider import *
 from .machine import *
-from .operation import *
\ No newline at end of file
+from .operation import *
diff --git a/netbox_sys_plugin/models/machine.py b/netbox_sys_plugin/models/machine.py
index 805fbab..6ffd6d9 100644
--- a/netbox_sys_plugin/models/machine.py
+++ b/netbox_sys_plugin/models/machine.py
@@ -1,4 +1,4 @@
-"""Models definitions"""
+"""Virutal Machine Models definitions"""
 
 from django.core.validators import (
     RegexValidator,
@@ -7,7 +7,7 @@ from django.urls import reverse
 from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
 from django.contrib.contenttypes.models import ContentType
 from django.db import models
-from virtualization.models import VirtualMachine, ClusterType
+from virtualization.models import VirtualMachine
 from netbox.models import NetBoxModel
 
 VM_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="virtualmachine"))
@@ -15,7 +15,7 @@ VM_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", model="virt
 #VM Assigned Type
 class VmAssignedVirtualMachineType(NetBoxModel):
     """Virtual Machine Type Info definition class"""
-  
+
     virtual_machine_type = models.ForeignKey(
         to="VirtualMachineType",
         on_delete=models.PROTECT,
@@ -24,7 +24,7 @@ class VmAssignedVirtualMachineType(NetBoxModel):
         related_name="assigned_vm_type",
         name='virtual_machine_type'
     )
-    
+
     virtual_machine_type_assignment_desc = models.CharField(
         default=None, blank=True, null=True,
         max_length=100)
@@ -117,7 +117,7 @@ GenericRelation(
 #Domain Names
 class DomainNames(NetBoxModel):
     """Cluster ProviderInfo definition class"""
-  
+
     domain_names = models.JSONField(
         blank=True,
         null=True,
@@ -160,8 +160,8 @@ GenericRelation(
 
 #VM Assigned Extra Config
 class VmAssignedExtraConfig(NetBoxModel):
-    """Virtual Machine Type Info definition class"""
-  
+    """Virtual Machine Assigned Extra Config definition class"""
+
     provider_type_extra_config = models.ForeignKey(
         to="ProviderTypeExtraConfig",
         on_delete=models.PROTECT,
@@ -175,7 +175,7 @@ class VmAssignedExtraConfig(NetBoxModel):
         blank=False,
         null=True,
     )
-    
+
     provider_type_extra_config_assignment_desc = models.CharField(
         default=None, blank=True, null=True,
         max_length=100)
diff --git a/netbox_sys_plugin/models/operation.py b/netbox_sys_plugin/models/operation.py
index 6b35db7..9666d0c 100644
--- a/netbox_sys_plugin/models/operation.py
+++ b/netbox_sys_plugin/models/operation.py
@@ -1,11 +1,9 @@
-from django.core.validators import (
-    URLValidator,    
-)  # pylint: disable=import-error
-from django.db import models
+"""Operational Models definitions"""
+
 from django.urls import reverse
-from netbox.models import NetBoxModel
 from django.db import models
 from django.utils.translation import gettext_lazy as _
+from netbox.models import NetBoxModel
 
 
 
@@ -25,7 +23,7 @@ class WebhookSettings(NetBoxModel):
         default='application/json',
         verbose_name=_('HTTP content type')
         )
-    
+
     class Meta:
         """Meta class"""
         unique_together = ["payload_url"]
@@ -35,4 +33,4 @@ class WebhookSettings(NetBoxModel):
 
     def get_absolute_url(self):
         """override"""
-        return reverse("plugins:netbox_sys_plugin:webhooksettings", args=[self.pk])
\ No newline at end of file
+        return reverse("plugins:netbox_sys_plugin:webhooksettings", args=[self.pk])
diff --git a/netbox_sys_plugin/models/provider.py b/netbox_sys_plugin/models/provider.py
index f116282..a42f9d4 100644
--- a/netbox_sys_plugin/models/provider.py
+++ b/netbox_sys_plugin/models/provider.py
@@ -1,4 +1,4 @@
-"""Models definitions"""
+"""Provider Models definitions"""
 
 from django.urls import reverse
 from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
@@ -13,7 +13,7 @@ CLUSTER_TYPE_ASSIGNMENT_MODELS = models.Q(models.Q(app_label="virtualization", m
 #Provider Credentials
 class ProviderCredentials(NetBoxModel):
     """Cluster ProviderInfo definition class"""
-  
+
     provider_username = models.CharField(
         default=None, blank=True, null=True,
         max_length=50)
@@ -66,7 +66,7 @@ class VirtualMachineType(NetBoxModel):
         default=None, blank=False, null=False,
         max_length=50,
         )
-    
+
     virtual_machine_type_desc = models.CharField(
         default=None, blank=False, null=False,
         max_length=100)
@@ -93,7 +93,7 @@ class VirtualMachineType(NetBoxModel):
 
 
     def __str__(self):
-        return self.virtual_machine_type_name
+        return f"{ self.virtual_machine_type_name }"
 
     def get_absolute_url(self):
         """override"""
@@ -108,8 +108,8 @@ GenericRelation(
 
 #Provider Extra Config
 class ProviderTypeExtraConfig(NetBoxModel):
-    """Cluster Type Extra configurations definition class"""
-  
+    """Provider Type Extra configurations definition class"""
+
     extra_config_name = models.CharField(
         default=None, blank=True, null=True,
         max_length=50)
diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py
index 97b3b44..1eea0d0 100644
--- a/netbox_sys_plugin/navigation.py
+++ b/netbox_sys_plugin/navigation.py
@@ -1,10 +1,7 @@
 """Navigation Menu definitions"""
-
 from django.utils.translation import gettext as _
 from extras.plugins import PluginMenuButton, PluginMenuItem, PluginMenu
-from netbox.registry import registry
 from utilities.choices import ButtonColorChoices
-from . import *
 
 #Buttons
 vm_maintenance_buttons = [
@@ -146,11 +143,10 @@ operItem =[
 menu = PluginMenu(
     label="System Squad",
     groups=(
-        
         ("Provider", clusterItem),
         ("Provider Type", ClusterTypeItem),
         ("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 d0028ee..70ae2e5 100644
--- a/netbox_sys_plugin/tables.py
+++ b/netbox_sys_plugin/tables.py
@@ -2,7 +2,15 @@
 
 import django_tables2 as tables
 from netbox.tables import NetBoxTable, columns
-from .models import VirtualMachineMaintenance, ProviderCredentials, VmAssignedVirtualMachineType, VirtualMachineType, WebhookSettings, DomainNames, ProviderTypeExtraConfig, VmAssignedExtraConfig
+from .models import (
+    VirtualMachineMaintenance,
+    ProviderCredentials,
+    VmAssignedVirtualMachineType,
+    VirtualMachineType,
+    WebhookSettings,
+    DomainNames,
+    ProviderTypeExtraConfig,
+    VmAssignedExtraConfig)
 
 #VmMaintenance
 class VmMaintenanceTable(NetBoxTable):
@@ -12,7 +20,7 @@ class VmMaintenanceTable(NetBoxTable):
     id = tables.Column(
         linkify=True,
     )
-    
+
     assigned_object = tables.Column(
     linkify=True,
     orderable=False,
@@ -43,7 +51,7 @@ class ProviderCredentialsTable(NetBoxTable):
     id = tables.Column(
         linkify=True,
     )
-    
+
     assigned_object = tables.Column(
         linkify=True,
         orderable=False,
@@ -83,7 +91,7 @@ class VmAssignedVmTypeTable(NetBoxTable):
     id = tables.Column(
         linkify=True,
     )
-    
+
     assigned_object = tables.Column(
         linkify=True,
         orderable=False,
@@ -118,7 +126,7 @@ class VmTypeTable(NetBoxTable):
     id = tables.Column(
         linkify=True,
     )
-    
+
     assigned_object = tables.Column(
         linkify=True,
         orderable=False,
@@ -154,7 +162,7 @@ class DomainNamesTable(NetBoxTable):
     id = tables.Column(
         linkify=True,
     )
-    
+
     assigned_object = tables.Column(
         linkify=True,
         orderable=False,
@@ -210,13 +218,13 @@ class WebhookSettingsTable(NetBoxTable):
 
 #ExtraConfig
 class ProviderTypeExtraConfigTable(NetBoxTable):
-    """Extra Configs Table definition class"""
+    """Provider Type Extra Configs Table definition class"""
 
     pk = columns.ToggleColumn()
     id = tables.Column(
         linkify=True,
     )
-    
+
     assigned_object = tables.Column(
         linkify=True,
         orderable=False,
@@ -245,14 +253,14 @@ class ProviderTypeExtraConfigTable(NetBoxTable):
         default_columns = ('id','assigned_object','extra_config_name','extra_config_structure')
 
 #VmAssignedType
-class VmAssignedExtraConfig(NetBoxTable):
-    """VM Maintenance Table definition class"""
+class VmAssignedExtraConfigTable(NetBoxTable):
+    """VM Vm Assigned Extra Config Table definition class"""
 
     pk = columns.ToggleColumn()
     id = tables.Column(
         linkify=True,
     )
-    
+
     assigned_object = tables.Column(
         linkify=True,
         orderable=True,
diff --git a/netbox_sys_plugin/template_content.py b/netbox_sys_plugin/template_content.py
index 43bc604..e3395dc 100644
--- a/netbox_sys_plugin/template_content.py
+++ b/netbox_sys_plugin/template_content.py
@@ -10,21 +10,33 @@ class VmTable(PluginTemplateExtension):
     model = 'virtualization.virtualmachine'
 
     def left_page(self):
-        return self.render('netbox_sys_plugin/vm_vmmaintenance.html', extra_context={'vmmaintenanceinfo': models.VirtualMachineMaintenance.objects.filter(VirtualMachine=self.context['object'])})
-    
+        """Render vm_vmmaintenance.html in left side"""
+        return self.render('netbox_sys_plugin/vm_vmmaintenance.html', extra_context={
+            'vmmaintenanceinfo': models.VirtualMachineMaintenance.objects.filter(VirtualMachine=self.context['object'])
+            })
+
     def right_page(self):
-        return self.render('netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html', extra_context={'vmassigntypeinfo': models.VmAssignedVirtualMachineType.objects.filter(VirtualMachine=self.context['object'])})
+        """Render vm_vmassignedvirtualmachinetype.html in right side"""
+        return self.render('netbox_sys_plugin/vm_vmassignedvirtualmachinetype.html', extra_context={
+            'vmassigntypeinfo': models.VmAssignedVirtualMachineType.objects.filter(VirtualMachine=self.context['object'])
+            })
 
 class VmTableDomainNames(PluginTemplateExtension):
     """VM Domain names object template"""
 
     model = 'virtualization.virtualmachine'
-    
+
     def left_page(self):
-        return self.render('netbox_sys_plugin/vm_domainnames.html', extra_context={'domainnamesinfo': models.DomainNames.objects.filter(VirtualMachine=self.context['object'])})
-    
+        """Render vm_domainnames.html in left side"""
+        return self.render('netbox_sys_plugin/vm_domainnames.html', extra_context={
+            'domainnamesinfo': models.DomainNames.objects.filter(VirtualMachine=self.context['object'])
+            })
+
     def full_width_page(self):
-        return self.render('netbox_sys_plugin/vm_vmassignedextraconfig.html', extra_context={'vmassignextraconfiginfo': models.VmAssignedExtraConfig.objects.filter(VirtualMachine=self.context['object'])})
+        """Render vm_vmassignedextraconfig.html in full width footer"""
+        return self.render('netbox_sys_plugin/vm_vmassignedextraconfig.html', extra_context={
+            'vmassignextraconfiginfo': models.VmAssignedExtraConfig.objects.filter(VirtualMachine=self.context['object'])
+            })
 
 
 class VmTypeTable(PluginTemplateExtension):
@@ -33,10 +45,16 @@ class VmTypeTable(PluginTemplateExtension):
     model = 'virtualization.clustertype'
 
     def right_page(self):
-        return self.render('netbox_sys_plugin/clustertype_virtualmachinetype.html', extra_context={'vmtypesinfo': models.VirtualMachineType.objects.filter(ClusterType=self.context['object'])})
-    
+        """Render clustertype_virtualmachinetype.html in right side"""
+        return self.render('netbox_sys_plugin/clustertype_virtualmachinetype.html', extra_context={
+            'vmtypesinfo': models.VirtualMachineType.objects.filter(ClusterType=self.context['object'])
+            })
+
     def left_page(self):
-        return self.render('netbox_sys_plugin/clustertype_providertypeextraconfig.html', extra_context={'extraconfiginfo': models.ProviderTypeExtraConfig.objects.filter(ClusterType=self.context['object'])})
+        """Render clustertype_providertypeextraconfig.html in left side"""
+        return self.render('netbox_sys_plugin/clustertype_providertypeextraconfig.html', extra_context={
+            'extraconfiginfo': models.ProviderTypeExtraConfig.objects.filter(ClusterType=self.context['object'])
+            })
 
 
 class ProviderCredentialsTable(PluginTemplateExtension):
@@ -45,7 +63,10 @@ class ProviderCredentialsTable(PluginTemplateExtension):
     model = 'virtualization.cluster'
 
     def right_page(self):
-        return self.render('netbox_sys_plugin/cluster_providercredentials.html', extra_context={'providercredentialsinfo': models.ProviderCredentials.objects.filter(Cluster=self.context['object'])})
+        """Render cluster_providercredentials.html in right side"""
+        return self.render('netbox_sys_plugin/cluster_providercredentials.html', extra_context={
+            'providercredentialsinfo': models.ProviderCredentials.objects.filter(Cluster=self.context['object'])
+            })
 
 
 template_extensions = [VmTable,ProviderCredentialsTable,VmTypeTable,VmTableDomainNames]
diff --git a/netbox_sys_plugin/urls.py b/netbox_sys_plugin/urls.py
index fc8bbab..fb24174 100644
--- a/netbox_sys_plugin/urls.py
+++ b/netbox_sys_plugin/urls.py
@@ -12,40 +12,50 @@ urlpatterns = (
     path('vm-maintenance/add/', views.VmMaintenanceEditView.as_view(), name='virtualmachinemaintenance_add'),
     path('vm-maintenance/<int:pk>/edit/', views.VmMaintenanceEditView.as_view(), name='virtualmachinemaintenance_edit'),
     path('vm-maintenance/<int:pk>/delete/', views.VmMaintenanceDeleteView.as_view(), name='virtualmachinemaintenance_delete'),
-    path('vm-maintenance/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualmachinemaintenance_changelog', kwargs={'model': models.VirtualMachineMaintenance }),
-    path('vm-maintenance/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinemaintenance_journal', kwargs={'model': models.VirtualMachineMaintenance}),
+    path('vm-maintenance/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualmachinemaintenance_changelog', kwargs={
+        'model': models.VirtualMachineMaintenance }),
+    path('vm-maintenance/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinemaintenance_journal', kwargs={
+        'model': models.VirtualMachineMaintenance}),
     #providerCredentials
     path('provider-credentials/<int:pk>/', views.ProviderCredentialsView.as_view(), name='providercredentials'),
     path('provider-credentials/', views.ProviderCredentialsListView.as_view(), name='providercredentials_list'),
     path('provider-credentials/add/', views.ProviderCredentialsEditView.as_view(), name='providercredentials_add'),
     path('provider-credentials/<int:pk>/edit/', views.ProviderCredentialsEditView.as_view(), name='providercredentials_edit'),
     path('provider-credentials/<int:pk>/delete/', views.ProviderCredentialsDeleteView.as_view(), name='providercredentials_delete'),
-    path('provider-credentials/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providercredentials_changelog', kwargs={'model': models.ProviderCredentials}),
-    path('provider-credentials/<int:pk>/journal/', ObjectJournalView.as_view(), name='providercredentials_journal', kwargs={'model': models.ProviderCredentials}),
+    path('provider-credentials/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providercredentials_changelog', kwargs={
+        'model': models.ProviderCredentials}),
+    path('provider-credentials/<int:pk>/journal/', ObjectJournalView.as_view(), name='providercredentials_journal', kwargs={
+        'model': models.ProviderCredentials}),
     #virtualMachineAssignedType
     path('vm-assigned-type/<int:pk>/', views.VmAssignedVmTypeView.as_view(), name='vmassignedvirtualmachinetype'),
     path('vm-assigned-type/', views.VmAssignedVmTypeListView.as_view(), name='vmassignedvirtualmachinetype_list'),
     path('vm-assigned-type/add/', views.VmAssignedVmTypeEditView.as_view(), name='vmassignedvirtualmachinetype_add'),
     path('vm-assigned-type/<int:pk>/edit/', views.VmAssignedVmTypeEditView.as_view(), name='vmassignedvirtualmachinetype_edit'),
     path('vm-assigned-type/<int:pk>/delete/', views.VmAssignedVmTypeDeleteView.as_view(), name='vmassignedvirtualmachinetype_delete'),
-    path('vm-assigned-type/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='vmassignedvirtualmachinetype_changelog', kwargs={'model': models.VmAssignedVirtualMachineType}),
-    path('vm-assigned-type/<int:pk>/journal/', ObjectJournalView.as_view(), name='vmassignedvirtualmachinetype_journal', kwargs={'model': models.VmAssignedVirtualMachineType}),
+    path('vm-assigned-type/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='vmassignedvirtualmachinetype_changelog', kwargs={
+        'model': models.VmAssignedVirtualMachineType}),
+    path('vm-assigned-type/<int:pk>/journal/', ObjectJournalView.as_view(), name='vmassignedvirtualmachinetype_journal', kwargs={
+        'model': models.VmAssignedVirtualMachineType}),
     #virtualMachineType
     path('vm-type/<int:pk>/', views.VmTypeView.as_view(), name='virtualmachinetype'),
     path('vm-type/', views.VmTypeListView.as_view(), name='virtualmachinetype_list'),
     path('vm-type/add/', views.VmTypeEditView.as_view(), name='virtualmachinetype_add'),
     path('vm-type/<int:pk>/edit/', views.VmTypeEditView.as_view(), name='virtualmachinetype_edit'),
     path('vm-type/<int:pk>/delete/', views.VmTypeDeleteView.as_view(), name='virtualmachinetype_delete'),
-    path('vm-type/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualmachinetype_changelog', kwargs={'model': models.VirtualMachineType}),
-    path('vm-type/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinetype_journal', kwargs={'model': models.VirtualMachineType}),
+    path('vm-type/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualmachinetype_changelog', kwargs={
+        'model': models.VirtualMachineType}),
+    path('vm-type/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualmachinetype_journal', kwargs={
+        'model': models.VirtualMachineType}),
     #DomainNames
     path('domain-names/<int:pk>/', views.DomainNamesView.as_view(), name='domainnames'),
     path('domain-names/', views.DomainNamesListView.as_view(), name='domainnames_list'),
     path('domain-names/add/', views.DomainNamesEditView.as_view(), name='domainnames_add'),
     path('domain-names/<int:pk>/edit/', views.DomainNamesEditView.as_view(), name='domainnames_edit'),
     path('domain-names/<int:pk>/delete/', views.DomainNamesDeleteView.as_view(), name='domainnames_delete'),
-    path('domain-names/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='domainnames_changelog', kwargs={'model': models.DomainNames}),
-    path('domain-names/<int:pk>/journal/', ObjectJournalView.as_view(), name='domainnames_journal', kwargs={'model': models.DomainNames}),
+    path('domain-names/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='domainnames_changelog', kwargs={
+        'model': models.DomainNames}),
+    path('domain-names/<int:pk>/journal/', ObjectJournalView.as_view(), name='domainnames_journal', kwargs={
+        'model': models.DomainNames}),
     #CreateVM
     path('create-vm/', CreateVmView.as_view(), name='creatvm_add'),
     #WebhookSettings
@@ -54,22 +64,28 @@ urlpatterns = (
     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}),
+    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}),
     #Extra Config
     path('extra-config/<int:pk>/', views.ProviderTypeExtraConfigView.as_view(), name='providertypeextraconfig'),
     path('extra-config/', views.ProviderTypeExtraConfigListView.as_view(), name='providertypeextraconfig_list'),
     path('extra-config/add/', views.ProviderTypeExtraConfigEditView.as_view(), name='providertypeextraconfig_add'),
     path('extra-config/<int:pk>/edit/', views.ProviderTypeExtraConfigEditView.as_view(), name='providertypeextraconfig_edit'),
     path('extra-config/<int:pk>/delete/', views.ProviderTypeExtraConfigDeleteView.as_view(), name='providertypeextraconfig_delete'),
-    path('extra-config/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providertypeextraconfig_changelog', kwargs={'model': models.ProviderTypeExtraConfig}),
-    path('extra-config/<int:pk>/journal/', ObjectJournalView.as_view(), name='providertypeextraconfig_journal', kwargs={'model': models.ProviderTypeExtraConfig}),
+    path('extra-config/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providertypeextraconfig_changelog', kwargs={
+        'model': models.ProviderTypeExtraConfig}),
+    path('extra-config/<int:pk>/journal/', ObjectJournalView.as_view(), name='providertypeextraconfig_journal', kwargs={
+        'model': models.ProviderTypeExtraConfig}),
     #virtualMachineAssignedExtraConfig
     path('vm-assigned-extra-config/<int:pk>/', views.VmAssignedExtraConfigView.as_view(), name='vmassignedextraconfig'),
     path('vm-assigned-extra-config/', views.VmAssignedExtraConfigListView.as_view(), name='vmassignedextraconfig_list'),
     path('vm-assigned-extra-config/add/', views.VmAssignedExtraConfigEditView.as_view(), name='vmassignedextraconfig_add'),
     path('vm-assigned-extra-config/<int:pk>/edit/', views.VmAssignedExtraConfigEditView.as_view(), name='vmassignedextraconfig_edit'),
     path('vm-assigned-extra-config/<int:pk>/delete/', views.VmAssignedExtraConfigDeleteView.as_view(), name='vmassignedextraconfig_delete'),
-    path('vm-assigned-extra-config/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='vmassignedextraconfig_changelog', kwargs={'model': models.VmAssignedExtraConfig}),
-    path('vm-assigned-extra-config/<int:pk>/journal/', ObjectJournalView.as_view(), name='vmassignedextraconfig_journal', kwargs={'model': models.VmAssignedExtraConfig}),
+    path('vm-assigned-extra-config/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='vmassignedextraconfig_changelog', kwargs={
+        'model': models.VmAssignedExtraConfig}),
+    path('vm-assigned-extra-config/<int:pk>/journal/', ObjectJournalView.as_view(), name='vmassignedextraconfig_journal', kwargs={
+        'model': models.VmAssignedExtraConfig}),
 )
diff --git a/netbox_sys_plugin/utils.py b/netbox_sys_plugin/utils.py
index e037a0a..d87bbf3 100644
--- a/netbox_sys_plugin/utils.py
+++ b/netbox_sys_plugin/utils.py
@@ -1,17 +1,20 @@
+"""Utils definition"""
+
 import requests
-from django.conf import settings
 from .models import WebhookSettings
 
 def get_webhook_settings():
+    """Get webhook user defined 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
         }
+    #pylint: disable=W0718
     except Exception as e:
         print(f"Error Fetching webhook settings: {e}")
         return None
@@ -24,13 +27,12 @@ def send_webhook(payload):
         return
     try:
         headers = {'Content-Type': settings['content_type']}
-        response = requests.post(settings['url'], json=payload, headers=headers)
+        response = requests.post(settings['url'], json=payload, headers=headers,timeout=60)
         response.raise_for_status()
         print(f"Webhook sent successfully: {response.status_code}")
     except requests.RequestException as e:
         print(f"Error sending webhook: {e}")
 
-
 def validate_extra_config_values(structure, values):
     """Validates the user-provided `extra_config_values` against the `extra_config_structure`."""
     errors = []
@@ -42,7 +44,7 @@ def validate_extra_config_values(structure, values):
 
         # Check for missing required fields
         if is_required:
-            if field_name not in values or values[field_name] in [None, ""]: 
+            if field_name not in values or values[field_name] in [None, ""]:
                 errors.append(f"Missing or empty required field: '{field_name}' with type {field_type}")
                 continue
 
@@ -55,12 +57,11 @@ def validate_extra_config_values(structure, values):
 
     return len(errors) == 0, errors
 
-
 def is_valid_type(value, expected_type):
     """Validates a value against the expected type."""
     if expected_type == "string":
         return isinstance(value, str)
-    elif expected_type == "integer":
+    if expected_type == "integer":
         try:
             int(value)  # Allow string representation of numbers
             return True
@@ -68,4 +69,4 @@ def is_valid_type(value, expected_type):
             return False
     elif expected_type == "boolean":
         return value in [True, False, "true", "false", "True", "False"]
-    return False  # Default to invalid for unknown types
\ No newline at end of file
+    return False  # Default to invalid for unknown types
diff --git a/netbox_sys_plugin/views.py b/netbox_sys_plugin/views.py
index 0e2d120..86d7834 100644
--- a/netbox_sys_plugin/views.py
+++ b/netbox_sys_plugin/views.py
@@ -1,10 +1,11 @@
 """Model views definitions"""
 
-from django.shortcuts import render, redirect
 from netbox.views import generic
-from . import forms, models, tables, filtersets
+from django.shortcuts import render, redirect
 from django.contrib import messages
 from django.urls import reverse
+from . import forms, models, tables, filtersets
+
 
 
 
@@ -127,25 +128,26 @@ class CreateVmView(generic.ObjectView):
     template_name = 'netbox_sys_plugin/create_vm.html'
     queryset = models.Cluster.objects.all()
 
-    def get(self, request, *args, **kwargs):
+    def get(self, request):
+        """Process GET Create VM Form"""
         form = self.form_class()
         return render(request, self.template_name, {'form': form})
 
-    def post(self, request, *args, **kwargs):
+    def post(self, request):
+        """Process POST Create VM Form"""
         form = self.form_class(data=request.POST)
 
         try:
             form.process_creation(request.POST)
-            messages.success(request, "ClusterType, Cluster, and VirtualMachine created successfully!")
+            messages.success(request, "Virtual Machine and all related the objects created successfully!")
             #return render(request, self.template_name, {'form': form})
             return redirect(reverse('virtualization:virtualmachine_list'))
         except ValueError as e:
-                messages.error(request, f"Error: {str(e)}")
+            messages.error(request, f"Error: {str(e)}")
         return render(request, self.template_name, {'form': form})
-    
+
 #Domain Names
 class  DomainNamesView(generic.ObjectView):
-
     """ Domain names view definition"""
 
     queryset = (
@@ -196,7 +198,7 @@ class WebhookSettingsEditView(generic.ObjectEditView):
     form = forms.WebhookSettingsForm
 
 class WebhookSettingsDeleteView(generic.ObjectDeleteView):
-        
+    """Webhook Settings Delete delete view definition"""
     queryset = models.WebhookSettings.objects.all()
 
 #ExtraConfig
@@ -223,7 +225,7 @@ class ProviderTypeExtraConfigEditView(generic.ObjectEditView):
     form = forms.ProviderTypeExtraConfigForm
 
 class ProviderTypeExtraConfigDeleteView(generic.ObjectDeleteView):
-        
+    """Provider Type Extra Config delete view definition"""
     queryset = models.ProviderTypeExtraConfig.objects.all()
 
 #VmAssignedExtraConfig
@@ -238,7 +240,7 @@ class VmAssignedExtraConfigListView(generic.ObjectListView):
     """Virtual Machine Assigned Extra Config list view definition"""
 
     queryset = models.VmAssignedExtraConfig.objects.all()
-    table = tables.VmAssignedExtraConfig
+    table = tables.VmAssignedExtraConfigTable
     filterset = filtersets.VmAssignedExtraConfigFilterSet
     filterset_form = forms.VmAssignedExtraConfigFilterForm
 
-- 
GitLab