Skip to content

Commit

Permalink
Merge pull request #1094 from digitalocean/develop
Browse files Browse the repository at this point in the history
Release v1.9.6
  • Loading branch information
jeremystretch authored Apr 21, 2017
2 parents e0ad2b4 + 5037046 commit 1787370
Show file tree
Hide file tree
Showing 33 changed files with 376 additions and 417 deletions.
15 changes: 13 additions & 2 deletions docs/installation/netbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Python 3:

```no-highlight
# apt-get install -y python3 python3-dev python3-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev
# update-alternatives --install /usr/bin/python python /usr/bin/python3 1
```

Python 2:
Expand All @@ -20,7 +21,9 @@ 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
# yum install -y gcc python34 python34-devel python34-setuptools libxml2-devel libxslt-devel libffi-devel graphviz openssl-devel
# easy_install-3.4 pip
# ln -s -f python3.4 /usr/bin/python
```

Python 2:
Expand Down Expand Up @@ -83,6 +86,14 @@ Checking connectivity... done.

Install the required Python packages using pip. (If you encounter any compilation errors during this step, ensure that you've installed all of the system dependencies listed above.)

Python 3:

```no-highlight
# pip3 install -r requirements.txt
```

Python 2:

```no-highlight
# pip install -r requirements.txt
```
Expand Down Expand Up @@ -172,7 +183,7 @@ Superuser created successfully.
# Collect Static Files

```no-highlight
# ./manage.py collectstatic
# ./manage.py collectstatic --no-input
You have requested to collect static files at the destination
location as specified in your settings:
Expand Down
5 changes: 3 additions & 2 deletions docs/installation/postgresql.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ NetBox requires a PostgreSQL database to store data. (Please note that MySQL is
**Debian/Ubuntu**

```no-highlight
# apt-get install -y postgresql libpq-dev python-psycopg2
# apt-get update
# apt-get install -y postgresql libpq-dev
```

**CentOS/RHEL**

```no-highlight
# yum install -y postgresql postgresql-server postgresql-devel python-psycopg2
# yum install -y postgresql postgresql-server postgresql-devel
# postgresql-setup initdb
```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-04-19 17:17
from __future__ import unicode_literals

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


class Migration(migrations.Migration):

dependencies = [
('circuits', '0007_circuit_add_description'),
]

operations = [
migrations.AlterField(
model_name='circuittermination',
name='interface',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_termination', to='dcim.Interface'),
),
]
10 changes: 7 additions & 3 deletions netbox/circuits/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,14 @@ 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')
site = models.ForeignKey('dcim.Site', related_name='circuit_terminations', on_delete=models.PROTECT)
interface = models.OneToOneField('dcim.Interface', related_name='circuit_termination', blank=True, null=True)
interface = models.OneToOneField(
'dcim.Interface', related_name='circuit_termination', blank=True, null=True, on_delete=models.PROTECT
)
port_speed = models.PositiveIntegerField(verbose_name='Port speed (Kbps)')
upstream_speed = models.PositiveIntegerField(blank=True, null=True, verbose_name='Upstream speed (Kbps)',
help_text='Upstream speed, if different from port speed')
upstream_speed = models.PositiveIntegerField(
blank=True, null=True, verbose_name='Upstream speed (Kbps)',
help_text='Upstream speed, if different from port speed'
)
xconnect_id = models.CharField(max_length=50, blank=True, verbose_name='Cross-connect ID')
pp_info = models.CharField(max_length=100, blank=True, verbose_name='Patch panel/port(s)')

Expand Down
6 changes: 2 additions & 4 deletions netbox/circuits/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ class CircuitTypeEditView(PermissionRequiredMixin, ObjectEditView):
model = CircuitType
form_class = forms.CircuitTypeForm

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return reverse('circuits:circuittype_list')


Expand Down Expand Up @@ -142,7 +142,6 @@ class CircuitEditView(PermissionRequiredMixin, ObjectEditView):
permission_required = 'circuits.change_circuit'
model = Circuit
form_class = forms.CircuitForm
fields_initial = ['provider']
template_name = 'circuits/circuit_edit.html'
default_return_url = 'circuits:circuit_list'

Expand Down Expand Up @@ -230,15 +229,14 @@ class CircuitTerminationEditView(PermissionRequiredMixin, ObjectEditView):
permission_required = 'circuits.change_circuittermination'
model = CircuitTermination
form_class = forms.CircuitTerminationForm
fields_initial = ['term_side']
template_name = 'circuits/circuittermination_edit.html'

def alter_obj(self, obj, request, url_args, url_kwargs):
if 'circuit' in url_kwargs:
obj.circuit = get_object_or_404(Circuit, pk=url_kwargs['circuit'])
return obj

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return obj.circuit.get_absolute_url()


Expand Down
41 changes: 9 additions & 32 deletions netbox/dcim/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1422,9 +1422,16 @@ def __init__(self, *args, **kwargs):
super(InterfaceBulkEditForm, self).__init__(*args, **kwargs)

# Limit LAG choices to interfaces which belong to the parent device.
device = None
if self.initial.get('device'):
self.fields['lag'].queryset = Interface.objects.filter(
device=self.initial['device'], form_factor=IFACE_FF_LAG
try:
device = Device.objects.get(pk=self.initial.get('device'))
except Device.DoesNotExist:
pass
if device is not None:
interface_ordering = device.device_type.interface_ordering
self.fields['lag'].queryset = Interface.objects.order_naturally(method=interface_ordering).filter(
device=device, form_factor=IFACE_FF_LAG
)
else:
self.fields['lag'].choices = []
Expand Down Expand Up @@ -1684,36 +1691,6 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
device = forms.CharField(required=False, label='Device name')


#
# IP addresses
#

class IPAddressForm(BootstrapMixin, CustomFieldForm):
set_as_primary = forms.BooleanField(label='Set as primary IP for device', required=False)

class Meta:
model = IPAddress
fields = ['address', 'vrf', 'tenant', 'status', 'interface', 'description']

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

super(IPAddressForm, self).__init__(*args, **kwargs)

self.fields['vrf'].empty_label = 'Global'

interfaces = device.interfaces.all()
self.fields['interface'].queryset = interfaces
self.fields['interface'].required = True

# If this device has only one interface, select it by default.
if len(interfaces) == 1:
self.fields['interface'].initial = interfaces[0]

# If this device does not have any IP addresses assigned, default to setting the first IP as its primary.
if not IPAddress.objects.filter(interface__device=device).count():
self.fields['set_as_primary'].initial = True


#
# Modules
#
Expand Down
1 change: 0 additions & 1 deletion netbox/dcim/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@
url(r'^devices/(?P<pk>\d+)/delete/$', views.DeviceDeleteView.as_view(), name='device_delete'),
url(r'^devices/(?P<pk>\d+)/inventory/$', views.device_inventory, name='device_inventory'),
url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', views.device_lldp_neighbors, name='device_lldp_neighbors'),
url(r'^devices/(?P<pk>\d+)/ip-addresses/assign/$', views.ipaddress_assign, name='ipaddress_assign'),
url(r'^devices/(?P<pk>\d+)/add-secret/$', secret_add, name='device_addsecret'),
url(r'^devices/(?P<device>\d+)/services/assign/$', ServiceEditView.as_view(), name='service_assign'),

Expand Down
73 changes: 13 additions & 60 deletions netbox/dcim/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from django.utils.http import urlencode
from django.views.generic import View

from ipam.models import Prefix, IPAddress, Service, VLAN
from ipam.models import Prefix, Service, VLAN
from circuits.models import Circuit
from extras.models import Graph, TopologyMap, GRAPH_TYPE_INTERFACE, GRAPH_TYPE_SITE
from utilities.forms import ConfirmationForm
Expand Down Expand Up @@ -124,13 +124,13 @@ def post(self, request, pk):

class ComponentEditView(ObjectEditView):

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return obj.device.get_absolute_url()


class ComponentDeleteView(ObjectDeleteView):

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return obj.device.get_absolute_url()


Expand All @@ -149,7 +149,7 @@ class RegionEditView(PermissionRequiredMixin, ObjectEditView):
model = Region
form_class = forms.RegionForm

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return reverse('dcim:region_list')


Expand Down Expand Up @@ -242,7 +242,7 @@ class RackGroupEditView(PermissionRequiredMixin, ObjectEditView):
model = RackGroup
form_class = forms.RackGroupForm

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return reverse('dcim:rackgroup_list')


Expand All @@ -268,7 +268,7 @@ class RackRoleEditView(PermissionRequiredMixin, ObjectEditView):
model = RackRole
form_class = forms.RackRoleForm

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return reverse('dcim:rackrole_list')


Expand Down Expand Up @@ -379,15 +379,15 @@ def alter_obj(self, obj, request, args, kwargs):
obj.user = request.user
return obj

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return obj.rack.get_absolute_url()


class RackReservationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
permission_required = 'dcim.delete_rackreservation'
model = RackReservation

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return obj.rack.get_absolute_url()


Expand All @@ -412,7 +412,7 @@ class ManufacturerEditView(PermissionRequiredMixin, ObjectEditView):
model = Manufacturer
form_class = forms.ManufacturerForm

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return reverse('dcim:manufacturer_list')


Expand Down Expand Up @@ -632,7 +632,7 @@ class DeviceRoleEditView(PermissionRequiredMixin, ObjectEditView):
model = DeviceRole
form_class = forms.DeviceRoleForm

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return reverse('dcim:devicerole_list')


Expand All @@ -657,7 +657,7 @@ class PlatformEditView(PermissionRequiredMixin, ObjectEditView):
model = Platform
form_class = forms.PlatformForm

def get_return_url(self, obj):
def get_return_url(self, request, obj):
return reverse('dcim:platform_list')


Expand Down Expand Up @@ -700,19 +700,15 @@ def device(request, pk):
interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering)\
.filter(device=device, mgmt_only=False)\
.select_related('connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
'circuit_termination__circuit')
'circuit_termination__circuit').prefetch_related('ip_addresses')
mgmt_interfaces = Interface.objects.order_naturally(device.device_type.interface_ordering)\
.filter(device=device, mgmt_only=True)\
.select_related('connected_as_a__interface_b__device', 'connected_as_b__interface_a__device',
'circuit_termination__circuit')
'circuit_termination__circuit').prefetch_related('ip_addresses')
device_bays = natsorted(
DeviceBay.objects.filter(device=device).select_related('installed_device__device_type__manufacturer'),
key=attrgetter('name')
)

# Gather relevant device objects
ip_addresses = IPAddress.objects.filter(interface__device=device).select_related('interface', 'vrf')\
.order_by('address')
services = Service.objects.filter(device=device)
secrets = device.secrets.all()

Expand Down Expand Up @@ -743,7 +739,6 @@ def device(request, pk):
'interfaces': interfaces,
'mgmt_interfaces': mgmt_interfaces,
'device_bays': device_bays,
'ip_addresses': ip_addresses,
'services': services,
'secrets': secrets,
'related_devices': related_devices,
Expand All @@ -755,7 +750,6 @@ class DeviceEditView(PermissionRequiredMixin, ObjectEditView):
permission_required = 'dcim.change_device'
model = Device
form_class = forms.DeviceForm
fields_initial = ['site', 'rack', 'position', 'face', 'device_bay']
template_name = 'dcim/device_edit.html'
default_return_url = 'dcim:device_list'

Expand Down Expand Up @@ -1567,47 +1561,6 @@ class InterfaceConnectionsListView(ObjectListView):
template_name = 'dcim/interface_connections_list.html'


#
# IP addresses
#

@permission_required(['dcim.change_device', 'ipam.add_ipaddress'])
def ipaddress_assign(request, pk):

device = get_object_or_404(Device, pk=pk)

if request.method == 'POST':
form = forms.IPAddressForm(device, request.POST)
if form.is_valid():

ipaddress = form.save(commit=False)
ipaddress.interface = form.cleaned_data['interface']
ipaddress.save()
form.save_custom_fields()
messages.success(request, u"Added new IP address {} to interface {}.".format(ipaddress, ipaddress.interface))

if form.cleaned_data['set_as_primary']:
if ipaddress.family == 4:
device.primary_ip4 = ipaddress
elif ipaddress.family == 6:
device.primary_ip6 = ipaddress
device.save()

if '_addanother' in request.POST:
return redirect('dcim:ipaddress_assign', pk=device.pk)
else:
return redirect('dcim:device', pk=device.pk)

else:
form = forms.IPAddressForm(device)

return render(request, 'dcim/ipaddress_assign.html', {
'device': device,
'form': form,
'return_url': reverse('dcim:device', kwargs={'pk': device.pk}),
})


#
# Modules
#
Expand Down
5 changes: 2 additions & 3 deletions netbox/generate_secret_key.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#!/usr/bin/env python
# This script will generate a random 50-character string suitable for use as a SECRET_KEY.
import os
import random

charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(-_=+)'
random.seed = (os.urandom(2048))
print(''.join(random.choice(charset) for c in range(50)))
secure_random = random.SystemRandom()
print(''.join(secure_random.sample(charset, 50)))
Loading

0 comments on commit 1787370

Please sign in to comment.