mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-17 09:12:18 -06:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a355783377 | ||
|
|
dafdbc9ddb | ||
|
|
14f5204548 | ||
|
|
5233463f0b | ||
|
|
1d4a416100 | ||
|
|
25ee796d5b | ||
|
|
e08107063a | ||
|
|
cd5a86bfcf | ||
|
|
97b67d0f93 | ||
|
|
3f82be7192 | ||
|
|
adfcb5f7b6 | ||
|
|
5aba1d9aec | ||
|
|
afdf5750b5 | ||
|
|
ea869d4ffc | ||
|
|
9d89eed873 | ||
|
|
c00eea7991 | ||
|
|
88239e0b0d | ||
|
|
9930e2745f | ||
|
|
da3879e928 | ||
|
|
7195b7c803 | ||
|
|
9b082eea14 | ||
|
|
a16218b311 | ||
|
|
29a71fd903 | ||
|
|
fcacac7c6f | ||
|
|
78d74261e9 | ||
|
|
16d694734b | ||
|
|
252ab0fbab | ||
|
|
8eb9c451a1 | ||
|
|
469c52be28 | ||
|
|
54fa51eeff | ||
|
|
5456af6867 | ||
|
|
180446c34d |
@@ -1,12 +1,11 @@
|
|||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
**Debian/Ubuntu**
|
**Ubuntu**
|
||||||
|
|
||||||
Python 3:
|
Python 3:
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# apt-get install -y python3 python3-dev python3-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev zlib1g-dev
|
# apt-get install -y python3 python3-dev python3-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev zlib1g-dev
|
||||||
# update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Python 2:
|
Python 2:
|
||||||
@@ -15,7 +14,7 @@ Python 2:
|
|||||||
# apt-get install -y python2.7 python-dev python-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev zlib1g-dev
|
# apt-get install -y python2.7 python-dev python-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev zlib1g-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
**CentOS/RHEL**
|
**CentOS**
|
||||||
|
|
||||||
Python 3:
|
Python 3:
|
||||||
|
|
||||||
@@ -57,13 +56,13 @@ Create the base directory for the NetBox installation. For this guide, we'll use
|
|||||||
|
|
||||||
If `git` is not already installed, install it:
|
If `git` is not already installed, install it:
|
||||||
|
|
||||||
**Debian/Ubuntu**
|
**Ubuntu**
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# apt-get install -y git
|
# apt-get install -y git
|
||||||
```
|
```
|
||||||
|
|
||||||
**CentOS/RHEL**
|
**CentOS**
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# yum install -y git
|
# yum install -y git
|
||||||
@@ -150,11 +149,14 @@ You may use the script located at `netbox/generate_secret_key.py` to generate a
|
|||||||
|
|
||||||
# Run Database Migrations
|
# Run Database Migrations
|
||||||
|
|
||||||
Before NetBox can run, we need to install the database schema. This is done by running `./manage.py migrate` from the `netbox` directory (`/opt/netbox/netbox/` in our example):
|
!!! warning
|
||||||
|
The examples on the rest of this page call the `python` executable, which will be Python2 on most systems. Replace this with `python3` if you're running NetBox on Python3.
|
||||||
|
|
||||||
|
Before NetBox can run, we need to install the database schema. This is done by running `python manage.py migrate` from the `netbox` directory (`/opt/netbox/netbox/` in our example):
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# cd /opt/netbox/netbox/
|
# cd /opt/netbox/netbox/
|
||||||
# ./manage.py migrate
|
# python manage.py migrate
|
||||||
Operations to perform:
|
Operations to perform:
|
||||||
Apply all migrations: dcim, sessions, admin, ipam, utilities, auth, circuits, contenttypes, extras, secrets, users
|
Apply all migrations: dcim, sessions, admin, ipam, utilities, auth, circuits, contenttypes, extras, secrets, users
|
||||||
Running migrations:
|
Running migrations:
|
||||||
@@ -172,7 +174,7 @@ If this step results in a PostgreSQL authentication error, ensure that the usern
|
|||||||
NetBox does not come with any predefined user accounts. You'll need to create a super user to be able to log into NetBox:
|
NetBox does not come with any predefined user accounts. You'll need to create a super user to be able to log into NetBox:
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# ./manage.py createsuperuser
|
# python manage.py createsuperuser
|
||||||
Username: admin
|
Username: admin
|
||||||
Email address: admin@example.com
|
Email address: admin@example.com
|
||||||
Password:
|
Password:
|
||||||
@@ -183,7 +185,7 @@ Superuser created successfully.
|
|||||||
# Collect Static Files
|
# Collect Static Files
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# ./manage.py collectstatic --no-input
|
# python manage.py collectstatic --no-input
|
||||||
|
|
||||||
You have requested to collect static files at the destination
|
You have requested to collect static files at the destination
|
||||||
location as specified in your settings:
|
location as specified in your settings:
|
||||||
@@ -204,7 +206,7 @@ NetBox ships with some initial data to help you get started: RIR definitions, co
|
|||||||
This step is optional. It's perfectly fine to start using NetBox without using this initial data if you'd rather create everything from scratch.
|
This step is optional. It's perfectly fine to start using NetBox without using this initial data if you'd rather create everything from scratch.
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# ./manage.py loaddata initial_data
|
# python manage.py loaddata initial_data
|
||||||
Installed 43 object(s) from 4 fixture(s)
|
Installed 43 object(s) from 4 fixture(s)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -213,7 +215,7 @@ Installed 43 object(s) from 4 fixture(s)
|
|||||||
At this point, NetBox should be able to run. We can verify this by starting a development instance:
|
At this point, NetBox should be able to run. We can verify this by starting a development instance:
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# ./manage.py runserver 0.0.0.0:8000 --insecure
|
# python manage.py runserver 0.0.0.0:8000 --insecure
|
||||||
Performing system checks...
|
Performing system checks...
|
||||||
|
|
||||||
System check identified no issues (0 silenced).
|
System check identified no issues (0 silenced).
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
NetBox requires a PostgreSQL database to store data. (Please note that MySQL is not supported, as NetBox leverages PostgreSQL's built-in [network address types](https://www.postgresql.org/docs/9.1/static/datatype-net-types.html).)
|
NetBox requires a PostgreSQL database to store data. (Please note that MySQL is not supported, as NetBox leverages PostgreSQL's built-in [network address types](https://www.postgresql.org/docs/9.1/static/datatype-net-types.html).)
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
The installation instructions provided here have been tested to work on Ubuntu 16.04 and CentOS 6.9. The particular commands needed to install dependencies on other distributions may vary significantly. Unfortunately, this is outside the control of the NetBox maintainers. Please consult your distribution's documentation for assistance with any errors.
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
**Debian/Ubuntu**
|
**Ubuntu**
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# apt-get update
|
# apt-get update
|
||||||
# apt-get install -y postgresql libpq-dev
|
# apt-get install -y postgresql libpq-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
**CentOS/RHEL**
|
**CentOS**
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# yum install -y postgresql postgresql-server postgresql-devel
|
# yum install -y postgresql postgresql-server postgresql-devel
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
We'll set up a simple WSGI front end using [gunicorn](http://gunicorn.org/) for the purposes of this guide. For web servers, we provide example configurations for both [nginx](https://www.nginx.com/resources/wiki/) and [Apache](http://httpd.apache.org/docs/2.4). (You are of course free to use whichever combination of HTTP and WSGI services you'd like.) We'll also use [supervisord](http://supervisord.org/) to enable service persistence.
|
We'll set up a simple WSGI front end using [gunicorn](http://gunicorn.org/) for the purposes of this guide. For web servers, we provide example configurations for both [nginx](https://www.nginx.com/resources/wiki/) and [Apache](http://httpd.apache.org/docs/2.4). (You are of course free to use whichever combination of HTTP and WSGI services you'd like.) We'll also use [supervisord](http://supervisord.org/) to enable service persistence.
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
Only Debian/Ubuntu instructions are provided here, but the installation process for CentOS/RHEL does not differ much. Please consult the documentation for those distributions for details.
|
For the sake of brevity, only Ubuntu 16.04 instructions are provided here, but this sort of web server and WSGI configuration is not unique to NetBox. Please consult your distribution's documentation for assistance if needed.
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# apt-get install -y gunicorn supervisor
|
# apt-get install -y gunicorn supervisor
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ class CircuitTerminationForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm
|
|||||||
label='Interface',
|
label='Interface',
|
||||||
widget=APISelect(
|
widget=APISelect(
|
||||||
api_url='/api/dcim/interfaces/?device_id={{device}}&type=physical',
|
api_url='/api/dcim/interfaces/?device_id={{device}}&type=physical',
|
||||||
disabled_indicator='is_connected'
|
disabled_indicator='connection'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Providers
|
# Providers
|
||||||
url(r'^providers/$', views.ProviderListView.as_view(), name='provider_list'),
|
url(r'^providers/$', views.ProviderListView.as_view(), name='provider_list'),
|
||||||
url(r'^providers/add/$', views.ProviderEditView.as_view(), name='provider_add'),
|
url(r'^providers/add/$', views.ProviderCreateView.as_view(), name='provider_add'),
|
||||||
url(r'^providers/import/$', views.ProviderBulkImportView.as_view(), name='provider_import'),
|
url(r'^providers/import/$', views.ProviderBulkImportView.as_view(), name='provider_import'),
|
||||||
url(r'^providers/edit/$', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'),
|
url(r'^providers/edit/$', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'),
|
||||||
url(r'^providers/delete/$', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
|
url(r'^providers/delete/$', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
|
||||||
@@ -20,13 +20,13 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Circuit types
|
# Circuit types
|
||||||
url(r'^circuit-types/$', views.CircuitTypeListView.as_view(), name='circuittype_list'),
|
url(r'^circuit-types/$', views.CircuitTypeListView.as_view(), name='circuittype_list'),
|
||||||
url(r'^circuit-types/add/$', views.CircuitTypeEditView.as_view(), name='circuittype_add'),
|
url(r'^circuit-types/add/$', views.CircuitTypeCreateView.as_view(), name='circuittype_add'),
|
||||||
url(r'^circuit-types/delete/$', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
|
url(r'^circuit-types/delete/$', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
|
||||||
url(r'^circuit-types/(?P<slug>[\w-]+)/edit/$', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
|
url(r'^circuit-types/(?P<slug>[\w-]+)/edit/$', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
|
||||||
|
|
||||||
# Circuits
|
# Circuits
|
||||||
url(r'^circuits/$', views.CircuitListView.as_view(), name='circuit_list'),
|
url(r'^circuits/$', views.CircuitListView.as_view(), name='circuit_list'),
|
||||||
url(r'^circuits/add/$', views.CircuitEditView.as_view(), name='circuit_add'),
|
url(r'^circuits/add/$', views.CircuitCreateView.as_view(), name='circuit_add'),
|
||||||
url(r'^circuits/import/$', views.CircuitBulkImportView.as_view(), name='circuit_import'),
|
url(r'^circuits/import/$', views.CircuitBulkImportView.as_view(), name='circuit_import'),
|
||||||
url(r'^circuits/edit/$', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'),
|
url(r'^circuits/edit/$', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'),
|
||||||
url(r'^circuits/delete/$', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'),
|
url(r'^circuits/delete/$', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'),
|
||||||
@@ -36,7 +36,7 @@ urlpatterns = [
|
|||||||
url(r'^circuits/(?P<pk>\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'),
|
url(r'^circuits/(?P<pk>\d+)/terminations/swap/$', views.circuit_terminations_swap, name='circuit_terminations_swap'),
|
||||||
|
|
||||||
# Circuit terminations
|
# Circuit terminations
|
||||||
url(r'^circuits/(?P<circuit>\d+)/terminations/add/$', views.CircuitTerminationEditView.as_view(), name='circuittermination_add'),
|
url(r'^circuits/(?P<circuit>\d+)/terminations/add/$', views.CircuitTerminationCreateView.as_view(), name='circuittermination_add'),
|
||||||
url(r'^circuit-terminations/(?P<pk>\d+)/edit/$', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'),
|
url(r'^circuit-terminations/(?P<pk>\d+)/edit/$', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'),
|
||||||
url(r'^circuit-terminations/(?P<pk>\d+)/delete/$', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'),
|
url(r'^circuit-terminations/(?P<pk>\d+)/delete/$', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'),
|
||||||
|
|
||||||
|
|||||||
@@ -49,14 +49,18 @@ class ProviderView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class ProviderEditView(PermissionRequiredMixin, ObjectEditView):
|
class ProviderCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'circuits.change_provider'
|
permission_required = 'circuits.add_provider'
|
||||||
model = Provider
|
model = Provider
|
||||||
form_class = forms.ProviderForm
|
form_class = forms.ProviderForm
|
||||||
template_name = 'circuits/provider_edit.html'
|
template_name = 'circuits/provider_edit.html'
|
||||||
default_return_url = 'circuits:provider_list'
|
default_return_url = 'circuits:provider_list'
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderEditView(ProviderCreateView):
|
||||||
|
permission_required = 'circuits.change_provider'
|
||||||
|
|
||||||
|
|
||||||
class ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'circuits.delete_provider'
|
permission_required = 'circuits.delete_provider'
|
||||||
model = Provider
|
model = Provider
|
||||||
@@ -96,8 +100,8 @@ class CircuitTypeListView(ObjectListView):
|
|||||||
template_name = 'circuits/circuittype_list.html'
|
template_name = 'circuits/circuittype_list.html'
|
||||||
|
|
||||||
|
|
||||||
class CircuitTypeEditView(PermissionRequiredMixin, ObjectEditView):
|
class CircuitTypeCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'circuits.change_circuittype'
|
permission_required = 'circuits.add_circuittype'
|
||||||
model = CircuitType
|
model = CircuitType
|
||||||
form_class = forms.CircuitTypeForm
|
form_class = forms.CircuitTypeForm
|
||||||
|
|
||||||
@@ -105,6 +109,10 @@ class CircuitTypeEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('circuits:circuittype_list')
|
return reverse('circuits:circuittype_list')
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitTypeEditView(CircuitTypeCreateView):
|
||||||
|
permission_required = 'circuits.change_circuittype'
|
||||||
|
|
||||||
|
|
||||||
class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'circuits.delete_circuittype'
|
permission_required = 'circuits.delete_circuittype'
|
||||||
cls = CircuitType
|
cls = CircuitType
|
||||||
@@ -146,14 +154,18 @@ class CircuitView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class CircuitEditView(PermissionRequiredMixin, ObjectEditView):
|
class CircuitCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'circuits.change_circuit'
|
permission_required = 'circuits.add_circuit'
|
||||||
model = Circuit
|
model = Circuit
|
||||||
form_class = forms.CircuitForm
|
form_class = forms.CircuitForm
|
||||||
template_name = 'circuits/circuit_edit.html'
|
template_name = 'circuits/circuit_edit.html'
|
||||||
default_return_url = 'circuits:circuit_list'
|
default_return_url = 'circuits:circuit_list'
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitEditView(CircuitCreateView):
|
||||||
|
permission_required = 'circuits.change_circuit'
|
||||||
|
|
||||||
|
|
||||||
class CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'circuits.delete_circuit'
|
permission_required = 'circuits.delete_circuit'
|
||||||
model = Circuit
|
model = Circuit
|
||||||
@@ -232,8 +244,8 @@ def circuit_terminations_swap(request, pk):
|
|||||||
# Circuit terminations
|
# Circuit terminations
|
||||||
#
|
#
|
||||||
|
|
||||||
class CircuitTerminationEditView(PermissionRequiredMixin, ObjectEditView):
|
class CircuitTerminationCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'circuits.change_circuittermination'
|
permission_required = 'circuits.add_circuittermination'
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
form_class = forms.CircuitTerminationForm
|
form_class = forms.CircuitTerminationForm
|
||||||
template_name = 'circuits/circuittermination_edit.html'
|
template_name = 'circuits/circuittermination_edit.html'
|
||||||
@@ -247,6 +259,10 @@ class CircuitTerminationEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return obj.circuit.get_absolute_url()
|
return obj.circuit.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
|
class CircuitTerminationEditView(CircuitTerminationCreateView):
|
||||||
|
permission_required = 'circuits.change_circuittermination'
|
||||||
|
|
||||||
|
|
||||||
class CircuitTerminationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class CircuitTerminationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'circuits.delete_circuittermination'
|
permission_required = 'circuits.delete_circuittermination'
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ from tenancy.forms import TenancyForm
|
|||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
||||||
ChainedFieldsMixin, ChainedModelChoiceField, CommentField, CSVChoiceField, ExpandableNameField, FilterChoiceField,
|
ChainedFieldsMixin, ChainedModelChoiceField, CommentField, ConfirmationForm, CSVChoiceField, ExpandableNameField,
|
||||||
FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
|
FilterChoiceField, FlexibleModelChoiceField, Livesearch, SelectWithDisabled, SmallTextarea, SlugField,
|
||||||
FilterTreeNodeMultipleChoiceField,
|
FilterTreeNodeMultipleChoiceField,
|
||||||
)
|
)
|
||||||
from .formfields import MACAddressFormField
|
from .formfields import MACAddressFormField
|
||||||
@@ -1174,6 +1174,10 @@ class ConsoleServerPortConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ConsoleServerPortBulkDisconnectForm(ConfirmationForm):
|
||||||
|
pk = forms.ModelMultipleChoiceField(queryset=ConsoleServerPort.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Power ports
|
# Power ports
|
||||||
#
|
#
|
||||||
@@ -1431,6 +1435,10 @@ class PowerOutletConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PowerOutletBulkDisconnectForm(ConfirmationForm):
|
||||||
|
pk = forms.ModelMultipleChoiceField(queryset=PowerOutlet.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Interfaces
|
# Interfaces
|
||||||
#
|
#
|
||||||
@@ -1508,6 +1516,10 @@ class InterfaceBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
self.fields['lag'].choices = []
|
self.fields['lag'].choices = []
|
||||||
|
|
||||||
|
|
||||||
|
class InterfaceBulkDisconnectForm(ConfirmationForm):
|
||||||
|
pk = forms.ModelMultipleChoiceField(queryset=Interface.objects.all(), widget=forms.MultipleHiddenInput)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Interface connections
|
# Interface connections
|
||||||
#
|
#
|
||||||
@@ -1594,6 +1606,7 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor
|
|||||||
]
|
]
|
||||||
|
|
||||||
# Mark connected interfaces as disabled
|
# Mark connected interfaces as disabled
|
||||||
|
if self.data.get('device_b'):
|
||||||
self.fields['interface_b'].choices = [
|
self.fields['interface_b'].choices = [
|
||||||
(iface.id, {'label': iface.name, 'disabled': iface.is_connected}) for iface in self.fields['interface_b'].queryset
|
(iface.id, {'label': iface.name, 'disabled': iface.is_connected}) for iface in self.fields['interface_b'].queryset
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
|
|||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from extras.views import ImageAttachmentEditView
|
from extras.views import ImageAttachmentEditView
|
||||||
from ipam.views import ServiceEditView
|
from ipam.views import ServiceCreateView
|
||||||
from secrets.views import secret_add
|
from secrets.views import secret_add
|
||||||
from .models import Device, Rack, Site
|
from .models import Device, Rack, Site
|
||||||
from . import views
|
from . import views
|
||||||
@@ -14,13 +14,13 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Regions
|
# Regions
|
||||||
url(r'^regions/$', views.RegionListView.as_view(), name='region_list'),
|
url(r'^regions/$', views.RegionListView.as_view(), name='region_list'),
|
||||||
url(r'^regions/add/$', views.RegionEditView.as_view(), name='region_add'),
|
url(r'^regions/add/$', views.RegionCreateView.as_view(), name='region_add'),
|
||||||
url(r'^regions/delete/$', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
|
url(r'^regions/delete/$', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
|
||||||
url(r'^regions/(?P<pk>\d+)/edit/$', views.RegionEditView.as_view(), name='region_edit'),
|
url(r'^regions/(?P<pk>\d+)/edit/$', views.RegionEditView.as_view(), name='region_edit'),
|
||||||
|
|
||||||
# Sites
|
# Sites
|
||||||
url(r'^sites/$', views.SiteListView.as_view(), name='site_list'),
|
url(r'^sites/$', views.SiteListView.as_view(), name='site_list'),
|
||||||
url(r'^sites/add/$', views.SiteEditView.as_view(), name='site_add'),
|
url(r'^sites/add/$', views.SiteCreateView.as_view(), name='site_add'),
|
||||||
url(r'^sites/import/$', views.SiteBulkImportView.as_view(), name='site_import'),
|
url(r'^sites/import/$', views.SiteBulkImportView.as_view(), name='site_import'),
|
||||||
url(r'^sites/edit/$', views.SiteBulkEditView.as_view(), name='site_bulk_edit'),
|
url(r'^sites/edit/$', views.SiteBulkEditView.as_view(), name='site_bulk_edit'),
|
||||||
url(r'^sites/(?P<slug>[\w-]+)/$', views.SiteView.as_view(), name='site'),
|
url(r'^sites/(?P<slug>[\w-]+)/$', views.SiteView.as_view(), name='site'),
|
||||||
@@ -30,13 +30,13 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Rack groups
|
# Rack groups
|
||||||
url(r'^rack-groups/$', views.RackGroupListView.as_view(), name='rackgroup_list'),
|
url(r'^rack-groups/$', views.RackGroupListView.as_view(), name='rackgroup_list'),
|
||||||
url(r'^rack-groups/add/$', views.RackGroupEditView.as_view(), name='rackgroup_add'),
|
url(r'^rack-groups/add/$', views.RackGroupCreateView.as_view(), name='rackgroup_add'),
|
||||||
url(r'^rack-groups/delete/$', views.RackGroupBulkDeleteView.as_view(), name='rackgroup_bulk_delete'),
|
url(r'^rack-groups/delete/$', views.RackGroupBulkDeleteView.as_view(), name='rackgroup_bulk_delete'),
|
||||||
url(r'^rack-groups/(?P<pk>\d+)/edit/$', views.RackGroupEditView.as_view(), name='rackgroup_edit'),
|
url(r'^rack-groups/(?P<pk>\d+)/edit/$', views.RackGroupEditView.as_view(), name='rackgroup_edit'),
|
||||||
|
|
||||||
# Rack roles
|
# Rack roles
|
||||||
url(r'^rack-roles/$', views.RackRoleListView.as_view(), name='rackrole_list'),
|
url(r'^rack-roles/$', views.RackRoleListView.as_view(), name='rackrole_list'),
|
||||||
url(r'^rack-roles/add/$', views.RackRoleEditView.as_view(), name='rackrole_add'),
|
url(r'^rack-roles/add/$', views.RackRoleCreateView.as_view(), name='rackrole_add'),
|
||||||
url(r'^rack-roles/delete/$', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'),
|
url(r'^rack-roles/delete/$', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'),
|
||||||
url(r'^rack-roles/(?P<pk>\d+)/edit/$', views.RackRoleEditView.as_view(), name='rackrole_edit'),
|
url(r'^rack-roles/(?P<pk>\d+)/edit/$', views.RackRoleEditView.as_view(), name='rackrole_edit'),
|
||||||
|
|
||||||
@@ -56,18 +56,18 @@ urlpatterns = [
|
|||||||
url(r'^racks/(?P<pk>\d+)/$', views.RackView.as_view(), name='rack'),
|
url(r'^racks/(?P<pk>\d+)/$', views.RackView.as_view(), name='rack'),
|
||||||
url(r'^racks/(?P<pk>\d+)/edit/$', views.RackEditView.as_view(), name='rack_edit'),
|
url(r'^racks/(?P<pk>\d+)/edit/$', views.RackEditView.as_view(), name='rack_edit'),
|
||||||
url(r'^racks/(?P<pk>\d+)/delete/$', views.RackDeleteView.as_view(), name='rack_delete'),
|
url(r'^racks/(?P<pk>\d+)/delete/$', views.RackDeleteView.as_view(), name='rack_delete'),
|
||||||
url(r'^racks/(?P<rack>\d+)/reservations/add/$', views.RackReservationEditView.as_view(), name='rack_add_reservation'),
|
url(r'^racks/(?P<rack>\d+)/reservations/add/$', views.RackReservationCreateView.as_view(), name='rack_add_reservation'),
|
||||||
url(r'^racks/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='rack_add_image', kwargs={'model': Rack}),
|
url(r'^racks/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='rack_add_image', kwargs={'model': Rack}),
|
||||||
|
|
||||||
# Manufacturers
|
# Manufacturers
|
||||||
url(r'^manufacturers/$', views.ManufacturerListView.as_view(), name='manufacturer_list'),
|
url(r'^manufacturers/$', views.ManufacturerListView.as_view(), name='manufacturer_list'),
|
||||||
url(r'^manufacturers/add/$', views.ManufacturerEditView.as_view(), name='manufacturer_add'),
|
url(r'^manufacturers/add/$', views.ManufacturerCreateView.as_view(), name='manufacturer_add'),
|
||||||
url(r'^manufacturers/delete/$', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
|
url(r'^manufacturers/delete/$', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
|
||||||
url(r'^manufacturers/(?P<slug>[\w-]+)/edit/$', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
|
url(r'^manufacturers/(?P<slug>[\w-]+)/edit/$', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
|
||||||
|
|
||||||
# Device types
|
# Device types
|
||||||
url(r'^device-types/$', views.DeviceTypeListView.as_view(), name='devicetype_list'),
|
url(r'^device-types/$', views.DeviceTypeListView.as_view(), name='devicetype_list'),
|
||||||
url(r'^device-types/add/$', views.DeviceTypeEditView.as_view(), name='devicetype_add'),
|
url(r'^device-types/add/$', views.DeviceTypeCreateView.as_view(), name='devicetype_add'),
|
||||||
url(r'^device-types/edit/$', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'),
|
url(r'^device-types/edit/$', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'),
|
||||||
url(r'^device-types/delete/$', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'),
|
url(r'^device-types/delete/$', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/$', views.DeviceTypeView.as_view(), name='devicetype'),
|
url(r'^device-types/(?P<pk>\d+)/$', views.DeviceTypeView.as_view(), name='devicetype'),
|
||||||
@@ -75,45 +75,45 @@ urlpatterns = [
|
|||||||
url(r'^device-types/(?P<pk>\d+)/delete/$', views.DeviceTypeDeleteView.as_view(), name='devicetype_delete'),
|
url(r'^device-types/(?P<pk>\d+)/delete/$', views.DeviceTypeDeleteView.as_view(), name='devicetype_delete'),
|
||||||
|
|
||||||
# Console port templates
|
# Console port templates
|
||||||
url(r'^device-types/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortTemplateAddView.as_view(), name='devicetype_add_consoleport'),
|
url(r'^device-types/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortTemplateCreateView.as_view(), name='devicetype_add_consoleport'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleport'),
|
url(r'^device-types/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleport'),
|
||||||
|
|
||||||
# Console server port templates
|
# Console server port templates
|
||||||
url(r'^device-types/(?P<pk>\d+)/console-server-ports/add/$', views.ConsoleServerPortTemplateAddView.as_view(), name='devicetype_add_consoleserverport'),
|
url(r'^device-types/(?P<pk>\d+)/console-server-ports/add/$', views.ConsoleServerPortTemplateCreateView.as_view(), name='devicetype_add_consoleserverport'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleserverport'),
|
url(r'^device-types/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleserverport'),
|
||||||
|
|
||||||
# Power port templates
|
# Power port templates
|
||||||
url(r'^device-types/(?P<pk>\d+)/power-ports/add/$', views.PowerPortTemplateAddView.as_view(), name='devicetype_add_powerport'),
|
url(r'^device-types/(?P<pk>\d+)/power-ports/add/$', views.PowerPortTemplateCreateView.as_view(), name='devicetype_add_powerport'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_powerport'),
|
url(r'^device-types/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_powerport'),
|
||||||
|
|
||||||
# Power outlet templates
|
# Power outlet templates
|
||||||
url(r'^device-types/(?P<pk>\d+)/power-outlets/add/$', views.PowerOutletTemplateAddView.as_view(), name='devicetype_add_poweroutlet'),
|
url(r'^device-types/(?P<pk>\d+)/power-outlets/add/$', views.PowerOutletTemplateCreateView.as_view(), name='devicetype_add_poweroutlet'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletTemplateBulkDeleteView.as_view(), name='devicetype_delete_poweroutlet'),
|
url(r'^device-types/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletTemplateBulkDeleteView.as_view(), name='devicetype_delete_poweroutlet'),
|
||||||
|
|
||||||
# Interface templates
|
# Interface templates
|
||||||
url(r'^device-types/(?P<pk>\d+)/interfaces/add/$', views.InterfaceTemplateAddView.as_view(), name='devicetype_add_interface'),
|
url(r'^device-types/(?P<pk>\d+)/interfaces/add/$', views.InterfaceTemplateCreateView.as_view(), name='devicetype_add_interface'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceTemplateBulkEditView.as_view(), name='devicetype_bulkedit_interface'),
|
url(r'^device-types/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceTemplateBulkEditView.as_view(), name='devicetype_bulkedit_interface'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceTemplateBulkDeleteView.as_view(), name='devicetype_delete_interface'),
|
url(r'^device-types/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceTemplateBulkDeleteView.as_view(), name='devicetype_delete_interface'),
|
||||||
|
|
||||||
# Device bay templates
|
# Device bay templates
|
||||||
url(r'^device-types/(?P<pk>\d+)/device-bays/add/$', views.DeviceBayTemplateAddView.as_view(), name='devicetype_add_devicebay'),
|
url(r'^device-types/(?P<pk>\d+)/device-bays/add/$', views.DeviceBayTemplateCreateView.as_view(), name='devicetype_add_devicebay'),
|
||||||
url(r'^device-types/(?P<pk>\d+)/device-bays/delete/$', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicetype_delete_devicebay'),
|
url(r'^device-types/(?P<pk>\d+)/device-bays/delete/$', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicetype_delete_devicebay'),
|
||||||
|
|
||||||
# Device roles
|
# Device roles
|
||||||
url(r'^device-roles/$', views.DeviceRoleListView.as_view(), name='devicerole_list'),
|
url(r'^device-roles/$', views.DeviceRoleListView.as_view(), name='devicerole_list'),
|
||||||
url(r'^device-roles/add/$', views.DeviceRoleEditView.as_view(), name='devicerole_add'),
|
url(r'^device-roles/add/$', views.DeviceRoleCreateView.as_view(), name='devicerole_add'),
|
||||||
url(r'^device-roles/delete/$', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
|
url(r'^device-roles/delete/$', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
|
||||||
url(r'^device-roles/(?P<slug>[\w-]+)/edit/$', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
|
url(r'^device-roles/(?P<slug>[\w-]+)/edit/$', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
|
||||||
|
|
||||||
# Platforms
|
# Platforms
|
||||||
url(r'^platforms/$', views.PlatformListView.as_view(), name='platform_list'),
|
url(r'^platforms/$', views.PlatformListView.as_view(), name='platform_list'),
|
||||||
url(r'^platforms/add/$', views.PlatformEditView.as_view(), name='platform_add'),
|
url(r'^platforms/add/$', views.PlatformCreateView.as_view(), name='platform_add'),
|
||||||
url(r'^platforms/delete/$', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
|
url(r'^platforms/delete/$', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
|
||||||
url(r'^platforms/(?P<slug>[\w-]+)/edit/$', views.PlatformEditView.as_view(), name='platform_edit'),
|
url(r'^platforms/(?P<slug>[\w-]+)/edit/$', views.PlatformEditView.as_view(), name='platform_edit'),
|
||||||
|
|
||||||
# Devices
|
# Devices
|
||||||
url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'),
|
url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'),
|
||||||
url(r'^devices/add/$', views.DeviceEditView.as_view(), name='device_add'),
|
url(r'^devices/add/$', views.DeviceCreateView.as_view(), name='device_add'),
|
||||||
url(r'^devices/import/$', views.DeviceBulkImportView.as_view(), name='device_import'),
|
url(r'^devices/import/$', views.DeviceBulkImportView.as_view(), name='device_import'),
|
||||||
url(r'^devices/import/child-devices/$', views.ChildDeviceBulkImportView.as_view(), name='device_import_child'),
|
url(r'^devices/import/child-devices/$', views.ChildDeviceBulkImportView.as_view(), name='device_import_child'),
|
||||||
url(r'^devices/edit/$', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'),
|
url(r'^devices/edit/$', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'),
|
||||||
@@ -124,12 +124,12 @@ urlpatterns = [
|
|||||||
url(r'^devices/(?P<pk>\d+)/inventory/$', views.DeviceInventoryView.as_view(), name='device_inventory'),
|
url(r'^devices/(?P<pk>\d+)/inventory/$', views.DeviceInventoryView.as_view(), name='device_inventory'),
|
||||||
url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'),
|
url(r'^devices/(?P<pk>\d+)/lldp-neighbors/$', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'),
|
||||||
url(r'^devices/(?P<pk>\d+)/add-secret/$', secret_add, name='device_addsecret'),
|
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'),
|
url(r'^devices/(?P<device>\d+)/services/assign/$', ServiceCreateView.as_view(), name='service_assign'),
|
||||||
url(r'^devices/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}),
|
url(r'^devices/(?P<object_id>\d+)/images/add/$', ImageAttachmentEditView.as_view(), name='device_add_image', kwargs={'model': Device}),
|
||||||
|
|
||||||
# Console ports
|
# Console ports
|
||||||
url(r'^devices/console-ports/add/$', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'),
|
url(r'^devices/console-ports/add/$', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'),
|
||||||
url(r'^devices/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortAddView.as_view(), name='consoleport_add'),
|
url(r'^devices/(?P<pk>\d+)/console-ports/add/$', views.ConsolePortCreateView.as_view(), name='consoleport_add'),
|
||||||
url(r'^devices/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
|
url(r'^devices/(?P<pk>\d+)/console-ports/delete/$', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
|
||||||
url(r'^console-ports/(?P<pk>\d+)/connect/$', views.consoleport_connect, name='consoleport_connect'),
|
url(r'^console-ports/(?P<pk>\d+)/connect/$', views.consoleport_connect, name='consoleport_connect'),
|
||||||
url(r'^console-ports/(?P<pk>\d+)/disconnect/$', views.consoleport_disconnect, name='consoleport_disconnect'),
|
url(r'^console-ports/(?P<pk>\d+)/disconnect/$', views.consoleport_disconnect, name='consoleport_disconnect'),
|
||||||
@@ -138,7 +138,8 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Console server ports
|
# Console server ports
|
||||||
url(r'^devices/console-server-ports/add/$', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'),
|
url(r'^devices/console-server-ports/add/$', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'),
|
||||||
url(r'^devices/(?P<pk>\d+)/console-server-ports/add/$', views.ConsoleServerPortAddView.as_view(), name='consoleserverport_add'),
|
url(r'^devices/(?P<pk>\d+)/console-server-ports/add/$', views.ConsoleServerPortCreateView.as_view(), name='consoleserverport_add'),
|
||||||
|
url(r'^devices/(?P<pk>\d+)/console-server-ports/disconnect/$', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'),
|
||||||
url(r'^devices/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
|
url(r'^devices/(?P<pk>\d+)/console-server-ports/delete/$', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
|
||||||
url(r'^console-server-ports/(?P<pk>\d+)/connect/$', views.consoleserverport_connect, name='consoleserverport_connect'),
|
url(r'^console-server-ports/(?P<pk>\d+)/connect/$', views.consoleserverport_connect, name='consoleserverport_connect'),
|
||||||
url(r'^console-server-ports/(?P<pk>\d+)/disconnect/$', views.consoleserverport_disconnect, name='consoleserverport_disconnect'),
|
url(r'^console-server-ports/(?P<pk>\d+)/disconnect/$', views.consoleserverport_disconnect, name='consoleserverport_disconnect'),
|
||||||
@@ -147,7 +148,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Power ports
|
# Power ports
|
||||||
url(r'^devices/power-ports/add/$', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
|
url(r'^devices/power-ports/add/$', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
|
||||||
url(r'^devices/(?P<pk>\d+)/power-ports/add/$', views.PowerPortAddView.as_view(), name='powerport_add'),
|
url(r'^devices/(?P<pk>\d+)/power-ports/add/$', views.PowerPortCreateView.as_view(), name='powerport_add'),
|
||||||
url(r'^devices/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
|
url(r'^devices/(?P<pk>\d+)/power-ports/delete/$', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
|
||||||
url(r'^power-ports/(?P<pk>\d+)/connect/$', views.powerport_connect, name='powerport_connect'),
|
url(r'^power-ports/(?P<pk>\d+)/connect/$', views.powerport_connect, name='powerport_connect'),
|
||||||
url(r'^power-ports/(?P<pk>\d+)/disconnect/$', views.powerport_disconnect, name='powerport_disconnect'),
|
url(r'^power-ports/(?P<pk>\d+)/disconnect/$', views.powerport_disconnect, name='powerport_disconnect'),
|
||||||
@@ -156,7 +157,8 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Power outlets
|
# Power outlets
|
||||||
url(r'^devices/power-outlets/add/$', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'),
|
url(r'^devices/power-outlets/add/$', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'),
|
||||||
url(r'^devices/(?P<pk>\d+)/power-outlets/add/$', views.PowerOutletAddView.as_view(), name='poweroutlet_add'),
|
url(r'^devices/(?P<pk>\d+)/power-outlets/add/$', views.PowerOutletCreateView.as_view(), name='poweroutlet_add'),
|
||||||
|
url(r'^devices/(?P<pk>\d+)/power-outlets/disconnect/$', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'),
|
||||||
url(r'^devices/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
|
url(r'^devices/(?P<pk>\d+)/power-outlets/delete/$', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
|
||||||
url(r'^power-outlets/(?P<pk>\d+)/connect/$', views.poweroutlet_connect, name='poweroutlet_connect'),
|
url(r'^power-outlets/(?P<pk>\d+)/connect/$', views.poweroutlet_connect, name='poweroutlet_connect'),
|
||||||
url(r'^power-outlets/(?P<pk>\d+)/disconnect/$', views.poweroutlet_disconnect, name='poweroutlet_disconnect'),
|
url(r'^power-outlets/(?P<pk>\d+)/disconnect/$', views.poweroutlet_disconnect, name='poweroutlet_disconnect'),
|
||||||
@@ -165,8 +167,9 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Interfaces
|
# Interfaces
|
||||||
url(r'^devices/interfaces/add/$', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
|
url(r'^devices/interfaces/add/$', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
|
||||||
url(r'^devices/(?P<pk>\d+)/interfaces/add/$', views.InterfaceAddView.as_view(), name='interface_add'),
|
url(r'^devices/(?P<pk>\d+)/interfaces/add/$', views.InterfaceCreateView.as_view(), name='interface_add'),
|
||||||
url(r'^devices/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'),
|
url(r'^devices/(?P<pk>\d+)/interfaces/edit/$', views.InterfaceBulkEditView.as_view(), name='interface_bulk_edit'),
|
||||||
|
url(r'^devices/(?P<pk>\d+)/interfaces/disconnect/$', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'),
|
||||||
url(r'^devices/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
|
url(r'^devices/(?P<pk>\d+)/interfaces/delete/$', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
|
||||||
url(r'^devices/(?P<pk>\d+)/interface-connections/add/$', views.interfaceconnection_add, name='interfaceconnection_add'),
|
url(r'^devices/(?P<pk>\d+)/interface-connections/add/$', views.interfaceconnection_add, name='interfaceconnection_add'),
|
||||||
url(r'^interface-connections/(?P<pk>\d+)/delete/$', views.interfaceconnection_delete, name='interfaceconnection_delete'),
|
url(r'^interface-connections/(?P<pk>\d+)/delete/$', views.interfaceconnection_delete, name='interfaceconnection_delete'),
|
||||||
@@ -175,7 +178,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Device bays
|
# Device bays
|
||||||
url(r'^devices/device-bays/add/$', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),
|
url(r'^devices/device-bays/add/$', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),
|
||||||
url(r'^devices/(?P<pk>\d+)/bays/add/$', views.DeviceBayAddView.as_view(), name='devicebay_add'),
|
url(r'^devices/(?P<pk>\d+)/bays/add/$', views.DeviceBayCreateView.as_view(), name='devicebay_add'),
|
||||||
url(r'^devices/(?P<pk>\d+)/bays/delete/$', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
|
url(r'^devices/(?P<pk>\d+)/bays/delete/$', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
|
||||||
url(r'^device-bays/(?P<pk>\d+)/edit/$', views.DeviceBayEditView.as_view(), name='devicebay_edit'),
|
url(r'^device-bays/(?P<pk>\d+)/edit/$', views.DeviceBayEditView.as_view(), name='devicebay_edit'),
|
||||||
url(r'^device-bays/(?P<pk>\d+)/delete/$', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'),
|
url(r'^device-bays/(?P<pk>\d+)/delete/$', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'),
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from difflib import SequenceMatcher
|
|
||||||
import re
|
import re
|
||||||
from natsort import natsorted
|
from natsort import natsorted
|
||||||
from operator import attrgetter
|
from operator import attrgetter
|
||||||
@@ -9,7 +8,7 @@ from django.contrib import messages
|
|||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from django.contrib.auth.mixins import PermissionRequiredMixin
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
||||||
from django.core.paginator import EmptyPage, PageNotAnInteger
|
from django.core.paginator import EmptyPage, PageNotAnInteger
|
||||||
from django.db.models import Count
|
from django.db.models import Count, Q
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@@ -142,6 +141,44 @@ class ComponentDeleteView(ObjectDeleteView):
|
|||||||
return obj.device.get_absolute_url()
|
return obj.device.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
|
class BulkDisconnectView(View):
|
||||||
|
"""
|
||||||
|
An extendable view for disconnection console/power/interface components in bulk.
|
||||||
|
"""
|
||||||
|
model = None
|
||||||
|
form = None
|
||||||
|
template_name = 'dcim/bulk_disconnect.html'
|
||||||
|
|
||||||
|
def disconnect_objects(self, objects):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def post(self, request, pk):
|
||||||
|
|
||||||
|
device = get_object_or_404(Device, pk=pk)
|
||||||
|
selected_objects = []
|
||||||
|
|
||||||
|
if '_confirm' in request.POST:
|
||||||
|
form = self.form(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
count = self.disconnect_objects(form.cleaned_data['pk'])
|
||||||
|
messages.success(request, "Disconnected {} {} on {}".format(
|
||||||
|
count, self.model._meta.verbose_name_plural, device
|
||||||
|
))
|
||||||
|
return redirect(device.get_absolute_url())
|
||||||
|
|
||||||
|
else:
|
||||||
|
form = self.form(initial={'pk': request.POST.getlist('pk')})
|
||||||
|
selected_objects = self.model.objects.filter(pk__in=form.initial['pk'])
|
||||||
|
|
||||||
|
return render(request, self.template_name, {
|
||||||
|
'form': form,
|
||||||
|
'device': device,
|
||||||
|
'obj_type_plural': self.model._meta.verbose_name_plural,
|
||||||
|
'selected_objects': selected_objects,
|
||||||
|
'return_url': device.get_absolute_url(),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Regions
|
# Regions
|
||||||
#
|
#
|
||||||
@@ -152,8 +189,8 @@ class RegionListView(ObjectListView):
|
|||||||
template_name = 'dcim/region_list.html'
|
template_name = 'dcim/region_list.html'
|
||||||
|
|
||||||
|
|
||||||
class RegionEditView(PermissionRequiredMixin, ObjectEditView):
|
class RegionCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_region'
|
permission_required = 'dcim.add_region'
|
||||||
model = Region
|
model = Region
|
||||||
form_class = forms.RegionForm
|
form_class = forms.RegionForm
|
||||||
|
|
||||||
@@ -161,6 +198,10 @@ class RegionEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('dcim:region_list')
|
return reverse('dcim:region_list')
|
||||||
|
|
||||||
|
|
||||||
|
class RegionEditView(RegionCreateView):
|
||||||
|
permission_required = 'dcim.change_region'
|
||||||
|
|
||||||
|
|
||||||
class RegionBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class RegionBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_region'
|
permission_required = 'dcim.delete_region'
|
||||||
cls = Region
|
cls = Region
|
||||||
@@ -204,14 +245,18 @@ class SiteView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class SiteEditView(PermissionRequiredMixin, ObjectEditView):
|
class SiteCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_site'
|
permission_required = 'dcim.add_site'
|
||||||
model = Site
|
model = Site
|
||||||
form_class = forms.SiteForm
|
form_class = forms.SiteForm
|
||||||
template_name = 'dcim/site_edit.html'
|
template_name = 'dcim/site_edit.html'
|
||||||
default_return_url = 'dcim:site_list'
|
default_return_url = 'dcim:site_list'
|
||||||
|
|
||||||
|
|
||||||
|
class SiteEditView(SiteCreateView):
|
||||||
|
permission_required = 'dcim.change_site'
|
||||||
|
|
||||||
|
|
||||||
class SiteDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class SiteDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'dcim.delete_site'
|
permission_required = 'dcim.delete_site'
|
||||||
model = Site
|
model = Site
|
||||||
@@ -246,8 +291,8 @@ class RackGroupListView(ObjectListView):
|
|||||||
template_name = 'dcim/rackgroup_list.html'
|
template_name = 'dcim/rackgroup_list.html'
|
||||||
|
|
||||||
|
|
||||||
class RackGroupEditView(PermissionRequiredMixin, ObjectEditView):
|
class RackGroupCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_rackgroup'
|
permission_required = 'dcim.add_rackgroup'
|
||||||
model = RackGroup
|
model = RackGroup
|
||||||
form_class = forms.RackGroupForm
|
form_class = forms.RackGroupForm
|
||||||
|
|
||||||
@@ -255,6 +300,10 @@ class RackGroupEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('dcim:rackgroup_list')
|
return reverse('dcim:rackgroup_list')
|
||||||
|
|
||||||
|
|
||||||
|
class RackGroupEditView(RackGroupCreateView):
|
||||||
|
permission_required = 'dcim.change_rackgroup'
|
||||||
|
|
||||||
|
|
||||||
class RackGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class RackGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_rackgroup'
|
permission_required = 'dcim.delete_rackgroup'
|
||||||
cls = RackGroup
|
cls = RackGroup
|
||||||
@@ -272,8 +321,8 @@ class RackRoleListView(ObjectListView):
|
|||||||
template_name = 'dcim/rackrole_list.html'
|
template_name = 'dcim/rackrole_list.html'
|
||||||
|
|
||||||
|
|
||||||
class RackRoleEditView(PermissionRequiredMixin, ObjectEditView):
|
class RackRoleCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_rackrole'
|
permission_required = 'dcim.add_rackrole'
|
||||||
model = RackRole
|
model = RackRole
|
||||||
form_class = forms.RackRoleForm
|
form_class = forms.RackRoleForm
|
||||||
|
|
||||||
@@ -281,6 +330,10 @@ class RackRoleEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('dcim:rackrole_list')
|
return reverse('dcim:rackrole_list')
|
||||||
|
|
||||||
|
|
||||||
|
class RackRoleEditView(RackRoleCreateView):
|
||||||
|
permission_required = 'dcim.change_rackrole'
|
||||||
|
|
||||||
|
|
||||||
class RackRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class RackRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_rackrole'
|
permission_required = 'dcim.delete_rackrole'
|
||||||
cls = RackRole
|
cls = RackRole
|
||||||
@@ -374,14 +427,18 @@ class RackView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class RackEditView(PermissionRequiredMixin, ObjectEditView):
|
class RackCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_rack'
|
permission_required = 'dcim.add_rack'
|
||||||
model = Rack
|
model = Rack
|
||||||
form_class = forms.RackForm
|
form_class = forms.RackForm
|
||||||
template_name = 'dcim/rack_edit.html'
|
template_name = 'dcim/rack_edit.html'
|
||||||
default_return_url = 'dcim:rack_list'
|
default_return_url = 'dcim:rack_list'
|
||||||
|
|
||||||
|
|
||||||
|
class RackEditView(RackCreateView):
|
||||||
|
permission_required = 'dcim.change_rack'
|
||||||
|
|
||||||
|
|
||||||
class RackDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class RackDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'dcim.delete_rack'
|
permission_required = 'dcim.delete_rack'
|
||||||
model = Rack
|
model = Rack
|
||||||
@@ -423,8 +480,8 @@ class RackReservationListView(ObjectListView):
|
|||||||
template_name = 'dcim/rackreservation_list.html'
|
template_name = 'dcim/rackreservation_list.html'
|
||||||
|
|
||||||
|
|
||||||
class RackReservationEditView(PermissionRequiredMixin, ObjectEditView):
|
class RackReservationCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_rackreservation'
|
permission_required = 'dcim.add_rackreservation'
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
form_class = forms.RackReservationForm
|
form_class = forms.RackReservationForm
|
||||||
|
|
||||||
@@ -438,6 +495,10 @@ class RackReservationEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return obj.rack.get_absolute_url()
|
return obj.rack.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
|
class RackReservationEditView(RackReservationCreateView):
|
||||||
|
permission_required = 'dcim.change_rackreservation'
|
||||||
|
|
||||||
|
|
||||||
class RackReservationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class RackReservationDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'dcim.delete_rackreservation'
|
permission_required = 'dcim.delete_rackreservation'
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
@@ -462,8 +523,8 @@ class ManufacturerListView(ObjectListView):
|
|||||||
template_name = 'dcim/manufacturer_list.html'
|
template_name = 'dcim/manufacturer_list.html'
|
||||||
|
|
||||||
|
|
||||||
class ManufacturerEditView(PermissionRequiredMixin, ObjectEditView):
|
class ManufacturerCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_manufacturer'
|
permission_required = 'dcim.add_manufacturer'
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
form_class = forms.ManufacturerForm
|
form_class = forms.ManufacturerForm
|
||||||
|
|
||||||
@@ -471,6 +532,10 @@ class ManufacturerEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('dcim:manufacturer_list')
|
return reverse('dcim:manufacturer_list')
|
||||||
|
|
||||||
|
|
||||||
|
class ManufacturerEditView(ManufacturerCreateView):
|
||||||
|
permission_required = 'dcim.change_manufacturer'
|
||||||
|
|
||||||
|
|
||||||
class ManufacturerBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class ManufacturerBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_manufacturer'
|
permission_required = 'dcim.delete_manufacturer'
|
||||||
cls = Manufacturer
|
cls = Manufacturer
|
||||||
@@ -542,14 +607,18 @@ class DeviceTypeView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class DeviceTypeEditView(PermissionRequiredMixin, ObjectEditView):
|
class DeviceTypeCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_devicetype'
|
permission_required = 'dcim.add_devicetype'
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
form_class = forms.DeviceTypeForm
|
form_class = forms.DeviceTypeForm
|
||||||
template_name = 'dcim/devicetype_edit.html'
|
template_name = 'dcim/devicetype_edit.html'
|
||||||
default_return_url = 'dcim:devicetype_list'
|
default_return_url = 'dcim:devicetype_list'
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceTypeEditView(DeviceTypeCreateView):
|
||||||
|
permission_required = 'dcim.change_devicetype'
|
||||||
|
|
||||||
|
|
||||||
class DeviceTypeDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class DeviceTypeDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'dcim.delete_devicetype'
|
permission_required = 'dcim.delete_devicetype'
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
@@ -576,7 +645,7 @@ class DeviceTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
# Device type components
|
# Device type components
|
||||||
#
|
#
|
||||||
|
|
||||||
class ConsolePortTemplateAddView(PermissionRequiredMixin, ComponentCreateView):
|
class ConsolePortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_consoleporttemplate'
|
permission_required = 'dcim.add_consoleporttemplate'
|
||||||
parent_model = DeviceType
|
parent_model = DeviceType
|
||||||
parent_field = 'device_type'
|
parent_field = 'device_type'
|
||||||
@@ -593,7 +662,7 @@ class ConsolePortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView)
|
|||||||
parent_cls = DeviceType
|
parent_cls = DeviceType
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortTemplateAddView(PermissionRequiredMixin, ComponentCreateView):
|
class ConsoleServerPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_consoleserverporttemplate'
|
permission_required = 'dcim.add_consoleserverporttemplate'
|
||||||
parent_model = DeviceType
|
parent_model = DeviceType
|
||||||
parent_field = 'device_type'
|
parent_field = 'device_type'
|
||||||
@@ -608,7 +677,7 @@ class ConsoleServerPortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDelet
|
|||||||
parent_cls = DeviceType
|
parent_cls = DeviceType
|
||||||
|
|
||||||
|
|
||||||
class PowerPortTemplateAddView(PermissionRequiredMixin, ComponentCreateView):
|
class PowerPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_powerporttemplate'
|
permission_required = 'dcim.add_powerporttemplate'
|
||||||
parent_model = DeviceType
|
parent_model = DeviceType
|
||||||
parent_field = 'device_type'
|
parent_field = 'device_type'
|
||||||
@@ -623,7 +692,7 @@ class PowerPortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
parent_cls = DeviceType
|
parent_cls = DeviceType
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletTemplateAddView(PermissionRequiredMixin, ComponentCreateView):
|
class PowerOutletTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_poweroutlettemplate'
|
permission_required = 'dcim.add_poweroutlettemplate'
|
||||||
parent_model = DeviceType
|
parent_model = DeviceType
|
||||||
parent_field = 'device_type'
|
parent_field = 'device_type'
|
||||||
@@ -638,7 +707,7 @@ class PowerOutletTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView)
|
|||||||
parent_cls = DeviceType
|
parent_cls = DeviceType
|
||||||
|
|
||||||
|
|
||||||
class InterfaceTemplateAddView(PermissionRequiredMixin, ComponentCreateView):
|
class InterfaceTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_interfacetemplate'
|
permission_required = 'dcim.add_interfacetemplate'
|
||||||
parent_model = DeviceType
|
parent_model = DeviceType
|
||||||
parent_field = 'device_type'
|
parent_field = 'device_type'
|
||||||
@@ -661,7 +730,7 @@ class InterfaceTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
parent_cls = DeviceType
|
parent_cls = DeviceType
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayTemplateAddView(PermissionRequiredMixin, ComponentCreateView):
|
class DeviceBayTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_devicebaytemplate'
|
permission_required = 'dcim.add_devicebaytemplate'
|
||||||
parent_model = DeviceType
|
parent_model = DeviceType
|
||||||
parent_field = 'device_type'
|
parent_field = 'device_type'
|
||||||
@@ -686,8 +755,8 @@ class DeviceRoleListView(ObjectListView):
|
|||||||
template_name = 'dcim/devicerole_list.html'
|
template_name = 'dcim/devicerole_list.html'
|
||||||
|
|
||||||
|
|
||||||
class DeviceRoleEditView(PermissionRequiredMixin, ObjectEditView):
|
class DeviceRoleCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_devicerole'
|
permission_required = 'dcim.add_devicerole'
|
||||||
model = DeviceRole
|
model = DeviceRole
|
||||||
form_class = forms.DeviceRoleForm
|
form_class = forms.DeviceRoleForm
|
||||||
|
|
||||||
@@ -695,6 +764,10 @@ class DeviceRoleEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('dcim:devicerole_list')
|
return reverse('dcim:devicerole_list')
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceRoleEditView(DeviceRoleCreateView):
|
||||||
|
permission_required = 'dcim.change_devicerole'
|
||||||
|
|
||||||
|
|
||||||
class DeviceRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class DeviceRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_devicerole'
|
permission_required = 'dcim.delete_devicerole'
|
||||||
cls = DeviceRole
|
cls = DeviceRole
|
||||||
@@ -711,8 +784,8 @@ class PlatformListView(ObjectListView):
|
|||||||
template_name = 'dcim/platform_list.html'
|
template_name = 'dcim/platform_list.html'
|
||||||
|
|
||||||
|
|
||||||
class PlatformEditView(PermissionRequiredMixin, ObjectEditView):
|
class PlatformCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_platform'
|
permission_required = 'dcim.add_platform'
|
||||||
model = Platform
|
model = Platform
|
||||||
form_class = forms.PlatformForm
|
form_class = forms.PlatformForm
|
||||||
|
|
||||||
@@ -720,6 +793,10 @@ class PlatformEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('dcim:platform_list')
|
return reverse('dcim:platform_list')
|
||||||
|
|
||||||
|
|
||||||
|
class PlatformEditView(PlatformCreateView):
|
||||||
|
permission_required = 'dcim.change_platform'
|
||||||
|
|
||||||
|
|
||||||
class PlatformBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class PlatformBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_platform'
|
permission_required = 'dcim.delete_platform'
|
||||||
cls = Platform
|
cls = Platform
|
||||||
@@ -843,14 +920,18 @@ class DeviceLLDPNeighborsView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class DeviceEditView(PermissionRequiredMixin, ObjectEditView):
|
class DeviceCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'dcim.change_device'
|
permission_required = 'dcim.add_device'
|
||||||
model = Device
|
model = Device
|
||||||
form_class = forms.DeviceForm
|
form_class = forms.DeviceForm
|
||||||
template_name = 'dcim/device_edit.html'
|
template_name = 'dcim/device_edit.html'
|
||||||
default_return_url = 'dcim:device_list'
|
default_return_url = 'dcim:device_list'
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceEditView(DeviceCreateView):
|
||||||
|
permission_required = 'dcim.change_device'
|
||||||
|
|
||||||
|
|
||||||
class DeviceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class DeviceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'dcim.delete_device'
|
permission_required = 'dcim.delete_device'
|
||||||
model = Device
|
model = Device
|
||||||
@@ -904,7 +985,7 @@ class DeviceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
# Console ports
|
# Console ports
|
||||||
#
|
#
|
||||||
|
|
||||||
class ConsolePortAddView(PermissionRequiredMixin, ComponentCreateView):
|
class ConsolePortCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_consoleport'
|
permission_required = 'dcim.add_consoleport'
|
||||||
parent_model = Device
|
parent_model = Device
|
||||||
parent_field = 'device'
|
parent_field = 'device'
|
||||||
@@ -1017,7 +1098,7 @@ class ConsoleConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|||||||
# Console server ports
|
# Console server ports
|
||||||
#
|
#
|
||||||
|
|
||||||
class ConsoleServerPortAddView(PermissionRequiredMixin, ComponentCreateView):
|
class ConsoleServerPortCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_consoleserverport'
|
permission_required = 'dcim.add_consoleserverport'
|
||||||
parent_model = Device
|
parent_model = Device
|
||||||
parent_field = 'device'
|
parent_field = 'device'
|
||||||
@@ -1116,6 +1197,15 @@ class ConsoleServerPortDeleteView(PermissionRequiredMixin, ComponentDeleteView):
|
|||||||
model = ConsoleServerPort
|
model = ConsoleServerPort
|
||||||
|
|
||||||
|
|
||||||
|
class ConsoleServerPortBulkDisconnectView(PermissionRequiredMixin, BulkDisconnectView):
|
||||||
|
permission_required = 'dcim.change_consoleserverport'
|
||||||
|
model = ConsoleServerPort
|
||||||
|
form = forms.ConsoleServerPortBulkDisconnectForm
|
||||||
|
|
||||||
|
def disconnect_objects(self, cs_ports):
|
||||||
|
return ConsolePort.objects.filter(cs_port__in=cs_ports).update(cs_port=None, connection_status=None)
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class ConsoleServerPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_consoleserverport'
|
permission_required = 'dcim.delete_consoleserverport'
|
||||||
cls = ConsoleServerPort
|
cls = ConsoleServerPort
|
||||||
@@ -1126,7 +1216,7 @@ class ConsoleServerPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
# Power ports
|
# Power ports
|
||||||
#
|
#
|
||||||
|
|
||||||
class PowerPortAddView(PermissionRequiredMixin, ComponentCreateView):
|
class PowerPortCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_powerport'
|
permission_required = 'dcim.add_powerport'
|
||||||
parent_model = Device
|
parent_model = Device
|
||||||
parent_field = 'device'
|
parent_field = 'device'
|
||||||
@@ -1239,7 +1329,7 @@ class PowerConnectionsBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|||||||
# Power outlets
|
# Power outlets
|
||||||
#
|
#
|
||||||
|
|
||||||
class PowerOutletAddView(PermissionRequiredMixin, ComponentCreateView):
|
class PowerOutletCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_poweroutlet'
|
permission_required = 'dcim.add_poweroutlet'
|
||||||
parent_model = Device
|
parent_model = Device
|
||||||
parent_field = 'device'
|
parent_field = 'device'
|
||||||
@@ -1338,6 +1428,17 @@ class PowerOutletDeleteView(PermissionRequiredMixin, ComponentDeleteView):
|
|||||||
model = PowerOutlet
|
model = PowerOutlet
|
||||||
|
|
||||||
|
|
||||||
|
class PowerOutletBulkDisconnectView(PermissionRequiredMixin, BulkDisconnectView):
|
||||||
|
permission_required = 'dcim.change_poweroutlet'
|
||||||
|
model = PowerOutlet
|
||||||
|
form = forms.PowerOutletBulkDisconnectForm
|
||||||
|
|
||||||
|
def disconnect_objects(self, power_outlets):
|
||||||
|
return PowerPort.objects.filter(power_outlet__in=power_outlets).update(
|
||||||
|
power_outlet=None, connection_status=None
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class PowerOutletBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'dcim.delete_poweroutlet'
|
permission_required = 'dcim.delete_poweroutlet'
|
||||||
cls = PowerOutlet
|
cls = PowerOutlet
|
||||||
@@ -1348,7 +1449,7 @@ class PowerOutletBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
# Interfaces
|
# Interfaces
|
||||||
#
|
#
|
||||||
|
|
||||||
class InterfaceAddView(PermissionRequiredMixin, ComponentCreateView):
|
class InterfaceCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_interface'
|
permission_required = 'dcim.add_interface'
|
||||||
parent_model = Device
|
parent_model = Device
|
||||||
parent_field = 'device'
|
parent_field = 'device'
|
||||||
@@ -1368,6 +1469,18 @@ class InterfaceDeleteView(PermissionRequiredMixin, ComponentDeleteView):
|
|||||||
model = Interface
|
model = Interface
|
||||||
|
|
||||||
|
|
||||||
|
class InterfaceBulkDisconnectView(PermissionRequiredMixin, BulkDisconnectView):
|
||||||
|
permission_required = 'dcim.change_interface'
|
||||||
|
model = Interface
|
||||||
|
form = forms.InterfaceBulkDisconnectForm
|
||||||
|
|
||||||
|
def disconnect_objects(self, interfaces):
|
||||||
|
count, _ = InterfaceConnection.objects.filter(
|
||||||
|
Q(interface_a__in=interfaces) | Q(interface_b__in=interfaces)
|
||||||
|
).delete()
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
class InterfaceBulkEditView(PermissionRequiredMixin, BulkEditView):
|
class InterfaceBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||||
permission_required = 'dcim.change_interface'
|
permission_required = 'dcim.change_interface'
|
||||||
cls = Interface
|
cls = Interface
|
||||||
@@ -1386,7 +1499,7 @@ class InterfaceBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
# Device bays
|
# Device bays
|
||||||
#
|
#
|
||||||
|
|
||||||
class DeviceBayAddView(PermissionRequiredMixin, ComponentCreateView):
|
class DeviceBayCreateView(PermissionRequiredMixin, ComponentCreateView):
|
||||||
permission_required = 'dcim.add_devicebay'
|
permission_required = 'dcim.add_devicebay'
|
||||||
parent_model = Device
|
parent_model = Device
|
||||||
parent_field = 'device'
|
parent_field = 'device'
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ class CustomFieldsSerializer(serializers.BaseSerializer):
|
|||||||
|
|
||||||
# Validate selected choice
|
# Validate selected choice
|
||||||
if cf.type == CF_TYPE_SELECT:
|
if cf.type == CF_TYPE_SELECT:
|
||||||
|
try:
|
||||||
|
value = int(value)
|
||||||
|
except ValueError:
|
||||||
|
raise ValidationError("{}: Choice selections must be passed as integers.".format(field_name))
|
||||||
valid_choices = [c.pk for c in cf.choices.all()]
|
valid_choices = [c.pk for c in cf.choices.all()]
|
||||||
if value not in valid_choices:
|
if value not in valid_choices:
|
||||||
raise ValidationError("Invalid choice for field {}: {}".format(field_name, value))
|
raise ValidationError("Invalid choice for field {}: {}".format(field_name, value))
|
||||||
|
|||||||
@@ -371,7 +371,8 @@ class TopologyMap(models.Model):
|
|||||||
# Add all circuits to the graph
|
# Add all circuits to the graph
|
||||||
for termination in CircuitTermination.objects.filter(term_side='A', interface__device__in=devices):
|
for termination in CircuitTermination.objects.filter(term_side='A', interface__device__in=devices):
|
||||||
peer_termination = termination.get_peer_termination()
|
peer_termination = termination.get_peer_termination()
|
||||||
if peer_termination is not None and peer_termination.interface.device in devices:
|
if (peer_termination is not None and peer_termination.interface is not None and
|
||||||
|
peer_termination.interface.device in devices):
|
||||||
graph.edge(termination.interface.device.name, peer_termination.interface.device.name, color='blue')
|
graph.edge(termination.interface.device.name, peer_termination.interface.device.name, color='blue')
|
||||||
|
|
||||||
return graph.pipe(format=img_format)
|
return graph.pipe(format=img_format)
|
||||||
@@ -386,7 +387,7 @@ def image_upload(instance, filename):
|
|||||||
path = 'image-attachments/'
|
path = 'image-attachments/'
|
||||||
|
|
||||||
# Rename the file to the provided name, if any. Attempt to preserve the file extension.
|
# Rename the file to the provided name, if any. Attempt to preserve the file extension.
|
||||||
extension = filename.rsplit('.')[-1]
|
extension = filename.rsplit('.')[-1].lower()
|
||||||
if instance.name and extension in ['bmp', 'gif', 'jpeg', 'jpg', 'png']:
|
if instance.name and extension in ['bmp', 'gif', 'jpeg', 'jpg', 'png']:
|
||||||
filename = '.'.join([instance.name, extension])
|
filename = '.'.join([instance.name, extension])
|
||||||
elif instance.name:
|
elif instance.name:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ImageAttachmentEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
|
|
||||||
|
|
||||||
class ImageAttachmentDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class ImageAttachmentDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'dcim.delete_imageattachment'
|
permission_required = 'extras.delete_imageattachment'
|
||||||
model = ImageAttachment
|
model = ImageAttachment
|
||||||
|
|
||||||
def get_return_url(self, request, imageattachment):
|
def get_return_url(self, request, imageattachment):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
from dcim.models import Site, Rack, Device, Interface
|
from dcim.models import Site, Rack, Device, Interface
|
||||||
@@ -301,6 +302,10 @@ class PrefixCSVForm(forms.ModelForm):
|
|||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
raise forms.ValidationError("Global VLAN {} not found in group {}".format(vlan_vid, vlan_group))
|
raise forms.ValidationError("Global VLAN {} not found in group {}".format(vlan_vid, vlan_group))
|
||||||
|
except MultipleObjectsReturned:
|
||||||
|
raise forms.ValidationError(
|
||||||
|
"Multiple VLANs with VID {} found in group {}".format(vlan_vid, vlan_group)
|
||||||
|
)
|
||||||
elif vlan_vid:
|
elif vlan_vid:
|
||||||
try:
|
try:
|
||||||
self.instance.vlan = VLAN.objects.get(site=site, group__isnull=True, vid=vlan_vid)
|
self.instance.vlan = VLAN.objects.get(site=site, group__isnull=True, vid=vlan_vid)
|
||||||
@@ -309,6 +314,8 @@ class PrefixCSVForm(forms.ModelForm):
|
|||||||
raise forms.ValidationError("VLAN {} not found in site {}".format(vlan_vid, site))
|
raise forms.ValidationError("VLAN {} not found in site {}".format(vlan_vid, site))
|
||||||
else:
|
else:
|
||||||
raise forms.ValidationError("Global VLAN {} not found".format(vlan_vid))
|
raise forms.ValidationError("Global VLAN {} not found".format(vlan_vid))
|
||||||
|
except MultipleObjectsReturned:
|
||||||
|
raise forms.ValidationError("Multiple VLANs with VID {} found".format(vlan_vid))
|
||||||
|
|
||||||
|
|
||||||
class PrefixBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
class PrefixBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||||
@@ -490,7 +497,7 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|||||||
initial['interface_site'] = instance.interface.device.site
|
initial['interface_site'] = instance.interface.device.site
|
||||||
initial['interface_rack'] = instance.interface.device.rack
|
initial['interface_rack'] = instance.interface.device.rack
|
||||||
initial['interface_device'] = instance.interface.device
|
initial['interface_device'] = instance.interface.device
|
||||||
if instance and instance.nat_inside is not None:
|
if instance and instance.nat_inside and instance.nat_inside.device is not None:
|
||||||
initial['nat_site'] = instance.nat_inside.device.site
|
initial['nat_site'] = instance.nat_inside.device.site
|
||||||
initial['nat_rack'] = instance.nat_inside.device.rack
|
initial['nat_rack'] = instance.nat_inside.device.rack
|
||||||
initial['nat_device'] = instance.nat_inside.device
|
initial['nat_device'] = instance.nat_inside.device
|
||||||
@@ -582,7 +589,7 @@ class IPAddressCSVForm(forms.ModelForm):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
status = CSVChoiceField(
|
status = CSVChoiceField(
|
||||||
choices=PREFIX_STATUS_CHOICES,
|
choices=IPADDRESS_STATUS_CHOICES,
|
||||||
help_text='Operational status'
|
help_text='Operational status'
|
||||||
)
|
)
|
||||||
device = FlexibleModelChoiceField(
|
device = FlexibleModelChoiceField(
|
||||||
@@ -634,16 +641,23 @@ class IPAddressCSVForm(forms.ModelForm):
|
|||||||
|
|
||||||
# Set interface
|
# Set interface
|
||||||
if self.cleaned_data['device'] and self.cleaned_data['interface_name']:
|
if self.cleaned_data['device'] and self.cleaned_data['interface_name']:
|
||||||
self.instance.interface = Interface.objects.get(device=self.cleaned_data['device'],
|
self.instance.interface = Interface.objects.get(
|
||||||
name=self.cleaned_data['interface_name'])
|
device=self.cleaned_data['device'],
|
||||||
|
name=self.cleaned_data['interface_name']
|
||||||
|
)
|
||||||
|
|
||||||
|
ipaddress = super(IPAddressCSVForm, self).save(*args, **kwargs)
|
||||||
|
|
||||||
# Set as primary for device
|
# Set as primary for device
|
||||||
if self.cleaned_data['is_primary']:
|
if self.cleaned_data['is_primary']:
|
||||||
|
device = self.cleaned_data['device']
|
||||||
if self.instance.address.version == 4:
|
if self.instance.address.version == 4:
|
||||||
self.instance.primary_ip4_for = self.cleaned_data['device']
|
device.primary_ip4 = ipaddress
|
||||||
elif self.instance.address.version == 6:
|
elif self.instance.address.version == 6:
|
||||||
self.instance.primary_ip6_for = self.cleaned_data['device']
|
device.primary_ip6 = ipaddress
|
||||||
|
device.save()
|
||||||
|
|
||||||
return super(IPAddressCSVForm, self).save(*args, **kwargs)
|
return ipaddress
|
||||||
|
|
||||||
|
|
||||||
class IPAddressBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
class IPAddressBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from netaddr import IPNetwork, cidr_merge
|
from netaddr import IPNetwork, IPSet
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.fields import GenericRelation
|
from django.contrib.contenttypes.fields import GenericRelation
|
||||||
@@ -206,13 +206,9 @@ class Aggregate(CreatedUpdatedModel, CustomFieldModel):
|
|||||||
"""
|
"""
|
||||||
Determine the prefix utilization of the aggregate and return it as a percentage.
|
Determine the prefix utilization of the aggregate and return it as a percentage.
|
||||||
"""
|
"""
|
||||||
child_prefixes = Prefix.objects.filter(prefix__net_contained_or_equal=str(self.prefix))
|
queryset = Prefix.objects.filter(prefix__net_contained_or_equal=str(self.prefix))
|
||||||
# Remove overlapping prefixes from list of children
|
child_prefixes = IPSet([p.prefix for p in queryset])
|
||||||
networks = cidr_merge([c.prefix for c in child_prefixes])
|
return int(float(child_prefixes.size) / self.prefix.size * 100)
|
||||||
children_size = float(0)
|
|
||||||
for p in networks:
|
|
||||||
children_size += p.size
|
|
||||||
return int(children_size / self.prefix.size * 100)
|
|
||||||
|
|
||||||
|
|
||||||
@python_2_unicode_compatible
|
@python_2_unicode_compatible
|
||||||
@@ -370,9 +366,17 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
|
|||||||
|
|
||||||
def get_utilization(self):
|
def get_utilization(self):
|
||||||
"""
|
"""
|
||||||
Determine the utilization of the prefix and return it as a percentage.
|
Determine the utilization of the prefix and return it as a percentage. For Prefixes with a status of
|
||||||
|
"container", calculate utilization based on child prefixes. For all others, count child IP addresses.
|
||||||
"""
|
"""
|
||||||
child_count = IPAddress.objects.filter(address__net_contained_or_equal=str(self.prefix), vrf=self.vrf).count()
|
if self.status == PREFIX_STATUS_CONTAINER:
|
||||||
|
queryset = Prefix.objects.filter(prefix__net_contained=str(self.prefix), vrf=self.vrf)
|
||||||
|
child_prefixes = IPSet([p.prefix for p in queryset])
|
||||||
|
return int(float(child_prefixes.size) / self.prefix.size * 100)
|
||||||
|
else:
|
||||||
|
child_count = IPAddress.objects.filter(
|
||||||
|
address__net_contained_or_equal=str(self.prefix), vrf=self.vrf
|
||||||
|
).count()
|
||||||
prefix_size = self.prefix.size
|
prefix_size = self.prefix.size
|
||||||
if self.family == 4 and self.prefix.prefixlen < 31 and not self.is_pool:
|
if self.family == 4 and self.prefix.prefixlen < 31 and not self.is_pool:
|
||||||
prefix_size -= 2
|
prefix_size -= 2
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ class PrefixTable(BaseTable):
|
|||||||
prefix = tables.TemplateColumn(PREFIX_LINK, attrs={'th': {'style': 'padding-left: 17px'}})
|
prefix = tables.TemplateColumn(PREFIX_LINK, attrs={'th': {'style': 'padding-left: 17px'}})
|
||||||
status = tables.TemplateColumn(STATUS_LABEL)
|
status = tables.TemplateColumn(STATUS_LABEL)
|
||||||
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
|
vrf = tables.TemplateColumn(VRF_LINK, verbose_name='VRF')
|
||||||
get_utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='IP Usage')
|
get_utilization = tables.TemplateColumn(UTILIZATION_GRAPH, orderable=False, verbose_name='Utilization')
|
||||||
tenant = tables.TemplateColumn(TENANT_LINK)
|
tenant = tables.TemplateColumn(TENANT_LINK)
|
||||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')])
|
||||||
vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')], verbose_name='VLAN')
|
vlan = tables.LinkColumn('ipam:vlan', args=[Accessor('vlan.pk')], verbose_name='VLAN')
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
# VRFs
|
# VRFs
|
||||||
url(r'^vrfs/$', views.VRFListView.as_view(), name='vrf_list'),
|
url(r'^vrfs/$', views.VRFListView.as_view(), name='vrf_list'),
|
||||||
url(r'^vrfs/add/$', views.VRFEditView.as_view(), name='vrf_add'),
|
url(r'^vrfs/add/$', views.VRFCreateView.as_view(), name='vrf_add'),
|
||||||
url(r'^vrfs/import/$', views.VRFBulkImportView.as_view(), name='vrf_import'),
|
url(r'^vrfs/import/$', views.VRFBulkImportView.as_view(), name='vrf_import'),
|
||||||
url(r'^vrfs/edit/$', views.VRFBulkEditView.as_view(), name='vrf_bulk_edit'),
|
url(r'^vrfs/edit/$', views.VRFBulkEditView.as_view(), name='vrf_bulk_edit'),
|
||||||
url(r'^vrfs/delete/$', views.VRFBulkDeleteView.as_view(), name='vrf_bulk_delete'),
|
url(r'^vrfs/delete/$', views.VRFBulkDeleteView.as_view(), name='vrf_bulk_delete'),
|
||||||
@@ -20,13 +20,13 @@ urlpatterns = [
|
|||||||
|
|
||||||
# RIRs
|
# RIRs
|
||||||
url(r'^rirs/$', views.RIRListView.as_view(), name='rir_list'),
|
url(r'^rirs/$', views.RIRListView.as_view(), name='rir_list'),
|
||||||
url(r'^rirs/add/$', views.RIREditView.as_view(), name='rir_add'),
|
url(r'^rirs/add/$', views.RIRCreateView.as_view(), name='rir_add'),
|
||||||
url(r'^rirs/delete/$', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'),
|
url(r'^rirs/delete/$', views.RIRBulkDeleteView.as_view(), name='rir_bulk_delete'),
|
||||||
url(r'^rirs/(?P<slug>[\w-]+)/edit/$', views.RIREditView.as_view(), name='rir_edit'),
|
url(r'^rirs/(?P<slug>[\w-]+)/edit/$', views.RIREditView.as_view(), name='rir_edit'),
|
||||||
|
|
||||||
# Aggregates
|
# Aggregates
|
||||||
url(r'^aggregates/$', views.AggregateListView.as_view(), name='aggregate_list'),
|
url(r'^aggregates/$', views.AggregateListView.as_view(), name='aggregate_list'),
|
||||||
url(r'^aggregates/add/$', views.AggregateEditView.as_view(), name='aggregate_add'),
|
url(r'^aggregates/add/$', views.AggregateCreateView.as_view(), name='aggregate_add'),
|
||||||
url(r'^aggregates/import/$', views.AggregateBulkImportView.as_view(), name='aggregate_import'),
|
url(r'^aggregates/import/$', views.AggregateBulkImportView.as_view(), name='aggregate_import'),
|
||||||
url(r'^aggregates/edit/$', views.AggregateBulkEditView.as_view(), name='aggregate_bulk_edit'),
|
url(r'^aggregates/edit/$', views.AggregateBulkEditView.as_view(), name='aggregate_bulk_edit'),
|
||||||
url(r'^aggregates/delete/$', views.AggregateBulkDeleteView.as_view(), name='aggregate_bulk_delete'),
|
url(r'^aggregates/delete/$', views.AggregateBulkDeleteView.as_view(), name='aggregate_bulk_delete'),
|
||||||
@@ -36,13 +36,13 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Roles
|
# Roles
|
||||||
url(r'^roles/$', views.RoleListView.as_view(), name='role_list'),
|
url(r'^roles/$', views.RoleListView.as_view(), name='role_list'),
|
||||||
url(r'^roles/add/$', views.RoleEditView.as_view(), name='role_add'),
|
url(r'^roles/add/$', views.RoleCreateView.as_view(), name='role_add'),
|
||||||
url(r'^roles/delete/$', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'),
|
url(r'^roles/delete/$', views.RoleBulkDeleteView.as_view(), name='role_bulk_delete'),
|
||||||
url(r'^roles/(?P<slug>[\w-]+)/edit/$', views.RoleEditView.as_view(), name='role_edit'),
|
url(r'^roles/(?P<slug>[\w-]+)/edit/$', views.RoleEditView.as_view(), name='role_edit'),
|
||||||
|
|
||||||
# Prefixes
|
# Prefixes
|
||||||
url(r'^prefixes/$', views.PrefixListView.as_view(), name='prefix_list'),
|
url(r'^prefixes/$', views.PrefixListView.as_view(), name='prefix_list'),
|
||||||
url(r'^prefixes/add/$', views.PrefixEditView.as_view(), name='prefix_add'),
|
url(r'^prefixes/add/$', views.PrefixCreateView.as_view(), name='prefix_add'),
|
||||||
url(r'^prefixes/import/$', views.PrefixBulkImportView.as_view(), name='prefix_import'),
|
url(r'^prefixes/import/$', views.PrefixBulkImportView.as_view(), name='prefix_import'),
|
||||||
url(r'^prefixes/edit/$', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'),
|
url(r'^prefixes/edit/$', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'),
|
||||||
url(r'^prefixes/delete/$', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'),
|
url(r'^prefixes/delete/$', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'),
|
||||||
@@ -53,8 +53,8 @@ urlpatterns = [
|
|||||||
|
|
||||||
# IP addresses
|
# IP addresses
|
||||||
url(r'^ip-addresses/$', views.IPAddressListView.as_view(), name='ipaddress_list'),
|
url(r'^ip-addresses/$', views.IPAddressListView.as_view(), name='ipaddress_list'),
|
||||||
url(r'^ip-addresses/add/$', views.IPAddressEditView.as_view(), name='ipaddress_add'),
|
url(r'^ip-addresses/add/$', views.IPAddressCreateView.as_view(), name='ipaddress_add'),
|
||||||
url(r'^ip-addresses/bulk-add/$', views.IPAddressBulkAddView.as_view(), name='ipaddress_bulk_add'),
|
url(r'^ip-addresses/bulk-add/$', views.IPAddressBulkCreateView.as_view(), name='ipaddress_bulk_add'),
|
||||||
url(r'^ip-addresses/import/$', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'),
|
url(r'^ip-addresses/import/$', views.IPAddressBulkImportView.as_view(), name='ipaddress_import'),
|
||||||
url(r'^ip-addresses/edit/$', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'),
|
url(r'^ip-addresses/edit/$', views.IPAddressBulkEditView.as_view(), name='ipaddress_bulk_edit'),
|
||||||
url(r'^ip-addresses/delete/$', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'),
|
url(r'^ip-addresses/delete/$', views.IPAddressBulkDeleteView.as_view(), name='ipaddress_bulk_delete'),
|
||||||
@@ -64,13 +64,13 @@ urlpatterns = [
|
|||||||
|
|
||||||
# VLAN groups
|
# VLAN groups
|
||||||
url(r'^vlan-groups/$', views.VLANGroupListView.as_view(), name='vlangroup_list'),
|
url(r'^vlan-groups/$', views.VLANGroupListView.as_view(), name='vlangroup_list'),
|
||||||
url(r'^vlan-groups/add/$', views.VLANGroupEditView.as_view(), name='vlangroup_add'),
|
url(r'^vlan-groups/add/$', views.VLANGroupCreateView.as_view(), name='vlangroup_add'),
|
||||||
url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'),
|
url(r'^vlan-groups/delete/$', views.VLANGroupBulkDeleteView.as_view(), name='vlangroup_bulk_delete'),
|
||||||
url(r'^vlan-groups/(?P<pk>\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'),
|
url(r'^vlan-groups/(?P<pk>\d+)/edit/$', views.VLANGroupEditView.as_view(), name='vlangroup_edit'),
|
||||||
|
|
||||||
# VLANs
|
# VLANs
|
||||||
url(r'^vlans/$', views.VLANListView.as_view(), name='vlan_list'),
|
url(r'^vlans/$', views.VLANListView.as_view(), name='vlan_list'),
|
||||||
url(r'^vlans/add/$', views.VLANEditView.as_view(), name='vlan_add'),
|
url(r'^vlans/add/$', views.VLANCreateView.as_view(), name='vlan_add'),
|
||||||
url(r'^vlans/import/$', views.VLANBulkImportView.as_view(), name='vlan_import'),
|
url(r'^vlans/import/$', views.VLANBulkImportView.as_view(), name='vlan_import'),
|
||||||
url(r'^vlans/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'),
|
url(r'^vlans/edit/$', views.VLANBulkEditView.as_view(), name='vlan_bulk_edit'),
|
||||||
url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'),
|
url(r'^vlans/delete/$', views.VLANBulkDeleteView.as_view(), name='vlan_bulk_delete'),
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from django.views.generic import View
|
|||||||
from dcim.models import Device
|
from dcim.models import Device
|
||||||
from utilities.paginator import EnhancedPaginator
|
from utilities.paginator import EnhancedPaginator
|
||||||
from utilities.views import (
|
from utilities.views import (
|
||||||
BulkAddView, BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
BulkCreateView, BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
|
||||||
)
|
)
|
||||||
from . import filters, forms, tables
|
from . import filters, forms, tables
|
||||||
from .models import (
|
from .models import (
|
||||||
@@ -114,14 +114,18 @@ class VRFView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class VRFEditView(PermissionRequiredMixin, ObjectEditView):
|
class VRFCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_vrf'
|
permission_required = 'ipam.add_vrf'
|
||||||
model = VRF
|
model = VRF
|
||||||
form_class = forms.VRFForm
|
form_class = forms.VRFForm
|
||||||
template_name = 'ipam/vrf_edit.html'
|
template_name = 'ipam/vrf_edit.html'
|
||||||
default_return_url = 'ipam:vrf_list'
|
default_return_url = 'ipam:vrf_list'
|
||||||
|
|
||||||
|
|
||||||
|
class VRFEditView(VRFCreateView):
|
||||||
|
permission_required = 'ipam.change_vrf'
|
||||||
|
|
||||||
|
|
||||||
class VRFDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class VRFDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'ipam.delete_vrf'
|
permission_required = 'ipam.delete_vrf'
|
||||||
model = VRF
|
model = VRF
|
||||||
@@ -239,8 +243,8 @@ class RIRListView(ObjectListView):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RIREditView(PermissionRequiredMixin, ObjectEditView):
|
class RIRCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_rir'
|
permission_required = 'ipam.add_rir'
|
||||||
model = RIR
|
model = RIR
|
||||||
form_class = forms.RIRForm
|
form_class = forms.RIRForm
|
||||||
|
|
||||||
@@ -248,6 +252,10 @@ class RIREditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('ipam:rir_list')
|
return reverse('ipam:rir_list')
|
||||||
|
|
||||||
|
|
||||||
|
class RIREditView(RIRCreateView):
|
||||||
|
permission_required = 'ipam.change_rir'
|
||||||
|
|
||||||
|
|
||||||
class RIRBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class RIRBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'ipam.delete_rir'
|
permission_required = 'ipam.delete_rir'
|
||||||
cls = RIR
|
cls = RIR
|
||||||
@@ -324,14 +332,18 @@ class AggregateView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class AggregateEditView(PermissionRequiredMixin, ObjectEditView):
|
class AggregateCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_aggregate'
|
permission_required = 'ipam.add_aggregate'
|
||||||
model = Aggregate
|
model = Aggregate
|
||||||
form_class = forms.AggregateForm
|
form_class = forms.AggregateForm
|
||||||
template_name = 'ipam/aggregate_edit.html'
|
template_name = 'ipam/aggregate_edit.html'
|
||||||
default_return_url = 'ipam:aggregate_list'
|
default_return_url = 'ipam:aggregate_list'
|
||||||
|
|
||||||
|
|
||||||
|
class AggregateEditView(AggregateCreateView):
|
||||||
|
permission_required = 'ipam.change_aggregate'
|
||||||
|
|
||||||
|
|
||||||
class AggregateDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class AggregateDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'ipam.delete_aggregate'
|
permission_required = 'ipam.delete_aggregate'
|
||||||
model = Aggregate
|
model = Aggregate
|
||||||
@@ -371,8 +383,8 @@ class RoleListView(ObjectListView):
|
|||||||
template_name = 'ipam/role_list.html'
|
template_name = 'ipam/role_list.html'
|
||||||
|
|
||||||
|
|
||||||
class RoleEditView(PermissionRequiredMixin, ObjectEditView):
|
class RoleCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_role'
|
permission_required = 'ipam.add_role'
|
||||||
model = Role
|
model = Role
|
||||||
form_class = forms.RoleForm
|
form_class = forms.RoleForm
|
||||||
|
|
||||||
@@ -380,6 +392,10 @@ class RoleEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('ipam:role_list')
|
return reverse('ipam:role_list')
|
||||||
|
|
||||||
|
|
||||||
|
class RoleEditView(RoleCreateView):
|
||||||
|
permission_required = 'ipam.change_role'
|
||||||
|
|
||||||
|
|
||||||
class RoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class RoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'ipam.delete_role'
|
permission_required = 'ipam.delete_role'
|
||||||
cls = Role
|
cls = Role
|
||||||
@@ -519,14 +535,18 @@ class PrefixIPAddressesView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class PrefixEditView(PermissionRequiredMixin, ObjectEditView):
|
class PrefixCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_prefix'
|
permission_required = 'ipam.add_prefix'
|
||||||
model = Prefix
|
model = Prefix
|
||||||
form_class = forms.PrefixForm
|
form_class = forms.PrefixForm
|
||||||
template_name = 'ipam/prefix_edit.html'
|
template_name = 'ipam/prefix_edit.html'
|
||||||
default_return_url = 'ipam:prefix_list'
|
default_return_url = 'ipam:prefix_list'
|
||||||
|
|
||||||
|
|
||||||
|
class PrefixEditView(PrefixCreateView):
|
||||||
|
permission_required = 'ipam.change_prefix'
|
||||||
|
|
||||||
|
|
||||||
class PrefixDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class PrefixDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'ipam.delete_prefix'
|
permission_required = 'ipam.delete_prefix'
|
||||||
model = Prefix
|
model = Prefix
|
||||||
@@ -612,21 +632,25 @@ class IPAddressView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class IPAddressEditView(PermissionRequiredMixin, ObjectEditView):
|
class IPAddressCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_ipaddress'
|
permission_required = 'ipam.add_ipaddress'
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
form_class = forms.IPAddressForm
|
form_class = forms.IPAddressForm
|
||||||
template_name = 'ipam/ipaddress_edit.html'
|
template_name = 'ipam/ipaddress_edit.html'
|
||||||
default_return_url = 'ipam:ipaddress_list'
|
default_return_url = 'ipam:ipaddress_list'
|
||||||
|
|
||||||
|
|
||||||
|
class IPAddressEditView(IPAddressCreateView):
|
||||||
|
permission_required = 'ipam.change_ipaddress'
|
||||||
|
|
||||||
|
|
||||||
class IPAddressDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class IPAddressDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'ipam.delete_ipaddress'
|
permission_required = 'ipam.delete_ipaddress'
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
default_return_url = 'ipam:ipaddress_list'
|
default_return_url = 'ipam:ipaddress_list'
|
||||||
|
|
||||||
|
|
||||||
class IPAddressBulkAddView(PermissionRequiredMixin, BulkAddView):
|
class IPAddressBulkCreateView(PermissionRequiredMixin, BulkCreateView):
|
||||||
permission_required = 'ipam.add_ipaddress'
|
permission_required = 'ipam.add_ipaddress'
|
||||||
pattern_form = forms.IPAddressPatternForm
|
pattern_form = forms.IPAddressPatternForm
|
||||||
model_form = forms.IPAddressBulkAddForm
|
model_form = forms.IPAddressBulkAddForm
|
||||||
@@ -641,19 +665,6 @@ class IPAddressBulkImportView(PermissionRequiredMixin, BulkImportView):
|
|||||||
table = tables.IPAddressTable
|
table = tables.IPAddressTable
|
||||||
default_return_url = 'ipam:ipaddress_list'
|
default_return_url = 'ipam:ipaddress_list'
|
||||||
|
|
||||||
def save_obj(self, obj):
|
|
||||||
obj.save()
|
|
||||||
|
|
||||||
# Update primary IP for device if needed. The Device must be updated directly in the database; otherwise we risk
|
|
||||||
# overwriting a previous IP assignment from the same import (see #861).
|
|
||||||
try:
|
|
||||||
if obj.family == 4 and obj.primary_ip4_for:
|
|
||||||
Device.objects.filter(pk=obj.primary_ip4_for.pk).update(primary_ip4=obj)
|
|
||||||
elif obj.family == 6 and obj.primary_ip6_for:
|
|
||||||
Device.objects.filter(pk=obj.primary_ip6_for.pk).update(primary_ip6=obj)
|
|
||||||
except Device.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
|
class IPAddressBulkEditView(PermissionRequiredMixin, BulkEditView):
|
||||||
permission_required = 'ipam.change_ipaddress'
|
permission_required = 'ipam.change_ipaddress'
|
||||||
@@ -683,8 +694,8 @@ class VLANGroupListView(ObjectListView):
|
|||||||
template_name = 'ipam/vlangroup_list.html'
|
template_name = 'ipam/vlangroup_list.html'
|
||||||
|
|
||||||
|
|
||||||
class VLANGroupEditView(PermissionRequiredMixin, ObjectEditView):
|
class VLANGroupCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_vlangroup'
|
permission_required = 'ipam.add_vlangroup'
|
||||||
model = VLANGroup
|
model = VLANGroup
|
||||||
form_class = forms.VLANGroupForm
|
form_class = forms.VLANGroupForm
|
||||||
|
|
||||||
@@ -692,6 +703,10 @@ class VLANGroupEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('ipam:vlangroup_list')
|
return reverse('ipam:vlangroup_list')
|
||||||
|
|
||||||
|
|
||||||
|
class VLANGroupEditView(VLANGroupCreateView):
|
||||||
|
permission_required = 'ipam.change_vlangroup'
|
||||||
|
|
||||||
|
|
||||||
class VLANGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class VLANGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'ipam.delete_vlangroup'
|
permission_required = 'ipam.delete_vlangroup'
|
||||||
cls = VLANGroup
|
cls = VLANGroup
|
||||||
@@ -728,14 +743,18 @@ class VLANView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class VLANEditView(PermissionRequiredMixin, ObjectEditView):
|
class VLANCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_vlan'
|
permission_required = 'ipam.add_vlan'
|
||||||
model = VLAN
|
model = VLAN
|
||||||
form_class = forms.VLANForm
|
form_class = forms.VLANForm
|
||||||
template_name = 'ipam/vlan_edit.html'
|
template_name = 'ipam/vlan_edit.html'
|
||||||
default_return_url = 'ipam:vlan_list'
|
default_return_url = 'ipam:vlan_list'
|
||||||
|
|
||||||
|
|
||||||
|
class VLANEditView(VLANCreateView):
|
||||||
|
permission_required = 'ipam.change_vlan'
|
||||||
|
|
||||||
|
|
||||||
class VLANDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class VLANDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'ipam.delete_vlan'
|
permission_required = 'ipam.delete_vlan'
|
||||||
model = VLAN
|
model = VLAN
|
||||||
@@ -769,8 +788,8 @@ class VLANBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
|||||||
# Services
|
# Services
|
||||||
#
|
#
|
||||||
|
|
||||||
class ServiceEditView(PermissionRequiredMixin, ObjectEditView):
|
class ServiceCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'ipam.change_service'
|
permission_required = 'ipam.add_service'
|
||||||
model = Service
|
model = Service
|
||||||
form_class = forms.ServiceForm
|
form_class = forms.ServiceForm
|
||||||
template_name = 'ipam/service_edit.html'
|
template_name = 'ipam/service_edit.html'
|
||||||
@@ -784,6 +803,10 @@ class ServiceEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return obj.device.get_absolute_url()
|
return obj.device.get_absolute_url()
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceEditView(ServiceCreateView):
|
||||||
|
permission_required = 'ipam.change_service'
|
||||||
|
|
||||||
|
|
||||||
class ServiceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class ServiceDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'ipam.delete_service'
|
permission_required = 'ipam.delete_service'
|
||||||
model = Service
|
model = Service
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ except ImportError:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
VERSION = '2.0.6'
|
VERSION = '2.0.8'
|
||||||
|
|
||||||
# Import required configuration parameters
|
# Import required configuration parameters
|
||||||
ALLOWED_HOSTS = DATABASE = SECRET_KEY = None
|
ALLOWED_HOSTS = DATABASE = SECRET_KEY = None
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var search_field = $('#id_livesearch');
|
var search_field = $('#id_livesearch');
|
||||||
var real_field = $('#id_' + search_field.attr('data-field'));
|
var real_field = $('#id_' + search_field.attr('data-field'));
|
||||||
|
var select_fields = $('#select select');
|
||||||
var search_key = search_field.attr('data-key');
|
var search_key = search_field.attr('data-key');
|
||||||
var label = search_field.attr('data-label');
|
var label = search_field.attr('data-label');
|
||||||
if (!label) {
|
if (!label) {
|
||||||
@@ -40,13 +41,22 @@ $(document).ready(function() {
|
|||||||
select: function(event, ui) {
|
select: function(event, ui) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
search_field.val(ui.item.label);
|
search_field.val(ui.item.label);
|
||||||
|
select_fields.val('');
|
||||||
|
select_fields.attr('disabled', 'disabled');
|
||||||
real_field.empty();
|
real_field.empty();
|
||||||
real_field.append($("<option></option>").attr('value', ui.item.value).text(ui.item.label));
|
real_field.append($("<option></option>").attr('value', ui.item.value).text(ui.item.label));
|
||||||
real_field.change();
|
real_field.change();
|
||||||
// If the field has a parent helper, reset the parent to no selection
|
// Disable parent selection fields
|
||||||
$('select[filter-for="' + real_field.attr('name') + '"]').val('');
|
// $('select[filter-for="' + real_field.attr('name') + '"]').val('');
|
||||||
},
|
},
|
||||||
minLength: 4,
|
minLength: 4,
|
||||||
delay: 500
|
delay: 500
|
||||||
});
|
});
|
||||||
|
|
||||||
|
search_field.change(function() {
|
||||||
|
if (!search_field.val()) {
|
||||||
|
select_fields.removeAttr('disabled');
|
||||||
|
select_fields.val('');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Secret roles
|
# Secret roles
|
||||||
url(r'^secret-roles/$', views.SecretRoleListView.as_view(), name='secretrole_list'),
|
url(r'^secret-roles/$', views.SecretRoleListView.as_view(), name='secretrole_list'),
|
||||||
url(r'^secret-roles/add/$', views.SecretRoleEditView.as_view(), name='secretrole_add'),
|
url(r'^secret-roles/add/$', views.SecretRoleCreateView.as_view(), name='secretrole_add'),
|
||||||
url(r'^secret-roles/delete/$', views.SecretRoleBulkDeleteView.as_view(), name='secretrole_bulk_delete'),
|
url(r'^secret-roles/delete/$', views.SecretRoleBulkDeleteView.as_view(), name='secretrole_bulk_delete'),
|
||||||
url(r'^secret-roles/(?P<slug>[\w-]+)/edit/$', views.SecretRoleEditView.as_view(), name='secretrole_edit'),
|
url(r'^secret-roles/(?P<slug>[\w-]+)/edit/$', views.SecretRoleEditView.as_view(), name='secretrole_edit'),
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ class SecretRoleListView(ObjectListView):
|
|||||||
template_name = 'secrets/secretrole_list.html'
|
template_name = 'secrets/secretrole_list.html'
|
||||||
|
|
||||||
|
|
||||||
class SecretRoleEditView(PermissionRequiredMixin, ObjectEditView):
|
class SecretRoleCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'secrets.change_secretrole'
|
permission_required = 'secrets.add_secretrole'
|
||||||
model = SecretRole
|
model = SecretRole
|
||||||
form_class = forms.SecretRoleForm
|
form_class = forms.SecretRoleForm
|
||||||
|
|
||||||
@@ -49,6 +49,10 @@ class SecretRoleEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('secrets:secretrole_list')
|
return reverse('secrets:secretrole_list')
|
||||||
|
|
||||||
|
|
||||||
|
class SecretRoleEditView(SecretRoleCreateView):
|
||||||
|
permission_required = 'secrets.change_secretrole'
|
||||||
|
|
||||||
|
|
||||||
class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'secrets.delete_secretrole'
|
permission_required = 'secrets.delete_secretrole'
|
||||||
cls = SecretRole
|
cls = SecretRole
|
||||||
|
|||||||
13
netbox/templates/dcim/bulk_disconnect.html
Normal file
13
netbox/templates/dcim/bulk_disconnect.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{% extends 'utilities/confirmation_form.html' %}
|
||||||
|
{% load helpers %}
|
||||||
|
|
||||||
|
{% block title %}Disconnect {{ obj_type_plural|bettertitle }}{% endblock %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
<p>Are you sure you want to disconnect all {{ selected_objects|length }} of these {{ obj_type_plural }} on <strong>{{ device }}</strong>?</p>
|
||||||
|
<ul>
|
||||||
|
{% for obj in selected_objects %}
|
||||||
|
<li>{{ obj }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
@@ -204,7 +204,7 @@
|
|||||||
None
|
None
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.add_service %}
|
{% if perms.ipam.add_service %}
|
||||||
<div class="panel-footer text-right">
|
<div class="panel-footer text-right">
|
||||||
<a href="{% url 'dcim:service_assign' device=device.pk %}" class="btn btn-xs btn-primary">
|
<a href="{% url 'dcim:service_assign' device=device.pk %}" class="btn btn-xs btn-primary">
|
||||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Assign service
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Assign service
|
||||||
@@ -424,12 +424,17 @@
|
|||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
{% if interfaces and perms.dcim.change_interface %}
|
{% if interfaces and perms.dcim.change_interface %}
|
||||||
<button type="submit" name="_edit" formaction="{% url 'dcim:interface_bulk_edit' pk=device.pk %}" class="btn btn-warning btn-xs">
|
<button type="submit" name="_edit" formaction="{% url 'dcim:interface_bulk_edit' pk=device.pk %}" class="btn btn-warning btn-xs">
|
||||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit selected
|
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
|
{% if interfaces and perms.dcim.delete_interfaceconnection %}
|
||||||
|
<button type="submit" name="_disconnect" formaction="{% url 'dcim:interface_bulk_disconnect' pk=device.pk %}" class="btn btn-danger btn-xs">
|
||||||
|
<span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if interfaces and perms.dcim.delete_interface %}
|
{% if interfaces and perms.dcim.delete_interface %}
|
||||||
<button type="submit" name="_delete" formaction="{% url 'dcim:interface_bulk_delete' pk=device.pk %}" class="btn btn-danger btn-xs">
|
<button type="submit" name="_delete" formaction="{% url 'dcim:interface_bulk_delete' pk=device.pk %}" class="btn btn-danger btn-xs">
|
||||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete selected
|
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.add_interface %}
|
{% if perms.dcim.add_interface %}
|
||||||
@@ -479,9 +484,14 @@
|
|||||||
</table>
|
</table>
|
||||||
{% if perms.dcim.add_consoleserverport or perms.dcim.delete_consoleserverport %}
|
{% if perms.dcim.add_consoleserverport or perms.dcim.delete_consoleserverport %}
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
|
{% if cs_ports and perms.dcim.change_consoleport %}
|
||||||
|
<button type="submit" name="_disconnect" formaction="{% url 'dcim:consoleserverport_bulk_disconnect' pk=device.pk %}" class="btn btn-danger btn-xs">
|
||||||
|
<span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
{% if cs_ports and perms.dcim.delete_consoleserverport %}
|
{% if cs_ports and perms.dcim.delete_consoleserverport %}
|
||||||
<button type="submit" class="btn btn-danger btn-xs">
|
<button type="submit" class="btn btn-danger btn-xs">
|
||||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete selected
|
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.add_consoleserverport %}
|
{% if perms.dcim.add_consoleserverport %}
|
||||||
@@ -531,9 +541,14 @@
|
|||||||
</table>
|
</table>
|
||||||
{% if perms.dcim.add_poweroutlet or perms.dcim.delete_poweroutlet %}
|
{% if perms.dcim.add_poweroutlet or perms.dcim.delete_poweroutlet %}
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
|
{% if power_outlets and perms.dcim.change_powerport %}
|
||||||
|
<button type="submit" name="_disconnect" formaction="{% url 'dcim:poweroutlet_bulk_disconnect' pk=device.pk %}" class="btn btn-danger btn-xs">
|
||||||
|
<span class="glyphicon glyphicon-resize-full" aria-hidden="true"></span> Disconnect
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
{% if power_outlets and perms.dcim.delete_poweroutlet %}
|
{% if power_outlets and perms.dcim.delete_poweroutlet %}
|
||||||
<button type="submit" class="btn btn-danger btn-xs">
|
<button type="submit" class="btn btn-danger btn-xs">
|
||||||
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete selected
|
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span> Delete
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.add_poweroutlet %}
|
{% if perms.dcim.add_poweroutlet %}
|
||||||
@@ -576,7 +591,7 @@ function toggleConnection(elem, api_url) {
|
|||||||
success: function() {
|
success: function() {
|
||||||
elem.parents('tr').removeClass('success').addClass('info');
|
elem.parents('tr').removeClass('success').addClass('info');
|
||||||
elem.removeClass('connected btn-warning').addClass('btn-success');
|
elem.removeClass('connected btn-warning').addClass('btn-success');
|
||||||
elem.attr('title', 'Mark connected');
|
elem.attr('title', 'Mark installed');
|
||||||
elem.children('i').removeClass('glyphicon glyphicon-ban-circle').addClass('fa fa-plug')
|
elem.children('i').removeClass('glyphicon glyphicon-ban-circle').addClass('fa fa-plug')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -595,7 +610,7 @@ function toggleConnection(elem, api_url) {
|
|||||||
success: function() {
|
success: function() {
|
||||||
elem.parents('tr').removeClass('info').addClass('success');
|
elem.parents('tr').removeClass('info').addClass('success');
|
||||||
elem.removeClass('btn-success').addClass('connected btn-warning');
|
elem.removeClass('btn-success').addClass('connected btn-warning');
|
||||||
elem.attr('title', 'Mark disconnected');
|
elem.attr('title', 'Mark planned');
|
||||||
elem.children('i').removeClass('fa fa-plug').addClass('glyphicon glyphicon-ban-circle')
|
elem.children('i').removeClass('fa fa-plug').addClass('glyphicon glyphicon-ban-circle')
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,24 +24,24 @@
|
|||||||
{% if perms.dcim.change_consoleport %}
|
{% if perms.dcim.change_consoleport %}
|
||||||
{% if cp.cs_port %}
|
{% if cp.cs_port %}
|
||||||
{% if cp.connection_status %}
|
{% if cp.connection_status %}
|
||||||
<a href="#" class="btn btn-warning btn-xs consoleport-toggle connected" data="{{ cp.pk }}">
|
<a href="#" class="btn btn-warning btn-xs consoleport-toggle connected" title="Mark planned" data="{{ cp.pk }}">
|
||||||
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true" title="Mark planned"></i>
|
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="#" class="btn btn-success btn-xs consoleport-toggle" data="{{ cp.pk }}">
|
<a href="#" class="btn btn-success btn-xs consoleport-toggle" title="Mark installed" data="{{ cp.pk }}">
|
||||||
<i class="fa fa-plug" aria-hidden="true" title="Mark connected"></i>
|
<i class="fa fa-plug" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleport_disconnect' pk=cp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:consoleport_disconnect' pk=cp.pk %}" title="Delete connection" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:consoleport_connect' pk=cp.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:consoleport_connect' pk=cp.pk %}" title="Connect" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleport_edit' pk=cp.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:consoleport_edit' pk=cp.pk %}" title="Edit port" class="btn btn-info btn-xs">
|
||||||
<i class="glyphicon glyphicon-pencil" aria-hidden="true" title="Edit port"></i>
|
<i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.delete_consoleport %}
|
{% if perms.dcim.delete_consoleport %}
|
||||||
@@ -50,8 +50,8 @@
|
|||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:consoleport_delete' pk=cp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:consoleport_delete' pk=cp.pk %}" title="Delete port" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete port"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -24,24 +24,24 @@
|
|||||||
{% if perms.dcim.change_consoleserverport %}
|
{% if perms.dcim.change_consoleserverport %}
|
||||||
{% if csp.connected_console %}
|
{% if csp.connected_console %}
|
||||||
{% if csp.connected_console.connection_status %}
|
{% if csp.connected_console.connection_status %}
|
||||||
<a href="#" class="btn btn-warning btn-xs consoleport-toggle connected" data="{{ csp.connected_console.pk }}">
|
<a href="#" class="btn btn-warning btn-xs consoleport-toggle connected" title="Mark planned" data="{{ csp.connected_console.pk }}">
|
||||||
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true" title="Mark planned"></i>
|
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="#" class="btn btn-success btn-xs consoleport-toggle" data="{{ csp.connected_console.pk }}">
|
<a href="#" class="btn btn-success btn-xs consoleport-toggle" title="Mark installed" data="{{ csp.connected_console.pk }}">
|
||||||
<i class="fa fa-plug" aria-hidden="true" title="Mark connected"></i>
|
<i class="fa fa-plug" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleserverport_disconnect' pk=csp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:consoleserverport_disconnect' pk=csp.pk %}" title="Delete connection" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:consoleserverport_connect' pk=csp.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:consoleserverport_connect' pk=csp.pk %}" title="Connect" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:consoleserverport_edit' pk=csp.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:consoleserverport_edit' pk=csp.pk %}" title="Edit port" class="btn btn-info btn-xs">
|
||||||
<i class="glyphicon glyphicon-pencil" aria-hidden="true" title="Edit port"></i>
|
<i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.delete_consoleserverport %}
|
{% if perms.dcim.delete_consoleserverport %}
|
||||||
@@ -50,8 +50,8 @@
|
|||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:consoleserverport_delete' pk=csp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:consoleserverport_delete' pk=csp.pk %}" title="Delete port" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete port"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
<ul class="nav nav-tabs" style="margin-bottom: 20px">
|
<ul class="nav nav-tabs" style="margin-bottom: 20px">
|
||||||
<li role="presentation"{% if active_tab == 'info' %} class="active"{% endif %}><a href="{% url 'dcim:device' pk=device.pk %}">Info</a></li>
|
<li role="presentation"{% if active_tab == 'info' %} class="active"{% endif %}><a href="{% url 'dcim:device' pk=device.pk %}">Info</a></li>
|
||||||
<li role="presentation"{% if active_tab == 'inventory' %} class="active"{% endif %}><a href="{% url 'dcim:device_inventory' pk=device.pk %}">Inventory</a></li>
|
<li role="presentation"{% if active_tab == 'inventory' %} class="active"{% endif %}><a href="{% url 'dcim:device_inventory' pk=device.pk %}">Inventory</a></li>
|
||||||
{% if device.status %}
|
{% if device.status == 1 and device.platform.rpc_client and device.primary_ip %}
|
||||||
<li role="presentation"{% if active_tab == 'lldp-neighbors' %} class="active"{% endif %}><a href="{% url 'dcim:device_lldp_neighbors' pk=device.pk %}">LLDP Neighbors</a></li>
|
<li role="presentation"{% if active_tab == 'lldp-neighbors' %} class="active"{% endif %}><a href="{% url 'dcim:device_lldp_neighbors' pk=device.pk %}">LLDP Neighbors</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<tr class="interface{% if iface.connection and not iface.connection.connection_status %} info{% endif %}">
|
<tr class="interface{% if iface.connection and iface.connection.connection_status %} success{% elif iface.connection and not iface.connection.connection_status %} info{% endif %}">
|
||||||
{% if selectable and perms.dcim.change_interface or perms.dcim.delete_interface %}
|
{% if selectable and perms.dcim.change_interface or perms.dcim.delete_interface %}
|
||||||
<td class="pk">
|
<td class="pk">
|
||||||
<input name="pk" type="checkbox" value="{{ iface.pk }}" />
|
<input name="pk" type="checkbox" value="{{ iface.pk }}" />
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true"></i>
|
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="#" class="btn btn-success btn-xs interface-toggle" data="{{ iface.connection.pk }}" title="Mark connected">
|
<a href="#" class="btn btn-success btn-xs interface-toggle" data="{{ iface.connection.pk }}" title="Mark installed">
|
||||||
<i class="fa fa-plug" aria-hidden="true"></i>
|
<i class="fa fa-plug" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -24,24 +24,24 @@
|
|||||||
{% if perms.dcim.change_poweroutlet %}
|
{% if perms.dcim.change_poweroutlet %}
|
||||||
{% if po.connected_port %}
|
{% if po.connected_port %}
|
||||||
{% if po.connected_port.connection_status %}
|
{% if po.connected_port.connection_status %}
|
||||||
<a href="#" class="btn btn-warning btn-xs powerport-toggle connected" data="{{ po.connected_port.pk }}">
|
<a href="#" class="btn btn-warning btn-xs powerport-toggle connected" title="Mark planned" data="{{ po.connected_port.pk }}">
|
||||||
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true" title="Mark planned"></i>
|
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="#" class="btn btn-success btn-xs consoleport-toggle" data="{{ po.connected_port.pk }}">
|
<a href="#" class="btn btn-success btn-xs consoleport-toggle" title="Mark installed" data="{{ po.connected_port.pk }}">
|
||||||
<i class="fa fa-plug" aria-hidden="true" title="Mark connected"></i>
|
<i class="fa fa-plug" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:poweroutlet_disconnect' pk=po.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:poweroutlet_disconnect' pk=po.pk %}" title="Delete connection" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:poweroutlet_connect' pk=po.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:poweroutlet_connect' pk=po.pk %}" title="Connect" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:poweroutlet_edit' pk=po.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:poweroutlet_edit' pk=po.pk %}" title="Edit outlet" class="btn btn-info btn-xs">
|
||||||
<i class="glyphicon glyphicon-pencil" aria-hidden="true" title="Edit outlet"></i>
|
<i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.delete_poweroutlet %}
|
{% if perms.dcim.delete_poweroutlet %}
|
||||||
@@ -50,8 +50,8 @@
|
|||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:poweroutlet_delete' pk=po.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:poweroutlet_delete' pk=po.pk %}" title="Delete outlet" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete outlet"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -24,24 +24,24 @@
|
|||||||
{% if perms.dcim.change_powerport %}
|
{% if perms.dcim.change_powerport %}
|
||||||
{% if pp.power_outlet %}
|
{% if pp.power_outlet %}
|
||||||
{% if pp.connection_status %}
|
{% if pp.connection_status %}
|
||||||
<a href="#" class="btn btn-warning btn-xs powerport-toggle connected" data="{{ pp.pk }}">
|
<a href="#" class="btn btn-warning btn-xs powerport-toggle connected" title="Mark planned" data="{{ pp.pk }}">
|
||||||
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true" title="Mark planned"></i>
|
<i class="glyphicon glyphicon-ban-circle" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="#" class="btn btn-success btn-xs powerport-toggle" data="{{ pp.pk }}">
|
<a href="#" class="btn btn-success btn-xs powerport-toggle" title="Mark installed" data="{{ pp.pk }}">
|
||||||
<i class="fa fa-plug" aria-hidden="true" title="Mark connected"></i>
|
<i class="fa fa-plug" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:powerport_disconnect' pk=pp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:powerport_disconnect' pk=pp.pk %}" title="Delete connection" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-full" aria-hidden="true" title="Delete connection"></i>
|
<i class="glyphicon glyphicon-resize-full" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:powerport_connect' pk=pp.pk %}" class="btn btn-success btn-xs">
|
<a href="{% url 'dcim:powerport_connect' pk=pp.pk %}" title="Connect" class="btn btn-success btn-xs">
|
||||||
<i class="glyphicon glyphicon-resize-small" aria-hidden="true" title="Connect"></i>
|
<i class="glyphicon glyphicon-resize-small" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{% url 'dcim:powerport_edit' pk=pp.pk %}" class="btn btn-info btn-xs">
|
<a href="{% url 'dcim:powerport_edit' pk=pp.pk %}" title="Edit port" class="btn btn-info btn-xs">
|
||||||
<i class="glyphicon glyphicon-pencil" aria-hidden="true" title="Edit port"></i>
|
<i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if perms.dcim.delete_powerport %}
|
{% if perms.dcim.delete_powerport %}
|
||||||
@@ -50,8 +50,8 @@
|
|||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{% url 'dcim:powerport_delete' pk=pp.pk %}" class="btn btn-danger btn-xs">
|
<a href="{% url 'dcim:powerport_delete' pk=pp.pk %}" title="Delete port" class="btn btn-danger btn-xs">
|
||||||
<i class="glyphicon glyphicon-trash" aria-hidden="true" title="Delete port"></i>
|
<i class="glyphicon glyphicon-trash" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -19,6 +19,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</h4>
|
</h4>
|
||||||
{% include 'inc/created_updated.html' with obj=userkey %}
|
{% include 'inc/created_updated.html' with obj=userkey %}
|
||||||
|
{% if not userkey.is_active %}
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
<i class="fa fa-warning"></i>
|
||||||
|
Your user key is inactive. Ask an administrator to enable it for you.
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<pre>{{ userkey.public_key }}</pre>
|
<pre>{{ userkey.public_key }}</pre>
|
||||||
<hr />
|
<hr />
|
||||||
{% if userkey.session_key %}
|
{% if userkey.session_key %}
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ urlpatterns = [
|
|||||||
|
|
||||||
# Tenant groups
|
# Tenant groups
|
||||||
url(r'^tenant-groups/$', views.TenantGroupListView.as_view(), name='tenantgroup_list'),
|
url(r'^tenant-groups/$', views.TenantGroupListView.as_view(), name='tenantgroup_list'),
|
||||||
url(r'^tenant-groups/add/$', views.TenantGroupEditView.as_view(), name='tenantgroup_add'),
|
url(r'^tenant-groups/add/$', views.TenantGroupCreateView.as_view(), name='tenantgroup_add'),
|
||||||
url(r'^tenant-groups/delete/$', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'),
|
url(r'^tenant-groups/delete/$', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'),
|
||||||
url(r'^tenant-groups/(?P<slug>[\w-]+)/edit/$', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
|
url(r'^tenant-groups/(?P<slug>[\w-]+)/edit/$', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'),
|
||||||
|
|
||||||
# Tenants
|
# Tenants
|
||||||
url(r'^tenants/$', views.TenantListView.as_view(), name='tenant_list'),
|
url(r'^tenants/$', views.TenantListView.as_view(), name='tenant_list'),
|
||||||
url(r'^tenants/add/$', views.TenantEditView.as_view(), name='tenant_add'),
|
url(r'^tenants/add/$', views.TenantCreateView.as_view(), name='tenant_add'),
|
||||||
url(r'^tenants/import/$', views.TenantBulkImportView.as_view(), name='tenant_import'),
|
url(r'^tenants/import/$', views.TenantBulkImportView.as_view(), name='tenant_import'),
|
||||||
url(r'^tenants/edit/$', views.TenantBulkEditView.as_view(), name='tenant_bulk_edit'),
|
url(r'^tenants/edit/$', views.TenantBulkEditView.as_view(), name='tenant_bulk_edit'),
|
||||||
url(r'^tenants/delete/$', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'),
|
url(r'^tenants/delete/$', views.TenantBulkDeleteView.as_view(), name='tenant_bulk_delete'),
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class TenantGroupListView(ObjectListView):
|
|||||||
template_name = 'tenancy/tenantgroup_list.html'
|
template_name = 'tenancy/tenantgroup_list.html'
|
||||||
|
|
||||||
|
|
||||||
class TenantGroupEditView(PermissionRequiredMixin, ObjectEditView):
|
class TenantGroupCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'tenancy.change_tenantgroup'
|
permission_required = 'tenancy.add_tenantgroup'
|
||||||
model = TenantGroup
|
model = TenantGroup
|
||||||
form_class = forms.TenantGroupForm
|
form_class = forms.TenantGroupForm
|
||||||
|
|
||||||
@@ -35,6 +35,10 @@ class TenantGroupEditView(PermissionRequiredMixin, ObjectEditView):
|
|||||||
return reverse('tenancy:tenantgroup_list')
|
return reverse('tenancy:tenantgroup_list')
|
||||||
|
|
||||||
|
|
||||||
|
class TenantGroupEditView(TenantGroupCreateView):
|
||||||
|
permission_required = 'tenancy.change_tenantgroup'
|
||||||
|
|
||||||
|
|
||||||
class TenantGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
class TenantGroupBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
|
||||||
permission_required = 'tenancy.delete_tenantgroup'
|
permission_required = 'tenancy.delete_tenantgroup'
|
||||||
cls = TenantGroup
|
cls = TenantGroup
|
||||||
@@ -81,14 +85,18 @@ class TenantView(View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class TenantEditView(PermissionRequiredMixin, ObjectEditView):
|
class TenantCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||||
permission_required = 'tenancy.change_tenant'
|
permission_required = 'tenancy.add_tenant'
|
||||||
model = Tenant
|
model = Tenant
|
||||||
form_class = forms.TenantForm
|
form_class = forms.TenantForm
|
||||||
template_name = 'tenancy/tenant_edit.html'
|
template_name = 'tenancy/tenant_edit.html'
|
||||||
default_return_url = 'tenancy:tenant_list'
|
default_return_url = 'tenancy:tenant_list'
|
||||||
|
|
||||||
|
|
||||||
|
class TenantEditView(TenantCreateView):
|
||||||
|
permission_required = 'tenancy.change_tenant'
|
||||||
|
|
||||||
|
|
||||||
class TenantDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
class TenantDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
||||||
permission_required = 'tenancy.delete_tenant'
|
permission_required = 'tenancy.delete_tenant'
|
||||||
model = Tenant
|
model = Tenant
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ class CSVDataField(forms.CharField):
|
|||||||
reader = csv.reader(value.splitlines())
|
reader = csv.reader(value.splitlines())
|
||||||
|
|
||||||
# Consume and valdiate the first line of CSV data as column headers
|
# Consume and valdiate the first line of CSV data as column headers
|
||||||
headers = reader.next()
|
headers = next(reader)
|
||||||
for f in self.required_fields:
|
for f in self.required_fields:
|
||||||
if f not in headers:
|
if f not in headers:
|
||||||
raise forms.ValidationError('Required column header "{}" not found.'.format(f))
|
raise forms.ValidationError('Required column header "{}" not found.'.format(f))
|
||||||
@@ -489,6 +489,12 @@ class ChainedFieldsMixin(forms.BaseForm):
|
|||||||
|
|
||||||
if filters_dict:
|
if filters_dict:
|
||||||
field.queryset = field.queryset.filter(**filters_dict)
|
field.queryset = field.queryset.filter(**filters_dict)
|
||||||
|
elif not self.is_bound and self.instance and hasattr(self.instance, field_name):
|
||||||
|
obj = getattr(self.instance, field_name)
|
||||||
|
if obj is not None:
|
||||||
|
field.queryset = field.queryset.filter(pk=obj.pk)
|
||||||
|
else:
|
||||||
|
field.queryset = field.queryset.none()
|
||||||
elif not self.is_bound:
|
elif not self.is_bound:
|
||||||
field.queryset = field.queryset.none()
|
field.queryset = field.queryset.none()
|
||||||
|
|
||||||
|
|||||||
@@ -234,7 +234,7 @@ class ObjectDeleteView(GetReturnURLMixin, View):
|
|||||||
"""
|
"""
|
||||||
Delete a single object.
|
Delete a single object.
|
||||||
|
|
||||||
model: The model of the object being edited
|
model: The model of the object being deleted
|
||||||
template_name: The name of the template
|
template_name: The name of the template
|
||||||
default_return_url: Name of the URL to which the user is redirected after deleting the object
|
default_return_url: Name of the URL to which the user is redirected after deleting the object
|
||||||
"""
|
"""
|
||||||
@@ -290,7 +290,7 @@ class ObjectDeleteView(GetReturnURLMixin, View):
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
class BulkAddView(View):
|
class BulkCreateView(View):
|
||||||
"""
|
"""
|
||||||
Create new objects in bulk.
|
Create new objects in bulk.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user