This commit is contained in:
Pavel Korovin 2016-07-11 20:48:06 +00:00 committed by GitHub
commit cedf4785d9
7 changed files with 89 additions and 56 deletions

View File

@ -1,4 +1,5 @@
from django import forms
from django.conf import settings
from django.db.models import Count
from dcim.models import Site, Device, Interface, Rack, IFACE_FF_VIRTUAL
@ -9,6 +10,10 @@ from utilities.forms import (
from .models import Circuit, CircuitType, Provider
url_prefix = ''
if settings.URL_PREFIX.strip('/'):
url_prefix = '/{0}'.format(settings.URL_PREFIX.strip('/'))
#
# Providers
@ -82,16 +87,16 @@ class CircuitTypeBulkDeleteForm(ConfirmationForm):
class CircuitForm(forms.ModelForm, BootstrapMixin):
site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.Select(attrs={'filter-for': 'rack'}))
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), required=False, label='Rack',
widget=APISelect(api_url='/api/dcim/racks/?site_id={{site}}',
widget=APISelect(api_url=url_prefix + '/api/dcim/racks/?site_id={{site}}',
attrs={'filter-for': 'device'}))
device = forms.ModelChoiceField(queryset=Device.objects.all(), required=False, label='Device',
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}',
attrs={'filter-for': 'interface'}))
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
)
interface = forms.ModelChoiceField(queryset=Interface.objects.all(), required=False, label='Interface',
widget=APISelect(api_url='/api/dcim/devices/{{device}}/interfaces/?type=physical',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device}}/interfaces/?type=physical',
disabled_indicator='is_connected'))
comments = CommentField()

View File

@ -1,6 +1,7 @@
import re
from django import forms
from django.conf import settings
from django.db.models import Count, Q
from ipam.models import IPAddress
@ -25,6 +26,10 @@ FORM_STATUS_CHOICES += STATUS_CHOICES
DEVICE_BY_PK_RE = '{\d+\}'
url_prefix = ''
if settings.URL_PREFIX.strip('/'):
url_prefix = '/{0}'.format(settings.URL_PREFIX.strip('/'))
def get_device_by_name_or_pk(name):
"""
@ -105,7 +110,7 @@ class RackGroupFilterForm(forms.Form, BootstrapMixin):
class RackForm(forms.ModelForm, BootstrapMixin):
group = forms.ModelChoiceField(queryset=RackGroup.objects.all(), required=False, label='Group', widget=APISelect(
api_url='/api/dcim/rack-groups/?site_id={{site}}',
api_url=url_prefix + '/api/dcim/rack-groups/?site_id={{site}}',
))
comments = CommentField()
@ -330,18 +335,18 @@ class PlatformBulkDeleteForm(ConfirmationForm):
class DeviceForm(forms.ModelForm, BootstrapMixin):
site = forms.ModelChoiceField(queryset=Site.objects.all(), widget=forms.Select(attrs={'filter-for': 'rack'}))
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), widget=APISelect(
api_url='/api/dcim/racks/?site_id={{site}}',
api_url=url_prefix + '/api/dcim/racks/?site_id={{site}}',
display_field='display_name',
attrs={'filter-for': 'position'}
))
position = forms.TypedChoiceField(required=False, empty_value=None,
help_text="For multi-U devices, this is the lowest occupied rack unit.",
widget=APISelect(api_url='/api/dcim/racks/{{rack}}/rack-units/?face={{face}}',
widget=APISelect(api_url=url_prefix + '/api/dcim/racks/{{rack}}/rack-units/?face={{face}}',
disabled_indicator='device'))
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(),
widget=forms.Select(attrs={'filter-for': 'device_type'}))
device_type = forms.ModelChoiceField(queryset=DeviceType.objects.all(), label='Device type', widget=APISelect(
api_url='/api/dcim/device-types/?manufacturer_id={{manufacturer}}',
api_url=url_prefix + '/api/dcim/device-types/?manufacturer_id={{manufacturer}}',
display_field='model'
))
comments = CommentField()
@ -614,13 +619,13 @@ class ConsolePortConnectionForm(forms.ModelForm, BootstrapMixin):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
widget=forms.Select(attrs={'filter-for': 'console_server'}))
console_server = forms.ModelChoiceField(queryset=Device.objects.all(), label='Console Server', required=False,
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_console_server=True',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}&is_console_server=True',
attrs={'filter-for': 'cs_port'}))
livesearch = forms.CharField(required=False, label='Console Server', widget=Livesearch(
query_key='q', query_url='dcim-api:device_list', field_to_update='console_server')
)
cs_port = forms.ModelChoiceField(queryset=ConsoleServerPort.objects.all(), label='Port',
widget=APISelect(api_url='/api/dcim/devices/{{console_server}}/console-server-ports/',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{console_server}}/console-server-ports/',
disabled_indicator='connected_console'))
class Meta:
@ -681,13 +686,13 @@ class ConsoleServerPortConnectionForm(forms.Form, BootstrapMixin):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
widget=forms.Select(attrs={'filter-for': 'device'}))
device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}',
attrs={'filter-for': 'port'}))
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
)
port = forms.ModelChoiceField(queryset=ConsolePort.objects.all(), label='Port',
widget=APISelect(api_url='/api/dcim/devices/{{device}}/console-ports/',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device}}/console-ports/',
disabled_indicator='cs_port'))
connection_status = forms.BooleanField(required=False, initial=CONNECTION_STATUS_CONNECTED, label='Status',
widget=forms.Select(choices=CONNECTION_STATUS_CHOICES))
@ -810,13 +815,13 @@ class PowerPortConnectionForm(forms.ModelForm, BootstrapMixin):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
widget=forms.Select(attrs={'filter-for': 'pdu'}))
pdu = forms.ModelChoiceField(queryset=Device.objects.all(), label='PDU', required=False,
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}&is_pdu=True',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}&is_pdu=True',
attrs={'filter-for': 'power_outlet'}))
livesearch = forms.CharField(required=False, label='PDU', widget=Livesearch(
query_key='q', query_url='dcim-api:device_list', field_to_update='pdu')
)
power_outlet = forms.ModelChoiceField(queryset=PowerOutlet.objects.all(), label='Outlet',
widget=APISelect(api_url='/api/dcim/devices/{{pdu}}/power-outlets/',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{pdu}}/power-outlets/',
disabled_indicator='connected_port'))
class Meta:
@ -877,13 +882,13 @@ class PowerOutletConnectionForm(forms.Form, BootstrapMixin):
rack = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
widget=forms.Select(attrs={'filter-for': 'device'}))
device = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack}}',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack}}',
attrs={'filter-for': 'port'}))
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
query_key='q', query_url='dcim-api:device_list', field_to_update='device')
)
port = forms.ModelChoiceField(queryset=PowerPort.objects.all(), label='Port',
widget=APISelect(api_url='/api/dcim/devices/{{device}}/power-ports/',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device}}/power-ports/',
disabled_indicator='power_outlet'))
connection_status = forms.BooleanField(required=False, initial=CONNECTION_STATUS_CONNECTED, label='Status',
widget=forms.Select(choices=CONNECTION_STATUS_CHOICES))
@ -952,13 +957,13 @@ class InterfaceConnectionForm(forms.ModelForm, BootstrapMixin):
rack_b = forms.ModelChoiceField(queryset=Rack.objects.all(), label='Rack', required=False,
widget=forms.Select(attrs={'filter-for': 'device_b'}))
device_b = forms.ModelChoiceField(queryset=Device.objects.all(), label='Device', required=False,
widget=APISelect(api_url='/api/dcim/devices/?rack_id={{rack_b}}',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?rack_id={{rack_b}}',
attrs={'filter-for': 'interface_b'}))
livesearch = forms.CharField(required=False, label='Device', widget=Livesearch(
query_key='q', query_url='dcim-api:device_list', field_to_update='device_b')
)
interface_b = forms.ModelChoiceField(queryset=Interface.objects.all(), label='Interface',
widget=APISelect(api_url='/api/dcim/devices/{{device_b}}/interfaces/?type=physical',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/{{device_b}}/interfaces/?type=physical',
disabled_indicator='is_connected'))
class Meta:

View File

@ -1,6 +1,7 @@
from netaddr import IPNetwork
from django import forms
from django.conf import settings
from django.db.models import Count
from dcim.models import Site, Device, Interface
@ -16,6 +17,10 @@ from .models import (
FORM_PREFIX_STATUS_CHOICES = (('', '---------'),) + PREFIX_STATUS_CHOICES
FORM_VLAN_STATUS_CHOICES = (('', '---------'),) + VLAN_STATUS_CHOICES
url_prefix = ''
if settings.URL_PREFIX.strip('/'):
url_prefix = '/{0}'.format(settings.URL_PREFIX.strip('/'))
#
# VRFs
@ -144,7 +149,7 @@ class PrefixForm(forms.ModelForm, BootstrapMixin):
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, label='Site',
widget=forms.Select(attrs={'filter-for': 'vlan'}))
vlan = forms.ModelChoiceField(queryset=VLAN.objects.all(), required=False, label='VLAN',
widget=APISelect(api_url='/api/ipam/vlans/?site_id={{site}}',
widget=APISelect(api_url=url_prefix + '/api/ipam/vlans/?site_id={{site}}',
display_field='display_name'))
class Meta:
@ -270,13 +275,13 @@ class IPAddressForm(forms.ModelForm, BootstrapMixin):
nat_site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, label='Site',
widget=forms.Select(attrs={'filter-for': 'nat_device'}))
nat_device = forms.ModelChoiceField(queryset=Device.objects.all(), required=False, label='Device',
widget=APISelect(api_url='/api/dcim/devices/?site_id={{nat_site}}',
widget=APISelect(api_url=url_prefix + '/api/dcim/devices/?site_id={{nat_site}}',
attrs={'filter-for': 'nat_inside'}))
livesearch = forms.CharField(required=False, label='IP Address', widget=Livesearch(
query_key='q', query_url='ipam-api:ipaddress_list', field_to_update='nat_inside', obj_label='address')
)
nat_inside = forms.ModelChoiceField(queryset=IPAddress.objects.all(), required=False, label='NAT (Inside)',
widget=APISelect(api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}',
widget=APISelect(api_url=url_prefix + '/api/ipam/ip-addresses/?device_id={{nat_device}}',
display_field='address'))
class Meta:

View File

@ -32,6 +32,15 @@ SECRET_KEY = ''
# #
#########################
# URL prefix if NetBox is served from non-root location, e.g. http://mysite/netbox/
# By default, URL_PREFIX = '/', i.e. NetBox is served from root location
# URL_PREFIX = '/netbox'
# Directory and URL from which static files will be served
# for more info, see https://docs.djangoproject.com/en/1.9/howto/static-files/
# STATIC_ROOT = '/var/www/htdocs/netbox/static/'
# STATIC_URL = '/static/netbox/'
# Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of
# application errors (assuming correct email settings are provided).
ADMINS = [

View File

@ -22,7 +22,15 @@ for setting in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY']:
raise ImproperlyConfigured("Mandatory setting {} is missing from configuration.py. Please define it per the "
"documentation.".format(setting))
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Default configurations
URL_PREFIX = getattr(configuration, 'URL_PREFIX', '/')
url_prefix = ''
if URL_PREFIX.strip('/'):
url_prefix = '/{0}'.format(URL_PREFIX.strip('/'))
STATIC_ROOT = getattr(configuration, 'STATIC_ROOT', BASE_DIR + '/static/')
STATIC_URL = getattr(configuration, 'STATIC_URL', '/static' + url_prefix + '/')
ADMINS = getattr(configuration, 'ADMINS', [])
DEBUG = getattr(configuration, 'DEBUG', False)
EMAIL = getattr(configuration, 'EMAIL', {})
@ -71,8 +79,6 @@ if LDAP_CONFIGURED:
raise ImproperlyConfigured("LDAP authentication has been configured, but django-auth-ldap is not installed. "
"You can remove netbox/ldap.py to disable LDAP.")
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Database
configuration.DATABASE.update({'ENGINE': 'django.db.backends.postgresql'})
DATABASES = {
@ -155,9 +161,7 @@ USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_ROOT = BASE_DIR + '/static/'
STATIC_URL = '/static/'
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "project-static"),
)
@ -168,9 +172,9 @@ MESSAGE_TAGS = {
}
# Authentication URLs
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
LOGOUT_URL = '/logout/'
LOGIN_URL = url_prefix + '/login/'
LOGIN_REDIRECT_URL = url_prefix + '/'
LOGOUT_URL = url_prefix + '/logout/'
# Secrets
SECRETS_MIN_PUBKEY_SIZE = 2048
@ -182,7 +186,7 @@ REST_FRAMEWORK = {
# Swagger settings (API docs)
SWAGGER_SETTINGS = {
'base_path': '{}/api/docs'.format(ALLOWED_HOSTS[0]),
'base_path': '{}'.format(ALLOWED_HOSTS[0]) + url_prefix + '/api/docs',
}

View File

@ -1,3 +1,4 @@
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
from django.views.defaults import page_not_found
@ -5,9 +6,13 @@ from django.views.defaults import page_not_found
from views import home, trigger_500
from users.views import login, logout
url_prefix = ''
if settings.URL_PREFIX.strip('/'):
url_prefix = '{0}/'.format(settings.URL_PREFIX.strip('/'))
urlpatterns = [
url(r'^{0}'.format(url_prefix),
include([
# Default page
url(r'^$', home, name='home'),
@ -36,5 +41,5 @@ urlpatterns = [
# Admin
url(r'^admin/', include(admin.site.urls)),
])),
]

View File

@ -19,7 +19,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">NetBox</a>
<a href="{% url 'home' %}" class="navbar-brand">NetBox</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
{% if request.user.is_authenticated or not settings.LOGIN_REQUIRED %}
@ -263,7 +263,7 @@
<div class="col-xs-4 text-right">
<p class="text-muted">
<i class="fa fa-fw fa-book text-primary"></i> <a href="http://netbox.readthedocs.io/" target="_blank">Docs</a> &middot;
<i class="fa fa-fw fa-cloud text-primary"></i> <a href="/api/docs/">API</a> &middot;
<i class="fa fa-fw fa-cloud text-primary"></i> <a href="{% url 'home' %}api/docs/">API</a> &middot;
<i class="fa fa-fw fa-code text-primary"></i> <a href="https://github.com/digitalocean/netbox">Code</a>
</p>
</div>