mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Merge pull request #4014 from hSaria/3886-config-context-cluster
Fixes #3886: Config context cluster (group)
This commit is contained in:
@ -20,6 +20,8 @@ from utilities.api import (
|
||||
ChoiceField, ContentTypeField, get_serializer_for_model, SerializerNotFound, SerializedPKRelatedField,
|
||||
ValidatedModelSerializer,
|
||||
)
|
||||
from virtualization.api.nested_serializers import NestedClusterGroupSerializer, NestedClusterSerializer
|
||||
from virtualization.models import Cluster, ClusterGroup
|
||||
from .nested_serializers import *
|
||||
|
||||
|
||||
@ -161,6 +163,18 @@ class ConfigContextSerializer(ValidatedModelSerializer):
|
||||
required=False,
|
||||
many=True
|
||||
)
|
||||
cluster_groups = SerializedPKRelatedField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
serializer=NestedClusterGroupSerializer,
|
||||
required=False,
|
||||
many=True
|
||||
)
|
||||
clusters = SerializedPKRelatedField(
|
||||
queryset=Cluster.objects.all(),
|
||||
serializer=NestedClusterSerializer,
|
||||
required=False,
|
||||
many=True
|
||||
)
|
||||
tenant_groups = SerializedPKRelatedField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
serializer=NestedTenantGroupSerializer,
|
||||
@ -184,7 +198,7 @@ class ConfigContextSerializer(ValidatedModelSerializer):
|
||||
model = ConfigContext
|
||||
fields = [
|
||||
'id', 'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms',
|
||||
'tenant_groups', 'tenants', 'tags', 'data',
|
||||
'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'data',
|
||||
]
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@ from django.db.models import Q
|
||||
|
||||
from dcim.models import DeviceRole, Platform, Region, Site
|
||||
from tenancy.models import Tenant, TenantGroup
|
||||
from virtualization.models import Cluster, ClusterGroup
|
||||
from .choices import *
|
||||
from .models import ConfigContext, CustomField, Graph, ExportTemplate, ObjectChange, Tag
|
||||
|
||||
@ -170,6 +171,22 @@ class ConfigContextFilterSet(django_filters.FilterSet):
|
||||
to_field_name='slug',
|
||||
label='Platform (slug)',
|
||||
)
|
||||
cluster_group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='cluster_groups',
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
label='Cluster group',
|
||||
)
|
||||
cluster_group = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='cluster_groups__slug',
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='Cluster group (slug)',
|
||||
)
|
||||
cluster_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='clusters',
|
||||
queryset=Cluster.objects.all(),
|
||||
label='Cluster',
|
||||
)
|
||||
tenant_group_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='tenant_groups',
|
||||
queryset=TenantGroup.objects.all(),
|
||||
|
@ -10,6 +10,7 @@ from utilities.forms import (
|
||||
CommentField, ContentTypeSelect, DateTimePicker, FilterChoiceField, JSONField, SlugField, StaticSelect2,
|
||||
BOOLEAN_WITH_BLANK_CHOICES,
|
||||
)
|
||||
from virtualization.models import Cluster, ClusterGroup
|
||||
from .choices import *
|
||||
from .models import ConfigContext, CustomField, CustomFieldValue, ImageAttachment, ObjectChange, Tag
|
||||
|
||||
@ -203,8 +204,8 @@ class ConfigContextForm(BootstrapMixin, forms.ModelForm):
|
||||
class Meta:
|
||||
model = ConfigContext
|
||||
fields = [
|
||||
'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms', 'tenant_groups',
|
||||
'tenants', 'tags', 'data',
|
||||
'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms', 'cluster_groups',
|
||||
'clusters', 'tenant_groups', 'tenants', 'tags', 'data',
|
||||
]
|
||||
widgets = {
|
||||
'regions': APISelectMultiple(
|
||||
@ -219,6 +220,12 @@ class ConfigContextForm(BootstrapMixin, forms.ModelForm):
|
||||
'platforms': APISelectMultiple(
|
||||
api_url="/api/dcim/platforms/"
|
||||
),
|
||||
'cluster_groups': APISelectMultiple(
|
||||
api_url="/api/virtualization/cluster-groups/"
|
||||
),
|
||||
'clusters': APISelectMultiple(
|
||||
api_url="/api/virtualization/clusters/"
|
||||
),
|
||||
'tenant_groups': APISelectMultiple(
|
||||
api_url="/api/tenancy/tenant-groups/"
|
||||
),
|
||||
@ -289,6 +296,21 @@ class ConfigContextFilterForm(BootstrapMixin, forms.Form):
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
cluster_group = FilterChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/virtualization/cluster-groups/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
cluster_id = FilterChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
label='Cluster',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/virtualization/clusters/",
|
||||
)
|
||||
)
|
||||
tenant_group = FilterChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
|
24
netbox/extras/migrations/0037_configcontexts_clusters.py
Normal file
24
netbox/extras/migrations/0037_configcontexts_clusters.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Generated by Django 2.2.8 on 2020-01-17 18:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('virtualization', '0013_deterministic_ordering'),
|
||||
('extras', '0036_contenttype_filters_to_q_objects'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='configcontext',
|
||||
name='cluster_groups',
|
||||
field=models.ManyToManyField(blank=True, related_name='_configcontext_cluster_groups_+', to='virtualization.ClusterGroup'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='configcontext',
|
||||
name='clusters',
|
||||
field=models.ManyToManyField(blank=True, related_name='_configcontext_clusters_+', to='virtualization.Cluster'),
|
||||
),
|
||||
]
|
@ -765,6 +765,16 @@ class ConfigContext(models.Model):
|
||||
related_name='+',
|
||||
blank=True
|
||||
)
|
||||
cluster_groups = models.ManyToManyField(
|
||||
to='virtualization.ClusterGroup',
|
||||
related_name='+',
|
||||
blank=True
|
||||
)
|
||||
clusters = models.ManyToManyField(
|
||||
to='virtualization.Cluster',
|
||||
related_name='+',
|
||||
blank=True
|
||||
)
|
||||
tenant_groups = models.ManyToManyField(
|
||||
to='tenancy.TenantGroup',
|
||||
related_name='+',
|
||||
|
@ -29,6 +29,10 @@ class ConfigContextQuerySet(QuerySet):
|
||||
# `device_role` for Device; `role` for VirtualMachine
|
||||
role = getattr(obj, 'device_role', None) or obj.role
|
||||
|
||||
# Virtualization cluster for VirtualMachine
|
||||
cluster = getattr(obj, 'cluster', None)
|
||||
cluster_group = getattr(cluster, 'group', None)
|
||||
|
||||
# Get the group of the assigned tenant, if any
|
||||
tenant_group = obj.tenant.group if obj.tenant else None
|
||||
|
||||
@ -44,6 +48,8 @@ class ConfigContextQuerySet(QuerySet):
|
||||
Q(sites=obj.site) | Q(sites=None),
|
||||
Q(roles=role) | Q(roles=None),
|
||||
Q(platforms=obj.platform) | Q(platforms=None),
|
||||
Q(cluster_groups=cluster_group) | Q(cluster_groups=None),
|
||||
Q(clusters=cluster) | Q(clusters=None),
|
||||
Q(tenant_groups=tenant_group) | Q(tenant_groups=None),
|
||||
Q(tenants=obj.tenant) | Q(tenants=None),
|
||||
Q(tags__slug__in=obj.tags.slugs()) | Q(tags=None),
|
||||
|
@ -7,6 +7,7 @@ from extras.constants import GRAPH_MODELS
|
||||
from extras.filters import *
|
||||
from extras.models import ConfigContext, ExportTemplate, Graph
|
||||
from tenancy.models import Tenant, TenantGroup
|
||||
from virtualization.models import Cluster, ClusterGroup, ClusterType
|
||||
|
||||
|
||||
class GraphTestCase(TestCase):
|
||||
@ -107,6 +108,21 @@ class ConfigContextTestCase(TestCase):
|
||||
)
|
||||
Platform.objects.bulk_create(platforms)
|
||||
|
||||
cluster_groups = (
|
||||
ClusterGroup(name='Cluster Group 1', slug='cluster-group-1'),
|
||||
ClusterGroup(name='Cluster Group 2', slug='cluster-group-2'),
|
||||
ClusterGroup(name='Cluster Group 3', slug='cluster-group-3'),
|
||||
)
|
||||
ClusterGroup.objects.bulk_create(cluster_groups)
|
||||
|
||||
cluster_type = ClusterType.objects.create(name='Cluster Type 1', slug='cluster-type-1')
|
||||
clusters = (
|
||||
Cluster(name='Cluster 1', type=cluster_type),
|
||||
Cluster(name='Cluster 2', type=cluster_type),
|
||||
Cluster(name='Cluster 3', type=cluster_type),
|
||||
)
|
||||
Cluster.objects.bulk_create(clusters)
|
||||
|
||||
tenant_groups = (
|
||||
TenantGroup(name='Tenant Group 1', slug='tenant-group-1'),
|
||||
TenantGroup(name='Tenant Group 2', slug='tenant-group-2'),
|
||||
@ -132,6 +148,8 @@ class ConfigContextTestCase(TestCase):
|
||||
c.sites.set([sites[i]])
|
||||
c.roles.set([device_roles[i]])
|
||||
c.platforms.set([platforms[i]])
|
||||
c.cluster_groups.set([cluster_groups[i]])
|
||||
c.clusters.set([clusters[i]])
|
||||
c.tenant_groups.set([tenant_groups[i]])
|
||||
c.tenants.set([tenants[i]])
|
||||
|
||||
@ -173,6 +191,18 @@ class ConfigContextTestCase(TestCase):
|
||||
params = {'platform': [platforms[0].slug, platforms[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_cluster_group(self):
|
||||
cluster_groups = ClusterGroup.objects.all()[:2]
|
||||
params = {'cluster_group_id': [cluster_groups[0].pk, cluster_groups[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'cluster_group': [cluster_groups[0].slug, cluster_groups[1].slug]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_cluster(self):
|
||||
clusters = Cluster.objects.all()[:2]
|
||||
params = {'cluster_id': [clusters[0].pk, clusters[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_tenant_group(self):
|
||||
tenant_groups = TenantGroup.objects.all()[:2]
|
||||
params = {'tenant_group_id': [tenant_groups[0].pk, tenant_groups[1].pk]}
|
||||
|
@ -134,6 +134,34 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cluster Groups</td>
|
||||
<td>
|
||||
{% if configcontext.cluster_groups.all %}
|
||||
<ul>
|
||||
{% for cluster_group in configcontext.cluster_groups.all %}
|
||||
<li><a href="{{ cluster_group.get_absolute_url }}">{{ cluster_group }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<span class="text-muted">None</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Clusters</td>
|
||||
<td>
|
||||
{% if configcontext.clusters.all %}
|
||||
<ul>
|
||||
{% for cluster in configcontext.clusters.all %}
|
||||
<li><a href="{{ cluster.get_absolute_url }}">{{ cluster }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<span class="text-muted">None</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tenant Groups</td>
|
||||
<td>
|
||||
|
@ -18,6 +18,8 @@
|
||||
{% render_field form.sites %}
|
||||
{% render_field form.roles %}
|
||||
{% render_field form.platforms %}
|
||||
{% render_field form.cluster_groups %}
|
||||
{% render_field form.clusters %}
|
||||
{% render_field form.tenant_groups %}
|
||||
{% render_field form.tenants %}
|
||||
{% render_field form.tags %}
|
||||
|
Reference in New Issue
Block a user