2
0
Эх сурвалжийг харах

Closes #1493: Added functional roles for virtual machines

Jeremy Stretch 8 жил өмнө
parent
commit
6243fbfd0d

+ 27 - 10
netbox/templates/virtualization/virtualmachine.html

@@ -58,24 +58,20 @@
                     </td>
                     </td>
                 </tr>
                 </tr>
                 <tr>
                 <tr>
-                    <td>Cluster</td>
+                    <td>Role</td>
                     <td>
                     <td>
-                        {% if vm.cluster.group %}
-                            <a href="{{ vm.cluster.group.get_absolute_url }}">{{ vm.cluster.group }}</a>
-                            <i class="fa fa-angle-right"></i>
+                        {% if vm.role %}
+                            <a href="{% url 'virtualization:virtualmachine_list' %}?role={{ vm.role.slug }}">{{ vm.role }}</a>
+                        {% else %}
+                            <span class="text-muted">None</span>
                         {% endif %}
                         {% endif %}
-                        <a href="{{ vm.cluster.get_absolute_url }}">{{ vm.cluster }}</a>
                     </td>
                     </td>
                 </tr>
                 </tr>
-                <tr>
-                    <td>Cluster Type</td>
-                    <td>{{ vm.cluster.type }}</td>
-                </tr>
                 <tr>
                 <tr>
                     <td>Platform</td>
                     <td>Platform</td>
                     <td>
                     <td>
                         {% if vm.platform %}
                         {% if vm.platform %}
-                            <span>{{ vm.platform }}</span>
+                            <a href="{% url 'virtualization:virtualmachine_list' %}?platform={{ vm.platform.slug }}">{{ vm.platform }}</a>
                         {% else %}
                         {% else %}
                             <span class="text-muted">None</span>
                             <span class="text-muted">None</span>
                         {% endif %}
                         {% endif %}
@@ -127,6 +123,27 @@
                 </tr>
                 </tr>
             </table>
             </table>
         </div>
         </div>
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                <strong>Cluster</strong>
+            </div>
+            <table class="table table-hover panel-body attr-table">
+                <tr>
+                    <td>Cluster</td>
+                    <td>
+                        {% if vm.cluster.group %}
+                            <a href="{{ vm.cluster.group.get_absolute_url }}">{{ vm.cluster.group }}</a>
+                            <i class="fa fa-angle-right"></i>
+                        {% endif %}
+                        <a href="{{ vm.cluster.get_absolute_url }}">{{ vm.cluster }}</a>
+                    </td>
+                </tr>
+                <tr>
+                    <td>Cluster Type</td>
+                    <td>{{ vm.cluster.type }}</td>
+                </tr>
+            </table>
+        </div>
         <div class="panel panel-default">
         <div class="panel panel-default">
             <div class="panel-heading">
             <div class="panel-heading">
                 <strong>Resources</strong>
                 <strong>Resources</strong>

+ 7 - 1
netbox/templates/virtualization/virtualmachine_edit.html

@@ -7,9 +7,15 @@
         <div class="panel-body">
         <div class="panel-body">
             {% render_field form.name %}
             {% render_field form.name %}
             {% render_field form.status %}
             {% render_field form.status %}
+            {% render_field form.role %}
+            {% render_field form.platform %}
+        </div>
+    </div>
+    <div class="panel panel-default">
+        <div class="panel-heading"><strong>Cluster</strong></div>
+        <div class="panel-body">
             {% render_field form.cluster_group %}
             {% render_field form.cluster_group %}
             {% render_field form.cluster %}
             {% render_field form.cluster %}
-            {% render_field form.platform %}
         </div>
         </div>
     </div>
     </div>
     <div class="panel panel-default">
     <div class="panel panel-default">

+ 6 - 5
netbox/virtualization/api/serializers.py

@@ -2,7 +2,7 @@ from __future__ import unicode_literals
 
 
 from rest_framework import serializers
 from rest_framework import serializers
 
 
-from dcim.api.serializers import NestedPlatformSerializer, NestedSiteSerializer
+from dcim.api.serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer
 from dcim.constants import VIFACE_FF_CHOICES
 from dcim.constants import VIFACE_FF_CHOICES
 from dcim.models import Interface
 from dcim.models import Interface
 from extras.api.customfields import CustomFieldModelSerializer
 from extras.api.customfields import CustomFieldModelSerializer
@@ -86,14 +86,15 @@ class WritableClusterSerializer(CustomFieldModelSerializer):
 class VirtualMachineSerializer(CustomFieldModelSerializer):
 class VirtualMachineSerializer(CustomFieldModelSerializer):
     status = ChoiceFieldSerializer(choices=STATUS_CHOICES)
     status = ChoiceFieldSerializer(choices=STATUS_CHOICES)
     cluster = NestedClusterSerializer()
     cluster = NestedClusterSerializer()
+    role = NestedDeviceRoleSerializer()
     tenant = NestedTenantSerializer()
     tenant = NestedTenantSerializer()
     platform = NestedPlatformSerializer()
     platform = NestedPlatformSerializer()
 
 
     class Meta:
     class Meta:
         model = VirtualMachine
         model = VirtualMachine
         fields = [
         fields = [
-            'id', 'name', 'status', 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory',
-            'disk', 'comments', 'custom_fields',
+            'id', 'name', 'status', 'cluster', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'vcpus',
+            'memory', 'disk', 'comments', 'custom_fields',
         ]
         ]
 
 
 
 
@@ -110,8 +111,8 @@ class WritableVirtualMachineSerializer(CustomFieldModelSerializer):
     class Meta:
     class Meta:
         model = VirtualMachine
         model = VirtualMachine
         fields = [
         fields = [
-            'id', 'name', 'status', 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory',
-            'disk', 'comments', 'custom_fields',
+            'id', 'name', 'status', 'cluster', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'vcpus',
+            'memory', 'disk', 'comments', 'custom_fields',
         ]
         ]
 
 
 
 

+ 13 - 2
netbox/virtualization/filters.py

@@ -3,7 +3,7 @@ from __future__ import unicode_literals
 import django_filters
 import django_filters
 from django.db.models import Q
 from django.db.models import Q
 
 
-from dcim.models import Platform, Site
+from dcim.models import DeviceRole, Platform, Site
 from extras.filters import CustomFieldFilterSet
 from extras.filters import CustomFieldFilterSet
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
 from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
@@ -80,10 +80,21 @@ class VirtualMachineFilter(CustomFieldFilterSet):
         to_field_name='slug',
         to_field_name='slug',
         label='Cluster group (slug)',
         label='Cluster group (slug)',
     )
     )
-    cluster_id = NullableModelMultipleChoiceFilter(
+    cluster_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
         label='Cluster (ID)',
         label='Cluster (ID)',
     )
     )
+    role_id = NullableModelMultipleChoiceFilter(
+        name='role_id',
+        queryset=DeviceRole.objects.all(),
+        label='Role (ID)',
+    )
+    role = NullableModelMultipleChoiceFilter(
+        name='role__slug',
+        queryset=DeviceRole.objects.all(),
+        to_field_name='slug',
+        label='Role (slug)',
+    )
     tenant_id = NullableModelMultipleChoiceFilter(
     tenant_id = NullableModelMultipleChoiceFilter(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
         label='Tenant (ID)',
         label='Tenant (ID)',

+ 31 - 5
netbox/virtualization/forms.py

@@ -8,7 +8,7 @@ from django.db.models import Count
 
 
 from dcim.constants import IFACE_FF_VIRTUAL, VIFACE_FF_CHOICES
 from dcim.constants import IFACE_FF_VIRTUAL, VIFACE_FF_CHOICES
 from dcim.formfields import MACAddressFormField
 from dcim.formfields import MACAddressFormField
-from dcim.models import Device, Interface, Platform, Rack, Region, Site
+from dcim.models import Device, DeviceRole, Interface, Platform, Rack, Region, Site
 from extras.forms import CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
 from extras.forms import CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFilterForm
 from tenancy.forms import TenancyForm
 from tenancy.forms import TenancyForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
@@ -222,7 +222,8 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
     class Meta:
     class Meta:
         model = VirtualMachine
         model = VirtualMachine
         fields = [
         fields = [
-            'name', 'status', 'cluster_group', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments',
+            'name', 'status', 'cluster_group', 'cluster', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk',
+            'comments',
         ]
         ]
 
 
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
@@ -251,6 +252,15 @@ class VirtualMachineCSVForm(forms.ModelForm):
             'invalid_choice': 'Invalid cluster name.',
             'invalid_choice': 'Invalid cluster name.',
         }
         }
     )
     )
+    role = forms.ModelChoiceField(
+        queryset=DeviceRole.objects.all(),
+        required=False,
+        to_field_name='name',
+        help_text='Name of functional role',
+        error_messages={
+            'invalid_choice': 'Invalid role name.'
+        }
+    )
     tenant = forms.ModelChoiceField(
     tenant = forms.ModelChoiceField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
         required=False,
         required=False,
@@ -272,13 +282,14 @@ class VirtualMachineCSVForm(forms.ModelForm):
 
 
     class Meta:
     class Meta:
         model = VirtualMachine
         model = VirtualMachine
-        fields = ['name', 'status', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
+        fields = ['name', 'status', 'cluster', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
 
 
 
 
 class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
     pk = forms.ModelMultipleChoiceField(queryset=VirtualMachine.objects.all(), widget=forms.MultipleHiddenInput)
     pk = forms.ModelMultipleChoiceField(queryset=VirtualMachine.objects.all(), widget=forms.MultipleHiddenInput)
     status = forms.ChoiceField(choices=add_blank_choice(STATUS_CHOICES), required=False, initial='')
     status = forms.ChoiceField(choices=add_blank_choice(STATUS_CHOICES), required=False, initial='')
     cluster = forms.ModelChoiceField(queryset=Cluster.objects.all(), required=False)
     cluster = forms.ModelChoiceField(queryset=Cluster.objects.all(), required=False)
+    role = forms.ModelChoiceField(queryset=DeviceRole.objects.all(), required=False)
     tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
     tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
     platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False)
     platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False)
     vcpus = forms.IntegerField(required=False, label='vCPUs')
     vcpus = forms.IntegerField(required=False, label='vCPUs')
@@ -287,7 +298,7 @@ class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
     comments = CommentField(widget=SmallTextarea)
     comments = CommentField(widget=SmallTextarea)
 
 
     class Meta:
     class Meta:
-        nullable_fields = ['tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
+        nullable_fields = ['role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
 
 
 
 
 def vm_status_choices():
 def vm_status_choices():
@@ -303,13 +314,28 @@ class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
     cluster_group = FilterChoiceField(
     cluster_group = FilterChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
-        null_option=(0, 'None'),
+        null_option=(0, 'None')
     )
     )
     cluster_id = FilterChoiceField(
     cluster_id = FilterChoiceField(
         queryset=Cluster.objects.annotate(filter_count=Count('virtual_machines')),
         queryset=Cluster.objects.annotate(filter_count=Count('virtual_machines')),
         label='Cluster'
         label='Cluster'
     )
     )
+    role = FilterChoiceField(
+        queryset=DeviceRole.objects.annotate(filter_count=Count('virtual_machines')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
     status = forms.MultipleChoiceField(choices=vm_status_choices, required=False)
     status = forms.MultipleChoiceField(choices=vm_status_choices, required=False)
+    tenant = FilterChoiceField(
+        queryset=Tenant.objects.annotate(filter_count=Count('virtual_machines')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
+    platform = FilterChoiceField(
+        queryset=Platform.objects.annotate(filter_count=Count('virtual_machines')),
+        to_field_name='slug',
+        null_option=(0, 'None')
+    )
 
 
 
 
 #
 #

+ 22 - 0
netbox/virtualization/migrations/0004_virtualmachine_add_role.py

@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.4 on 2017-09-29 14:32
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0044_virtualization'),
+        ('virtualization', '0003_cluster_add_site'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='virtualmachine',
+            name='role',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='virtual_machines', to='dcim.DeviceRole'),
+        ),
+    ]

+ 7 - 0
netbox/virtualization/models.py

@@ -179,6 +179,13 @@ class VirtualMachine(CreatedUpdatedModel, CustomFieldModel):
         default=STATUS_ACTIVE,
         default=STATUS_ACTIVE,
         verbose_name='Status'
         verbose_name='Status'
     )
     )
+    role = models.ForeignKey(
+        to='dcim.DeviceRole',
+        on_delete=models.PROTECT,
+        related_name='virtual_machines',
+        blank=True,
+        null=True
+    )
     primary_ip4 = models.OneToOneField(
     primary_ip4 = models.OneToOneField(
         to='ipam.IPAddress',
         to='ipam.IPAddress',
         on_delete=models.SET_NULL,
         on_delete=models.SET_NULL,

+ 2 - 2
netbox/virtualization/tables.py

@@ -95,7 +95,7 @@ class VirtualMachineTable(BaseTable):
 
 
     class Meta(BaseTable.Meta):
     class Meta(BaseTable.Meta):
         model = VirtualMachine
         model = VirtualMachine
-        fields = ('pk', 'name', 'status', 'cluster', 'tenant', 'vcpus', 'memory', 'disk')
+        fields = ('pk', 'name', 'status', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk')
 
 
 
 
 class VirtualMachineDetailTable(VirtualMachineTable):
 class VirtualMachineDetailTable(VirtualMachineTable):
@@ -105,7 +105,7 @@ class VirtualMachineDetailTable(VirtualMachineTable):
 
 
     class Meta(BaseTable.Meta):
     class Meta(BaseTable.Meta):
         model = VirtualMachine
         model = VirtualMachine
-        fields = ('pk', 'name', 'status', 'cluster', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip')
+        fields = ('pk', 'name', 'status', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip')
 
 
 
 
 #
 #