Added a status field for virtual machines

This commit is contained in:
Jeremy Stretch 2017-09-14 14:35:34 -04:00
parent 136d16b7fd
commit 6872ab0e14
9 changed files with 93 additions and 8 deletions

View File

@ -51,6 +51,12 @@
<td>Name</td>
<td>{{ vm.name }}</td>
</tr>
<tr>
<td>Status</td>
<td>
<span class="label label-{{ vm.get_status_class }}">{{ vm.get_status_display }}</span>
</td>
</tr>
<tr>
<td>Cluster</td>
<td>

View File

@ -6,6 +6,7 @@
<div class="panel-heading"><strong>Virtual Machine</strong></div>
<div class="panel-body">
{% render_field form.name %}
{% render_field form.status %}
{% render_field form.cluster_group %}
{% render_field form.cluster %}
{% render_field form.platform %}

View File

@ -8,6 +8,7 @@ from dcim.models import Interface
from extras.api.customfields import CustomFieldModelSerializer
from tenancy.api.serializers import NestedTenantSerializer
from utilities.api import ChoiceFieldSerializer, ValidatedModelSerializer
from virtualization.constants import STATUS_CHOICES
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
@ -82,6 +83,7 @@ class WritableClusterSerializer(CustomFieldModelSerializer):
#
class VirtualMachineSerializer(CustomFieldModelSerializer):
status = ChoiceFieldSerializer(choices=STATUS_CHOICES)
cluster = NestedClusterSerializer()
tenant = NestedTenantSerializer()
platform = NestedPlatformSerializer()
@ -89,7 +91,8 @@ class VirtualMachineSerializer(CustomFieldModelSerializer):
class Meta:
model = VirtualMachine
fields = [
'id', 'name', 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'comments', 'custom_fields',
'id', 'name', 'status', 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'comments',
'custom_fields',
]
@ -106,7 +109,8 @@ class WritableVirtualMachineSerializer(CustomFieldModelSerializer):
class Meta:
model = VirtualMachine
fields = [
'id', 'name', 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'comments', 'custom_fields',
'id', 'name', 'status', 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'comments',
'custom_fields',
]

View File

@ -0,0 +1,19 @@
from __future__ import unicode_literals
# VirtualMachine statuses (replicated from Device statuses)
STATUS_OFFLINE = 0
STATUS_ACTIVE = 1
STATUS_STAGED = 3
STATUS_CHOICES = [
[STATUS_ACTIVE, 'Active'],
[STATUS_OFFLINE, 'Offline'],
[STATUS_STAGED, 'Staged'],
]
# Bootstrap CSS classes for VirtualMachine statuses
VM_STATUS_CLASSES = {
0: 'warning',
1: 'success',
3: 'primary',
}

View File

@ -7,6 +7,7 @@ from dcim.models import Platform
from extras.filters import CustomFieldFilterSet
from tenancy.models import Tenant
from utilities.filters import NullableModelMultipleChoiceFilter, NumericInFilter
from .constants import STATUS_CHOICES
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
@ -55,6 +56,9 @@ class VirtualMachineFilter(CustomFieldFilterSet):
method='search',
label='Search',
)
status = django_filters.MultipleChoiceFilter(
choices=STATUS_CHOICES
)
cluster_group_id = NullableModelMultipleChoiceFilter(
name='cluster__group',
queryset=ClusterGroup.objects.all(),

View File

@ -12,10 +12,11 @@ from extras.forms import CustomFieldBulkEditForm, CustomFieldForm, CustomFieldFi
from tenancy.forms import TenancyForm
from tenancy.models import Tenant
from utilities.forms import (
APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ChainedFieldsMixin,
ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm, ConfirmationForm,
ExpandableNameField, FilterChoiceField, SlugField, SmallTextarea,
add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm,
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, SlugField, SmallTextarea,
)
from .constants import STATUS_CHOICES
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
@ -185,7 +186,9 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
class Meta:
model = VirtualMachine
fields = ['name', 'cluster_group', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
fields = [
'name', 'status', 'cluster_group', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments',
]
def __init__(self, *args, **kwargs):
@ -200,6 +203,11 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
class VirtualMachineCSVForm(forms.ModelForm):
status = CSVChoiceField(
choices=STATUS_CHOICES,
required=False,
help_text='Operational status of device'
)
cluster = forms.ModelChoiceField(
queryset=Cluster.objects.all(),
to_field_name='name',
@ -229,11 +237,12 @@ class VirtualMachineCSVForm(forms.ModelForm):
class Meta:
model = VirtualMachine
fields = ['name', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
fields = ['name', 'status', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments']
class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=VirtualMachine.objects.all(), widget=forms.MultipleHiddenInput)
status = forms.ChoiceField(choices=add_blank_choice(STATUS_CHOICES), required=False, initial='')
cluster = forms.ModelChoiceField(queryset=Cluster.objects.all(), required=False)
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False)
@ -246,6 +255,13 @@ class VirtualMachineBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
nullable_fields = ['tenant', 'platform', 'vcpus', 'memory', 'disk']
def vm_status_choices():
status_counts = {}
for status in VirtualMachine.objects.values('status').annotate(count=Count('status')).order_by('status'):
status_counts[status['status']] = status['count']
return [(s[0], '{} ({})'.format(s[1], status_counts.get(s[0], 0))) for s in STATUS_CHOICES]
class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = VirtualMachine
q = forms.CharField(required=False, label='Search')
@ -258,6 +274,7 @@ class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
queryset=Cluster.objects.annotate(filter_count=Count('virtual_machines')),
label='Cluster'
)
status = forms.MultipleChoiceField(choices=vm_status_choices, required=False)
#

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.4 on 2017-09-14 17:49
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('virtualization', '0001_virtualization'),
]
operations = [
migrations.AddField(
model_name='virtualmachine',
name='status',
field=models.PositiveSmallIntegerField(choices=[[1, 'Active'], [0, 'Offline'], [3, 'Staged']], default=1, verbose_name='Status'),
),
]

View File

@ -7,6 +7,7 @@ from django.utils.encoding import python_2_unicode_compatible
from extras.models import CustomFieldModel, CustomFieldValue
from utilities.models import CreatedUpdatedModel
from .constants import STATUS_ACTIVE, STATUS_CHOICES, VM_STATUS_CLASSES
#
@ -139,6 +140,11 @@ class VirtualMachine(CreatedUpdatedModel, CustomFieldModel):
max_length=64,
unique=True
)
status = models.PositiveSmallIntegerField(
choices=STATUS_CHOICES,
default=STATUS_ACTIVE,
verbose_name='Status'
)
primary_ip4 = models.OneToOneField(
to='ipam.IPAddress',
on_delete=models.SET_NULL,
@ -187,3 +193,6 @@ class VirtualMachine(CreatedUpdatedModel, CustomFieldModel):
def get_absolute_url(self):
return reverse('virtualization:virtualmachine', args=[self.pk])
def get_status_class(self):
return VM_STATUS_CLASSES[self.status]

View File

@ -20,6 +20,10 @@ CLUSTERGROUP_ACTIONS = """
{% endif %}
"""
VIRTUALMACHINE_STATUS = """
<span class="label label-{{ record.get_status_class }}">{{ record.get_status_display }}</span>
"""
#
# Cluster types
@ -79,12 +83,13 @@ class ClusterTable(BaseTable):
class VirtualMachineTable(BaseTable):
pk = ToggleColumn()
name = tables.LinkColumn()
status = tables.TemplateColumn(template_code=VIRTUALMACHINE_STATUS)
cluster = tables.LinkColumn('virtualization:cluster', args=[Accessor('cluster.pk')])
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
class Meta(BaseTable.Meta):
model = VirtualMachine
fields = ('pk', 'name', 'cluster', 'tenant', 'vcpus', 'memory', 'disk')
fields = ('pk', 'name', 'status', 'cluster', 'tenant', 'vcpus', 'memory', 'disk')
#