Skip to content

Commit

Permalink
Merge pull request #849 from digitalocean/develop
Browse files Browse the repository at this point in the history
Release v1.8.3
  • Loading branch information
jeremystretch authored Jan 26, 2017
2 parents b6bbcb0 + b2ef7bb commit c90cecc
Show file tree
Hide file tree
Showing 99 changed files with 662 additions and 459 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
*.pyc
/netbox/netbox/configuration.py
/netbox/netbox/ldap_config.py
/netbox/static
.idea
/*.sh
!upgrade.sh
fabfile.py
*.swp
gunicorn_config.py
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ env:
language: python
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
install:
- pip install -r requirements.txt
- pip install pep8
Expand Down
17 changes: 17 additions & 0 deletions docs/installation/netbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,29 @@

**Debian/Ubuntu**

Python 3:

```no-highlight
# apt-get install -y python3 python3-dev python3-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev
```

Python 2:

```no-highlight
# apt-get install -y python2.7 python-dev python-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev
```

**CentOS/RHEL**

Python 3:

```no-highlight
# yum install -y epel-release
# yum install -y gcc python3 python3-devel python3-pip libxml2-devel libxslt-devel libffi-devel graphviz openssl-devel
```

Python 2:

```no-highlight
# yum install -y epel-release
# yum install -y gcc python2 python-devel python-pip libxml2-devel libxslt-devel libffi-devel graphviz openssl-devel
Expand Down
1 change: 1 addition & 0 deletions netbox/circuits/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default_app_config = 'circuits.apps.CircuitsConfig'
9 changes: 9 additions & 0 deletions netbox/circuits/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.apps import AppConfig


class CircuitsConfig(AppConfig):
name = "circuits"
verbose_name = "Circuits"

def ready(self):
import circuits.signals
2 changes: 2 additions & 0 deletions netbox/circuits/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class Meta:

class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Provider
q = forms.CharField(required=False, label='Search')
site = FilterChoiceField(queryset=Site.objects.all(), to_field_name='slug')


Expand Down Expand Up @@ -126,6 +127,7 @@ class Meta:

class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Circuit
q = forms.CharField(required=False, label='Search')
type = FilterChoiceField(queryset=CircuitType.objects.annotate(filter_count=Count('circuits')),
to_field_name='slug')
provider = FilterChoiceField(queryset=Provider.objects.annotate(filter_count=Count('circuits')),
Expand Down
13 changes: 9 additions & 4 deletions netbox/circuits/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.contrib.contenttypes.fields import GenericRelation
from django.core.urlresolvers import reverse
from django.db import models
from django.utils.encoding import python_2_unicode_compatible

from dcim.fields import ASNField
from extras.models import CustomFieldModel, CustomFieldValue
Expand Down Expand Up @@ -33,6 +34,7 @@ def humanize_speed(speed):
return '{} Kbps'.format(speed)


@python_2_unicode_compatible
class Provider(CreatedUpdatedModel, CustomFieldModel):
"""
Each Circuit belongs to a Provider. This is usually a telecommunications company or similar organization. This model
Expand All @@ -51,7 +53,7 @@ class Provider(CreatedUpdatedModel, CustomFieldModel):
class Meta:
ordering = ['name']

def __unicode__(self):
def __str__(self):
return self.name

def get_absolute_url(self):
Expand All @@ -67,6 +69,7 @@ def to_csv(self):
])


@python_2_unicode_compatible
class CircuitType(models.Model):
"""
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
Expand All @@ -78,13 +81,14 @@ class CircuitType(models.Model):
class Meta:
ordering = ['name']

def __unicode__(self):
def __str__(self):
return self.name

def get_absolute_url(self):
return "{}?type={}".format(reverse('circuits:circuit_list'), self.slug)


@python_2_unicode_compatible
class Circuit(CreatedUpdatedModel, CustomFieldModel):
"""
A communications circuit connects two points. Each Circuit belongs to a Provider; Providers may have multiple
Expand All @@ -105,7 +109,7 @@ class Meta:
ordering = ['provider', 'cid']
unique_together = ['provider', 'cid']

def __unicode__(self):
def __str__(self):
return u'{} {}'.format(self.provider, self.cid)

def get_absolute_url(self):
Expand Down Expand Up @@ -141,6 +145,7 @@ def commit_rate_human(self):
commit_rate_human.admin_order_field = 'commit_rate'


@python_2_unicode_compatible
class CircuitTermination(models.Model):
circuit = models.ForeignKey('Circuit', related_name='terminations', on_delete=models.CASCADE)
term_side = models.CharField(max_length=1, choices=TERM_SIDE_CHOICES, verbose_name='Termination')
Expand All @@ -156,7 +161,7 @@ class Meta:
ordering = ['circuit', 'term_side']
unique_together = ['circuit', 'term_side']

def __unicode__(self):
def __str__(self):
return u'{} (Side {})'.format(self.circuit, self.get_term_side_display())

def get_peer_termination(self):
Expand Down
13 changes: 13 additions & 0 deletions netbox/circuits/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from django.utils import timezone

from .models import Circuit, CircuitTermination


@receiver((post_save, post_delete), sender=CircuitTermination)
def update_circuit(instance, **kwargs):
"""
When a CircuitTermination has been modified, update the last_updated time of its parent Circuit.
"""
Circuit.objects.filter(pk=instance.circuit_id).update(last_updated=timezone.now())
27 changes: 14 additions & 13 deletions netbox/circuits/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class ProviderListView(ObjectListView):
filter = filters.ProviderFilter
filter_form = forms.ProviderFilterForm
table = tables.ProviderTable
edit_permissions = ['circuits.change_provider', 'circuits.delete_provider']
template_name = 'circuits/provider_list.html'


Expand All @@ -47,7 +46,7 @@ class ProviderEditView(PermissionRequiredMixin, ObjectEditView):
model = Provider
form_class = forms.ProviderForm
template_name = 'circuits/provider_edit.html'
obj_list_url = 'circuits:provider_list'
default_return_url = 'circuits:provider_list'


class ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):
Expand All @@ -61,21 +60,23 @@ class ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):
form = forms.ProviderImportForm
table = tables.ProviderTable
template_name = 'circuits/provider_import.html'
obj_list_url = 'circuits:provider_list'
default_return_url = 'circuits:provider_list'


class ProviderBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'circuits.change_provider'
cls = Provider
filter = filters.ProviderFilter
form = forms.ProviderBulkEditForm
template_name = 'circuits/provider_bulk_edit.html'
default_redirect_url = 'circuits:provider_list'
default_return_url = 'circuits:provider_list'


class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'circuits.delete_provider'
cls = Provider
default_redirect_url = 'circuits:provider_list'
filter = filters.ProviderFilter
default_return_url = 'circuits:provider_list'


#
Expand All @@ -85,7 +86,6 @@ class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
class CircuitTypeListView(ObjectListView):
queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
table = tables.CircuitTypeTable
edit_permissions = ['circuits.change_circuittype', 'circuits.delete_circuittype']
template_name = 'circuits/circuittype_list.html'


Expand All @@ -101,7 +101,7 @@ def get_return_url(self, obj):
class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'circuits.delete_circuittype'
cls = CircuitType
default_redirect_url = 'circuits:circuittype_list'
default_return_url = 'circuits:circuittype_list'


#
Expand All @@ -113,7 +113,6 @@ class CircuitListView(ObjectListView):
filter = filters.CircuitFilter
filter_form = forms.CircuitFilterForm
table = tables.CircuitTable
edit_permissions = ['circuits.change_circuit', 'circuits.delete_circuit']
template_name = 'circuits/circuit_list.html'


Expand All @@ -136,7 +135,7 @@ class CircuitEditView(PermissionRequiredMixin, ObjectEditView):
form_class = forms.CircuitForm
fields_initial = ['provider']
template_name = 'circuits/circuit_edit.html'
obj_list_url = 'circuits:circuit_list'
default_return_url = 'circuits:circuit_list'


class CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):
Expand All @@ -150,21 +149,23 @@ class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
form = forms.CircuitImportForm
table = tables.CircuitTable
template_name = 'circuits/circuit_import.html'
obj_list_url = 'circuits:circuit_list'
default_return_url = 'circuits:circuit_list'


class CircuitBulkEditView(PermissionRequiredMixin, BulkEditView):
permission_required = 'circuits.change_circuit'
cls = Circuit
filter = filters.CircuitFilter
form = forms.CircuitBulkEditForm
template_name = 'circuits/circuit_bulk_edit.html'
default_redirect_url = 'circuits:circuit_list'
default_return_url = 'circuits:circuit_list'


class CircuitBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
permission_required = 'circuits.delete_circuit'
cls = Circuit
default_redirect_url = 'circuits:circuit_list'
filter = filters.CircuitFilter
default_return_url = 'circuits:circuit_list'


@permission_required('circuits.change_circuittermination')
Expand Down Expand Up @@ -208,7 +209,7 @@ def circuit_terminations_swap(request, pk):
'form': form,
'panel_class': 'default',
'button_class': 'primary',
'cancel_url': circuit.get_absolute_url(),
'return_url': circuit.get_absolute_url(),
})


Expand Down
3 changes: 2 additions & 1 deletion netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ class Meta(ManufacturerSerializer.Meta):
class DeviceTypeSerializer(CustomFieldSerializer, serializers.ModelSerializer):
manufacturer = ManufacturerNestedSerializer()
subdevice_role = serializers.SerializerMethodField()
instance_count = serializers.IntegerField(source='instances.count', read_only=True)

class Meta:
model = DeviceType
fields = ['id', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
'interface_ordering', 'is_console_server', 'is_pdu', 'is_network_device', 'subdevice_role',
'comments', 'custom_fields']
'comments', 'custom_fields', 'instance_count']

def get_subdevice_role(self, obj):
return {
Expand Down
7 changes: 4 additions & 3 deletions netbox/dcim/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,8 @@ class InterfaceListView(generics.ListAPIView):
def get_queryset(self):

device = get_object_or_404(Device, pk=self.kwargs['pk'])
queryset = Interface.objects.filter(device=device).select_related('connected_as_a', 'connected_as_b')
queryset = Interface.objects.order_naturally(device.device_type.interface_ordering).filter(device=device)\
.select_related('connected_as_a', 'connected_as_b', 'circuit_termination')

# Filter by type (physical or virtual)
iface_type = self.request.query_params.get('type')
Expand Down Expand Up @@ -489,8 +490,8 @@ def get(self, request):
response['power-ports'].append(data)

# Interface connections
interfaces = Interface.objects.filter(device=device).select_related('connected_as_a', 'connected_as_b',
'circuit_termination')
interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering).filter(device=device)\
.select_related('connected_as_a', 'connected_as_b', 'circuit_termination')
for iface in interfaces:
data = serializers.InterfaceDetailSerializer(instance=iface).data
del(data['device'])
Expand Down
Loading

0 comments on commit c90cecc

Please sign in to comment.