Skip to content

Commit

Permalink
Merge pull request #8968 from netbox-community/develop
Browse files Browse the repository at this point in the history
Release v3.1.10
  • Loading branch information
jeremystretch authored Mar 25, 2022
2 parents 6807db4 + 271c2ea commit d50148f
Show file tree
Hide file tree
Showing 60 changed files with 666 additions and 432 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.1.9
placeholder: v3.1.10
validations:
required: true
- type: dropdown
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ body:
attributes:
label: NetBox version
description: What version of NetBox are you currently running?
placeholder: v3.1.9
placeholder: v3.1.10
validations:
required: true
- type: dropdown
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pycodestyle coverage
pip install pycodestyle coverage tblib
ln -s configuration.testing.py netbox/netbox/configuration.py
- name: Build documentation
Expand Down
2 changes: 1 addition & 1 deletion base_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ markdown-include
mkdocs-material

# Library for manipulating IP prefixes and addresses
# https://github.com/drkjam/netaddr
# https://github.com/netaddr/netaddr
netaddr

# Fork of PIL (Python Imaging Library) for image processing
Expand Down
1 change: 1 addition & 0 deletions docs/core-functionality/ipam.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
---

{!models/ipam/fhrpgroup.md!}
{!models/ipam/fhrpgroupassignment.md!}

---

Expand Down
4 changes: 3 additions & 1 deletion docs/development/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,10 @@ The demo data is provided in JSON format and loaded into an empty database using

Prior to committing any substantial changes to the code base, be sure to run NetBox's test suite to catch any potential errors. Tests are run using the `test` management command. Remember to ensure the Python virtual environment is active before running this command. Also keep in mind that these commands are executed in the `/netbox/` directory, not the root directory of the repository.

When running tests, it's advised to use the special testing configuration file that ships with NetBox. This ensures that tests are run with the same configuration parameters consistently. To override your local configuration when running tests, set the `NETBOX_CONFIGURATION` environment variable to `netbox.configuration_testing`.

```no-highlight
$ python manage.py test
$ NETBOX_CONFIGURATION=netbox.configuration_testing python manage.py test
```

In cases where you haven't made any changes to the database (which is most of the time), you can append the `--keepdb` argument to this command to reuse the test database between runs. This cuts down on the time it takes to run the test suite since the database doesn't have to be rebuilt each time. (Note that this argument will cause errors if you've modified any model fields since the previous test run.)
Expand Down
6 changes: 0 additions & 6 deletions docs/models/ipam/fhrpgroup.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,3 @@ A first-hop redundancy protocol (FHRP) enables multiple physical interfaces to p
* Gateway Load Balancing Protocol (GLBP)

NetBox models these redundancy groups by protocol and group ID. Each group may optionally be assigned an authentication type and key. (Note that the authentication key is stored as a plaintext value in NetBox.) Each group may be assigned or more virtual IPv4 and/or IPv6 addresses.

## FHRP Group Assignments

Member device and VM interfaces can be assigned to FHRP groups, along with a numeric priority value. For instance, three interfaces, each belonging to a different router, may each be assigned to the same FHRP group to serve a common virtual IP address. Each of these assignments would typically receive a different priority.

Interfaces are assigned to FHRP groups under the interface detail view.
5 changes: 5 additions & 0 deletions docs/models/ipam/fhrpgroupassignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# FHRP Group Assignments

Member device and VM interfaces can be assigned to FHRP groups, along with a numeric priority value. For instance, three interfaces, each belonging to a different router, may each be assigned to the same FHRP group to serve a common virtual IP address. Each of these assignments would typically receive a different priority.

Interfaces are assigned to FHRP groups under the interface detail view.
28 changes: 28 additions & 0 deletions docs/release-notes/version-3.1.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# NetBox v3.1

## v3.1.10 (2022-03-25)

### Enhancements

* [#8232](https://github.com/netbox-community/netbox/issues/8232) - Use a different color for 100% utilization bars
* [#8457](https://github.com/netbox-community/netbox/issues/8457) - Enable adding non-racked devices from site & location views
* [#8553](https://github.com/netbox-community/netbox/issues/8553) - Add missing object types to global search form
* [#8575](https://github.com/netbox-community/netbox/issues/8575) - Add rack columns to cables list
* [#8645](https://github.com/netbox-community/netbox/issues/8645) - Enable filtering objects by assigned contacts & contact roles
* [#8926](https://github.com/netbox-community/netbox/issues/8926) - Add device type, role columns to device bay table

### Bug Fixes

* [#8696](https://github.com/netbox-community/netbox/issues/8696) - Fix help link under FHRP group assigment creation view
* [#8813](https://github.com/netbox-community/netbox/issues/8813) - Retain global search bar query after submitting
* [#8820](https://github.com/netbox-community/netbox/issues/8820) - Fix navbar background color in dark mode
* [#8850](https://github.com/netbox-community/netbox/issues/8850) - Show airflow field on device REST API serializer when config context data is included
* [#8905](https://github.com/netbox-community/netbox/issues/8905) - Disable ordering by assigned tags to prevent erroneous results
* [#8919](https://github.com/netbox-community/netbox/issues/8919) - Fix filtering of VLAN groups by site under prefix edit form
* [#8924](https://github.com/netbox-community/netbox/issues/8924) - Improve load time of custom script list
* [#8932](https://github.com/netbox-community/netbox/issues/8932) - Fix error when setting null value for interface `rf_role` via REST API
* [#8935](https://github.com/netbox-community/netbox/issues/8935) - Correct ordering of next/previous racks to use naturalized names
* [#8947](https://github.com/netbox-community/netbox/issues/8947) - Retain filter parameters when handling an export template exception
* [#8951](https://github.com/netbox-community/netbox/issues/8951) - Allow changing device type & platform to different manufacturer simultaneously
* [#8952](https://github.com/netbox-community/netbox/issues/8952) - Device images in rear rack elevations should be hyperlinked

---

## v3.1.9 (2022-03-07)

### Enhancements
Expand Down
6 changes: 3 additions & 3 deletions netbox/circuits/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from dcim.models import Region, Site, SiteGroup
from extras.filters import TagFilter
from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet
from tenancy.filtersets import TenancyFilterSet
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from utilities.filters import TreeNodeMultipleChoiceFilter
from .choices import *
from .models import *
Expand All @@ -19,7 +19,7 @@
)


class ProviderFilterSet(PrimaryModelFilterSet):
class ProviderFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
Expand Down Expand Up @@ -118,7 +118,7 @@ class Meta:
fields = ['id', 'name', 'slug', 'description']


class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
Expand Down
8 changes: 5 additions & 3 deletions netbox/circuits/forms/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from circuits.models import *
from dcim.models import Region, Site, SiteGroup
from extras.forms import CustomFieldModelFilterForm
from tenancy.forms import TenancyFilterForm
from tenancy.forms import TenancyFilterForm, ContactModelFilterForm
from utilities.forms import DynamicModelMultipleChoiceField, StaticSelectMultiple, TagFilterField

__all__ = (
Expand All @@ -16,12 +16,13 @@
)


class ProviderFilterForm(CustomFieldModelFilterForm):
class ProviderFilterForm(ContactModelFilterForm, CustomFieldModelFilterForm):
model = Provider
field_groups = [
['q', 'tag'],
['region_id', 'site_group_id', 'site_id'],
['asn'],
['contact', 'contact_role']
]
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
Expand Down Expand Up @@ -68,14 +69,15 @@ class CircuitTypeFilterForm(CustomFieldModelFilterForm):
tag = TagFilterField(model)


class CircuitFilterForm(TenancyFilterForm, CustomFieldModelFilterForm):
class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, CustomFieldModelFilterForm):
model = Circuit
field_groups = [
['q', 'tag'],
['provider_id', 'provider_network_id'],
['type_id', 'status', 'commit_rate'],
['region_id', 'site_group_id', 'site_id'],
['tenant_group_id', 'tenant_id'],
['contact', 'contact_role']
]
type_id = DynamicModelMultipleChoiceField(
queryset=CircuitType.objects.all(),
Expand Down
10 changes: 8 additions & 2 deletions netbox/circuits/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class ProviderTable(BaseTable):
verbose_name='Circuits'
)
comments = MarkdownColumn()
contacts = tables.ManyToManyColumn(
linkify_item=True
)
tags = TagColumn(
url_name='circuits:provider_list'
)
Expand All @@ -66,7 +69,7 @@ class Meta(BaseTable.Meta):
model = Provider
fields = (
'pk', 'id', 'name', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'circuit_count',
'comments', 'tags', 'created', 'last_updated',
'comments', 'contacts', 'tags', 'created', 'last_updated',
)
default_columns = ('pk', 'name', 'asn', 'account', 'circuit_count')

Expand Down Expand Up @@ -142,6 +145,9 @@ class CircuitTable(BaseTable):
)
commit_rate = CommitRateColumn()
comments = MarkdownColumn()
contacts = tables.ManyToManyColumn(
linkify_item=True
)
tags = TagColumn(
url_name='circuits:circuit_list'
)
Expand All @@ -150,7 +156,7 @@ class Meta(BaseTable.Meta):
model = Circuit
fields = (
'pk', 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'install_date',
'commit_rate', 'description', 'comments', 'tags', 'created', 'last_updated',
'commit_rate', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated',
)
default_columns = (
'pk', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'description',
Expand Down
10 changes: 5 additions & 5 deletions netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,9 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
class Meta(DeviceSerializer.Meta):
fields = [
'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'primary_ip', 'primary_ip4',
'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'local_context_data',
'tags', 'custom_fields', 'config_context', 'created', 'last_updated',
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip',
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments',
'local_context_data', 'tags', 'custom_fields', 'config_context', 'created', 'last_updated',
]

@swagger_serializer_method(serializer_or_field=serializers.DictField)
Expand Down Expand Up @@ -619,8 +619,8 @@ class InterfaceSerializer(PrimaryModelSerializer, LinkTerminationSerializer, Con
parent = NestedInterfaceSerializer(required=False, allow_null=True)
bridge = NestedInterfaceSerializer(required=False, allow_null=True)
lag = NestedInterfaceSerializer(required=False, allow_null=True)
mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
rf_role = ChoiceField(choices=WirelessRoleChoices, required=False, allow_null=True)
mode = ChoiceField(choices=InterfaceModeChoices, required=False, allow_blank=True)
rf_role = ChoiceField(choices=WirelessRoleChoices, required=False, allow_blank=True)
rf_channel = ChoiceField(choices=WirelessChannelChoices, required=False, allow_blank=True)
untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
tagged_vlans = SerializedPKRelatedField(
Expand Down
20 changes: 10 additions & 10 deletions netbox/dcim/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from netbox.filtersets import (
BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet,
)
from tenancy.filtersets import TenancyFilterSet
from tenancy.models import Tenant
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
from tenancy.models import *
from utilities.choices import ColorChoices
from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter,
Expand Down Expand Up @@ -62,7 +62,7 @@
)


class RegionFilterSet(OrganizationalModelFilterSet):
class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=Region.objects.all(),
label='Parent region (ID)',
Expand All @@ -80,7 +80,7 @@ class Meta:
fields = ['id', 'name', 'slug', 'description']


class SiteGroupFilterSet(OrganizationalModelFilterSet):
class SiteGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
label='Parent site group (ID)',
Expand All @@ -98,7 +98,7 @@ class Meta:
fields = ['id', 'name', 'slug', 'description']


class SiteFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
class SiteFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
Expand Down Expand Up @@ -167,7 +167,7 @@ def search(self, queryset, name, value):
return queryset.filter(qs_filter)


class LocationFilterSet(TenancyFilterSet, OrganizationalModelFilterSet):
class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalModelFilterSet):
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='site__region',
Expand Down Expand Up @@ -240,7 +240,7 @@ class Meta:
fields = ['id', 'name', 'slug', 'color', 'description']


class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
Expand Down Expand Up @@ -398,7 +398,7 @@ def search(self, queryset, name, value):
)


class ManufacturerFilterSet(OrganizationalModelFilterSet):
class ManufacturerFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
tag = TagFilter()

class Meta:
Expand Down Expand Up @@ -608,7 +608,7 @@ class Meta:
fields = ['id', 'name', 'slug', 'napalm_driver', 'description']


class DeviceFilterSet(PrimaryModelFilterSet, TenancyFilterSet, LocalConfigContextFilterSet):
class DeviceFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet, LocalConfigContextFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
Expand Down Expand Up @@ -1289,7 +1289,7 @@ def filter_device(self, queryset, name, value):
return queryset


class PowerPanelFilterSet(PrimaryModelFilterSet):
class PowerPanelFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
Expand Down
Loading

0 comments on commit d50148f

Please sign in to comment.