mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-16 04:02:52 -06:00
Merge branch 'develop' into v2-develop
Conflicts: netbox/circuits/models.py netbox/netbox/settings.py upgrade.sh
This commit is contained in:
commit
f73693206f
@ -6,6 +6,7 @@ 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
|
# apt-get install -y python3 python3-dev python3-pip libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev
|
||||||
|
# update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Python 2:
|
Python 2:
|
||||||
@ -22,6 +23,7 @@ Python 3:
|
|||||||
# yum install -y epel-release
|
# yum install -y epel-release
|
||||||
# yum install -y gcc python34 python34-devel python34-setuptools libxml2-devel libxslt-devel libffi-devel graphviz openssl-devel
|
# yum install -y gcc python34 python34-devel python34-setuptools libxml2-devel libxslt-devel libffi-devel graphviz openssl-devel
|
||||||
# easy_install-3.4 pip
|
# easy_install-3.4 pip
|
||||||
|
# ln -s -f python3.4 /usr/bin/python
|
||||||
```
|
```
|
||||||
|
|
||||||
Python 2:
|
Python 2:
|
||||||
@ -84,6 +86,14 @@ Checking connectivity... done.
|
|||||||
|
|
||||||
Install the required Python packages using pip. (If you encounter any compilation errors during this step, ensure that you've installed all of the system dependencies listed above.)
|
Install the required Python packages using pip. (If you encounter any compilation errors during this step, ensure that you've installed all of the system dependencies listed above.)
|
||||||
|
|
||||||
|
Python 3:
|
||||||
|
|
||||||
|
```no-highlight
|
||||||
|
# pip3 install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Python 2:
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# pip install -r requirements.txt
|
# pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
@ -173,7 +183,7 @@ Superuser created successfully.
|
|||||||
# Collect Static Files
|
# Collect Static Files
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# ./manage.py collectstatic
|
# ./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:
|
||||||
|
@ -5,13 +5,14 @@ NetBox requires a PostgreSQL database to store data. (Please note that MySQL is
|
|||||||
**Debian/Ubuntu**
|
**Debian/Ubuntu**
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# apt-get install -y postgresql libpq-dev python-psycopg2
|
# apt-get update
|
||||||
|
# apt-get install -y postgresql libpq-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
**CentOS/RHEL**
|
**CentOS/RHEL**
|
||||||
|
|
||||||
```no-highlight
|
```no-highlight
|
||||||
# yum install -y postgresql postgresql-server postgresql-devel python-psycopg2
|
# yum install -y postgresql postgresql-server postgresql-devel
|
||||||
# postgresql-setup initdb
|
# postgresql-setup initdb
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.11 on 2017-04-19 17:17
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('circuits', '0007_circuit_add_description'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='circuittermination',
|
||||||
|
name='interface',
|
||||||
|
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_termination', to='dcim.Interface'),
|
||||||
|
),
|
||||||
|
]
|
@ -151,11 +151,13 @@ class CircuitTermination(models.Model):
|
|||||||
term_side = models.CharField(max_length=1, choices=TERM_SIDE_CHOICES, verbose_name='Termination')
|
term_side = models.CharField(max_length=1, choices=TERM_SIDE_CHOICES, verbose_name='Termination')
|
||||||
site = models.ForeignKey('dcim.Site', related_name='circuit_terminations', on_delete=models.PROTECT)
|
site = models.ForeignKey('dcim.Site', related_name='circuit_terminations', on_delete=models.PROTECT)
|
||||||
interface = models.OneToOneField(
|
interface = models.OneToOneField(
|
||||||
'dcim.Interface', related_name='circuit_termination', blank=True, null=True, on_delete=models.CASCADE
|
'dcim.Interface', related_name='circuit_termination', blank=True, null=True, on_delete=models.PROTECT
|
||||||
)
|
)
|
||||||
port_speed = models.PositiveIntegerField(verbose_name='Port speed (Kbps)')
|
port_speed = models.PositiveIntegerField(verbose_name='Port speed (Kbps)')
|
||||||
upstream_speed = models.PositiveIntegerField(blank=True, null=True, verbose_name='Upstream speed (Kbps)',
|
upstream_speed = models.PositiveIntegerField(
|
||||||
help_text='Upstream speed, if different from port speed')
|
blank=True, null=True, verbose_name='Upstream speed (Kbps)',
|
||||||
|
help_text='Upstream speed, if different from port speed'
|
||||||
|
)
|
||||||
xconnect_id = models.CharField(max_length=50, blank=True, verbose_name='Cross-connect ID')
|
xconnect_id = models.CharField(max_length=50, blank=True, verbose_name='Cross-connect ID')
|
||||||
pp_info = models.CharField(max_length=100, blank=True, verbose_name='Patch panel/port(s)')
|
pp_info = models.CharField(max_length=100, blank=True, verbose_name='Patch panel/port(s)')
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# This script will generate a random 50-character string suitable for use as a SECRET_KEY.
|
# This script will generate a random 50-character string suitable for use as a SECRET_KEY.
|
||||||
import os
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(-_=+)'
|
charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(-_=+)'
|
||||||
random.seed = (os.urandom(2048))
|
secure_random = random.SystemRandom()
|
||||||
print(''.join(random.choice(charset) for c in range(50)))
|
print(''.join(secure_random.sample(charset, 50)))
|
||||||
|
@ -418,12 +418,15 @@ class IPAddressForm(BootstrapMixin, ReturnURLForm, CustomFieldForm):
|
|||||||
self.fields['nat_inside'].choices = []
|
self.fields['nat_inside'].choices = []
|
||||||
|
|
||||||
|
|
||||||
class IPAddressBulkAddForm(BootstrapMixin, forms.Form):
|
class IPAddressBulkAddForm(BootstrapMixin, CustomFieldForm):
|
||||||
address = ExpandableIPAddressField()
|
address_pattern = ExpandableIPAddressField(label='Address Pattern')
|
||||||
vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', empty_label='Global')
|
vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', empty_label='Global')
|
||||||
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
||||||
status = forms.ChoiceField(choices=IPADDRESS_STATUS_CHOICES)
|
pattern_map = ('address_pattern', 'address')
|
||||||
description = forms.CharField(max_length=100, required=False)
|
|
||||||
|
class Meta:
|
||||||
|
model = IPAddress
|
||||||
|
fields = ['address_pattern', 'vrf', 'tenant', 'status', 'description']
|
||||||
|
|
||||||
|
|
||||||
class IPAddressAssignForm(BootstrapMixin, forms.Form):
|
class IPAddressAssignForm(BootstrapMixin, forms.Form):
|
||||||
|
@ -588,7 +588,7 @@ class IPAddressDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
|||||||
class IPAddressBulkAddView(PermissionRequiredMixin, BulkAddView):
|
class IPAddressBulkAddView(PermissionRequiredMixin, BulkAddView):
|
||||||
permission_required = 'ipam.add_ipaddress'
|
permission_required = 'ipam.add_ipaddress'
|
||||||
form = forms.IPAddressBulkAddForm
|
form = forms.IPAddressBulkAddForm
|
||||||
model = IPAddress
|
model_form = forms.IPAddressForm
|
||||||
template_name = 'ipam/ipaddress_bulk_add.html'
|
template_name = 'ipam/ipaddress_bulk_add.html'
|
||||||
default_return_url = 'ipam:ipaddress_list'
|
default_return_url = 'ipam:ipaddress_list'
|
||||||
|
|
||||||
|
@ -10,13 +10,21 @@
|
|||||||
|
|
||||||
{% block form %}
|
{% block form %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><strong>IP Address</strong></div>
|
<div class="panel-heading"><strong>IP Addresses</strong></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% render_field form.address %}
|
{% render_field form.address_pattern %}
|
||||||
{% render_field form.vrf %}
|
{% render_field form.vrf %}
|
||||||
{% render_field form.tenant %}
|
{% render_field form.tenant %}
|
||||||
{% render_field form.status %}
|
{% render_field form.status %}
|
||||||
{% render_field form.description %}
|
{% render_field form.description %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if form.custom_fields %}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"><strong>Custom Fields</strong></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{% render_custom_fields form %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -296,12 +296,12 @@ class BulkAddView(View):
|
|||||||
Create new objects in bulk.
|
Create new objects in bulk.
|
||||||
|
|
||||||
form: Form class
|
form: Form class
|
||||||
model: The model of the objects being created
|
model_form: The ModelForm used to create individual objects
|
||||||
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 creating the objects
|
default_return_url: Name of the URL to which the user is redirected after creating the objects
|
||||||
"""
|
"""
|
||||||
form = None
|
form = None
|
||||||
model = None
|
model_form = None
|
||||||
template_name = None
|
template_name = None
|
||||||
default_return_url = 'home'
|
default_return_url = 'home'
|
||||||
|
|
||||||
@ -310,47 +310,44 @@ class BulkAddView(View):
|
|||||||
form = self.form()
|
form = self.form()
|
||||||
|
|
||||||
return render(request, self.template_name, {
|
return render(request, self.template_name, {
|
||||||
'obj_type': self.model._meta.verbose_name,
|
'obj_type': self.model_form._meta.model._meta.verbose_name,
|
||||||
'form': form,
|
'form': form,
|
||||||
'return_url': reverse(self.default_return_url),
|
'return_url': reverse(self.default_return_url),
|
||||||
})
|
})
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
|
|
||||||
|
model = self.model_form._meta.model
|
||||||
form = self.form(request.POST)
|
form = self.form(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
# The first field will be used as the pattern
|
# Read the pattern field and target from the form's pattern_map
|
||||||
field_names = list(form.fields.keys())
|
pattern_field, pattern_target = form.pattern_map
|
||||||
pattern_field = field_names[0]
|
|
||||||
pattern = form.cleaned_data[pattern_field]
|
pattern = form.cleaned_data[pattern_field]
|
||||||
|
model_form_data = form.cleaned_data
|
||||||
# All other fields will be copied as object attributes
|
|
||||||
kwargs = {k: form.cleaned_data[k] for k in field_names[1:]}
|
|
||||||
|
|
||||||
new_objs = []
|
new_objs = []
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
for value in pattern:
|
for value in pattern:
|
||||||
obj = self.model(**kwargs)
|
model_form_data[pattern_target] = value
|
||||||
setattr(obj, pattern_field, value)
|
model_form = self.model_form(model_form_data)
|
||||||
obj.full_clean()
|
obj = model_form.save()
|
||||||
obj.save()
|
|
||||||
new_objs.append(obj)
|
new_objs.append(obj)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
form.add_error(None, e)
|
form.add_error(None, e)
|
||||||
|
|
||||||
if not form.errors:
|
if not form.errors:
|
||||||
msg = u"Added {} {}".format(len(new_objs), self.model._meta.verbose_name_plural)
|
msg = u"Added {} {}".format(len(new_objs), model._meta.verbose_name_plural)
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
UserAction.objects.log_bulk_create(request.user, ContentType.objects.get_for_model(self.model), msg)
|
UserAction.objects.log_bulk_create(request.user, ContentType.objects.get_for_model(model), msg)
|
||||||
if '_addanother' in request.POST:
|
if '_addanother' in request.POST:
|
||||||
return redirect(request.path)
|
return redirect(request.path)
|
||||||
return redirect(self.default_return_url)
|
return redirect(self.default_return_url)
|
||||||
|
|
||||||
return render(request, self.template_name, {
|
return render(request, self.template_name, {
|
||||||
'form': form,
|
'form': form,
|
||||||
'obj_type': self.model._meta.verbose_name,
|
'obj_type': model._meta.verbose_name,
|
||||||
'return_url': reverse(self.default_return_url),
|
'return_url': reverse(self.default_return_url),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -15,8 +15,12 @@ if [ "$(whoami)" = "root" ]; then
|
|||||||
PREFIX=""
|
PREFIX=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Fall back to pip3 if pip is missing
|
||||||
|
PIP="pip"
|
||||||
|
type $PIP >/dev/null 2>&1 || PIP="pip3"
|
||||||
|
|
||||||
# Install any new Python packages
|
# Install any new Python packages
|
||||||
COMMAND="${PREFIX}pip install -r requirements.txt --upgrade"
|
COMMAND="${PREFIX}${PIP} install -r requirements.txt --upgrade"
|
||||||
echo "Updating required Python packages ($COMMAND)..."
|
echo "Updating required Python packages ($COMMAND)..."
|
||||||
eval $COMMAND
|
eval $COMMAND
|
||||||
|
|
||||||
@ -24,7 +28,7 @@ eval $COMMAND
|
|||||||
./netbox/manage.py migrate
|
./netbox/manage.py migrate
|
||||||
|
|
||||||
# Collect static files
|
# Collect static files
|
||||||
./netbox/manage.py collectstatic --noinput
|
./netbox/manage.py collectstatic --no-input
|
||||||
|
|
||||||
# Delete old bytecode
|
# Delete old bytecode
|
||||||
find . -name "*.pyc" -delete
|
find . -name "*.pyc" -delete
|
||||||
|
Loading…
Reference in New Issue
Block a user