Explorar o código

Merge v2.11.11

jeremystretch %!s(int64=4) %!d(string=hai) anos
pai
achega
aed07a8ec5

+ 1 - 1
.github/ISSUE_TEMPLATE/bug_report.yaml

@@ -17,7 +17,7 @@ body:
         What version of NetBox are you currently running? (If you don't have access to the most
         What version of NetBox are you currently running? (If you don't have access to the most
         recent NetBox release, consider testing on our [demo instance](https://demo.netbox.dev/)
         recent NetBox release, consider testing on our [demo instance](https://demo.netbox.dev/)
         before opening a bug report to see if your issue has already been addressed.)
         before opening a bug report to see if your issue has already been addressed.)
-      placeholder: v2.11.10
+      placeholder: v2.11.11
     validations:
     validations:
       required: true
       required: true
   - type: dropdown
   - type: dropdown

+ 1 - 1
.github/ISSUE_TEMPLATE/feature_request.yaml

@@ -14,7 +14,7 @@ body:
     attributes:
     attributes:
       label: NetBox version
       label: NetBox version
       description: What version of NetBox are you currently running?
       description: What version of NetBox are you currently running?
-      placeholder: v2.11.10
+      placeholder: v2.11.11
     validations:
     validations:
       required: true
       required: true
   - type: dropdown
   - type: dropdown

+ 3 - 1
docs/release-notes/version-2.11.md

@@ -1,6 +1,6 @@
 # NetBox v2.11
 # NetBox v2.11
 
 
-## v2.11.11 (FUTURE)
+## v2.11.11 (2021-08-12)
 
 
 ### Enhancements
 ### Enhancements
 
 
@@ -11,10 +11,12 @@
 
 
 * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list
 * [#6740](https://github.com/netbox-community/netbox/issues/6740) - Add import button to VM interfaces list
 * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation
 * [#6892](https://github.com/netbox-community/netbox/issues/6892) - Fix validation of unit ranges when creating a rack reservation
+* [#6896](https://github.com/netbox-community/netbox/issues/6896) - Fix validation of IP address assigned as device/VM primary via NAT relation
 * [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components
 * [#6902](https://github.com/netbox-community/netbox/issues/6902) - Populate device field when cloning device components
 * [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import
 * [#6908](https://github.com/netbox-community/netbox/issues/6908) - Allow assignment of scope to VLAN groups upon import
 * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form
 * [#6909](https://github.com/netbox-community/netbox/issues/6909) - Remove extraneous `site` column from VLAN group import form
 * [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name
 * [#6910](https://github.com/netbox-community/netbox/issues/6910) - Fix exception on invalid CSV import column name
+* [#6918](https://github.com/netbox-community/netbox/issues/6918) - Fix return URL persistence when adding multiple objects sequentially
 * [#6935](https://github.com/netbox-community/netbox/issues/6935) - Remove extraneous columns from inventory item and device bay tables
 * [#6935](https://github.com/netbox-community/netbox/issues/6935) - Remove extraneous columns from inventory item and device bay tables
 * [#6936](https://github.com/netbox-community/netbox/issues/6936) - Add missing `parent` column to inventory item import form
 * [#6936](https://github.com/netbox-community/netbox/issues/6936) - Add missing `parent` column to inventory item import form
 
 

+ 5 - 4
netbox/ipam/forms.py

@@ -4,7 +4,8 @@ from django.utils.translation import gettext as _
 
 
 from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup
 from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup
 from extras.forms import (
 from extras.forms import (
-    AddRemoveTagsForm, CustomFieldModelBulkEditForm, CustomFieldModelCSVForm, CustomFieldModelForm, CustomFieldModelFilterForm,
+    AddRemoveTagsForm, CustomFieldModelBulkEditForm, CustomFieldModelCSVForm, CustomFieldModelForm,
+    CustomFieldModelFilterForm,
 )
 )
 from extras.models import Tag
 from extras.models import Tag
 from tenancy.forms import TenancyFilterForm, TenancyForm
 from tenancy.forms import TenancyFilterForm, TenancyForm
@@ -12,8 +13,8 @@ from tenancy.models import Tenant
 from utilities.forms import (
 from utilities.forms import (
     add_blank_choice, BootstrapMixin, BulkEditNullBooleanSelect, ContentTypeChoiceField, CSVChoiceField,
     add_blank_choice, BootstrapMixin, BulkEditNullBooleanSelect, ContentTypeChoiceField, CSVChoiceField,
     CSVContentTypeField, CSVModelChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
     CSVContentTypeField, CSVModelChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
-    ExpandableIPAddressField, NumericArrayField, ReturnURLForm, SlugField, StaticSelect, StaticSelectMultiple,
-    TagFilterField, BOOLEAN_WITH_BLANK_CHOICES,
+    ExpandableIPAddressField, NumericArrayField, SlugField, StaticSelect, StaticSelectMultiple, TagFilterField,
+    BOOLEAN_WITH_BLANK_CHOICES,
 )
 )
 from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface
 from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface
 from .choices import *
 from .choices import *
@@ -882,7 +883,7 @@ class IPRangeFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
 # IP addresses
 # IP addresses
 #
 #
 
 
-class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldModelForm):
+class IPAddressForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
     device = DynamicModelChoiceField(
     device = DynamicModelChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,

+ 9 - 12
netbox/ipam/models/ip.py

@@ -811,18 +811,15 @@ class IPAddress(PrimaryModel):
 
 
         # Check for primary IP assignment that doesn't match the assigned device/VM
         # Check for primary IP assignment that doesn't match the assigned device/VM
         if self.pk:
         if self.pk:
-            device = Device.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first()
-            if device:
-                if getattr(self.assigned_object, 'device', None) != device:
-                    raise ValidationError({
-                        'interface': f"IP address is primary for device {device} but not assigned to it!"
-                    })
-            vm = VirtualMachine.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first()
-            if vm:
-                if getattr(self.assigned_object, 'virtual_machine', None) != vm:
-                    raise ValidationError({
-                        'vminterface': f"IP address is primary for virtual machine {vm} but not assigned to it!"
-                    })
+            for cls, attr in ((Device, 'device'), (VirtualMachine, 'virtual_machine')):
+                parent = cls.objects.filter(Q(primary_ip4=self) | Q(primary_ip6=self)).first()
+                if parent and getattr(self.assigned_object, attr) != parent:
+                    # Check for a NAT relationship
+                    if not self.nat_inside or getattr(self.nat_inside.assigned_object, attr) != parent:
+                        raise ValidationError({
+                            'interface': f"IP address is primary for {cls._meta.model_name} {parent} but "
+                                         f"not assigned to it!"
+                        })
 
 
         # Validate IP status selection
         # Validate IP status selection
         if self.status == IPAddressStatusChoices.STATUS_SLAAC and self.family != 6:
         if self.status == IPAddressStatusChoices.STATUS_SLAAC and self.family != 6:

+ 9 - 8
netbox/netbox/views/generic.py

@@ -283,19 +283,20 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
                 messages.success(request, mark_safe(msg))
                 messages.success(request, mark_safe(msg))
 
 
                 if '_addanother' in request.POST:
                 if '_addanother' in request.POST:
+                    redirect_url = request.path
+                    return_url = request.GET.get('return_url')
+                    if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()):
+                        redirect_url = f'{redirect_url}?return_url={return_url}'
 
 
                     # If the object has clone_fields, pre-populate a new instance of the form
                     # If the object has clone_fields, pre-populate a new instance of the form
                     if hasattr(obj, 'clone_fields'):
                     if hasattr(obj, 'clone_fields'):
-                        url = '{}?{}'.format(request.path, prepare_cloned_fields(obj))
-                        return redirect(url)
+                        redirect_url += f"{'&' if return_url else '?'}{prepare_cloned_fields(obj)}"
 
 
-                    return redirect(request.get_full_path())
+                    return redirect(redirect_url)
 
 
-                return_url = form.cleaned_data.get('return_url')
-                if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()):
-                    return redirect(return_url)
-                else:
-                    return redirect(self.get_return_url(request, obj))
+                return_url = self.get_return_url(request, obj)
+
+                return redirect(return_url)
 
 
             except PermissionsViolation:
             except PermissionsViolation:
                 msg = "Object save failed due to object-level permissions violation"
                 msg = "Object save failed due to object-level permissions violation"

+ 2 - 2
requirements.txt

@@ -1,4 +1,4 @@
-Django==3.2.5
+Django==3.2.6
 django-cors-headers==3.7.0
 django-cors-headers==3.7.0
 django-debug-toolbar==3.2.1
 django-debug-toolbar==3.2.1
 django-filter==2.4.0
 django-filter==2.4.0
@@ -18,7 +18,7 @@ gunicorn==20.1.0
 Jinja2==3.0.1
 Jinja2==3.0.1
 Markdown==3.3.4
 Markdown==3.3.4
 markdown-include==0.6.0
 markdown-include==0.6.0
-mkdocs-material==7.2.0
+mkdocs-material==7.2.4
 netaddr==0.8.0
 netaddr==0.8.0
 Pillow==8.3.1
 Pillow==8.3.1
 psycopg2-binary==2.9.1
 psycopg2-binary==2.9.1