Parcourir la source

Merge pull request #85 from digitalocean/develop

Release v1.0.4
Jeremy Stretch il y a 8 ans
Parent
commit
2ddb4b90c5

+ 1 - 0
.travis.yml

@@ -3,5 +3,6 @@ python:
   - "2.7"
 install:
   - pip install -r requirements.txt
+  - pip install pep8
 script:
   - ./scripts/cibuild.sh

+ 9 - 9
docs/getting-started.md

@@ -210,7 +210,7 @@ If the test service does not run, or you cannot reach the NetBox home page, some
 
 ## Installation
 
-We'll set up a simple HTTP front end using [gunicorn](http://gunicorn.org/) for the purposes of this guide. For web servers, we have 2 configurations ready to go - we provide instructions 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/) for service persistence. 
+We'll set up a simple HTTP 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/) for service persistence. 
 
 ```
 # apt-get install gunicorn supervisor
@@ -264,34 +264,35 @@ Restart the nginx service to use the new configuration.
 ```
 ## Apache Configuration
 
-If you're feeling adventurous, or you already have Apache installed and can't run a dual-stack on your server - an Apache configuration has been created:
+If you're feeling adventurous, or you already have Apache installed and can't run a dual-stack on your server, the following configuration should work for Apache:
 
 ```
 <VirtualHost *:80>
     ProxyPreserveHost On
     
-    ServerName netbox.totallycool.tld
+    ServerName netbox.example.com
 
-    Alias /static/ /opt/netbox/static/static
+    Alias /static/ /opt/netbox/netbox/static
 
     <Directory /opt/netbox/netbox/static>
         Options Indexes FollowSymLinks MultiViews
         AllowOverride None
         Order allow,deny
         Allow from all
-        #Require all granted [UNCOMMENT THIS IF RUNNING APACHE 2.4]
+        # Uncomment the line below if running Apache 2.4
+        #Require all granted
     </Directory>
 
     <Location /static>
         ProxyPass !
     </Location>
 
-    ProxyPass / http://127.0.0.1:8001;
-    ProxyPassReverse / http://127.0.0.1:8001;
+    ProxyPass / http://127.0.0.1:8001
+    ProxyPassReverse / http://127.0.0.1:8001
 </VirtualHost>
 ```
 
-Save the contents of the above example in `/etc/apache2/sites-available/netbox.conf`, add in the newly saved configuration and reload Apache:
+Save the contents of the above example in `/etc/apache2/sites-available/netbox.conf` and reload Apache:
 
 ```
 # a2ensite netbox; service apache2 restart
@@ -329,4 +330,3 @@ Finally, restart the supervisor service to detect and run the gunicorn service:
 At this point, you should be able to connect to the nginx HTTP service at the server name or IP address you provided. If you are unable to connect, check that the nginx service is running and properly configured. If you receive a 502 (bad gateway) error, this indicates that gunicorn is misconfigured or not running.
 
 Please keep in mind that the configurations provided here are a bare minimum to get NetBox up and running. You will almost certainly want to make some changes to better suit your production environment.
-

+ 2 - 0
docs/ipam.md

@@ -32,6 +32,8 @@ Additionally, you might define an aggregate for each large swath of public IPv4
 
 Any prefixes you create in NetBox (discussed below) will be automatically organized under their respective aggregates. Any space within an aggregate which is not covered by an existing prefix will be annotated as available for allocation.
 
+Aggregates cannot overlap with one another; they can only exist in parallel. For instance, you cannot define both 10.0.0.0/8 and 10.16.0.0/16 as aggregates, because they overlap. 10.16.0.0/16 in this example would be created as a prefix.
+
 ### RIRs
 
 Regional Internet Registries (RIRs) are responsible for the allocation of global address space. The five RIRs are ARIN, RIPE, APNIC, LACNIC, and AFRINIC. However, some address space has been set aside for private or internal use only, such as defined in RFCs 1918 and 6598. NetBox considers these RFCs as a sort of RIR as well; that is, an authority which "owns" certain address space.

+ 10 - 1
netbox/dcim/forms.py

@@ -424,7 +424,7 @@ class DeviceFromCSVForm(forms.ModelForm):
         'invalid_choice': 'Invalid site name.',
     })
     rack_name = forms.CharField()
-    face = forms.ChoiceField(choices=[('front', 'Front'), ('rear', 'Rear')])
+    face = forms.ChoiceField(choices=[('Front', 'Front'), ('Rear', 'Rear')])
 
     class Meta:
         model = Device
@@ -1036,20 +1036,29 @@ class InterfaceConnectionImportForm(BulkImportForm, BootstrapMixin):
             return
 
         connection_list = []
+        occupied_interfaces = []
 
         for i, record in enumerate(records, start=1):
             form = self.fields['csv'].csv_form(data=record)
             if form.is_valid():
                 interface_a = Interface.objects.get(device=form.cleaned_data['device_a'],
                                                     name=form.cleaned_data['interface_a'])
+                if interface_a in occupied_interfaces:
+                    raise forms.ValidationError("{} {} found in multiple connections"
+                                                .format(interface_a.device.name, interface_a.name))
                 interface_b = Interface.objects.get(device=form.cleaned_data['device_b'],
                                                     name=form.cleaned_data['interface_b'])
+                if interface_b in occupied_interfaces:
+                    raise forms.ValidationError("{} {} found in multiple connections"
+                                                .format(interface_b.device.name, interface_b.name))
                 connection = InterfaceConnection(interface_a=interface_a, interface_b=interface_b)
                 if form.cleaned_data['status'] == 'planned':
                     connection.connection_status = CONNECTION_STATUS_PLANNED
                 else:
                     connection.connection_status = CONNECTION_STATUS_CONNECTED
                 connection_list.append(connection)
+                occupied_interfaces.append(interface_a)
+                occupied_interfaces.append(interface_b)
             else:
                 for field, errors in form.errors.items():
                     for e in errors:

+ 1 - 1
netbox/dcim/tests/test_apis.py

@@ -47,7 +47,7 @@ class SiteTest(APITestCase):
     graph_fields = [
         'name',
         'embed_url',
-        'link',
+        'embed_link',
     ]
 
     def test_get_list(self, endpoint='/api/dcim/sites/'):

+ 1 - 1
netbox/dcim/tests/test_models.py

@@ -64,7 +64,7 @@ class RackTestCase(TestCase):
             rack=rack1,
             position=10,
             face=RACK_FACE_REAR,
-            )
+        )
         device1.save()
 
         # Validate rack height

+ 6 - 0
netbox/ipam/models.py

@@ -121,6 +121,12 @@ class Aggregate(CreatedUpdatedModel):
                 raise ValidationError("{} is already covered by an existing aggregate ({})"
                                       .format(self.prefix, covering_aggregates[0]))
 
+            # Ensure that the aggregate being added does not cover an existing aggregate
+            covered_aggregates = Aggregate.objects.filter(prefix__net_contained=str(self.prefix))
+            if covered_aggregates:
+                raise ValidationError("{} is overlaps with an existing aggregate ({})"
+                                      .format(self.prefix, covered_aggregates[0]))
+
     def save(self, *args, **kwargs):
         if self.prefix:
             # Infer address family from IPNetwork object

+ 2 - 1
netbox/project-static/css/base.css

@@ -9,7 +9,8 @@ body {
     padding-top: 70px;
 }
 .container {
-    width: 1340px;
+    width: auto;
+    max-width: 1340px;
 }
 .wrapper {
     min-height: 100%;

+ 2 - 2
netbox/project-static/js/forms.js

@@ -7,9 +7,9 @@ $(document).ready(function() {
 
     // Slugify
     function slugify(s, num_chars) {
-        s = s.replace(/[^-\.\+\w\s]/g, '');  // Remove unneeded chars
+        s = s.replace(/[^\-\.\w\s]/g, '');   // Remove unneeded chars
         s = s.replace(/^\s+|\s+$/g, '');     // Trim leading/trailing spaces
-        s = s.replace(/[-\s]+/g, '-');       // Convert spaces to hyphens
+        s = s.replace(/[\-\.\s]+/g, '-');    // Convert spaces and decimals to hyphens
         s = s.toLowerCase();                 // Convert to lowercase
         return s.substring(0, num_chars);    // Trim to first num_chars chars
     }

+ 8 - 0
netbox/templates/dcim/interface_connections_import.html

@@ -8,6 +8,14 @@
 <h1>Interface Connections Import</h1>
 <div class="row">
 	<div class="col-md-6">
+        {% if form.non_field_errors %}
+            <div class="panel panel-danger">
+                <div class="panel-heading"><strong>Errors</strong></div>
+                <div class="panel-body">
+                    {{ form.non_field_errors }}
+                </div>
+            </div>
+        {% endif %}
 		<form action="." method="post" class="form">
 		    {% csrf_token %}
 		    {% render_form form %}

+ 24 - 0
scripts/cibuild.sh

@@ -21,6 +21,30 @@ if [[ ! -z $SYNTAX ]]; then
 	EXIT=1
 fi
 
+# Check all python source files for PEP 8 compliance, but explicitly
+# ignore:
+#  - E501: line greater than 80 characters in length
+pep8 --ignore=E501 netbox/
+RC=$?
+if [[ $RC != 0 ]]; then
+	echo -e "\n$(info) one or more PEP 8 errors detected, failing build."
+	EXIT=$RC
+fi
+
+# Prepare configuration file for use in CI
+CONFIG="netbox/netbox/configuration.py"
+cp netbox/netbox/configuration.example.py $CONFIG
+sed -i -e "s/ALLOWED_HOSTS = \[\]/ALLOWED_HOSTS = \['*'\]/g" $CONFIG
+sed -i -e "s/SECRET_KEY = ''/SECRET_KEY = 'netboxci'/g" $CONFIG
+
+# Run NetBox tests
+./netbox/manage.py test netbox/
+RC=$?
+if [[ $RC != 0 ]]; then
+	echo -e "\n$(info) one or more tests failed, failing build."
+	EXIT=$RC
+fi
+
 # Show build duration
 END=$(date +%s)
 echo "$(info) exiting with code $EXIT after $(($END - $START)) seconds."