mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Closes #8471: Add status field to Cluster
This commit is contained in:
parent
e208404e3a
commit
64146b8cb1
@ -1,5 +1,5 @@
|
|||||||
# Clusters
|
# Clusters
|
||||||
|
|
||||||
A cluster is a logical grouping of physical resources within which virtual machines run. A cluster must be assigned a type (technological classification), and may optionally be assigned to a cluster group, site, and/or tenant. Each cluster must have a unique name within its assigned group and/or site, if any.
|
A cluster is a logical grouping of physical resources within which virtual machines run. A cluster must be assigned a type (technological classification) and operational status, and may optionally be assigned to a cluster group, site, and/or tenant. Each cluster must have a unique name within its assigned group and/or site, if any.
|
||||||
|
|
||||||
Physical devices may be associated with clusters as hosts. This allows users to track on which host(s) a particular virtual machine may reside. However, NetBox does not support pinning a specific VM within a cluster to a particular host device.
|
Physical devices may be associated with clusters as hosts. This allows users to track on which host(s) a particular virtual machine may reside. However, NetBox does not support pinning a specific VM within a cluster to a particular host device.
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
### Enhancements
|
### Enhancements
|
||||||
|
|
||||||
* [#1202](https://github.com/netbox-community/netbox/issues/1202) - Support overlapping assignment of NAT IP addresses
|
* [#1202](https://github.com/netbox-community/netbox/issues/1202) - Support overlapping assignment of NAT IP addresses
|
||||||
|
* [#8471](https://github.com/netbox-community/netbox/issues/8471) - Add `status` field to Cluster
|
||||||
* [#8495](https://github.com/netbox-community/netbox/issues/8495) - Enable custom field grouping
|
* [#8495](https://github.com/netbox-community/netbox/issues/8495) - Enable custom field grouping
|
||||||
* [#8995](https://github.com/netbox-community/netbox/issues/8995) - Enable arbitrary ordering of REST API results
|
* [#8995](https://github.com/netbox-community/netbox/issues/8995) - Enable arbitrary ordering of REST API results
|
||||||
|
|
||||||
@ -23,3 +24,5 @@
|
|||||||
* ipam.IPAddress
|
* ipam.IPAddress
|
||||||
* The `nat_inside` field no longer requires a unique value
|
* The `nat_inside` field no longer requires a unique value
|
||||||
* The `nat_outside` field has changed from a single IP address instance to a list of multiple IP addresses
|
* The `nat_outside` field has changed from a single IP address instance to a list of multiple IP addresses
|
||||||
|
* virtualization.Cluster
|
||||||
|
* Add required `status` field (default value: `active`)
|
||||||
|
@ -45,6 +45,7 @@ class ClusterSerializer(NetBoxModelSerializer):
|
|||||||
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:cluster-detail')
|
||||||
type = NestedClusterTypeSerializer()
|
type = NestedClusterTypeSerializer()
|
||||||
group = NestedClusterGroupSerializer(required=False, allow_null=True, default=None)
|
group = NestedClusterGroupSerializer(required=False, allow_null=True, default=None)
|
||||||
|
status = ChoiceField(choices=ClusterStatusChoices, required=False)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||||
site = NestedSiteSerializer(required=False, allow_null=True, default=None)
|
site = NestedSiteSerializer(required=False, allow_null=True, default=None)
|
||||||
device_count = serializers.IntegerField(read_only=True)
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
@ -53,8 +54,8 @@ class ClusterSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'tags', 'custom_fields',
|
'id', 'url', 'display', 'name', 'type', 'group', 'status', 'tenant', 'site', 'comments', 'tags',
|
||||||
'created', 'last_updated', 'device_count', 'virtualmachine_count',
|
'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,28 @@
|
|||||||
from utilities.choices import ChoiceSet
|
from utilities.choices import ChoiceSet
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Clusters
|
||||||
|
#
|
||||||
|
|
||||||
|
class ClusterStatusChoices(ChoiceSet):
|
||||||
|
key = 'Cluster.status'
|
||||||
|
|
||||||
|
STATUS_PLANNED = 'planned'
|
||||||
|
STATUS_STAGING = 'staging'
|
||||||
|
STATUS_ACTIVE = 'active'
|
||||||
|
STATUS_DECOMMISSIONING = 'decommissioning'
|
||||||
|
STATUS_OFFLINE = 'offline'
|
||||||
|
|
||||||
|
CHOICES = [
|
||||||
|
(STATUS_PLANNED, 'Planned', 'cyan'),
|
||||||
|
(STATUS_STAGING, 'Staging', 'blue'),
|
||||||
|
(STATUS_ACTIVE, 'Active', 'green'),
|
||||||
|
(STATUS_DECOMMISSIONING, 'Decommissioning', 'yellow'),
|
||||||
|
(STATUS_OFFLINE, 'Offline', 'red'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# VirtualMachines
|
# VirtualMachines
|
||||||
#
|
#
|
||||||
|
@ -90,6 +90,10 @@ class ClusterFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Cluster type (slug)',
|
label='Cluster type (slug)',
|
||||||
)
|
)
|
||||||
|
status = django_filters.MultipleChoiceFilter(
|
||||||
|
choices=ClusterStatusChoices,
|
||||||
|
null_value=None
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
|
@ -58,6 +58,12 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
queryset=ClusterGroup.objects.all(),
|
queryset=ClusterGroup.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
status = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(ClusterStatusChoices),
|
||||||
|
required=False,
|
||||||
|
initial='',
|
||||||
|
widget=StaticSelect()
|
||||||
|
)
|
||||||
tenant = DynamicModelChoiceField(
|
tenant = DynamicModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
@ -85,7 +91,7 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('type', 'group', 'tenant',)),
|
(None, ('type', 'group', 'status', 'tenant',)),
|
||||||
('Site', ('region', 'site_group', 'site',)),
|
('Site', ('region', 'site_group', 'site',)),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
|
@ -44,6 +44,10 @@ class ClusterCSVForm(NetBoxModelCSVForm):
|
|||||||
required=False,
|
required=False,
|
||||||
help_text='Assigned cluster group'
|
help_text='Assigned cluster group'
|
||||||
)
|
)
|
||||||
|
status = CSVChoiceField(
|
||||||
|
choices=ClusterStatusChoices,
|
||||||
|
help_text='Operational status'
|
||||||
|
)
|
||||||
site = CSVModelChoiceField(
|
site = CSVModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
@ -59,7 +63,7 @@ class ClusterCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = ('name', 'type', 'group', 'site', 'comments')
|
fields = ('name', 'type', 'group', 'status', 'site', 'comments')
|
||||||
|
|
||||||
|
|
||||||
class VirtualMachineCSVForm(NetBoxModelCSVForm):
|
class VirtualMachineCSVForm(NetBoxModelCSVForm):
|
||||||
|
@ -35,7 +35,7 @@ class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi
|
|||||||
model = Cluster
|
model = Cluster
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'tag')),
|
||||||
('Attributes', ('group_id', 'type_id')),
|
('Attributes', ('group_id', 'type_id', 'status')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
('Contacts', ('contact', 'contact_role')),
|
('Contacts', ('contact', 'contact_role')),
|
||||||
@ -50,6 +50,10 @@ class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFi
|
|||||||
required=False,
|
required=False,
|
||||||
label=_('Region')
|
label=_('Region')
|
||||||
)
|
)
|
||||||
|
status = MultipleChoiceField(
|
||||||
|
choices=ClusterStatusChoices,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
site_group_id = DynamicModelMultipleChoiceField(
|
site_group_id = DynamicModelMultipleChoiceField(
|
||||||
queryset=SiteGroup.objects.all(),
|
queryset=SiteGroup.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -79,15 +79,19 @@ class ClusterForm(TenancyForm, NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Cluster', ('name', 'type', 'group', 'region', 'site_group', 'site', 'tags')),
|
('Cluster', ('name', 'type', 'group', 'status', 'tags')),
|
||||||
|
('Site', ('region', 'site_group', 'site')),
|
||||||
('Tenancy', ('tenant_group', 'tenant')),
|
('Tenancy', ('tenant_group', 'tenant')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = (
|
fields = (
|
||||||
'name', 'type', 'group', 'tenant', 'region', 'site_group', 'site', 'comments', 'tags',
|
'name', 'type', 'group', 'status', 'tenant', 'region', 'site_group', 'site', 'comments', 'tags',
|
||||||
)
|
)
|
||||||
|
widgets = {
|
||||||
|
'status': StaticSelect(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ClusterAddDevicesForm(BootstrapMixin, forms.Form):
|
class ClusterAddDevicesForm(BootstrapMixin, forms.Form):
|
||||||
|
18
netbox/virtualization/migrations/0030_cluster_status.py
Normal file
18
netbox/virtualization/migrations/0030_cluster_status.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.0.4 on 2022-05-19 19:36
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('virtualization', '0029_created_datetimefield'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='cluster',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(default='active', max_length=50),
|
||||||
|
),
|
||||||
|
]
|
@ -119,6 +119,11 @@ class Cluster(NetBoxModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
|
status = models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=ClusterStatusChoices,
|
||||||
|
default=ClusterStatusChoices.STATUS_ACTIVE
|
||||||
|
)
|
||||||
tenant = models.ForeignKey(
|
tenant = models.ForeignKey(
|
||||||
to='tenancy.Tenant',
|
to='tenancy.Tenant',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
@ -165,6 +170,9 @@ class Cluster(NetBoxModel):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('virtualization:cluster', args=[self.pk])
|
return reverse('virtualization:cluster', args=[self.pk])
|
||||||
|
|
||||||
|
def get_status_color(self):
|
||||||
|
return ClusterStatusChoices.colors.get(self.status)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super().clean()
|
super().clean()
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ class ClusterTable(NetBoxTable):
|
|||||||
group = tables.Column(
|
group = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
|
status = columns.ChoiceFieldColumn()
|
||||||
tenant = tables.Column(
|
tenant = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -93,7 +94,7 @@ class ClusterTable(NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'device_count', 'vm_count', 'contacts',
|
'pk', 'id', 'name', 'type', 'group', 'status', 'tenant', 'site', 'comments', 'device_count', 'vm_count',
|
||||||
'tags', 'created', 'last_updated',
|
'contacts', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'name', 'type', 'group', 'tenant', 'site', 'device_count', 'vm_count')
|
default_columns = ('pk', 'name', 'type', 'group', 'status', 'tenant', 'site', 'device_count', 'vm_count')
|
||||||
|
@ -4,6 +4,7 @@ from rest_framework import status
|
|||||||
from dcim.choices import InterfaceModeChoices
|
from dcim.choices import InterfaceModeChoices
|
||||||
from ipam.models import VLAN, VRF
|
from ipam.models import VLAN, VRF
|
||||||
from utilities.testing import APITestCase, APIViewTestCases
|
from utilities.testing import APITestCase, APIViewTestCases
|
||||||
|
from virtualization.choices import *
|
||||||
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
|
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
|
||||||
|
|
||||||
|
|
||||||
@ -85,6 +86,7 @@ class ClusterTest(APIViewTestCases.APIViewTestCase):
|
|||||||
model = Cluster
|
model = Cluster
|
||||||
brief_fields = ['display', 'id', 'name', 'url', 'virtualmachine_count']
|
brief_fields = ['display', 'id', 'name', 'url', 'virtualmachine_count']
|
||||||
bulk_update_data = {
|
bulk_update_data = {
|
||||||
|
'status': 'offline',
|
||||||
'comments': 'New comment',
|
'comments': 'New comment',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,9 +106,9 @@ class ClusterTest(APIViewTestCases.APIViewTestCase):
|
|||||||
ClusterGroup.objects.bulk_create(cluster_groups)
|
ClusterGroup.objects.bulk_create(cluster_groups)
|
||||||
|
|
||||||
clusters = (
|
clusters = (
|
||||||
Cluster(name='Cluster 1', type=cluster_types[0], group=cluster_groups[0]),
|
Cluster(name='Cluster 1', type=cluster_types[0], group=cluster_groups[0], status=ClusterStatusChoices.STATUS_PLANNED),
|
||||||
Cluster(name='Cluster 2', type=cluster_types[0], group=cluster_groups[0]),
|
Cluster(name='Cluster 2', type=cluster_types[0], group=cluster_groups[0], status=ClusterStatusChoices.STATUS_PLANNED),
|
||||||
Cluster(name='Cluster 3', type=cluster_types[0], group=cluster_groups[0]),
|
Cluster(name='Cluster 3', type=cluster_types[0], group=cluster_groups[0], status=ClusterStatusChoices.STATUS_PLANNED),
|
||||||
)
|
)
|
||||||
Cluster.objects.bulk_create(clusters)
|
Cluster.objects.bulk_create(clusters)
|
||||||
|
|
||||||
@ -115,16 +117,19 @@ class ClusterTest(APIViewTestCases.APIViewTestCase):
|
|||||||
'name': 'Cluster 4',
|
'name': 'Cluster 4',
|
||||||
'type': cluster_types[1].pk,
|
'type': cluster_types[1].pk,
|
||||||
'group': cluster_groups[1].pk,
|
'group': cluster_groups[1].pk,
|
||||||
|
'status': ClusterStatusChoices.STATUS_STAGING,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'Cluster 5',
|
'name': 'Cluster 5',
|
||||||
'type': cluster_types[1].pk,
|
'type': cluster_types[1].pk,
|
||||||
'group': cluster_groups[1].pk,
|
'group': cluster_groups[1].pk,
|
||||||
|
'status': ClusterStatusChoices.STATUS_STAGING,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'Cluster 6',
|
'name': 'Cluster 6',
|
||||||
'type': cluster_types[1].pk,
|
'type': cluster_types[1].pk,
|
||||||
'group': cluster_groups[1].pk,
|
'group': cluster_groups[1].pk,
|
||||||
|
'status': ClusterStatusChoices.STATUS_STAGING,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -123,9 +123,9 @@ class ClusterTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
Tenant.objects.bulk_create(tenants)
|
Tenant.objects.bulk_create(tenants)
|
||||||
|
|
||||||
clusters = (
|
clusters = (
|
||||||
Cluster(name='Cluster 1', type=cluster_types[0], group=cluster_groups[0], site=sites[0], tenant=tenants[0]),
|
Cluster(name='Cluster 1', type=cluster_types[0], group=cluster_groups[0], status=ClusterStatusChoices.STATUS_PLANNED, site=sites[0], tenant=tenants[0]),
|
||||||
Cluster(name='Cluster 2', type=cluster_types[1], group=cluster_groups[1], site=sites[1], tenant=tenants[1]),
|
Cluster(name='Cluster 2', type=cluster_types[1], group=cluster_groups[1], status=ClusterStatusChoices.STATUS_STAGING, site=sites[1], tenant=tenants[1]),
|
||||||
Cluster(name='Cluster 3', type=cluster_types[2], group=cluster_groups[2], site=sites[2], tenant=tenants[2]),
|
Cluster(name='Cluster 3', type=cluster_types[2], group=cluster_groups[2], status=ClusterStatusChoices.STATUS_ACTIVE, site=sites[2], tenant=tenants[2]),
|
||||||
)
|
)
|
||||||
Cluster.objects.bulk_create(clusters)
|
Cluster.objects.bulk_create(clusters)
|
||||||
|
|
||||||
@ -161,6 +161,10 @@ class ClusterTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'group': [groups[0].slug, groups[1].slug]}
|
params = {'group': [groups[0].slug, groups[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_status(self):
|
||||||
|
params = {'status': [ClusterStatusChoices.STATUS_PLANNED, ClusterStatusChoices.STATUS_STAGING]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_type(self):
|
def test_type(self):
|
||||||
types = ClusterType.objects.all()[:2]
|
types = ClusterType.objects.all()[:2]
|
||||||
params = {'type_id': [types[0].pk, types[1].pk]}
|
params = {'type_id': [types[0].pk, types[1].pk]}
|
||||||
|
@ -101,9 +101,9 @@ class ClusterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
ClusterType.objects.bulk_create(clustertypes)
|
ClusterType.objects.bulk_create(clustertypes)
|
||||||
|
|
||||||
Cluster.objects.bulk_create([
|
Cluster.objects.bulk_create([
|
||||||
Cluster(name='Cluster 1', group=clustergroups[0], type=clustertypes[0], site=sites[0]),
|
Cluster(name='Cluster 1', group=clustergroups[0], type=clustertypes[0], status=ClusterStatusChoices.STATUS_ACTIVE, site=sites[0]),
|
||||||
Cluster(name='Cluster 2', group=clustergroups[0], type=clustertypes[0], site=sites[0]),
|
Cluster(name='Cluster 2', group=clustergroups[0], type=clustertypes[0], status=ClusterStatusChoices.STATUS_ACTIVE, site=sites[0]),
|
||||||
Cluster(name='Cluster 3', group=clustergroups[0], type=clustertypes[0], site=sites[0]),
|
Cluster(name='Cluster 3', group=clustergroups[0], type=clustertypes[0], status=ClusterStatusChoices.STATUS_ACTIVE, site=sites[0]),
|
||||||
])
|
])
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
@ -112,6 +112,7 @@ class ClusterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
'name': 'Cluster X',
|
'name': 'Cluster X',
|
||||||
'group': clustergroups[1].pk,
|
'group': clustergroups[1].pk,
|
||||||
'type': clustertypes[1].pk,
|
'type': clustertypes[1].pk,
|
||||||
|
'status': ClusterStatusChoices.STATUS_OFFLINE,
|
||||||
'tenant': None,
|
'tenant': None,
|
||||||
'site': sites[1].pk,
|
'site': sites[1].pk,
|
||||||
'comments': 'Some comments',
|
'comments': 'Some comments',
|
||||||
@ -119,15 +120,16 @@ class ClusterTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
}
|
}
|
||||||
|
|
||||||
cls.csv_data = (
|
cls.csv_data = (
|
||||||
"name,type",
|
"name,type,status",
|
||||||
"Cluster 4,Cluster Type 1",
|
"Cluster 4,Cluster Type 1,active",
|
||||||
"Cluster 5,Cluster Type 1",
|
"Cluster 5,Cluster Type 1,active",
|
||||||
"Cluster 6,Cluster Type 1",
|
"Cluster 6,Cluster Type 1,active",
|
||||||
)
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'group': clustergroups[1].pk,
|
'group': clustergroups[1].pk,
|
||||||
'type': clustertypes[1].pk,
|
'type': clustertypes[1].pk,
|
||||||
|
'status': ClusterStatusChoices.STATUS_OFFLINE,
|
||||||
'tenant': None,
|
'tenant': None,
|
||||||
'site': sites[1].pk,
|
'site': sites[1].pk,
|
||||||
'comments': 'New comments',
|
'comments': 'New comments',
|
||||||
|
Loading…
Reference in New Issue
Block a user