Skip to content

Commit

Permalink
Add Tenancy to Rack Reservations; Fixes #1592 (#1672)
Browse files Browse the repository at this point in the history
* fixed prefix header to represent new serial "vlan_vid"

* shows option in creation now

* fixed visibility on rack page

* cleanup

* Added view to Tenant page

* Moved migration for update from #1666 and fixed tenant enumeration in FilterForm

* Fixed conflict #1

* Fixed filters from merge and made migration merge

* added tenant to api

* Fixed migrations problem

* Added Tenant to bulkedit option
  • Loading branch information
dirtycajunrice authored and jeremystretch committed Nov 15, 2017
1 parent db0ef95 commit fbd39da
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 11 deletions.
2 changes: 1 addition & 1 deletion netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ class RackReservationSerializer(serializers.ModelSerializer):

class Meta:
model = RackReservation
fields = ['id', 'rack', 'units', 'created', 'user', 'description']
fields = ['id', 'rack', 'units', 'created', 'user', 'tenant', 'description']


class WritableRackReservationSerializer(ValidatedModelSerializer):
Expand Down
10 changes: 10 additions & 0 deletions netbox/dcim/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,16 @@ class RackReservationFilter(django_filters.FilterSet):
to_field_name='slug',
label='Group',
)
tenant_id = django_filters.ModelMultipleChoiceFilter(
queryset=Tenant.objects.all(),
label='Tenant (ID)',
)
tenant = django_filters.ModelMultipleChoiceFilter(
name='tenant__slug',
queryset=Tenant.objects.all(),
to_field_name='slug',
label='Tenant (slug)',
)
user_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(),
label='User (ID)',
Expand Down
14 changes: 10 additions & 4 deletions netbox/dcim/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,13 +379,13 @@ class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
# Rack reservations
#

class RackReservationForm(BootstrapMixin, forms.ModelForm):
class RackReservationForm(BootstrapMixin, TenancyForm, forms.ModelForm):
units = SimpleArrayField(forms.IntegerField(), widget=ArrayFieldSelectMultiple(attrs={'size': 10}))
user = forms.ModelChoiceField(queryset=User.objects.order_by('username'))

class Meta:
model = RackReservation
fields = ['units', 'user', 'description']
fields = ['units', 'user', 'tenant_group', 'tenant', 'description']

def __init__(self, *args, **kwargs):

Expand Down Expand Up @@ -415,11 +415,17 @@ class RackReservationFilterForm(BootstrapMixin, forms.Form):
label='Rack group',
null_option=(0, 'None')
)
tenant = FilterChoiceField(
queryset=Tenant.objects.annotate(filter_count=Count('rackreservations')),
to_field_name='slug',
null_option=(0, 'None')
)


class RackReservationBulkEditForm(BootstrapMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=RackReservation.objects.all(), widget=forms.MultipleHiddenInput)
user = forms.ModelChoiceField(queryset=User.objects.order_by('username'), required=False)
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
description = forms.CharField(max_length=100, required=False)

class Meta:
Expand Down Expand Up @@ -805,10 +811,10 @@ def __init__(self, *args, **kwargs):
pk = self.instance.pk if self.instance.pk else None
try:
if self.is_bound and self.data.get('rack') and str(self.data.get('face')):
position_choices = Rack.objects.get(pk=self.data['rack'])\
position_choices = Rack.objects.get(pk=self.data['rack']) \
.get_rack_units(face=self.data.get('face'), exclude=pk)
elif self.initial.get('rack') and str(self.initial.get('face')):
position_choices = Rack.objects.get(pk=self.initial['rack'])\
position_choices = Rack.objects.get(pk=self.initial['rack']) \
.get_rack_units(face=self.initial.get('face'), exclude=pk)
else:
position_choices = []
Expand Down
22 changes: 22 additions & 0 deletions netbox/dcim/migrations/0050_rackreservation_tenant.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-10-30 20:43
from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('tenancy', '0003_unicode_literals'),
('dcim', '0049_rackreservation_change_user'),
]

operations = [
migrations.AddField(
model_name='rackreservation',
name='tenant',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='rackreservations', to='tenancy.Tenant'),
),
]
1 change: 1 addition & 0 deletions netbox/dcim/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ class RackReservation(models.Model):
rack = models.ForeignKey('Rack', related_name='reservations', on_delete=models.CASCADE)
units = ArrayField(models.PositiveSmallIntegerField())
created = models.DateTimeField(auto_now_add=True)
tenant = models.ForeignKey(Tenant, blank=True, null=True, related_name='rackreservations', on_delete=models.PROTECT)
user = models.ForeignKey(User, on_delete=models.PROTECT)
description = models.CharField(max_length=100)

Expand Down
3 changes: 2 additions & 1 deletion netbox/dcim/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class Meta(BaseTable.Meta):

class RackReservationTable(BaseTable):
pk = ToggleColumn()
tenant = tables.LinkColumn('tenancy:tenant', args=[Accessor('tenant.slug')])
rack = tables.LinkColumn('dcim:rack', args=[Accessor('rack.pk')])
unit_list = tables.Column(orderable=False, verbose_name='Units')
actions = tables.TemplateColumn(
Expand All @@ -252,7 +253,7 @@ class RackReservationTable(BaseTable):

class Meta(BaseTable.Meta):
model = RackReservation
fields = ('pk', 'rack', 'unit_list', 'user', 'created', 'description', 'actions')
fields = ('pk', 'rack', 'unit_list', 'user', 'created', 'tenant', 'description', 'actions')


#
Expand Down
8 changes: 4 additions & 4 deletions netbox/dcim/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def get(self, request, pk):

rack = get_object_or_404(Rack.objects.select_related('site__region', 'tenant__group', 'group', 'role'), pk=pk)

nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True)\
nonracked_devices = Device.objects.filter(rack=rack, position__isnull=True, parent_bay__isnull=True) \
.select_related('device_type__manufacturer')
next_rack = Rack.objects.filter(site=rack.site, name__gt=rack.name).order_by('name').first()
prev_rack = Rack.objects.filter(site=rack.site, name__lt=rack.name).order_by('-name').first()
Expand Down Expand Up @@ -1783,7 +1783,7 @@ class InterfaceConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView
#

class ConsoleConnectionsListView(ObjectListView):
queryset = ConsolePort.objects.select_related('device', 'cs_port__device').filter(cs_port__isnull=False)\
queryset = ConsolePort.objects.select_related('device', 'cs_port__device').filter(cs_port__isnull=False) \
.order_by('cs_port__device__name', 'cs_port__name')
filter = filters.ConsoleConnectionFilter
filter_form = forms.ConsoleConnectionFilterForm
Expand All @@ -1792,7 +1792,7 @@ class ConsoleConnectionsListView(ObjectListView):


class PowerConnectionsListView(ObjectListView):
queryset = PowerPort.objects.select_related('device', 'power_outlet__device').filter(power_outlet__isnull=False)\
queryset = PowerPort.objects.select_related('device', 'power_outlet__device').filter(power_outlet__isnull=False) \
.order_by('power_outlet__device__name', 'power_outlet__name')
filter = filters.PowerConnectionFilter
filter_form = forms.PowerConnectionFilterForm
Expand All @@ -1801,7 +1801,7 @@ class PowerConnectionsListView(ObjectListView):


class InterfaceConnectionsListView(ObjectListView):
queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device')\
queryset = InterfaceConnection.objects.select_related('interface_a__device', 'interface_b__device') \
.order_by('interface_a__device__name', 'interface_a__name')
filter = filters.InterfaceConnectionFilter
filter_form = forms.InterfaceConnectionFilterForm
Expand Down
2 changes: 2 additions & 0 deletions netbox/templates/dcim/rack.html
Original file line number Diff line number Diff line change
Expand Up @@ -233,12 +233,14 @@ <h1>{% block title %}Rack {{ rack }}{% endblock %}</h1>
<table class="table table-hover panel-body">
<tr>
<th>Units</th>
<th>Tenant</th>
<th>Description</th>
<th></th>
</tr>
{% for resv in reservations %}
<tr>
<td>{{ resv.unit_list }}</td>
<td>{{ resv.tenant }}</td>
<td>
{{ resv.description }}<br />
<small>{{ resv.user }} &middot; {{ resv.created }}</small>
Expand Down
4 changes: 4 additions & 0 deletions netbox/templates/tenancy/tenant.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ <h2><a href="{% url 'dcim:site_list' %}?tenant={{ tenant.slug }}" class="btn {%
<h2><a href="{% url 'dcim:rack_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.rack_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.rack_count }}</a></h2>
<p>Racks</p>
</div>
<div class="col-md-4 text-center">
<h2><a href="{% url 'dcim:rackreservation_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.rackreservation_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.rackreservation_count }}</a></h2>
<p>Rack Reservations</p>
</div>
<div class="col-md-4 text-center">
<h2><a href="{% url 'dcim:device_list' %}?tenant={{ tenant.slug }}" class="btn {% if stats.device_count %}btn-primary{% else %}btn-default{% endif %} btn-lg">{{ stats.device_count }}</a></h2>
<p>Devices</p>
Expand Down
3 changes: 2 additions & 1 deletion netbox/tenancy/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.views.generic import View

from circuits.models import Circuit
from dcim.models import Site, Rack, Device
from dcim.models import Site, Rack, Device, RackReservation
from ipam.models import IPAddress, Prefix, VLAN, VRF
from utilities.views import (
BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
Expand Down Expand Up @@ -75,6 +75,7 @@ def get(self, request, slug):
stats = {
'site_count': Site.objects.filter(tenant=tenant).count(),
'rack_count': Rack.objects.filter(tenant=tenant).count(),
'rackreservation_count': RackReservation.objects.filter(tenant=tenant).count(),
'device_count': Device.objects.filter(tenant=tenant).count(),
'vrf_count': VRF.objects.filter(tenant=tenant).count(),
'prefix_count': Prefix.objects.filter(
Expand Down

0 comments on commit fbd39da

Please sign in to comment.