mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
commit
300aff71bb
@ -27,9 +27,10 @@ IRC.
|
||||
|
||||
## Feature Requests
|
||||
|
||||
* First, check the [issues list](https://github.com/digitalocean/netbox/issues) to see if the feature you'd like to see
|
||||
has already been requested (and possibly rejected). If it is, be sure to comment with a "+1" and any additional
|
||||
justification you have for the feature.
|
||||
* First, check the [issues list](https://github.com/digitalocean/netbox/issues) to see if the feature you're requesting
|
||||
has already been requested (and possibly rejected). If it has, click "add a reaction" in the top right corner of the
|
||||
issue and add a thumbs up (+1). This ensures that the issue has a better chance of making it onto the roadmap. Also feel
|
||||
free to add a comment with any additional justification for the feature.
|
||||
|
||||
* While discussion of new features is welcome, it's important to limit the scope of NetBox's feature set to avoid
|
||||
feature creep. For example, the following features would be firmly out of scope for NetBox:
|
||||
|
@ -4,6 +4,8 @@ NetBox is an IP address management (IPAM) and data center infrastructure managem
|
||||
|
||||
NetBox runs as a web application atop the [Django](https://www.djangoproject.com/) Python framework with a [PostgreSQL](http://www.postgresql.org/) database. For a complete list of requirements, see `requirements.txt`. The code is available [on GitHub](https://github.com/digitalocean/netbox).
|
||||
|
||||
The complete documentation for Netbox can be found at [Read the Docs](http://netbox.readthedocs.io/en/latest/).
|
||||
|
||||
Questions? Comments? Please join us on IRC in **#netbox** on **irc.freenode.net**!
|
||||
|
||||
### Build Status
|
||||
|
@ -13,11 +13,24 @@ ADMINS = [
|
||||
|
||||
---
|
||||
|
||||
## BANNER_TOP
|
||||
|
||||
## BANNER_BOTTOM
|
||||
|
||||
Setting these variables will display content in a banner at the top and/or bottom of the page, respectively. To replicate the content of the top banner in the bottom banner, set:
|
||||
|
||||
```
|
||||
BANNER_TOP = 'Your banner text'
|
||||
BANNER_BOTTOM = BANNER_TOP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DEBUG
|
||||
|
||||
Default: False
|
||||
|
||||
This setting enables debugging. This should be done only during development or troubleshooting. Never enable debugging on a production system, as it can expose sensitive data to unauthenticated users.
|
||||
This setting enables debugging. This should be done only during development or troubleshooting. Never enable debugging on a production system, as it can expose sensitive data to unauthenticated users.
|
||||
|
||||
---
|
||||
|
||||
@ -66,6 +79,14 @@ Determine how many objects to display per page within each list of objects.
|
||||
|
||||
---
|
||||
|
||||
## PREFER_IPV4
|
||||
|
||||
Default: False
|
||||
|
||||
When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to prefer IPv4 instead.
|
||||
|
||||
---
|
||||
|
||||
## TIME_ZONE
|
||||
|
||||
Default: UTC
|
||||
|
@ -4,42 +4,40 @@ As with the initial installation, you can upgrade NetBox by either downloading t
|
||||
|
||||
## Option A: Download a Release
|
||||
|
||||
Download the [latest stable release](https://github.com/digitalocean/netbox/releases) from GitHub as a tarball or ZIP archive. Extract it to your desired path. In this example, we'll use `/opt/netbox`. For this guide we are using 1.0.4 as the old version and 1.0.7 as the new version.
|
||||
Download the [latest stable release](https://github.com/digitalocean/netbox/releases) from GitHub as a tarball or ZIP archive. Extract it to your desired path. In this example, we'll use `/opt/netbox`.
|
||||
|
||||
Download and extract the latest version:
|
||||
|
||||
Download & extract latest version:
|
||||
```
|
||||
# wget https://github.com/digitalocean/netbox/archive/vX.Y.Z.tar.gz
|
||||
# tar -xzf vX.Y.Z.tar.gz -C /opt
|
||||
# cd /opt/
|
||||
# ln -sf netbox-1.0.7/ netbox
|
||||
# ln -sf netbox-X.Y.Z/ netbox
|
||||
```
|
||||
|
||||
Copy the 'configuration.py' you created when first installing to the new version:
|
||||
|
||||
```
|
||||
# cp /opt/netbox-1.0.4/configuration.py /opt/netbox/configuration.py
|
||||
# cp /opt/netbox-X.Y.Z/configuration.py /opt/netbox/configuration.py
|
||||
```
|
||||
|
||||
If you followed the original installation guide to set up gunicorn, be sure to copy its configuration as well:
|
||||
|
||||
```
|
||||
# cp /opt/netbox-X.Y.Z/gunicorn_config.py /opt/netbox/gunicorn_config.py
|
||||
```
|
||||
|
||||
## Option B: Clone the Git Repository (latest master release)
|
||||
|
||||
For this guide, we'll use `/opt/netbox`.
|
||||
This guide assumes that NetBox is installed at `/opt/netbox`. Pull down the most recent iteration of the master branch:
|
||||
|
||||
Check that your git branch is up to date & is set to master:
|
||||
```
|
||||
# cd /opt/netbox
|
||||
# git status
|
||||
```
|
||||
|
||||
If not on branch master, set it and verify status:
|
||||
```
|
||||
# git checkout master
|
||||
# git pull origin master
|
||||
# git status
|
||||
```
|
||||
|
||||
Pull down the set branch from git status above:
|
||||
```
|
||||
# git pull
|
||||
```
|
||||
|
||||
# Run the Upgrade Script
|
||||
|
||||
Once the new code is in place, run the upgrade script (which may need to be run as root depending on how your environment is configured).
|
||||
|
@ -1 +1 @@
|
||||
default_app_config = 'dcim.apps.IPAMConfig'
|
||||
default_app_config = 'dcim.apps.DCIMConfig'
|
||||
|
@ -180,4 +180,4 @@ class DeviceAdmin(admin.ModelAdmin):
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super(DeviceAdmin, self).get_queryset(request)
|
||||
return qs.select_related('device_type__manufacturer', 'device_role', 'primary_ip', 'rack')
|
||||
return qs.select_related('device_type__manufacturer', 'device_role', 'primary_ip4', 'primary_ip6', 'rack')
|
||||
|
@ -1,6 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class IPAMConfig(AppConfig):
|
||||
class DCIMConfig(AppConfig):
|
||||
name = "dcim"
|
||||
verbose_name = "DCIM"
|
||||
|
@ -1,5 +1,6 @@
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.validators import MinValueValidator
|
||||
@ -713,7 +714,9 @@ class Device(CreatedUpdatedModel):
|
||||
|
||||
@property
|
||||
def primary_ip(self):
|
||||
if self.primary_ip6:
|
||||
if settings.PREFER_IPV4 and self.primary_ip4:
|
||||
return self.primary_ip4
|
||||
elif self.primary_ip6:
|
||||
return self.primary_ip6
|
||||
elif self.primary_ip4:
|
||||
return self.primary_ip4
|
||||
|
@ -1,4 +1,6 @@
|
||||
import re
|
||||
from natsort import natsorted
|
||||
from operator import attrgetter
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
@ -259,13 +261,22 @@ def devicetype(request, pk):
|
||||
devicetype = get_object_or_404(DeviceType, pk=pk)
|
||||
|
||||
# Component tables
|
||||
consoleport_table = tables.ConsolePortTemplateTable(ConsolePortTemplate.objects.filter(device_type=devicetype))
|
||||
consoleserverport_table = tables.ConsoleServerPortTemplateTable(ConsoleServerPortTemplate.objects
|
||||
.filter(device_type=devicetype))
|
||||
powerport_table = tables.PowerPortTemplateTable(PowerPortTemplate.objects.filter(device_type=devicetype))
|
||||
poweroutlet_table = tables.PowerOutletTemplateTable(PowerOutletTemplate.objects.filter(device_type=devicetype))
|
||||
consoleport_table = tables.ConsolePortTemplateTable(
|
||||
natsorted(ConsolePortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
|
||||
)
|
||||
consoleserverport_table = tables.ConsoleServerPortTemplateTable(
|
||||
natsorted(ConsoleServerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
|
||||
)
|
||||
powerport_table = tables.PowerPortTemplateTable(
|
||||
natsorted(PowerPortTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
|
||||
)
|
||||
poweroutlet_table = tables.PowerOutletTemplateTable(
|
||||
natsorted(PowerOutletTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
|
||||
)
|
||||
interface_table = tables.InterfaceTemplateTable(InterfaceTemplate.objects.filter(device_type=devicetype))
|
||||
devicebay_table = tables.DeviceBayTemplateTable(DeviceBayTemplate.objects.filter(device_type=devicetype))
|
||||
devicebay_table = tables.DeviceBayTemplateTable(
|
||||
natsorted(DeviceBayTemplate.objects.filter(device_type=devicetype), key=attrgetter('name'))
|
||||
)
|
||||
if request.user.has_perm('dcim.change_devicetype'):
|
||||
consoleport_table.base_columns['pk'].visible = True
|
||||
consoleserverport_table.base_columns['pk'].visible = True
|
||||
@ -513,15 +524,26 @@ class DeviceListView(ObjectListView):
|
||||
def device(request, pk):
|
||||
|
||||
device = get_object_or_404(Device, pk=pk)
|
||||
console_ports = ConsolePort.objects.filter(device=device).select_related('cs_port__device')
|
||||
cs_ports = ConsoleServerPort.objects.filter(device=device).select_related('connected_console')
|
||||
power_ports = PowerPort.objects.filter(device=device).select_related('power_outlet__device')
|
||||
power_outlets = PowerOutlet.objects.filter(device=device).select_related('connected_port')
|
||||
console_ports = natsorted(
|
||||
ConsolePort.objects.filter(device=device).select_related('cs_port__device'), key=attrgetter('name')
|
||||
)
|
||||
cs_ports = natsorted(
|
||||
ConsoleServerPort.objects.filter(device=device).select_related('connected_console'), key=attrgetter('name')
|
||||
)
|
||||
power_ports = natsorted(
|
||||
PowerPort.objects.filter(device=device).select_related('power_outlet__device'), key=attrgetter('name')
|
||||
)
|
||||
power_outlets = natsorted(
|
||||
PowerOutlet.objects.filter(device=device).select_related('connected_port'), key=attrgetter('name')
|
||||
)
|
||||
interfaces = Interface.objects.filter(device=device, mgmt_only=False)\
|
||||
.select_related('connected_as_a', 'connected_as_b', 'circuit')
|
||||
mgmt_interfaces = Interface.objects.filter(device=device, mgmt_only=True)\
|
||||
.select_related('connected_as_a', 'connected_as_b', 'circuit')
|
||||
device_bays = DeviceBay.objects.filter(device=device).select_related('installed_device__device_type__manufacturer')
|
||||
device_bays = natsorted(
|
||||
DeviceBay.objects.filter(device=device).select_related('installed_device__device_type__manufacturer'),
|
||||
key=attrgetter('name')
|
||||
)
|
||||
|
||||
# Gather any secrets which belong to this device
|
||||
secrets = device.secrets.all()
|
||||
|
@ -123,6 +123,8 @@ class Aggregate(CreatedUpdatedModel):
|
||||
|
||||
# Ensure that the aggregate being added does not cover an existing aggregate
|
||||
covered_aggregates = Aggregate.objects.filter(prefix__net_contained=str(self.prefix))
|
||||
if self.pk:
|
||||
covered_aggregates = covered_aggregates.exclude(pk=self.pk)
|
||||
if covered_aggregates:
|
||||
raise ValidationError("{} is overlaps with an existing aggregate ({})"
|
||||
.format(self.prefix, covered_aggregates[0]))
|
||||
|
@ -78,3 +78,7 @@ SHORT_DATETIME_FORMAT = 'Y-m-d H:i'
|
||||
# banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP.
|
||||
BANNER_TOP = ''
|
||||
BANNER_BOTTOM = ''
|
||||
|
||||
# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to
|
||||
# prefer IPv4 instead.
|
||||
PREFER_IPV4 = False
|
||||
|
@ -12,7 +12,7 @@ except ImportError:
|
||||
"the documentation.")
|
||||
|
||||
|
||||
VERSION = '1.2.0'
|
||||
VERSION = '1.2.1'
|
||||
|
||||
# Import local configuration
|
||||
for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
|
||||
@ -40,6 +40,7 @@ DATETIME_FORMAT = getattr(configuration, 'DATETIME_FORMAT', 'N j, Y g:i a')
|
||||
SHORT_DATETIME_FORMAT = getattr(configuration, 'SHORT_DATETIME_FORMAT', 'Y-m-d H:i')
|
||||
BANNER_TOP = getattr(configuration, 'BANNER_TOP', False)
|
||||
BANNER_BOTTOM = getattr(configuration, 'BANNER_BOTTOM', False)
|
||||
PREFER_IPV4 = getattr(configuration, 'PREFER_IPV4', False)
|
||||
CSRF_TRUSTED_ORIGINS = ALLOWED_HOSTS
|
||||
|
||||
# Attempt to import LDAP configuration if it has been defined
|
||||
|
@ -42,7 +42,7 @@ class SecretListView(generics.GenericAPIView):
|
||||
"""
|
||||
List secrets (filterable). If a private key is POSTed, attempt to decrypt each Secret.
|
||||
"""
|
||||
queryset = Secret.objects.select_related('device__primary_ip', 'role')\
|
||||
queryset = Secret.objects.select_related('device__primary_ip4', 'device__primary_ip6', 'role')\
|
||||
.prefetch_related('role__users', 'role__groups')
|
||||
serializer_class = serializers.SecretSerializer
|
||||
filter_class = SecretFilter
|
||||
@ -87,7 +87,7 @@ class SecretDetailView(generics.GenericAPIView):
|
||||
"""
|
||||
Retrieve a single Secret. If a private key is POSTed, attempt to decrypt the Secret.
|
||||
"""
|
||||
queryset = Secret.objects.select_related('device__primary_ip', 'role')\
|
||||
queryset = Secret.objects.select_related('device__primary_ip4', 'device__primary_ip6', 'role')\
|
||||
.prefetch_related('role__users', 'role__groups')
|
||||
serializer_class = serializers.SecretSerializer
|
||||
renderer_classes = [FormlessBrowsableAPIRenderer, JSONRenderer, FreeRADIUSClientsRenderer]
|
||||
|
@ -15,3 +15,4 @@ py-gfm==0.1.3
|
||||
pycrypto==2.6.1
|
||||
sqlparse==0.1.19
|
||||
xmltodict==0.10.2
|
||||
natsort>=5.0.0
|
||||
|
Loading…
Reference in New Issue
Block a user