From 9dbce602be17e5884f4b04d5695a14fbce1ac066 Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Mon, 2 Dec 2024 15:09:33 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=E2=9C=A8=20Add=20tags=20to=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 57 +++++++++++++++++-- .../netbox_sys_plugin/create_vm.html | 10 +++- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index e8c94bf..740f5ce 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -5,6 +5,7 @@ from netbox.forms import NetBoxModelForm from virtualization.models import ClusterType, Cluster, VirtualMachine, VMInterface from ipam.models import IPAddress, Service from dcim.models import DeviceRole,Site, Platform +from extras.models import Tag from utilities.forms.fields import DynamicModelChoiceField from django.db import transaction @@ -38,7 +39,7 @@ class ClusterFormList(NetBoxModelForm): class Meta: model = Cluster - fields = ('cluster_type','cluster') + fields = ('cluster_type','cluster','tags') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -90,6 +91,21 @@ class IPAddressForm(NetBoxModelForm): super().__init__(*args, **kwargs) self.fields.pop('tags',None) +class TagsForm(NetBoxModelForm): + """Form for IP Addresses.""" + tag = DynamicModelChoiceField( + queryset=Tag.objects.all(), required=False, label="Tag" + ) + class Meta: + model = Tag + fields = ('tag',) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields.pop('tags',None) + + + # Inline formsets for managing relationships ClusterFormSet = inlineformset_factory( @@ -122,6 +138,10 @@ ClusterListFormSet = forms.modelformset_factory( Cluster, form=ClusterFormList, formset=ClusterFormList, extra=1, can_delete=False ) +TagFormSet = forms.modelformset_factory( + Tag, form=TagsForm, formset=TagsForm, extra=1, can_delete=False +) + # Combined form class CreateVmForm(NetBoxModelForm): @@ -172,6 +192,10 @@ class CreateVmForm(NetBoxModelForm): self.cl_list_formsets = [] empty_cl_list_formset = ClusterListFormSet(data=data, prefix='cl_list_new') self.cl_list_formsets.append(('new', empty_cl_list_formset)) + # Tags + self.tagformsets = [] + empty_tagformset = TagFormSet(data=data, prefix='tag_new') + self.tagformsets.append(('new', empty_tagformset)) @staticmethod def check_cluster_exist(data): @@ -194,14 +218,28 @@ class CreateVmForm(NetBoxModelForm): return ports except ValueError: raise ValueError(f"Invalid ports value: {ports_field}") + + @staticmethod + def get_parse_tags(data): + tag_id = data.get('tag_new-tag', '') + tags_field = Tag.objects.get(pk=tag_id) + #try: + # tags = [int(tag.strip()) for tag in tags_field.split(',') if tag.strip().isdigit()] + # return tags + #except ValueError: + # raise ValueError(f"Invalid ports value: {tags_field}") + + return tags_field @staticmethod def create_cluster_type(data): """Create and save a ClusterType object.""" + tags = CreateVmForm.get_parse_tags(data) cluster_type = ClusterType( name=data.get('name', ''), slug=data.get('slug', ''), - description=data.get('description', '') + description=data.get('description', ''), + tags=tags ) cluster_type.full_clean() cluster_type.save() @@ -215,13 +253,15 @@ class CreateVmForm(NetBoxModelForm): site = Site.objects.get(pk=site_id) except Site.DoesNotExist: raise ValueError(f"Invalid Site ID: {site_id}") + tags = CreateVmForm.get_parse_tags(data) cluster = Cluster( name=data.get('clusters-0-name', ''), type=cluster_type, status=data.get('clusters-0-status', ''), site=site, - description=data.get('clusters-0-description', '') + description=data.get('clusters-0-description', ''), + tags=tags ) cluster.full_clean() cluster.save() @@ -241,6 +281,7 @@ class CreateVmForm(NetBoxModelForm): platform = Platform.objects.get(pk=platform_id) except Platform.DoesNotExist: raise ValueError(f"Invalid Platform ID: {platform_id}") + tags = CreateVmForm.get_parse_tags(data) vm = VirtualMachine( name=data.get('vms_new-0-name', ''), @@ -249,7 +290,8 @@ class CreateVmForm(NetBoxModelForm): site=cluster.site, platform=platform, description=data.get('vms_new-0-description', ''), - cluster=cluster + cluster=cluster, + tags=tags ) vm.full_clean() vm.save() @@ -271,13 +313,15 @@ class CreateVmForm(NetBoxModelForm): """Create and save a Service object.""" ports_field = data.get(f'{prefix}-0-ports', '') ports = CreateVmForm.parse_ports(ports_field) + tags = CreateVmForm.get_parse_tags(data) service = Service( name=data.get(f'{prefix}-0-name', ''), protocol=data.get(f'{prefix}-0-protocol', ''), ports=ports, description=description, - virtual_machine=vm + virtual_machine=vm, + tags=tags ) service.full_clean() service.save() @@ -296,7 +340,8 @@ class CreateVmForm(NetBoxModelForm): address=data.get('ip_new-address', ''), status=data.get('ip_new-status', ''), role=data.get('ip_new-role', ''), - assigned_object=vm_interface + assigned_object=vm_interface, + tags=data.get('tag_new-tag', '') ) ip_address.full_clean() ip_address.save() diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html b/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html index d267c46..ad1def9 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/create_vm.html @@ -122,7 +122,15 @@ SYS - Virtual Machine {% endfor %} {% endfor %} </div> - + <div class="field-group my-5"> + <h5>Tag</h5> + {% for tagformset in form.tagformsets %} + {% for tag_form in tagformset %} + <div class="form-group" class="field-group mb-5"> + {{ tag_form.as_p }} + </div> + {% endfor %} + {% endfor %} <div class="text-end my-3"> {% block buttons %} <button type="submit" class="btn btn-primary">Save</button> -- GitLab From 922197b939724ee459ef1c30cdb2c1293f0c132e Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Mon, 2 Dec 2024 15:58:49 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=90=9B=20Fix=20not=20assigned=20tags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 52 ++++++++++++++++++----------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index 740f5ce..f0483a8 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -1,13 +1,15 @@ from django import forms from django.forms import inlineformset_factory +from django.contrib.contenttypes.models import ContentType +from django.db import transaction +from utilities.forms.fields import DynamicModelChoiceField from netbox.forms import NetBoxModelForm - from virtualization.models import ClusterType, Cluster, VirtualMachine, VMInterface from ipam.models import IPAddress, Service from dcim.models import DeviceRole,Site, Platform -from extras.models import Tag -from utilities.forms.fields import DynamicModelChoiceField -from django.db import transaction +from extras.models import Tag, TaggedItem + + @@ -222,27 +224,39 @@ class CreateVmForm(NetBoxModelForm): @staticmethod def get_parse_tags(data): tag_id = data.get('tag_new-tag', '') - tags_field = Tag.objects.get(pk=tag_id) - #try: - # tags = [int(tag.strip()) for tag in tags_field.split(',') if tag.strip().isdigit()] - # return tags - #except ValueError: - # raise ValueError(f"Invalid ports value: {tags_field}") - return tags_field + 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}") + + @staticmethod + def assign_tags(obj,data): + """Assign Tags to the created objects""" + + tags = CreateVmForm.get_parse_tags(data) + content_type = ContentType.objects.get_for_model(obj) + for tag in tags: + TaggedItem.objects.create( + tag=tag, + content_type=content_type, + object_id=obj.pk + ) @staticmethod def create_cluster_type(data): """Create and save a ClusterType object.""" - tags = CreateVmForm.get_parse_tags(data) cluster_type = ClusterType( name=data.get('name', ''), slug=data.get('slug', ''), description=data.get('description', ''), - tags=tags ) cluster_type.full_clean() cluster_type.save() + CreateVmForm.assign_tags(cluster_type,data) return cluster_type @staticmethod @@ -253,7 +267,6 @@ class CreateVmForm(NetBoxModelForm): site = Site.objects.get(pk=site_id) except Site.DoesNotExist: raise ValueError(f"Invalid Site ID: {site_id}") - tags = CreateVmForm.get_parse_tags(data) cluster = Cluster( name=data.get('clusters-0-name', ''), @@ -261,10 +274,10 @@ class CreateVmForm(NetBoxModelForm): status=data.get('clusters-0-status', ''), site=site, description=data.get('clusters-0-description', ''), - tags=tags ) cluster.full_clean() cluster.save() + CreateVmForm.assign_tags(cluster,data) return cluster @staticmethod @@ -281,7 +294,6 @@ class CreateVmForm(NetBoxModelForm): platform = Platform.objects.get(pk=platform_id) except Platform.DoesNotExist: raise ValueError(f"Invalid Platform ID: {platform_id}") - tags = CreateVmForm.get_parse_tags(data) vm = VirtualMachine( name=data.get('vms_new-0-name', ''), @@ -291,10 +303,10 @@ class CreateVmForm(NetBoxModelForm): platform=platform, description=data.get('vms_new-0-description', ''), cluster=cluster, - tags=tags ) vm.full_clean() vm.save() + CreateVmForm.assign_tags(vm,data) return vm @staticmethod @@ -306,6 +318,7 @@ class CreateVmForm(NetBoxModelForm): ) vmi.full_clean() vmi.save() + CreateVmForm.assign_tags(vmi,data) return vmi @staticmethod @@ -313,7 +326,6 @@ class CreateVmForm(NetBoxModelForm): """Create and save a Service object.""" ports_field = data.get(f'{prefix}-0-ports', '') ports = CreateVmForm.parse_ports(ports_field) - tags = CreateVmForm.get_parse_tags(data) service = Service( name=data.get(f'{prefix}-0-name', ''), @@ -321,10 +333,10 @@ class CreateVmForm(NetBoxModelForm): ports=ports, description=description, virtual_machine=vm, - tags=tags ) service.full_clean() service.save() + CreateVmForm.assign_tags(service,data) return service def create_all_services(self, data, vm): @@ -341,10 +353,10 @@ class CreateVmForm(NetBoxModelForm): status=data.get('ip_new-status', ''), role=data.get('ip_new-role', ''), assigned_object=vm_interface, - tags=data.get('tag_new-tag', '') ) ip_address.full_clean() ip_address.save() + CreateVmForm.assign_tags(ip_address,data) return ip_address def process_creation(self, data): -- GitLab From bd367838bf3881d6a15f393f185fabbcb22c73ce Mon Sep 17 00:00:00 2001 From: Frederico Sequeira <frederico.sequeira@ext.ec.europa.eu> Date: Tue, 3 Dec 2024 11:31:47 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=90=9B=20Fix=20several=20issues?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- netbox_sys_plugin/forms/createvm.py | 6 ++--- netbox_sys_plugin/navigation.py | 27 ++++++++++--------- netbox_sys_plugin/tables.py | 2 +- .../providercredentials.html | 2 +- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/netbox_sys_plugin/forms/createvm.py b/netbox_sys_plugin/forms/createvm.py index f0483a8..9bbfbb4 100644 --- a/netbox_sys_plugin/forms/createvm.py +++ b/netbox_sys_plugin/forms/createvm.py @@ -28,7 +28,7 @@ class ClusterForm(NetBoxModelForm): super().__init__(*args, **kwargs) self.fields.pop('tags',None) -class ClusterFormList(NetBoxModelForm): +class ClusterFormList(NetBoxModelForm, forms.Form): """Form for Cluster List.""" cluster_type = DynamicModelChoiceField( queryset=ClusterType.objects.all(), required=False, label="Provider Type" @@ -147,7 +147,7 @@ TagFormSet = forms.modelformset_factory( # Combined form class CreateVmForm(NetBoxModelForm): - """Combined form for managing ClusterType, Cluster, and VirtualMachine.""" + """Combined form for managing ClusterType, Cluster, and VirtualMachine, etc""" name = forms.CharField(max_length=50, min_length=1, required=False, label="Name") slug = forms.CharField(max_length=100, min_length=1, required=False, label="Slug") @@ -360,7 +360,7 @@ class CreateVmForm(NetBoxModelForm): return ip_address def process_creation(self, data): - """Process creation of ClusterType, Cluster, VM, and related objects.""" + """Object creation""" try: with transaction.atomic(): cluster_exists = self.check_cluster_exist(data) diff --git a/netbox_sys_plugin/navigation.py b/netbox_sys_plugin/navigation.py index 2391977..8a4fa9b 100644 --- a/netbox_sys_plugin/navigation.py +++ b/netbox_sys_plugin/navigation.py @@ -68,37 +68,38 @@ clusterProviderCredentialsItem = [ ] vmMachineItem = [ + PluginMenuItem( + link="plugins:netbox_sys_plugin:virtualmachinetype_list", + link_text="VM Type", + buttons=vm_machine_type_buttons + ), PluginMenuItem( link="plugins:netbox_sys_plugin:vmassignedvirtualmachinetype_list", - link_text="Type Assignment", + link_text="VM Type Assignment", buttons=vm_assigned_machine_type_buttons, ), PluginMenuItem( link="plugins:netbox_sys_plugin:virtualmachinemaintenance_list", - link_text="Maintenance", + link_text="VM Maintenance", buttons=vm_maintenance_buttons, ), -] - -operItem =[ - PluginMenuItem( - link="plugins:netbox_sys_plugin:virtualmachinetype_list", - link_text="Virtual Machine Types", - buttons=vm_machine_type_buttons - ), PluginMenuItem( link="plugins:netbox_sys_plugin:creatvm_add", - link_text="Create Virtual Machine ", + link_text="Create VM", buttons=create_vm_buttons ), ] + +operItem =[ + +] #Menu menu = PluginMenu( label="Sys", groups=( - ("Virtual Machine", (vmMachineItem)), + ("Provider", clusterProviderCredentialsItem), - ("Operation", (operItem)), + ("Virtual Machine", (vmMachineItem)), ), 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 b7de3e4..374b9b2 100644 --- a/netbox_sys_plugin/tables.py +++ b/netbox_sys_plugin/tables.py @@ -57,7 +57,7 @@ class ProviderCredentialsTable(NetBoxTable): ) provider_password_vault_path = tables.Column( linkify=False, - verbose_name="Password Vault URL", + verbose_name="Password Vault Path", ) class Meta(NetBoxTable.Meta): diff --git a/netbox_sys_plugin/templates/netbox_sys_plugin/providercredentials.html b/netbox_sys_plugin/templates/netbox_sys_plugin/providercredentials.html index cb91198..f6c63b9 100644 --- a/netbox_sys_plugin/templates/netbox_sys_plugin/providercredentials.html +++ b/netbox_sys_plugin/templates/netbox_sys_plugin/providercredentials.html @@ -16,7 +16,7 @@ Provider Credentials for {{ object.assigned_object }} <td>{{ object.provider_username }}</td> </tr> <tr> - <th scope="row">Password vault URL</th> + <th scope="row">Password vault Path</th> <td>{{ object.provider_password_vault_path }}</td> </tr> </table> -- GitLab