diff --git a/CHANGELOG.md b/CHANGELOG.md index f1bc7f499..3284d1d03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,16 +19,25 @@ v2.5.0 (FUTURE) --- -v2.4.4 (FUTURE) +v2.4.4 (2018-08-22) ## Enhancements +* [#2168](https://github.com/digitalocean/netbox/issues/2168) - Added Extreme SummitStack interface form factors * [#2356](https://github.com/digitalocean/netbox/issues/2356) - Include cluster site as read-only field in VirtualMachine serializer * [#2362](https://github.com/digitalocean/netbox/issues/2362) - Implemented custom admin site to properly handle BASE_PATH +* [#2254](https://github.com/digitalocean/netbox/issues/2254) - Implemented searchability for Rack Groups ## Bug Fixes +* [#2353](https://github.com/digitalocean/netbox/issues/2353) - Handle `DoesNotExist` exception when deleting a device with connected interfaces +* [#2354](https://github.com/digitalocean/netbox/issues/2354) - Increased maximum MTU for interfaces to 65536 bytes * [#2355](https://github.com/digitalocean/netbox/issues/2355) - Added item count to inventory tab on device view +* [#2368](https://github.com/digitalocean/netbox/issues/2368) - Record change in device changelog when altering cluster assignment +* [#2369](https://github.com/digitalocean/netbox/issues/2369) - Corrected time zone validation on site API serializer +* [#2370](https://github.com/digitalocean/netbox/issues/2370) - Redirect to parent device after deleting device bays +* [#2374](https://github.com/digitalocean/netbox/issues/2374) - Fix toggling display of IP addresses in virtual machine interfaces list +* [#2378](https://github.com/digitalocean/netbox/issues/2378) - Corrected "edit" link for virtual machine interfaces --- diff --git a/docs/configuration/index.md b/docs/configuration/index.md index 97857a4c4..619af171c 100644 --- a/docs/configuration/index.md +++ b/docs/configuration/index.md @@ -12,5 +12,5 @@ While NetBox has many configuration settings, only a few of them must be defined Configuration settings may be changed at any time. However, the NetBox service must be restarted before the changes will take effect: ```no-highlight -# sudo supervsiorctl restart netbox +# sudo supervisorctl restart netbox ``` diff --git a/docs/development/release-checklist.md b/docs/development/release-checklist.md index cce096b48..5e1f92fcc 100644 --- a/docs/development/release-checklist.md +++ b/docs/development/release-checklist.md @@ -48,9 +48,9 @@ Close the release milestone on GitHub. Ensure that there are no remaining open i Ensure that continuous integration testing on the `develop` branch is completing successfully. -## Update VERSION +## Update Version and Changelog -Update the `VERSION` constant in `settings.py` to the new release. +Update the `VERSION` constant in `settings.py` to the new release version and add the current date to the release notes in `CHANGELOG.md`. ## Submit a Pull Request diff --git a/docs/installation/3-http-daemon.md b/docs/installation/3-http-daemon.md index 9ed8fdd74..6ca38783e 100644 --- a/docs/installation/3-http-daemon.md +++ b/docs/installation/3-http-daemon.md @@ -56,7 +56,7 @@ To enable SSL, consider this guide on [securing nginx with Let's Encrypt](https: ## Option B: Apache ```no-highlight -# apt-get install -y apache2 +# apt-get install -y apache2 libapache2-mod-wsgi-py3 ``` Once Apache is installed, proceed with the following configuration (Be sure to modify the `ServerName` appropriately): diff --git a/netbox/dcim/constants.py b/netbox/dcim/constants.py index 0bec76bf3..a3226a6b2 100644 --- a/netbox/dcim/constants.py +++ b/netbox/dcim/constants.py @@ -91,6 +91,11 @@ IFACE_FF_STACKWISE_PLUS = 5050 IFACE_FF_FLEXSTACK = 5100 IFACE_FF_FLEXSTACK_PLUS = 5150 IFACE_FF_JUNIPER_VCP = 5200 +IFACE_FF_SUMMITSTACK = 5300 +IFACE_FF_SUMMITSTACK128 = 5310 +IFACE_FF_SUMMITSTACK256 = 5320 +IFACE_FF_SUMMITSTACK512 = 5330 + # Other IFACE_FF_OTHER = 32767 @@ -166,6 +171,10 @@ IFACE_FF_CHOICES = [ [IFACE_FF_FLEXSTACK, 'Cisco FlexStack'], [IFACE_FF_FLEXSTACK_PLUS, 'Cisco FlexStack Plus'], [IFACE_FF_JUNIPER_VCP, 'Juniper VCP'], + [IFACE_FF_SUMMITSTACK, 'Extreme SummitStack'], + [IFACE_FF_SUMMITSTACK128, 'Extreme SummitStack-128'], + [IFACE_FF_SUMMITSTACK256, 'Extreme SummitStack-256'], + [IFACE_FF_SUMMITSTACK512, 'Extreme SummitStack-512'], ] ], [ diff --git a/netbox/dcim/filters.py b/netbox/dcim/filters.py index ea8f068fa..60cbbfcc1 100644 --- a/netbox/dcim/filters.py +++ b/netbox/dcim/filters.py @@ -110,6 +110,10 @@ class SiteFilter(CustomFieldFilterSet, django_filters.FilterSet): class RackGroupFilter(django_filters.FilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), label='Site (ID)', @@ -125,6 +129,15 @@ class RackGroupFilter(django_filters.FilterSet): model = RackGroup fields = ['site_id', 'name', 'slug'] + def search(self, queryset, name, value): + if not value.strip(): + return queryset + qs_filter = ( + Q(name__icontains=value) | + Q(slug__icontains=value) + ) + return queryset.filter(qs_filter) + class RackRoleFilter(django_filters.FilterSet): diff --git a/netbox/dcim/migrations/0062_interface_mtu.py b/netbox/dcim/migrations/0062_interface_mtu.py new file mode 100644 index 000000000..592f11bb7 --- /dev/null +++ b/netbox/dcim/migrations/0062_interface_mtu.py @@ -0,0 +1,29 @@ +# Generated by Django 2.0.8 on 2018-08-22 14:23 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0061_platform_napalm_args'), + ] + + operations = [ + migrations.AlterField( + model_name='interface', + name='mtu', + field=models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(65536)], verbose_name='MTU'), + ), + migrations.AlterField( + model_name='interface', + name='form_factor', + field=models.PositiveSmallIntegerField(choices=[['Virtual interfaces', [[0, 'Virtual'], [200, 'Link Aggregation Group (LAG)']]], ['Ethernet (fixed)', [[800, '100BASE-TX (10/100ME)'], [1000, '1000BASE-T (1GE)'], [1150, '10GBASE-T (10GE)'], [1170, '10GBASE-CX4 (10GE)']]], ['Ethernet (modular)', [[1050, 'GBIC (1GE)'], [1100, 'SFP (1GE)'], [1200, 'SFP+ (10GE)'], [1300, 'XFP (10GE)'], [1310, 'XENPAK (10GE)'], [1320, 'X2 (10GE)'], [1350, 'SFP28 (25GE)'], [1400, 'QSFP+ (40GE)'], [1500, 'CFP (100GE)'], [1510, 'CFP2 (100GE)'], [1520, 'CFP4 (100GE)'], [1550, 'Cisco CPAK (100GE)'], [1600, 'QSFP28 (100GE)']]], ['Wireless', [[2600, 'IEEE 802.11a'], [2610, 'IEEE 802.11b/g'], [2620, 'IEEE 802.11n'], [2630, 'IEEE 802.11ac'], [2640, 'IEEE 802.11ad']]], ['FibreChannel', [[3010, 'SFP (1GFC)'], [3020, 'SFP (2GFC)'], [3040, 'SFP (4GFC)'], [3080, 'SFP+ (8GFC)'], [3160, 'SFP+ (16GFC)']]], ['Serial', [[4000, 'T1 (1.544 Mbps)'], [4010, 'E1 (2.048 Mbps)'], [4040, 'T3 (45 Mbps)'], [4050, 'E3 (34 Mbps)']]], ['Stacking', [[5000, 'Cisco StackWise'], [5050, 'Cisco StackWise Plus'], [5100, 'Cisco FlexStack'], [5150, 'Cisco FlexStack Plus'], [5200, 'Juniper VCP'], [5300, 'Extreme SummitStack'], [5310, 'Extreme SummitStack-128'], [5320, 'Extreme SummitStack-256'], [5330, 'Extreme SummitStack-512']]], ['Other', [[32767, 'Other']]]], default=1200), + ), + migrations.AlterField( + model_name='interfacetemplate', + name='form_factor', + field=models.PositiveSmallIntegerField(choices=[['Virtual interfaces', [[0, 'Virtual'], [200, 'Link Aggregation Group (LAG)']]], ['Ethernet (fixed)', [[800, '100BASE-TX (10/100ME)'], [1000, '1000BASE-T (1GE)'], [1150, '10GBASE-T (10GE)'], [1170, '10GBASE-CX4 (10GE)']]], ['Ethernet (modular)', [[1050, 'GBIC (1GE)'], [1100, 'SFP (1GE)'], [1200, 'SFP+ (10GE)'], [1300, 'XFP (10GE)'], [1310, 'XENPAK (10GE)'], [1320, 'X2 (10GE)'], [1350, 'SFP28 (25GE)'], [1400, 'QSFP+ (40GE)'], [1500, 'CFP (100GE)'], [1510, 'CFP2 (100GE)'], [1520, 'CFP4 (100GE)'], [1550, 'Cisco CPAK (100GE)'], [1600, 'QSFP28 (100GE)']]], ['Wireless', [[2600, 'IEEE 802.11a'], [2610, 'IEEE 802.11b/g'], [2620, 'IEEE 802.11n'], [2630, 'IEEE 802.11ac'], [2640, 'IEEE 802.11ad']]], ['FibreChannel', [[3010, 'SFP (1GFC)'], [3020, 'SFP (2GFC)'], [3040, 'SFP (4GFC)'], [3080, 'SFP+ (8GFC)'], [3160, 'SFP+ (16GFC)']]], ['Serial', [[4000, 'T1 (1.544 Mbps)'], [4010, 'E1 (2.048 Mbps)'], [4040, 'T3 (45 Mbps)'], [4050, 'E3 (34 Mbps)']]], ['Stacking', [[5000, 'Cisco StackWise'], [5050, 'Cisco StackWise Plus'], [5100, 'Cisco FlexStack'], [5150, 'Cisco FlexStack Plus'], [5200, 'Juniper VCP'], [5300, 'Extreme SummitStack'], [5310, 'Extreme SummitStack-128'], [5320, 'Extreme SummitStack-256'], [5330, 'Extreme SummitStack-512']]], ['Other', [[32767, 'Other']]]], default=1200), + ), + ] diff --git a/netbox/dcim/migrations/0062_remove_platform_rpc_client.py b/netbox/dcim/migrations/0063_remove_platform_rpc_client.py similarity index 71% rename from netbox/dcim/migrations/0062_remove_platform_rpc_client.py rename to netbox/dcim/migrations/0063_remove_platform_rpc_client.py index 22a4900d1..80874c27f 100644 --- a/netbox/dcim/migrations/0062_remove_platform_rpc_client.py +++ b/netbox/dcim/migrations/0063_remove_platform_rpc_client.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.8 on 2018-08-16 16:17 +# Generated by Django 2.0.8 on 2018-08-22 16:09 from django.db import migrations @@ -6,7 +6,7 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ - ('dcim', '0061_platform_napalm_args'), + ('dcim', '0062_interface_mtu'), ] operations = [ diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 432d78977..5e02fab4a 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -1754,9 +1754,10 @@ class Interface(ComponentModel): blank=True, verbose_name='MAC Address' ) - mtu = models.PositiveSmallIntegerField( + mtu = models.PositiveIntegerField( blank=True, null=True, + validators=[MinValueValidator(1), MaxValueValidator(65536)], verbose_name='MTU' ) mgmt_only = models.BooleanField( @@ -2012,6 +2013,7 @@ class InterfaceConnection(models.Model): (self.interface_a, self.interface_b), (self.interface_b, self.interface_a), ) + for interface, peer_interface in interfaces: if action == OBJECTCHANGE_ACTION_DELETE: connection_data = { @@ -2022,11 +2024,17 @@ class InterfaceConnection(models.Model): 'connected_interface': peer_interface.pk, 'connection_status': self.connection_status } + + try: + parent_obj = interface.parent + except ObjectDoesNotExist: + parent_obj = None + ObjectChange( user=user, request_id=request_id, changed_object=interface, - related_object=interface.parent, + related_object=parent_obj, action=OBJECTCHANGE_ACTION_UPDATE, object_data=serialize_object(interface, extra=connection_data) ).save() diff --git a/netbox/netbox/forms.py b/netbox/netbox/forms.py index b87e6ddd5..d5ab09410 100644 --- a/netbox/netbox/forms.py +++ b/netbox/netbox/forms.py @@ -11,6 +11,7 @@ OBJ_TYPE_CHOICES = ( ('DCIM', ( ('site', 'Sites'), ('rack', 'Racks'), + ('rackgroup', 'Rack Groups'), ('devicetype', 'Device types'), ('device', 'Devices'), ('virtualchassis', 'Virtual Chassis'), diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 625066d79..12910650d 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -21,7 +21,7 @@ except ImportError: "Configuration file is not present. Please define netbox/netbox/configuration.py per the documentation." ) -VERSION = '2.4.4-dev' +VERSION = '2.5.0-dev' BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index f6e59221c..b2f726060 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -10,9 +10,16 @@ from rest_framework.views import APIView from circuits.filters import CircuitFilter, ProviderFilter from circuits.models import Circuit, Provider from circuits.tables import CircuitTable, ProviderTable -from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter, VirtualChassisFilter -from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site, VirtualChassis -from dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable, VirtualChassisTable +from dcim.filters import ( + DeviceFilter, DeviceTypeFilter, RackFilter, RackGroupFilter, SiteFilter, VirtualChassisFilter +) +from dcim.models import ( + ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, RackGroup, Site, + VirtualChassis +) +from dcim.tables import ( + DeviceDetailTable, DeviceTypeTable, RackTable, RackGroupTable, SiteTable, VirtualChassisTable +) from extras.models import ObjectChange, ReportResult, TopologyMap from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF @@ -56,6 +63,12 @@ SEARCH_TYPES = OrderedDict(( 'table': RackTable, 'url': 'dcim:rack_list', }), + ('rackgroup', { + 'queryset': RackGroup.objects.select_related('site').annotate(rack_count=Count('racks')), + 'filter': RackGroupFilter, + 'table': RackGroupTable, + 'url': 'dcim:rackgroup_list', + }), ('devicetype', { 'queryset': DeviceType.objects.select_related('manufacturer').annotate(instance_count=Count('instances')), 'filter': DeviceTypeFilter, diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index 4852823b7..7b56269b1 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -447,7 +447,7 @@