1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Merge pull request #3572 from frelon/cluster-tenant

Add tenancy to cluster
This commit is contained in:
Jeremy Stretch
2019-10-23 11:53:22 -04:00
committed by GitHub
13 changed files with 80 additions and 8 deletions

View File

@ -142,6 +142,10 @@
<h2><a href="{% url 'virtualization:virtualmachine_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.virtualmachine_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.virtualmachine_count }}</a></h2>
<p>Virtual machines</p>
</div>
<div class="col-md-4 text-center">
<h2><a href="{% url 'virtualization:cluster_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.cluster_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.cluster_count }}</a></h2>
<p>Clusters</p>
</div>
</div>
</div>
</div>

View File

@ -83,6 +83,16 @@
{% endif %}
</td>
</tr>
<tr>
<td>Tenant</td>
<td>
{% if cluster.tenant %}
<a href="{{ cluster.tenant.get_absolute_url }}">{{ cluster.tenant }}</a>
{% else %}
<span class="text-muted">None</span>
{% endif %}
</td>
</tr>
<tr>
<td>Site</td>
<td>

View File

@ -8,6 +8,7 @@
{% render_field form.name %}
{% render_field form.type %}
{% render_field form.group %}
{% render_field form.tenant %}
{% render_field form.site %}
</div>
</div>

View File

@ -31,11 +31,12 @@ class TenantSerializer(TaggitSerializer, CustomFieldModelSerializer):
virtualmachine_count = serializers.IntegerField(read_only=True)
vlan_count = serializers.IntegerField(read_only=True)
vrf_count = serializers.IntegerField(read_only=True)
cluster_count = serializers.IntegerField(read_only=True)
class Meta:
model = Tenant
fields = [
'id', 'name', 'slug', 'group', 'description', 'comments', 'tags', 'custom_fields', 'created',
'last_updated', 'circuit_count', 'device_count', 'ipaddress_count', 'prefix_count', 'rack_count',
'site_count', 'virtualmachine_count', 'vlan_count', 'vrf_count',
'site_count', 'virtualmachine_count', 'vlan_count', 'vrf_count', 'cluster_count',
]

View File

@ -9,7 +9,7 @@ from ipam.models import IPAddress, Prefix, VLAN, VRF
from utilities.views import (
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
)
from virtualization.models import VirtualMachine
from virtualization.models import VirtualMachine, Cluster
from . import filters, forms, tables
from .models import Tenant, TenantGroup
@ -80,6 +80,7 @@ class TenantView(PermissionRequiredMixin, View):
'vlan_count': VLAN.objects.filter(tenant=tenant).count(),
'circuit_count': Circuit.objects.filter(tenant=tenant).count(),
'virtualmachine_count': VirtualMachine.objects.filter(tenant=tenant).count(),
'cluster_count': Cluster.objects.filter(tenant=tenant).count(),
}
return render(request, 'tenancy/tenant.html', {

View File

@ -38,6 +38,7 @@ class ClusterGroupSerializer(ValidatedModelSerializer):
class ClusterSerializer(TaggitSerializer, CustomFieldModelSerializer):
type = NestedClusterTypeSerializer()
group = NestedClusterGroupSerializer(required=False, allow_null=True)
tenant = NestedTenantSerializer(required=False, allow_null=True)
site = NestedSiteSerializer(required=False, allow_null=True)
tags = TagListSerializerField(required=False)
device_count = serializers.IntegerField(read_only=True)
@ -46,7 +47,7 @@ class ClusterSerializer(TaggitSerializer, CustomFieldModelSerializer):
class Meta:
model = Cluster
fields = [
'id', 'name', 'type', 'group', 'site', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'id', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'device_count', 'virtualmachine_count',
]

View File

@ -41,7 +41,7 @@ class ClusterGroupViewSet(ModelViewSet):
class ClusterViewSet(CustomFieldModelViewSet):
queryset = Cluster.objects.prefetch_related(
'type', 'group', 'site', 'tags'
'type', 'group', 'tenant', 'site', 'tags'
).annotate(
device_count=get_subquery(Device, 'cluster'),
virtualmachine_count=get_subquery(VirtualMachine, 'cluster')

View File

@ -4,6 +4,7 @@ from netaddr import EUI
from netaddr.core import AddrFormatError
from dcim.models import DeviceRole, Interface, Platform, Region, Site
from tenancy.models import Tenant
from extras.filters import CustomFieldFilterSet
from tenancy.filtersets import TenancyFilterSet
from utilities.filters import (
@ -56,6 +57,10 @@ class ClusterFilter(CustomFieldFilterSet):
to_field_name='slug',
label='Cluster type (slug)',
)
tenant = django_filters.ModelMultipleChoiceFilter(
queryset=Tenant.objects.all(),
label="Tenant (ID)"
)
site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(),
label='Site (ID)',

View File

@ -86,7 +86,7 @@ class ClusterForm(BootstrapMixin, CustomFieldForm):
class Meta:
model = Cluster
fields = [
'name', 'type', 'group', 'site', 'comments', 'tags',
'name', 'type', 'group', 'tenant', 'site', 'comments', 'tags',
]
widgets = {
'type': APISelect(
@ -128,6 +128,15 @@ class ClusterCSVForm(forms.ModelForm):
'invalid_choice': 'Invalid site name.',
}
)
tenant = forms.ModelChoiceField(
queryset=Tenant.objects.all(),
to_field_name='name',
required=False,
help_text='Name of assigned tenant',
error_messages={
'invalid_choice': 'Invalid tenant name'
}
)
class Meta:
model = Cluster
@ -153,6 +162,10 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
api_url="/api/virtualization/cluster-groups/"
)
)
tenant = forms.ModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
site = forms.ModelChoiceField(
queryset=Site.objects.all(),
required=False,
@ -166,7 +179,7 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
class Meta:
nullable_fields = [
'group', 'site', 'comments',
'group', 'site', 'comments', 'tenant',
]
@ -193,6 +206,15 @@ class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
null_option=True,
)
)
tenant = FilterChoiceField(
queryset=Tenant.objects.all(),
null_label='-- None --',
required=False,
widget=APISelectMultiple(
api_url="/api/tenancy/tenants/",
null_option=True,
)
)
site = FilterChoiceField(
queryset=Site.objects.all(),
to_field_name='slug',

View File

@ -0,0 +1,18 @@
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('tenancy', '0001_initial'),
('virtualization', '0009_custom_tag_models'),
]
operations = [
migrations.AddField(
model_name='cluster',
name='tenant',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='clusters', to='tenancy.Tenant'),
),
]

View File

@ -103,6 +103,13 @@ class Cluster(ChangeLoggedModel, CustomFieldModel):
blank=True,
null=True
)
tenant = models.ForeignKey(
to='tenancy.Tenant',
on_delete=models.PROTECT,
related_name='tenants',
blank=True,
null=True
)
site = models.ForeignKey(
to='dcim.Site',
on_delete=models.PROTECT,
@ -150,6 +157,7 @@ class Cluster(ChangeLoggedModel, CustomFieldModel):
self.type.name,
self.group.name if self.group else None,
self.site.name if self.site else None,
self.tenant.name if self.tenant else None,
self.comments,
)

View File

@ -84,13 +84,14 @@ class ClusterGroupTable(BaseTable):
class ClusterTable(BaseTable):
pk = ToggleColumn()
name = tables.LinkColumn()
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
device_count = tables.Column(accessor=Accessor('devices.count'), orderable=False, verbose_name='Devices')
vm_count = tables.Column(accessor=Accessor('virtual_machines.count'), orderable=False, verbose_name='VMs')
class Meta(BaseTable.Meta):
model = Cluster
fields = ('pk', 'name', 'type', 'group', 'site', 'device_count', 'vm_count')
fields = ('pk', 'name', 'type', 'group', 'tenant', 'site', 'device_count', 'vm_count')
#

View File

@ -96,7 +96,7 @@ class ClusterGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class ClusterListView(PermissionRequiredMixin, ObjectListView):
permission_required = 'virtualization.view_cluster'
queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
queryset = Cluster.objects.prefetch_related('type', 'group', 'site', 'tenant')
table = tables.ClusterTable
filter = filters.ClusterFilter
filter_form = forms.ClusterFilterForm