mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-25 01:48:38 -06:00
Applied tenancy to sites, racks, and devices
This commit is contained in:
parent
1939db1574
commit
82a98f0e8f
@ -6,6 +6,7 @@ from dcim.models import (
|
|||||||
DeviceRole, Interface, InterfaceConnection, InterfaceTemplate, Manufacturer, Platform, PowerOutlet,
|
DeviceRole, Interface, InterfaceConnection, InterfaceTemplate, Manufacturer, Platform, PowerOutlet,
|
||||||
PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RACK_FACE_FRONT, RACK_FACE_REAR, Site,
|
PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RACK_FACE_FRONT, RACK_FACE_REAR, Site,
|
||||||
)
|
)
|
||||||
|
from tenancy.api.serializers import TenantNestedSerializer
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -13,10 +14,11 @@ from dcim.models import (
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SiteSerializer(serializers.ModelSerializer):
|
class SiteSerializer(serializers.ModelSerializer):
|
||||||
|
tenant = TenantNestedSerializer()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Site
|
model = Site
|
||||||
fields = ['id', 'name', 'slug', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments',
|
fields = ['id', 'name', 'slug', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments',
|
||||||
'count_prefixes', 'count_vlans', 'count_racks', 'count_devices', 'count_circuits']
|
'count_prefixes', 'count_vlans', 'count_racks', 'count_devices', 'count_circuits']
|
||||||
|
|
||||||
|
|
||||||
@ -52,10 +54,11 @@ class RackGroupNestedSerializer(RackGroupSerializer):
|
|||||||
class RackSerializer(serializers.ModelSerializer):
|
class RackSerializer(serializers.ModelSerializer):
|
||||||
site = SiteNestedSerializer()
|
site = SiteNestedSerializer()
|
||||||
group = RackGroupNestedSerializer()
|
group = RackGroupNestedSerializer()
|
||||||
|
tenant = TenantNestedSerializer()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'u_height', 'comments']
|
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'u_height', 'comments']
|
||||||
|
|
||||||
|
|
||||||
class RackNestedSerializer(RackSerializer):
|
class RackNestedSerializer(RackSerializer):
|
||||||
@ -69,8 +72,8 @@ class RackDetailSerializer(RackSerializer):
|
|||||||
rear_units = serializers.SerializerMethodField()
|
rear_units = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta(RackSerializer.Meta):
|
class Meta(RackSerializer.Meta):
|
||||||
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'u_height', 'comments', 'front_units',
|
fields = ['id', 'name', 'facility_id', 'display_name', 'site', 'group', 'tenant', 'u_height', 'comments',
|
||||||
'rear_units']
|
'front_units', 'rear_units']
|
||||||
|
|
||||||
def get_front_units(self, obj):
|
def get_front_units(self, obj):
|
||||||
units = obj.get_rack_units(face=RACK_FACE_FRONT)
|
units = obj.get_rack_units(face=RACK_FACE_FRONT)
|
||||||
@ -218,6 +221,7 @@ class DeviceIPAddressNestedSerializer(serializers.ModelSerializer):
|
|||||||
class DeviceSerializer(serializers.ModelSerializer):
|
class DeviceSerializer(serializers.ModelSerializer):
|
||||||
device_type = DeviceTypeNestedSerializer()
|
device_type = DeviceTypeNestedSerializer()
|
||||||
device_role = DeviceRoleNestedSerializer()
|
device_role = DeviceRoleNestedSerializer()
|
||||||
|
tenant = TenantNestedSerializer()
|
||||||
platform = PlatformNestedSerializer()
|
platform = PlatformNestedSerializer()
|
||||||
rack = RackNestedSerializer()
|
rack = RackNestedSerializer()
|
||||||
primary_ip = DeviceIPAddressNestedSerializer()
|
primary_ip = DeviceIPAddressNestedSerializer()
|
||||||
@ -227,8 +231,8 @@ class DeviceSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
fields = ['id', 'name', 'display_name', 'device_type', 'device_role', 'platform', 'serial', 'rack', 'position',
|
fields = ['id', 'name', 'display_name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'rack',
|
||||||
'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6', 'comments']
|
'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4', 'primary_ip6', 'comments']
|
||||||
|
|
||||||
def get_parent_device(self, obj):
|
def get_parent_device(self, obj):
|
||||||
try:
|
try:
|
||||||
|
@ -4,6 +4,7 @@ from django import forms
|
|||||||
from django.db.models import Count, Q
|
from django.db.models import Count, Q
|
||||||
|
|
||||||
from ipam.models import IPAddress
|
from ipam.models import IPAddress
|
||||||
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
APISelect, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, ExpandableNameField,
|
APISelect, BootstrapMixin, BulkImportForm, CommentField, CSVDataField, ExpandableNameField,
|
||||||
FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
|
FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
|
||||||
@ -48,7 +49,7 @@ class SiteForm(forms.ModelForm, BootstrapMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Site
|
model = Site
|
||||||
fields = ['name', 'slug', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments']
|
fields = ['name', 'slug', 'tenant', 'facility', 'asn', 'physical_address', 'shipping_address', 'comments']
|
||||||
widgets = {
|
widgets = {
|
||||||
'physical_address': SmallTextarea(attrs={'rows': 3}),
|
'physical_address': SmallTextarea(attrs={'rows': 3}),
|
||||||
'shipping_address': SmallTextarea(attrs={'rows': 3}),
|
'shipping_address': SmallTextarea(attrs={'rows': 3}),
|
||||||
@ -63,10 +64,12 @@ class SiteForm(forms.ModelForm, BootstrapMixin):
|
|||||||
|
|
||||||
|
|
||||||
class SiteFromCSVForm(forms.ModelForm):
|
class SiteFromCSVForm(forms.ModelForm):
|
||||||
|
tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
||||||
|
error_messages={'invalid_choice': 'Tenant not found.'})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Site
|
model = Site
|
||||||
fields = ['name', 'slug', 'facility', 'asn']
|
fields = ['name', 'slug', 'tenant', 'facility', 'asn']
|
||||||
|
|
||||||
|
|
||||||
class SiteImportForm(BulkImportForm, BootstrapMixin):
|
class SiteImportForm(BulkImportForm, BootstrapMixin):
|
||||||
@ -107,7 +110,7 @@ class RackForm(forms.ModelForm, BootstrapMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = ['site', 'group', 'name', 'facility_id', 'u_height', 'comments']
|
fields = ['site', 'group', 'name', 'facility_id', 'tenant', 'u_height', 'comments']
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'site': "The site at which the rack exists",
|
'site': "The site at which the rack exists",
|
||||||
'name': "Organizational rack name",
|
'name': "Organizational rack name",
|
||||||
@ -135,10 +138,12 @@ class RackFromCSVForm(forms.ModelForm):
|
|||||||
site = forms.ModelChoiceField(queryset=Site.objects.all(), to_field_name='name',
|
site = forms.ModelChoiceField(queryset=Site.objects.all(), to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Site not found.'})
|
error_messages={'invalid_choice': 'Site not found.'})
|
||||||
group_name = forms.CharField(required=False)
|
group_name = forms.CharField(required=False)
|
||||||
|
tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
||||||
|
error_messages={'invalid_choice': 'Tenant not found.'})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = ['site', 'group_name', 'name', 'facility_id', 'u_height']
|
fields = ['site', 'group_name', 'name', 'facility_id', 'tenant', 'u_height']
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
||||||
@ -161,6 +166,7 @@ class RackBulkEditForm(forms.Form, BootstrapMixin):
|
|||||||
pk = forms.ModelMultipleChoiceField(queryset=Rack.objects.all(), widget=forms.MultipleHiddenInput)
|
pk = forms.ModelMultipleChoiceField(queryset=Rack.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False)
|
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False)
|
||||||
group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False)
|
group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False)
|
||||||
|
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
||||||
u_height = forms.IntegerField(required=False, label='Height (U)')
|
u_height = forms.IntegerField(required=False, label='Height (U)')
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
@ -203,8 +209,8 @@ class DeviceTypeForm(forms.ModelForm, BootstrapMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = ['manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server', 'is_pdu',
|
fields = ['manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'is_console_server',
|
||||||
'is_network_device', 'subdevice_role']
|
'is_pdu', 'is_network_device', 'subdevice_role']
|
||||||
|
|
||||||
|
|
||||||
class DeviceTypeBulkEditForm(forms.Form, BootstrapMixin):
|
class DeviceTypeBulkEditForm(forms.Form, BootstrapMixin):
|
||||||
@ -324,7 +330,7 @@ class DeviceForm(forms.ModelForm, BootstrapMixin):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
fields = ['name', 'device_role', 'device_type', 'serial', 'site', 'rack', 'position', 'face', 'status',
|
fields = ['name', 'device_role', 'tenant', 'device_type', 'serial', 'site', 'rack', 'position', 'face', 'status',
|
||||||
'platform', 'primary_ip4', 'primary_ip6', 'comments']
|
'platform', 'primary_ip4', 'primary_ip6', 'comments']
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'device_role': "The function this device serves",
|
'device_role': "The function this device serves",
|
||||||
@ -410,6 +416,8 @@ class DeviceForm(forms.ModelForm, BootstrapMixin):
|
|||||||
class BaseDeviceFromCSVForm(forms.ModelForm):
|
class BaseDeviceFromCSVForm(forms.ModelForm):
|
||||||
device_role = forms.ModelChoiceField(queryset=DeviceRole.objects.all(), to_field_name='name',
|
device_role = forms.ModelChoiceField(queryset=DeviceRole.objects.all(), to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Invalid device role.'})
|
error_messages={'invalid_choice': 'Invalid device role.'})
|
||||||
|
tenant = forms.ModelChoiceField(Tenant.objects.all(), to_field_name='name', required=False,
|
||||||
|
error_messages={'invalid_choice': 'Tenant not found.'})
|
||||||
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), to_field_name='name',
|
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Invalid manufacturer.'})
|
error_messages={'invalid_choice': 'Invalid manufacturer.'})
|
||||||
model_name = forms.CharField()
|
model_name = forms.CharField()
|
||||||
@ -441,8 +449,8 @@ class DeviceFromCSVForm(BaseDeviceFromCSVForm):
|
|||||||
face = forms.CharField(required=False)
|
face = forms.CharField(required=False)
|
||||||
|
|
||||||
class Meta(BaseDeviceFromCSVForm.Meta):
|
class Meta(BaseDeviceFromCSVForm.Meta):
|
||||||
fields = ['name', 'device_role', 'manufacturer', 'model_name', 'platform', 'serial', 'site', 'rack_name',
|
fields = ['name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'site',
|
||||||
'position', 'face']
|
'rack_name', 'position', 'face']
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
||||||
@ -477,7 +485,7 @@ class ChildDeviceFromCSVForm(BaseDeviceFromCSVForm):
|
|||||||
device_bay_name = forms.CharField(required=False)
|
device_bay_name = forms.CharField(required=False)
|
||||||
|
|
||||||
class Meta(BaseDeviceFromCSVForm.Meta):
|
class Meta(BaseDeviceFromCSVForm.Meta):
|
||||||
fields = ['name', 'device_role', 'manufacturer', 'model_name', 'platform', 'serial', 'parent',
|
fields = ['name', 'device_role', 'tenant', 'manufacturer', 'model_name', 'platform', 'serial', 'parent',
|
||||||
'device_bay_name']
|
'device_bay_name']
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
@ -512,6 +520,7 @@ class DeviceBulkEditForm(forms.Form, BootstrapMixin):
|
|||||||
pk = forms.ModelMultipleChoiceField(queryset=Device.objects.all(), widget=forms.MultipleHiddenInput)
|
pk = forms.ModelMultipleChoiceField(queryset=Device.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
device_type = forms.ModelChoiceField(queryset=DeviceType.objects.all(), required=False, label='Type')
|
device_type = forms.ModelChoiceField(queryset=DeviceType.objects.all(), required=False, label='Type')
|
||||||
device_role = forms.ModelChoiceField(queryset=DeviceRole.objects.all(), required=False, label='Role')
|
device_role = forms.ModelChoiceField(queryset=DeviceRole.objects.all(), required=False, label='Role')
|
||||||
|
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False, label='Tenant')
|
||||||
platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False, label='Platform')
|
platform = forms.ModelChoiceField(queryset=Platform.objects.all(), required=False, label='Platform')
|
||||||
platform_delete = forms.BooleanField(required=False, label='Set platform to "none"')
|
platform_delete = forms.BooleanField(required=False, label='Set platform to "none"')
|
||||||
status = forms.ChoiceField(choices=FORM_STATUS_CHOICES, required=False, initial='', label='Status')
|
status = forms.ChoiceField(choices=FORM_STATUS_CHOICES, required=False, initial='', label='Status')
|
||||||
|
32
netbox/dcim/migrations/0012_site_rack_device_add_tenant.py
Normal file
32
netbox/dcim/migrations/0012_site_rack_device_add_tenant.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.8 on 2016-07-26 20:06
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tenancy', '0001_initial'),
|
||||||
|
('dcim', '0011_devicetype_part_number'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='tenant',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='tenancy.Tenant'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rack',
|
||||||
|
name='tenant',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='tenancy.Tenant'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='site',
|
||||||
|
name='tenant',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='tenancy.Tenant'),
|
||||||
|
),
|
||||||
|
]
|
@ -8,6 +8,7 @@ from django.db import models
|
|||||||
from django.db.models import Count, Q, ObjectDoesNotExist
|
from django.db.models import Count, Q, ObjectDoesNotExist
|
||||||
|
|
||||||
from extras.rpc import RPC_CLIENTS
|
from extras.rpc import RPC_CLIENTS
|
||||||
|
from tenancy.models import Tenant
|
||||||
from utilities.fields import NullableCharField
|
from utilities.fields import NullableCharField
|
||||||
from utilities.managers import NaturalOrderByManager
|
from utilities.managers import NaturalOrderByManager
|
||||||
from utilities.models import CreatedUpdatedModel
|
from utilities.models import CreatedUpdatedModel
|
||||||
@ -152,6 +153,7 @@ class Site(CreatedUpdatedModel):
|
|||||||
"""
|
"""
|
||||||
name = models.CharField(max_length=50, unique=True)
|
name = models.CharField(max_length=50, unique=True)
|
||||||
slug = models.SlugField(unique=True)
|
slug = models.SlugField(unique=True)
|
||||||
|
tenant = models.ForeignKey(Tenant, blank=True, null=True, on_delete=models.PROTECT)
|
||||||
facility = models.CharField(max_length=50, blank=True)
|
facility = models.CharField(max_length=50, blank=True)
|
||||||
asn = ASNField(blank=True, null=True, verbose_name='ASN')
|
asn = ASNField(blank=True, null=True, verbose_name='ASN')
|
||||||
physical_address = models.CharField(max_length=200, blank=True)
|
physical_address = models.CharField(max_length=200, blank=True)
|
||||||
@ -173,6 +175,7 @@ class Site(CreatedUpdatedModel):
|
|||||||
return ','.join([
|
return ','.join([
|
||||||
self.name,
|
self.name,
|
||||||
self.slug,
|
self.slug,
|
||||||
|
self.tenant.name if self.tenant else '',
|
||||||
self.facility,
|
self.facility,
|
||||||
str(self.asn),
|
str(self.asn),
|
||||||
])
|
])
|
||||||
@ -237,6 +240,7 @@ class Rack(CreatedUpdatedModel):
|
|||||||
facility_id = NullableCharField(max_length=30, blank=True, null=True, verbose_name='Facility ID')
|
facility_id = NullableCharField(max_length=30, blank=True, null=True, verbose_name='Facility ID')
|
||||||
site = models.ForeignKey('Site', related_name='racks', on_delete=models.PROTECT)
|
site = models.ForeignKey('Site', related_name='racks', on_delete=models.PROTECT)
|
||||||
group = models.ForeignKey('RackGroup', related_name='racks', blank=True, null=True, on_delete=models.SET_NULL)
|
group = models.ForeignKey('RackGroup', related_name='racks', blank=True, null=True, on_delete=models.SET_NULL)
|
||||||
|
tenant = models.ForeignKey(Tenant, blank=True, null=True, on_delete=models.PROTECT)
|
||||||
u_height = models.PositiveSmallIntegerField(default=42, verbose_name='Height (U)')
|
u_height = models.PositiveSmallIntegerField(default=42, verbose_name='Height (U)')
|
||||||
comments = models.TextField(blank=True)
|
comments = models.TextField(blank=True)
|
||||||
|
|
||||||
@ -272,6 +276,7 @@ class Rack(CreatedUpdatedModel):
|
|||||||
self.group.name if self.group else '',
|
self.group.name if self.group else '',
|
||||||
self.name,
|
self.name,
|
||||||
self.facility_id or '',
|
self.facility_id or '',
|
||||||
|
self.tenant.name if self.tenant else '',
|
||||||
str(self.u_height),
|
str(self.u_height),
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -631,6 +636,7 @@ class Device(CreatedUpdatedModel):
|
|||||||
"""
|
"""
|
||||||
device_type = models.ForeignKey('DeviceType', related_name='instances', on_delete=models.PROTECT)
|
device_type = models.ForeignKey('DeviceType', related_name='instances', on_delete=models.PROTECT)
|
||||||
device_role = models.ForeignKey('DeviceRole', related_name='devices', on_delete=models.PROTECT)
|
device_role = models.ForeignKey('DeviceRole', related_name='devices', on_delete=models.PROTECT)
|
||||||
|
tenant = models.ForeignKey(Tenant, blank=True, null=True, on_delete=models.PROTECT)
|
||||||
platform = models.ForeignKey('Platform', related_name='devices', blank=True, null=True, on_delete=models.SET_NULL)
|
platform = models.ForeignKey('Platform', related_name='devices', blank=True, null=True, on_delete=models.SET_NULL)
|
||||||
name = NullableCharField(max_length=50, blank=True, null=True, unique=True)
|
name = NullableCharField(max_length=50, blank=True, null=True, unique=True)
|
||||||
serial = models.CharField(max_length=50, blank=True, verbose_name='Serial number')
|
serial = models.CharField(max_length=50, blank=True, verbose_name='Serial number')
|
||||||
@ -724,6 +730,7 @@ class Device(CreatedUpdatedModel):
|
|||||||
return ','.join([
|
return ','.join([
|
||||||
self.name or '',
|
self.name or '',
|
||||||
self.device_role.name,
|
self.device_role.name,
|
||||||
|
self.tenant.name if self.tenant else '',
|
||||||
self.device_type.manufacturer.name,
|
self.device_type.manufacturer.name,
|
||||||
self.device_type.model,
|
self.device_type.model,
|
||||||
self.platform.name if self.platform else '',
|
self.platform.name if self.platform else '',
|
||||||
|
@ -61,6 +61,7 @@ UTILIZATION_GRAPH = """
|
|||||||
class SiteTable(BaseTable):
|
class SiteTable(BaseTable):
|
||||||
name = tables.LinkColumn('dcim:site', args=[Accessor('slug')], verbose_name='Name')
|
name = tables.LinkColumn('dcim:site', args=[Accessor('slug')], verbose_name='Name')
|
||||||
facility = tables.Column(verbose_name='Facility')
|
facility = tables.Column(verbose_name='Facility')
|
||||||
|
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
|
||||||
asn = tables.Column(verbose_name='ASN')
|
asn = tables.Column(verbose_name='ASN')
|
||||||
rack_count = tables.Column(accessor=Accessor('count_racks'), orderable=False, verbose_name='Racks')
|
rack_count = tables.Column(accessor=Accessor('count_racks'), orderable=False, verbose_name='Racks')
|
||||||
device_count = tables.Column(accessor=Accessor('count_devices'), orderable=False, verbose_name='Devices')
|
device_count = tables.Column(accessor=Accessor('count_devices'), orderable=False, verbose_name='Devices')
|
||||||
@ -70,7 +71,7 @@ class SiteTable(BaseTable):
|
|||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = Site
|
model = Site
|
||||||
fields = ('name', 'facility', 'asn', 'rack_count', 'device_count', 'prefix_count', 'vlan_count',
|
fields = ('name', 'facility', 'tenant', 'asn', 'rack_count', 'device_count', 'prefix_count', 'vlan_count',
|
||||||
'circuit_count')
|
'circuit_count')
|
||||||
|
|
||||||
|
|
||||||
@ -101,14 +102,16 @@ class RackTable(BaseTable):
|
|||||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
||||||
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
|
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
|
||||||
facility_id = tables.Column(verbose_name='Facility ID')
|
facility_id = tables.Column(verbose_name='Facility ID')
|
||||||
u_height = tables.Column(verbose_name='Height (U)')
|
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
|
||||||
|
u_height = tables.TemplateColumn("{{ record.u_height }}U", verbose_name='Height')
|
||||||
devices = tables.Column(accessor=Accessor('device_count'), verbose_name='Devices')
|
devices = tables.Column(accessor=Accessor('device_count'), verbose_name='Devices')
|
||||||
u_consumed = tables.Column(accessor=Accessor('u_consumed'), verbose_name='Used (U)')
|
u_consumed = tables.TemplateColumn("{{ record.u_consumed|default:'0' }}U", verbose_name='Used')
|
||||||
utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization')
|
utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization')
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = ('pk', 'name', 'site', 'group', 'facility_id', 'u_height', 'devices', 'u_consumed', 'utilization')
|
fields = ('pk', 'name', 'site', 'group', 'facility_id', 'tenant', 'u_height', 'devices', 'u_consumed',
|
||||||
|
'utilization')
|
||||||
|
|
||||||
|
|
||||||
class RackImportTable(BaseTable):
|
class RackImportTable(BaseTable):
|
||||||
@ -116,11 +119,12 @@ class RackImportTable(BaseTable):
|
|||||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
||||||
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
|
group = tables.Column(accessor=Accessor('group.name'), verbose_name='Group')
|
||||||
facility_id = tables.Column(verbose_name='Facility ID')
|
facility_id = tables.Column(verbose_name='Facility ID')
|
||||||
|
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
|
||||||
u_height = tables.Column(verbose_name='Height (U)')
|
u_height = tables.Column(verbose_name='Height (U)')
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = ('site', 'group', 'name', 'facility_id', 'u_height')
|
fields = ('site', 'group', 'name', 'facility_id', 'tenant', 'u_height')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -259,6 +263,7 @@ class DeviceTable(BaseTable):
|
|||||||
pk = ToggleColumn()
|
pk = ToggleColumn()
|
||||||
status = tables.TemplateColumn(template_code=STATUS_ICON, verbose_name='')
|
status = tables.TemplateColumn(template_code=STATUS_ICON, verbose_name='')
|
||||||
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name')
|
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name')
|
||||||
|
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
|
||||||
site = tables.Column(accessor=Accessor('rack.site'), verbose_name='Site')
|
site = tables.Column(accessor=Accessor('rack.site'), verbose_name='Site')
|
||||||
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')], verbose_name='Rack')
|
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')], verbose_name='Rack')
|
||||||
device_role = tables.Column(verbose_name='Role')
|
device_role = tables.Column(verbose_name='Role')
|
||||||
@ -268,11 +273,12 @@ class DeviceTable(BaseTable):
|
|||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = Device
|
model = Device
|
||||||
fields = ('pk', 'name', 'status', 'site', 'rack', 'device_role', 'device_type', 'primary_ip')
|
fields = ('pk', 'name', 'status', 'tenant', 'site', 'rack', 'device_role', 'device_type', 'primary_ip')
|
||||||
|
|
||||||
|
|
||||||
class DeviceImportTable(BaseTable):
|
class DeviceImportTable(BaseTable):
|
||||||
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name')
|
name = tables.TemplateColumn(template_code=DEVICE_LINK, verbose_name='Name')
|
||||||
|
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')], verbose_name='Tenant')
|
||||||
site = tables.Column(accessor=Accessor('rack.site'), verbose_name='Site')
|
site = tables.Column(accessor=Accessor('rack.site'), verbose_name='Site')
|
||||||
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')], verbose_name='Rack')
|
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')], verbose_name='Rack')
|
||||||
position = tables.Column(verbose_name='Position')
|
position = tables.Column(verbose_name='Position')
|
||||||
@ -281,7 +287,7 @@ class DeviceImportTable(BaseTable):
|
|||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = Device
|
model = Device
|
||||||
fields = ('name', 'site', 'rack', 'position', 'device_role', 'device_type')
|
fields = ('name', 'tenant', 'site', 'rack', 'position', 'device_role', 'device_type')
|
||||||
empty_text = False
|
empty_text = False
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ def expand_pattern(string):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SiteListView(ObjectListView):
|
class SiteListView(ObjectListView):
|
||||||
queryset = Site.objects.all()
|
queryset = Site.objects.select_related('tenant')
|
||||||
filter = filters.SiteFilter
|
filter = filters.SiteFilter
|
||||||
table = tables.SiteTable
|
table = tables.SiteTable
|
||||||
template_name = 'dcim/site_list.html'
|
template_name = 'dcim/site_list.html'
|
||||||
|
@ -14,6 +14,16 @@
|
|||||||
<strong>Device</strong>
|
<strong>Device</strong>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-hover panel-body">
|
<table class="table table-hover panel-body">
|
||||||
|
<tr>
|
||||||
|
<td>Tenant</td>
|
||||||
|
<td>
|
||||||
|
{% if device.tenant %}
|
||||||
|
<a href="{{ device.tenant.get_absolute_url }}">{{ device.tenant }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">None</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Site</td>
|
<td>Site</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<td><a href="{% url 'dcim:device' pk=device.pk %}">{{ device }}</a></td>
|
<td><a href="{% url 'dcim:device' pk=device.pk %}">{{ device }}</a></td>
|
||||||
<td>{{ device.device_type }}</td>
|
<td>{{ device.device_type }}</td>
|
||||||
<td>{{ device.device_role }}</td>
|
<td>{{ device.device_role }}</td>
|
||||||
|
<td>{{ device.tenant }}</td>
|
||||||
<td>{{ device.serial }}</td>
|
<td>{{ device.serial }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% render_field form.name %}
|
{% render_field form.name %}
|
||||||
{% render_field form.device_role %}
|
{% render_field form.device_role %}
|
||||||
|
{% render_field form.tenant %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
@ -36,6 +36,11 @@
|
|||||||
<td>Functional role of device</td>
|
<td>Functional role of device</td>
|
||||||
<td>ToR Switch</td>
|
<td>ToR Switch</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tenant</td>
|
||||||
|
<td>Name of tenant (optional)</td>
|
||||||
|
<td>Pied Piper</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Device manufacturer</td>
|
<td>Device manufacturer</td>
|
||||||
<td>Hardware manufacturer</td>
|
<td>Hardware manufacturer</td>
|
||||||
@ -79,7 +84,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>rack101_sw1,ToR Switch,Juniper,EX4300-48T,Juniper Junos,CAB00577291,Ashburn-VA,R101,21,Rear</pre>
|
<pre>rack101_sw1,ToR Switch,Pied Piper,Juniper,EX4300-48T,Juniper Junos,CAB00577291,Ashburn-VA,R101,21,Rear</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -86,6 +86,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tenant</td>
|
||||||
|
<td>
|
||||||
|
{% if rack.tenant %}
|
||||||
|
<a href="{{ rack.tenant.get_absolute_url }}">{{ rack.tenant }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">None</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Height</td>
|
<td>Height</td>
|
||||||
<td>{{ rack.u_height }}U</td>
|
<td>{{ rack.u_height }}U</td>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<td><a href="{% url 'dcim:rack' pk=rack.pk %}">{{ rack }}</a></td>
|
<td><a href="{% url 'dcim:rack' pk=rack.pk %}">{{ rack }}</a></td>
|
||||||
<td>{{ rack.facility_id }}</td>
|
<td>{{ rack.facility_id }}</td>
|
||||||
<td>{{ rack.site }}</td>
|
<td>{{ rack.site }}</td>
|
||||||
|
<td>{{ rack.tenant }}</td>
|
||||||
<td>{{ rack.u_height }}</td>
|
<td>{{ rack.u_height }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
{% render_field form.group %}
|
{% render_field form.group %}
|
||||||
{% render_field form.name %}
|
{% render_field form.name %}
|
||||||
{% render_field form.facility_id %}
|
{% render_field form.facility_id %}
|
||||||
|
{% render_field form.tenant %}
|
||||||
{% render_field form.u_height %}
|
{% render_field form.u_height %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -48,6 +48,11 @@
|
|||||||
<td>Rack ID assigned by the facility (optional)</td>
|
<td>Rack ID assigned by the facility (optional)</td>
|
||||||
<td>J12.100</td>
|
<td>J12.100</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tenant</td>
|
||||||
|
<td>Name of tenant (optional)</td>
|
||||||
|
<td>Pied Piper</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Height</td>
|
<td>Height</td>
|
||||||
<td>Height in rack units</td>
|
<td>Height in rack units</td>
|
||||||
@ -56,7 +61,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>DC-4,Cage 1400,R101,J12.100,42</pre>
|
<pre>DC-4,Cage 1400,R101,J12.100,Pied Piper,42</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -52,6 +52,16 @@
|
|||||||
<strong>Site</strong>
|
<strong>Site</strong>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-hover panel-body">
|
<table class="table table-hover panel-body">
|
||||||
|
<tr>
|
||||||
|
<td>Tenant</td>
|
||||||
|
<td>
|
||||||
|
{% if site.tenant %}
|
||||||
|
<a href="{{ site.tenant.get_absolute_url }}">{{ site.tenant }}</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="text-muted">None</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Facility</td>
|
<td>Facility</td>
|
||||||
<td>{{ site.facility }}</td>
|
<td>{{ site.facility }}</td>
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% render_field form.name %}
|
{% render_field form.name %}
|
||||||
{% render_field form.slug %}
|
{% render_field form.slug %}
|
||||||
|
{% render_field form.tenant %}
|
||||||
{% render_field form.facility %}
|
{% render_field form.facility %}
|
||||||
{% render_field form.asn %}
|
{% render_field form.asn %}
|
||||||
{% render_field form.physical_address %}
|
{% render_field form.physical_address %}
|
||||||
|
@ -38,6 +38,11 @@
|
|||||||
<td>URL-friendly name</td>
|
<td>URL-friendly name</td>
|
||||||
<td>ash4-south</td>
|
<td>ash4-south</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tenant</td>
|
||||||
|
<td>Name of tenant (optional)</td>
|
||||||
|
<td>Pied Piper</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Facility</td>
|
<td>Facility</td>
|
||||||
<td>Name of the hosting facility (optional)</td>
|
<td>Name of the hosting facility (optional)</td>
|
||||||
@ -51,7 +56,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>ASH-4 South,ash4-south,Equinix DC6,65000</pre>
|
<pre>ASH-4 South,ash4-south,Pied Piper,Equinix DC6,65000</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Loading…
Reference in New Issue
Block a user