From 75f9959a133fc630951cf25d724bd18983056b0c Mon Sep 17 00:00:00 2001 From: Roberth1993 Date: Wed, 5 Nov 2025 16:22:16 +0100 Subject: [PATCH 1/3] Closes #18658: Add start on boot field to VirtualMachine model --- docs/models/virtualization/virtualmachine.md | 7 +++++++ .../virtualization/virtualmachine.html | 4 ++++ .../api/serializers_/virtualmachines.py | 6 ++++-- netbox/virtualization/choices.py | 14 ++++++++++++++ netbox/virtualization/filtersets.py | 4 ++++ netbox/virtualization/forms/bulk_edit.py | 8 +++++++- netbox/virtualization/forms/bulk_import.py | 8 +++++++- netbox/virtualization/forms/filtersets.py | 8 +++++++- netbox/virtualization/forms/model_forms.py | 4 ++-- .../0050_virtualmachine_start_on_boot.py | 18 ++++++++++++++++++ .../0051_alter_virtualmachine_start_on_boot.py | 18 ++++++++++++++++++ .../virtualization/models/virtualmachines.py | 9 +++++++++ .../virtualization/tables/virtualmachines.py | 5 ++++- netbox/virtualization/tests/test_api.py | 5 ++++- netbox/virtualization/tests/test_filtersets.py | 10 ++++++++-- netbox/virtualization/tests/test_views.py | 2 ++ 16 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 netbox/virtualization/migrations/0050_virtualmachine_start_on_boot.py create mode 100644 netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py diff --git a/docs/models/virtualization/virtualmachine.md b/docs/models/virtualization/virtualmachine.md index a90b2752d6d..66cb8867582 100644 --- a/docs/models/virtualization/virtualmachine.md +++ b/docs/models/virtualization/virtualmachine.md @@ -21,6 +21,13 @@ The VM's operational status. !!! tip Additional statuses may be defined by setting `VirtualMachine.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. +### Start on boot + +The start on boot setting from the hypervisor. + +!!! tip + Additional status may be defined by setting `VirtualMachine.start_on_boot` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. + ### Site & Cluster The [site](../dcim/site.md) and/or [cluster](./cluster.md) to which the VM is assigned. diff --git a/netbox/templates/virtualization/virtualmachine.html b/netbox/templates/virtualization/virtualmachine.html index 7f902a20ded..3a07b080c58 100644 --- a/netbox/templates/virtualization/virtualmachine.html +++ b/netbox/templates/virtualization/virtualmachine.html @@ -19,6 +19,10 @@

{% trans "Virtual Machine" %}

{% trans "Status" %} {% badge object.get_status_display bg_color=object.get_status_color %} + + {% trans "Start on boot" %} + {{ object.get_start_on_boot_display|placeholder }} + {% trans "Role" %} {{ object.role|linkify|placeholder }} diff --git a/netbox/virtualization/api/serializers_/virtualmachines.py b/netbox/virtualization/api/serializers_/virtualmachines.py index c035a436a0a..4a3c51eceaf 100644 --- a/netbox/virtualization/api/serializers_/virtualmachines.py +++ b/netbox/virtualization/api/serializers_/virtualmachines.py @@ -29,8 +29,10 @@ ) + class VirtualMachineSerializer(PrimaryModelSerializer): status = ChoiceField(choices=VirtualMachineStatusChoices, required=False) + start_on_boot = ChoiceField(choices=VirtualMachineStartOnBootChoices, required=False) site = SiteSerializer(nested=True, required=False, allow_null=True, default=None) cluster = ClusterSerializer(nested=True, required=False, allow_null=True, default=None) device = DeviceSerializer(nested=True, required=False, allow_null=True, default=None) @@ -49,7 +51,7 @@ class VirtualMachineSerializer(PrimaryModelSerializer): class Meta: model = VirtualMachine fields = [ - 'id', 'url', 'display_url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'serial', 'role', + 'id', 'url', 'display_url', 'display', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'serial', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'owner', 'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', 'interface_count', 'virtual_disk_count', @@ -62,7 +64,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer): class Meta(VirtualMachineSerializer.Meta): fields = [ - 'id', 'url', 'display_url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'serial', 'role', + 'id', 'url', 'display_url', 'display', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'serial', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'config_context', 'created', 'last_updated', 'interface_count', 'virtual_disk_count', diff --git a/netbox/virtualization/choices.py b/netbox/virtualization/choices.py index b60a6e1ff34..0e111be48d4 100644 --- a/netbox/virtualization/choices.py +++ b/netbox/virtualization/choices.py @@ -49,3 +49,17 @@ class VirtualMachineStatusChoices(ChoiceSet): (STATUS_DECOMMISSIONING, _('Decommissioning'), 'yellow'), (STATUS_PAUSED, _('Paused'), 'orange'), ] + + +class VirtualMachineStartOnBootChoices(ChoiceSet): + key = 'VirtualMachine.start_on_boot' + + STATUS_ON = 'on' + STATUS_OFF = 'off' + STATUS_LAST_STATE = 'laststate' + + CHOICES = [ + (STATUS_ON, _('On'), 'green'), + (STATUS_OFF, _('Off'), 'gray'), + (STATUS_LAST_STATE, _('Last State'), 'cyan') + ] \ No newline at end of file diff --git a/netbox/virtualization/filtersets.py b/netbox/virtualization/filtersets.py index e2ef8cb6a8a..b96f1dc24e9 100644 --- a/netbox/virtualization/filtersets.py +++ b/netbox/virtualization/filtersets.py @@ -92,6 +92,10 @@ class VirtualMachineFilterSet( choices=VirtualMachineStatusChoices, null_value=None ) + start_on_boot = django_filters.MultipleChoiceFilter( + choices=VirtualMachineStartOnBootChoices, + null_value=None + ) cluster_group_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster__group', queryset=ClusterGroup.objects.all(), diff --git a/netbox/virtualization/forms/bulk_edit.py b/netbox/virtualization/forms/bulk_edit.py index 092bf576b0a..b8a7f0c10db 100644 --- a/netbox/virtualization/forms/bulk_edit.py +++ b/netbox/virtualization/forms/bulk_edit.py @@ -85,6 +85,12 @@ class VirtualMachineBulkEditForm(PrimaryModelBulkEditForm): required=False, initial='', ) + start_on_boot = forms.ChoiceField( + label=_('Start on boot'), + choices=add_blank_choice(VirtualMachineStartOnBootChoices), + required=False, + initial='', + ) site = DynamicModelChoiceField( label=_('Site'), queryset=Site.objects.all(), @@ -145,7 +151,7 @@ class VirtualMachineBulkEditForm(PrimaryModelBulkEditForm): model = VirtualMachine fieldsets = ( - FieldSet('site', 'cluster', 'device', 'status', 'role', 'tenant', 'platform', 'description'), + FieldSet('site', 'cluster', 'device', 'status', 'start_on_boot', 'role', 'tenant', 'platform', 'description'), FieldSet('vcpus', 'memory', 'disk', name=_('Resources')), FieldSet('config_template', name=_('Configuration')), ) diff --git a/netbox/virtualization/forms/bulk_import.py b/netbox/virtualization/forms/bulk_import.py index 67f39b6f531..97b3311fbef 100644 --- a/netbox/virtualization/forms/bulk_import.py +++ b/netbox/virtualization/forms/bulk_import.py @@ -88,6 +88,12 @@ class VirtualMachineImportForm(PrimaryModelImportForm): choices=VirtualMachineStatusChoices, help_text=_('Operational status') ) + start_on_boot = CSVChoiceField( + label=_('Start on boot'), + choices=VirtualMachineStartOnBootChoices, + help_text=_('Start on boot in hypervisor'), + required=False, + ) site = CSVModelChoiceField( label=_('Site'), queryset=Site.objects.all(), @@ -143,7 +149,7 @@ class VirtualMachineImportForm(PrimaryModelImportForm): class Meta: model = VirtualMachine fields = ( - 'name', 'status', 'role', 'site', 'cluster', 'device', 'tenant', 'platform', 'vcpus', 'memory', 'disk', + 'name', 'status', 'start_on_boot', 'role', 'site', 'cluster', 'device', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'description', 'serial', 'config_template', 'comments', 'owner', 'tags', ) diff --git a/netbox/virtualization/forms/filtersets.py b/netbox/virtualization/forms/filtersets.py index 3e0db175e4f..d787dbb9345 100644 --- a/netbox/virtualization/forms/filtersets.py +++ b/netbox/virtualization/forms/filtersets.py @@ -26,6 +26,7 @@ ) + class ClusterTypeFilterForm(OrganizationalModelFilterSetForm): model = ClusterType fieldsets = ( @@ -109,7 +110,7 @@ class VirtualMachineFilterForm( FieldSet('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id', name=_('Cluster')), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet( - 'status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'config_template_id', + 'status', 'start_on_boot', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'config_template_id', 'local_context_data', 'serial', name=_('Attributes') ), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), @@ -171,6 +172,11 @@ class VirtualMachineFilterForm( choices=VirtualMachineStatusChoices, required=False ) + start_on_boot = forms.MultipleChoiceField( + label=_('Start on boot'), + choices=VirtualMachineStartOnBootChoices, + required=False + ) platform_id = DynamicModelMultipleChoiceField( queryset=Platform.objects.all(), required=False, diff --git a/netbox/virtualization/forms/model_forms.py b/netbox/virtualization/forms/model_forms.py index fa4966b2b3b..3690d4fc3a2 100644 --- a/netbox/virtualization/forms/model_forms.py +++ b/netbox/virtualization/forms/model_forms.py @@ -217,7 +217,7 @@ class VirtualMachineForm(TenancyForm, PrimaryModelForm): ) fieldsets = ( - FieldSet('name', 'role', 'status', 'description', 'serial', 'tags', name=_('Virtual Machine')), + FieldSet('name', 'role', 'status', 'start_on_boot', 'description', 'serial', 'tags', name=_('Virtual Machine')), FieldSet('site', 'cluster', 'device', name=_('Site/Cluster')), FieldSet('tenant_group', 'tenant', name=_('Tenancy')), FieldSet('platform', 'primary_ip4', 'primary_ip6', 'config_template', name=_('Management')), @@ -228,7 +228,7 @@ class VirtualMachineForm(TenancyForm, PrimaryModelForm): class Meta: model = VirtualMachine fields = [ - 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant_group', 'tenant', 'platform', 'primary_ip4', + 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'role', 'tenant_group', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'serial', 'owner', 'comments', 'tags', 'local_context_data', 'config_template', ] diff --git a/netbox/virtualization/migrations/0050_virtualmachine_start_on_boot.py b/netbox/virtualization/migrations/0050_virtualmachine_start_on_boot.py new file mode 100644 index 00000000000..899cb28a8a0 --- /dev/null +++ b/netbox/virtualization/migrations/0050_virtualmachine_start_on_boot.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2025-11-05 13:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('virtualization', '0049_owner'), + ] + + operations = [ + migrations.AddField( + model_name='virtualmachine', + name='start_on_boot', + field=models.CharField(default='off', max_length=32), + ), + ] diff --git a/netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py b/netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py new file mode 100644 index 00000000000..6eca711535d --- /dev/null +++ b/netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2025-11-05 13:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('virtualization', '0050_virtualmachine_start_on_boot'), + ] + + operations = [ + migrations.AlterField( + model_name='virtualmachine', + name='start_on_boot', + field=models.CharField(blank=True, default='off', max_length=32, null=True), + ), + ] diff --git a/netbox/virtualization/models/virtualmachines.py b/netbox/virtualization/models/virtualmachines.py index de6fde745f9..d0663fa2623 100644 --- a/netbox/virtualization/models/virtualmachines.py +++ b/netbox/virtualization/models/virtualmachines.py @@ -79,6 +79,14 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co default=VirtualMachineStatusChoices.STATUS_ACTIVE, verbose_name=_('status') ) + start_on_boot = models.CharField( + max_length=32, + choices=VirtualMachineStartOnBootChoices, + default=VirtualMachineStartOnBootChoices.STATUS_OFF, + verbose_name=_('start on boot'), + blank=True, + null=True, + ) role = models.ForeignKey( to='dcim.DeviceRole', on_delete=models.PROTECT, @@ -247,6 +255,7 @@ def save(self, *args, **kwargs): def get_status_color(self): return VirtualMachineStatusChoices.colors.get(self.status) + @property def primary_ip(self): if get_config().PREFER_IPV4 and self.primary_ip4: diff --git a/netbox/virtualization/tables/virtualmachines.py b/netbox/virtualization/tables/virtualmachines.py index fcb9017df50..088d174eaa5 100644 --- a/netbox/virtualization/tables/virtualmachines.py +++ b/netbox/virtualization/tables/virtualmachines.py @@ -29,6 +29,9 @@ class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModel status = columns.ChoiceFieldColumn( verbose_name=_('Status'), ) + start_on_boot = columns.ChoiceFieldColumn( + verbose_name=_('Start on boot'), + ) site = tables.Column( verbose_name=_('Site'), linkify=True @@ -81,7 +84,7 @@ class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModel class Meta(PrimaryModelTable.Meta): model = VirtualMachine fields = ( - 'pk', 'id', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'tenant_group', 'vcpus', + 'pk', 'id', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'role', 'tenant', 'tenant_group', 'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'description', 'comments', 'config_template', 'serial', 'contacts', 'tags', 'created', 'last_updated', ) diff --git a/netbox/virtualization/tests/test_api.py b/netbox/virtualization/tests/test_api.py index 56f9132abe3..adaa6ddc8a7 100644 --- a/netbox/virtualization/tests/test_api.py +++ b/netbox/virtualization/tests/test_api.py @@ -21,6 +21,7 @@ from virtualization.models import * + class AppTest(APITestCase): def test_root(self): @@ -211,7 +212,8 @@ def setUpTestData(cls): name='Virtual Machine 3', site=sites[0], cluster=clusters[0], - local_context_data={'C': 3} + local_context_data={'C': 3}, + start_on_boot=VirtualMachineStartOnBootChoices.STATUS_ON, ), ) VirtualMachine.objects.bulk_create(virtual_machines) @@ -235,6 +237,7 @@ def setUpTestData(cls): { 'name': 'Virtual Machine 7', 'cluster': clusters[2].pk, + 'start_on_boot': VirtualMachineStartOnBootChoices.STATUS_ON, }, ] diff --git a/netbox/virtualization/tests/test_filtersets.py b/netbox/virtualization/tests/test_filtersets.py index 0179069af06..13a007c1539 100644 --- a/netbox/virtualization/tests/test_filtersets.py +++ b/netbox/virtualization/tests/test_filtersets.py @@ -349,7 +349,8 @@ def setUpTestData(cls): memory=2, disk=2, description='foobar2', - serial='222-bbb' + serial='222-bbb', + start_on_boot=VirtualMachineStartOnBootChoices.STATUS_OFF, ), VirtualMachine( name='Virtual Machine 3', @@ -363,7 +364,8 @@ def setUpTestData(cls): vcpus=3, memory=3, disk=3, - description='foobar3' + description='foobar3', + start_on_boot=VirtualMachineStartOnBootChoices.STATUS_ON, ), ) VirtualMachine.objects.bulk_create(vms) @@ -430,6 +432,10 @@ def test_status(self): params = {'status': [VirtualMachineStatusChoices.STATUS_ACTIVE, VirtualMachineStatusChoices.STATUS_STAGED]} self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + def test_start_on_boot(self): + params = {'start_on_boot': [VirtualMachineStartOnBootChoices.STATUS_ON]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) + def test_cluster_group(self): groups = ClusterGroup.objects.all()[:2] params = {'cluster_group_id': [groups[0].pk, groups[1].pk]} diff --git a/netbox/virtualization/tests/test_views.py b/netbox/virtualization/tests/test_views.py index 35226c16dc3..556dd6f8856 100644 --- a/netbox/virtualization/tests/test_views.py +++ b/netbox/virtualization/tests/test_views.py @@ -271,6 +271,7 @@ def setUpTestData(cls): 'platform': platforms[1].pk, 'name': 'Virtual Machine X', 'status': VirtualMachineStatusChoices.STATUS_STAGED, + 'start_on_boot': VirtualMachineStartOnBootChoices.STATUS_ON, 'role': roles[1].pk, 'primary_ip4': None, 'primary_ip6': None, @@ -309,6 +310,7 @@ def setUpTestData(cls): 'memory': 65535, 'disk': 8000, 'comments': 'New comments', + 'start_on_boot': VirtualMachineStartOnBootChoices.STATUS_OFF, } @override_settings(EXEMPT_VIEW_PERMISSIONS=['*']) From 8dc76b7a961ba24aea1cce1d1d358d9ce3caf822 Mon Sep 17 00:00:00 2001 From: Roberth1993 Date: Wed, 5 Nov 2025 17:39:32 +0100 Subject: [PATCH 2/3] Closes #18658: Add start on boot field to VirtualMachine model, fixed identation --- .../api/serializers_/virtualmachines.py | 17 ++++++++--------- netbox/virtualization/choices.py | 2 +- netbox/virtualization/forms/bulk_import.py | 4 ++-- netbox/virtualization/forms/filtersets.py | 1 - netbox/virtualization/forms/model_forms.py | 6 +++--- netbox/virtualization/models/virtualmachines.py | 1 - netbox/virtualization/tables/virtualmachines.py | 6 +++--- netbox/virtualization/tests/test_api.py | 1 - 8 files changed, 17 insertions(+), 21 deletions(-) diff --git a/netbox/virtualization/api/serializers_/virtualmachines.py b/netbox/virtualization/api/serializers_/virtualmachines.py index 4a3c51eceaf..25030eaf3f9 100644 --- a/netbox/virtualization/api/serializers_/virtualmachines.py +++ b/netbox/virtualization/api/serializers_/virtualmachines.py @@ -29,7 +29,6 @@ ) - class VirtualMachineSerializer(PrimaryModelSerializer): status = ChoiceField(choices=VirtualMachineStatusChoices, required=False) start_on_boot = ChoiceField(choices=VirtualMachineStartOnBootChoices, required=False) @@ -51,10 +50,10 @@ class VirtualMachineSerializer(PrimaryModelSerializer): class Meta: model = VirtualMachine fields = [ - 'id', 'url', 'display_url', 'display', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'serial', 'role', - 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', - 'owner', 'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'created', - 'last_updated', 'interface_count', 'virtual_disk_count', + 'id', 'url', 'display_url', 'display', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', + 'serial', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', + 'disk', 'description', 'owner', 'comments', 'config_template', 'local_context_data', 'tags', + 'custom_fields', 'created', 'last_updated', 'interface_count', 'virtual_disk_count', ] brief_fields = ('id', 'url', 'display', 'name', 'description') @@ -64,10 +63,10 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer): class Meta(VirtualMachineSerializer.Meta): fields = [ - 'id', 'url', 'display_url', 'display', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'serial', 'role', - 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', - 'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'config_context', 'created', - 'last_updated', 'interface_count', 'virtual_disk_count', + 'id', 'url', 'display_url', 'display', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', + 'serial', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', + 'disk', 'description', 'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', + 'config_context', 'created', 'last_updated', 'interface_count', 'virtual_disk_count', ] @extend_schema_field(serializers.JSONField(allow_null=True)) diff --git a/netbox/virtualization/choices.py b/netbox/virtualization/choices.py index 0e111be48d4..b00c9f1e26b 100644 --- a/netbox/virtualization/choices.py +++ b/netbox/virtualization/choices.py @@ -62,4 +62,4 @@ class VirtualMachineStartOnBootChoices(ChoiceSet): (STATUS_ON, _('On'), 'green'), (STATUS_OFF, _('Off'), 'gray'), (STATUS_LAST_STATE, _('Last State'), 'cyan') - ] \ No newline at end of file + ] diff --git a/netbox/virtualization/forms/bulk_import.py b/netbox/virtualization/forms/bulk_import.py index 97b3311fbef..10b973e8cb0 100644 --- a/netbox/virtualization/forms/bulk_import.py +++ b/netbox/virtualization/forms/bulk_import.py @@ -149,8 +149,8 @@ class VirtualMachineImportForm(PrimaryModelImportForm): class Meta: model = VirtualMachine fields = ( - 'name', 'status', 'start_on_boot', 'role', 'site', 'cluster', 'device', 'tenant', 'platform', 'vcpus', 'memory', 'disk', - 'description', 'serial', 'config_template', 'comments', 'owner', 'tags', + 'name', 'status', 'start_on_boot', 'role', 'site', 'cluster', 'device', 'tenant', 'platform', 'vcpus', + 'memory', 'disk', 'description', 'serial', 'config_template', 'comments', 'owner', 'tags', ) diff --git a/netbox/virtualization/forms/filtersets.py b/netbox/virtualization/forms/filtersets.py index d787dbb9345..27fda4a85a6 100644 --- a/netbox/virtualization/forms/filtersets.py +++ b/netbox/virtualization/forms/filtersets.py @@ -26,7 +26,6 @@ ) - class ClusterTypeFilterForm(OrganizationalModelFilterSetForm): model = ClusterType fieldsets = ( diff --git a/netbox/virtualization/forms/model_forms.py b/netbox/virtualization/forms/model_forms.py index 3690d4fc3a2..e3ba36bad04 100644 --- a/netbox/virtualization/forms/model_forms.py +++ b/netbox/virtualization/forms/model_forms.py @@ -228,9 +228,9 @@ class VirtualMachineForm(TenancyForm, PrimaryModelForm): class Meta: model = VirtualMachine fields = [ - 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'role', 'tenant_group', 'tenant', 'platform', 'primary_ip4', - 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'serial', 'owner', 'comments', 'tags', - 'local_context_data', 'config_template', + 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'role', 'tenant_group', 'tenant', + 'platform', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'serial', 'owner', + 'comments', 'tags', 'local_context_data', 'config_template', ] def __init__(self, *args, **kwargs): diff --git a/netbox/virtualization/models/virtualmachines.py b/netbox/virtualization/models/virtualmachines.py index d0663fa2623..8246e08fbca 100644 --- a/netbox/virtualization/models/virtualmachines.py +++ b/netbox/virtualization/models/virtualmachines.py @@ -255,7 +255,6 @@ def save(self, *args, **kwargs): def get_status_color(self): return VirtualMachineStatusChoices.colors.get(self.status) - @property def primary_ip(self): if get_config().PREFER_IPV4 and self.primary_ip4: diff --git a/netbox/virtualization/tables/virtualmachines.py b/netbox/virtualization/tables/virtualmachines.py index 088d174eaa5..c770581d02e 100644 --- a/netbox/virtualization/tables/virtualmachines.py +++ b/netbox/virtualization/tables/virtualmachines.py @@ -84,9 +84,9 @@ class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModel class Meta(PrimaryModelTable.Meta): model = VirtualMachine fields = ( - 'pk', 'id', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'role', 'tenant', 'tenant_group', 'vcpus', - 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'description', 'comments', 'config_template', - 'serial', 'contacts', 'tags', 'created', 'last_updated', + 'pk', 'id', 'name', 'status', 'start_on_boot', 'site', 'cluster', 'device', 'role', 'tenant', + 'tenant_group', 'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'description', + 'comments', 'config_template', 'serial', 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip', diff --git a/netbox/virtualization/tests/test_api.py b/netbox/virtualization/tests/test_api.py index adaa6ddc8a7..40c4df2ba3b 100644 --- a/netbox/virtualization/tests/test_api.py +++ b/netbox/virtualization/tests/test_api.py @@ -21,7 +21,6 @@ from virtualization.models import * - class AppTest(APITestCase): def test_root(self): From a21894d8d9249d653a69b78796782ac79a4e13b9 Mon Sep 17 00:00:00 2001 From: Roberth1993 Date: Sat, 8 Nov 2025 10:12:40 +0100 Subject: [PATCH 3/3] Changed according to feedback, removed migration, fixed typo in docs, fixed inconsistent diplay of start_on_boot --- docs/models/virtualization/virtualmachine.md | 2 +- .../virtualization/virtualmachine.html | 2 +- .../0051_alter_virtualmachine_start_on_boot.py | 18 ------------------ .../virtualization/models/virtualmachines.py | 5 +++-- 4 files changed, 5 insertions(+), 22 deletions(-) delete mode 100644 netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py diff --git a/docs/models/virtualization/virtualmachine.md b/docs/models/virtualization/virtualmachine.md index 66cb8867582..189a4ba7566 100644 --- a/docs/models/virtualization/virtualmachine.md +++ b/docs/models/virtualization/virtualmachine.md @@ -26,7 +26,7 @@ The VM's operational status. The start on boot setting from the hypervisor. !!! tip - Additional status may be defined by setting `VirtualMachine.start_on_boot` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. + Additional statuses may be defined by setting `VirtualMachine.start_on_boot` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter. ### Site & Cluster diff --git a/netbox/templates/virtualization/virtualmachine.html b/netbox/templates/virtualization/virtualmachine.html index 3a07b080c58..1ee566eb0b8 100644 --- a/netbox/templates/virtualization/virtualmachine.html +++ b/netbox/templates/virtualization/virtualmachine.html @@ -21,7 +21,7 @@

{% trans "Virtual Machine" %}

{% trans "Start on boot" %} - {{ object.get_start_on_boot_display|placeholder }} + {% badge object.get_start_on_boot_display bg_color=object.get_start_on_boot_color %} {% trans "Role" %} diff --git a/netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py b/netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py deleted file mode 100644 index 6eca711535d..00000000000 --- a/netbox/virtualization/migrations/0051_alter_virtualmachine_start_on_boot.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.7 on 2025-11-05 13:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('virtualization', '0050_virtualmachine_start_on_boot'), - ] - - operations = [ - migrations.AlterField( - model_name='virtualmachine', - name='start_on_boot', - field=models.CharField(blank=True, default='off', max_length=32, null=True), - ), - ] diff --git a/netbox/virtualization/models/virtualmachines.py b/netbox/virtualization/models/virtualmachines.py index 8246e08fbca..f4679c9c2ff 100644 --- a/netbox/virtualization/models/virtualmachines.py +++ b/netbox/virtualization/models/virtualmachines.py @@ -84,8 +84,6 @@ class VirtualMachine(ContactsMixin, ImageAttachmentsMixin, RenderConfigMixin, Co choices=VirtualMachineStartOnBootChoices, default=VirtualMachineStartOnBootChoices.STATUS_OFF, verbose_name=_('start on boot'), - blank=True, - null=True, ) role = models.ForeignKey( to='dcim.DeviceRole', @@ -255,6 +253,9 @@ def save(self, *args, **kwargs): def get_status_color(self): return VirtualMachineStatusChoices.colors.get(self.status) + def get_start_on_boot_color(self): + return VirtualMachineStartOnBootChoices.colors.get(self.start_on_boot) + @property def primary_ip(self): if get_config().PREFER_IPV4 and self.primary_ip4: