Merged develop

This commit is contained in:
Jeremy Stretch 2016-08-22 15:49:41 -04:00
commit faed3c1314
23 changed files with 53 additions and 145 deletions

View File

@ -1,24 +1,11 @@
FROM ubuntu:14.04 FROM python:2.7-wheezy
RUN apt-get update && apt-get install -y \ WORKDIR /opt/netbox
python2.7 \
python-dev \ ARG BRANCH=master
git \ ARG URL=https://github.com/digitalocean/netbox.git
python-pip \ RUN git clone --depth 1 $URL -b $BRANCH . && \
libxml2-dev \ pip install gunicorn==17.5 && pip install -r requirements.txt
libxslt1-dev \
libffi-dev \
graphviz \
libpq-dev \
build-essential \
gunicorn \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /opt/netbox \
&& cd /opt/netbox \
&& git clone --depth 1 https://github.com/digitalocean/netbox.git -b master . \
&& pip install -r requirements.txt \
&& apt-get purge -y --auto-remove git build-essential
ADD docker/docker-entrypoint.sh /docker-entrypoint.sh ADD docker/docker-entrypoint.sh /docker-entrypoint.sh
ADD netbox/netbox/configuration.docker.py /opt/netbox/netbox/netbox/configuration.py ADD netbox/netbox/configuration.docker.py /opt/netbox/netbox/netbox/configuration.py

View File

@ -280,6 +280,7 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
return ','.join([ return ','.join([
str(self.prefix), str(self.prefix),
self.vrf.rd if self.vrf else '', self.vrf.rd if self.vrf else '',
self.tenant.name if self.tenant else '',
self.site.name if self.site else '', self.site.name if self.site else '',
self.get_status_display(), self.get_status_display(),
self.role.name if self.role else '', self.role.name if self.role else '',
@ -384,6 +385,7 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel):
return ','.join([ return ','.join([
str(self.address), str(self.address),
self.vrf.rd if self.vrf else '', self.vrf.rd if self.vrf else '',
self.tenant.name if self.tenant else '',
self.device.identifier if self.device else '', self.device.identifier if self.device else '',
self.interface.name if self.interface else '', self.interface.name if self.interface else '',
'True' if is_primary else '', 'True' if is_primary else '',

View File

@ -164,6 +164,9 @@ STATICFILES_DIRS = (
os.path.join(BASE_DIR, "project-static"), os.path.join(BASE_DIR, "project-static"),
) )
# Disable default limit of 1000 fields per request. Needed for bulk deletion of objects. (Added in Django 1.10.)
DATA_UPLOAD_MAX_NUMBER_FIELDS = None
# Messages # Messages
MESSAGE_TAGS = { MESSAGE_TAGS = {
messages.ERROR: 'danger', messages.ERROR: 'danger',

View File

@ -25,17 +25,20 @@ $(document).ready(function() {
}); });
// Adding/editing a secret // Adding/editing a secret
$('form.requires-private-key').submit(function(event) { private_key_field = $('#id_private_key');
private_key_field.parents('form').submit(function(event) {
console.log("form submitted");
var private_key = sessionStorage.getItem('private_key'); var private_key = sessionStorage.getItem('private_key');
if (private_key) { if (private_key) {
$('#id_private_key').val(private_key); private_key_field.val(private_key);
} else { } else if ($('form .requires-private-key:first').val()) {
console.log("we need a key!");
$('#privkey_modal').modal('show'); $('#privkey_modal').modal('show');
return false; return false;
} }
}); });
// Prompt the user to enter a private RSA key for decryption // Saving a private RSA key locally
$('#submit_privkey').click(function() { $('#submit_privkey').click(function() {
var private_key = $('#user_privkey').val(); var private_key = $('#user_privkey').val();
sessionStorage.setItem('private_key', private_key); sessionStorage.setItem('private_key', private_key);

View File

@ -47,8 +47,9 @@ class SecretRoleForm(forms.ModelForm, BootstrapMixin):
# #
class SecretForm(forms.ModelForm, BootstrapMixin): class SecretForm(forms.ModelForm, BootstrapMixin):
private_key = forms.CharField(widget=forms.HiddenInput()) private_key = forms.CharField(required=False, widget=forms.HiddenInput())
plaintext = forms.CharField(max_length=65535, required=False, label='Plaintext') plaintext = forms.CharField(max_length=65535, required=False, label='Plaintext',
widget=forms.TextInput(attrs={'class': 'requires-private-key'}))
plaintext2 = forms.CharField(max_length=65535, required=False, label='Plaintext (verify)') plaintext2 = forms.CharField(max_length=65535, required=False, label='Plaintext (verify)')
class Meta: class Meta:
@ -56,6 +57,7 @@ class SecretForm(forms.ModelForm, BootstrapMixin):
fields = ['role', 'name', 'plaintext', 'plaintext2'] fields = ['role', 'name', 'plaintext', 'plaintext2']
def clean(self): def clean(self):
if self.cleaned_data['plaintext']:
validate_rsa_key(self.cleaned_data['private_key']) validate_rsa_key(self.cleaned_data['private_key'])
def clean_plaintext2(self): def clean_plaintext2(self):
@ -84,7 +86,7 @@ class SecretFromCSVForm(forms.ModelForm):
class SecretImportForm(BulkImportForm, BootstrapMixin): class SecretImportForm(BulkImportForm, BootstrapMixin):
private_key = forms.CharField(widget=forms.HiddenInput()) private_key = forms.CharField(widget=forms.HiddenInput())
csv = CSVDataField(csv_form=SecretFromCSVForm) csv = CSVDataField(csv_form=SecretFromCSVForm, widget=forms.Textarea(attrs={'class': 'requires-private-key'}))
class SecretBulkEditForm(forms.Form, BootstrapMixin): class SecretBulkEditForm(forms.Form, BootstrapMixin):

View File

@ -95,26 +95,16 @@
<tr> <tr>
<td>Commit Rate</td> <td>Commit Rate</td>
<td> <td>
{% if circuit.commit_speed %} {% if circuit.commit_rate %}
{{ circuit.commit_speed_human }} {{ circuit.commit_rate_human }}
{% else %} {% else %}
<span class="text-muted">N/A</span> <span class="text-muted">N/A</span>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ circuit.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ circuit.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% with circuit.custom_fields as custom_fields %} {% include 'inc/created_updated.html' with obj=circuit %}
{% include 'inc/custom_fields_panel.html' %}
{% endwith %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="panel panel-default"> <div class="panel panel-default">

View File

@ -103,14 +103,6 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ provider.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ provider.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% with provider.custom_fields as custom_fields %} {% with provider.custom_fields as custom_fields %}
@ -128,6 +120,7 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% include 'inc/created_updated.html' with obj=provider %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="panel panel-default"> <div class="panel panel-default">

View File

@ -79,14 +79,6 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ device.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ device.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
<div class="panel panel-default"> <div class="panel panel-default">
@ -309,6 +301,7 @@
<div class="panel-body text-muted">None found</div> <div class="panel-body text-muted">None found</div>
{% endif %} {% endif %}
</div> </div>
{% include 'inc/created_updated.html' with obj=device %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% if device_bays or device.device_type.is_parent_device %} {% if device_bays or device.device_type.is_parent_device %}

View File

@ -130,14 +130,6 @@
<a href="{% url 'dcim:device_list' %}?rack_id={{ rack.id }}">{{ rack.devices.count }}</a> <a href="{% url 'dcim:device_list' %}?rack_id={{ rack.id }}">{{ rack.devices.count }}</a>
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ rack.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ rack.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% with rack.custom_fields as custom_fields %} {% with rack.custom_fields as custom_fields %}
@ -190,6 +182,7 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% include 'inc/created_updated.html' with obj=rack %}
</div> </div>
<div class="row col-md-6"> <div class="row col-md-6">
<div class="col-md-6 col-sm-6 col-xs-12"> <div class="col-md-6 col-sm-6 col-xs-12">

View File

@ -53,6 +53,11 @@
<td>Name of tenant (optional)</td> <td>Name of tenant (optional)</td>
<td>Pied Piper</td> <td>Pied Piper</td>
</tr> </tr>
<tr>
<td>Role</td>
<td>Functional role (optional)</td>
<td>Compute</td>
</tr>
<tr> <tr>
<td>Type</td> <td>Type</td>
<td>Rack type (optional)</td> <td>Rack type (optional)</td>
@ -71,7 +76,7 @@
</tbody> </tbody>
</table> </table>
<h4>Example</h4> <h4>Example</h4>
<pre>DC-4,Cage 1400,R101,J12.100,Pied Piper,4-post cabinet,19,42</pre> <pre>DC-4,Cage 1400,R101,J12.100,Pied Piper,Compute,4-post cabinet,19,42</pre>
</div> </div>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -109,14 +109,6 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ site.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ site.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% with site.custom_fields as custom_fields %} {% with site.custom_fields as custom_fields %}
@ -134,6 +126,7 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% include 'inc/created_updated.html' with obj=site %}
</div> </div>
<div class="col-md-5"> <div class="col-md-5">
<div class="panel panel-default"> <div class="panel panel-default">

View File

@ -0,0 +1,3 @@
<p>
<small class="text-muted">Created {{ obj.created }} &middot; Updated <span title="{{ obj.last_updated }}">{{ obj.last_updated|timesince }}</span> ago</small>
</p>

View File

@ -77,16 +77,9 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ aggregate.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ aggregate.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% include 'inc/created_updated.html' with obj=aggregate %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% with aggregate.custom_fields as custom_fields %} {% with aggregate.custom_fields as custom_fields %}

View File

@ -119,19 +119,9 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ ipaddress.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ ipaddress.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% with ipaddress.custom_fields as custom_fields %} {% include 'inc/created_updated.html' with obj=ipaddress %}
{% include 'inc/custom_fields_panel.html' %}
{% endwith %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% with heading='Parent Prefixes' %} {% with heading='Parent Prefixes' %}

View File

@ -99,19 +99,10 @@
<td>IP Addresses</td> <td>IP Addresses</td>
<td><a href="{% url 'ipam:prefix_ipaddresses' pk=prefix.pk %}">{{ ipaddress_count }}</a></td> <td><a href="{% url 'ipam:prefix_ipaddresses' pk=prefix.pk %}">{{ ipaddress_count }}</a></td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ prefix.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ prefix.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% with prefix.custom_fields as custom_fields %} {% include 'inc/created_updated.html' with obj=prefix %}
{% include 'inc/custom_fields_panel.html' %} <br />
{% endwith %}
</div> </div>
<div class="col-md-7"> <div class="col-md-7">
{% if duplicate_prefix_table.rows %} {% if duplicate_prefix_table.rows %}

View File

@ -107,20 +107,10 @@
<span class="text-muted">N/A</span> <span class="text-muted">N/A</span>
{% endif %} {% endif %}
</td> </td>
</tr>
<tr>
<td>Created</td>
<td>{{ vlan.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ vlan.last_updated }}</td>
</tr> </tr>
</table> </table>
</div> </div>
{% with vlan.custom_fields as custom_fields %} {% include 'inc/created_updated.html' with obj=vlan %}
{% include 'inc/custom_fields_panel.html' %}
{% endwith %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="panel panel-default"> <div class="panel panel-default">

View File

@ -79,20 +79,10 @@
<span class="text-muted">N/A</span> <span class="text-muted">N/A</span>
{% endif %} {% endif %}
</td> </td>
</tr>
<tr>
<td>Created</td>
<td>{{ vrf.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ vrf.last_updated }}</td>
</tr> </tr>
</table> </table>
</div> </div>
{% with vrf.custom_fields as custom_fields %} {% include 'inc/created_updated.html' with obj=vrf %}
{% include 'inc/custom_fields_panel.html' %}
{% endwith %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<div class="panel panel-default"> <div class="panel panel-default">

View File

@ -56,16 +56,9 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ secret.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ secret.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% include 'inc/created_updated.html' with obj=secret %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% if secret|decryptable_by:request.user %} {% if secret|decryptable_by:request.user %}

View File

@ -5,7 +5,7 @@
{% block title %}{% if secret.pk %}Editing {{ secret }}{% else %}Add a Secret{% endif %}{% endblock %} {% block title %}{% if secret.pk %}Editing {{ secret }}{% else %}Add a Secret{% endif %}{% endblock %}
{% block content %} {% block content %}
<form action="." method="post" class="form form-horizontal requires-private-key"> <form action="." method="post" class="form form-horizontal">
{% csrf_token %} {% csrf_token %}
{{ form.private_key }} {{ form.private_key }}
<div class="row"> <div class="row">

View File

@ -17,7 +17,7 @@
</div> </div>
</div> </div>
{% endif %} {% endif %}
<form action="." method="post" class="form requires-private-key"> <form action="." method="post" class="form">
{% csrf_token %} {% csrf_token %}
{% render_form form %} {% render_form form %}
<div class="form-group"> <div class="form-group">

View File

@ -63,14 +63,6 @@
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
<tr>
<td>Created</td>
<td>{{ tenant.created }}</td>
</tr>
<tr>
<td>Last Updated</td>
<td>{{ tenant.last_updated }}</td>
</tr>
</table> </table>
</div> </div>
{% with tenant.custom_fields as custom_fields %} {% with tenant.custom_fields as custom_fields %}
@ -88,6 +80,7 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
{% include 'inc/created_updated.html' with obj=tenant %}
</div> </div>
<div class="col-md-5"> <div class="col-md-5">
<div class="panel panel-default"> <div class="panel panel-default">

View File

@ -31,6 +31,7 @@
Edit user key Edit user key
</a> </a>
</div> </div>
{% include 'inc/created_updated.html' with obj=userkey %}
{% else %} {% else %}
<p>You don't have a user key on file.</p> <p>You don't have a user key on file.</p>
<p> <p>

View File

@ -130,11 +130,11 @@ class CSVDataField(forms.CharField):
'"New York, NY",new-york-ny,Other stuff' => ['New York, NY', 'new-york-ny', 'Other stuff'] '"New York, NY",new-york-ny,Other stuff' => ['New York, NY', 'new-york-ny', 'Other stuff']
""" """
csv_form = None csv_form = None
widget = forms.Textarea
def __init__(self, csv_form, *args, **kwargs): def __init__(self, csv_form, *args, **kwargs):
self.csv_form = csv_form self.csv_form = csv_form
self.columns = self.csv_form().fields.keys() self.columns = self.csv_form().fields.keys()
self.widget = forms.Textarea
super(CSVDataField, self).__init__(*args, **kwargs) super(CSVDataField, self).__init__(*args, **kwargs)
self.strip = False self.strip = False
if not self.label: if not self.label: