Skip to content

Commit

Permalink
Merge branch 'develop' into feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremystretch committed Mar 15, 2024
2 parents b58c85c + 4adb44f commit 78bd7de
Show file tree
Hide file tree
Showing 28 changed files with 153 additions and 74 deletions.
5 changes: 3 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ body:
How are you running NetBox? (For issues with the Docker image, please go to the
[netbox-docker](https://github.com/netbox-community/netbox-docker) repo.)
options:
- Self-hosted
- NetBox Cloud
- NetBox Enterprise
- Self-hosted
validations:
required: true
- type: input
attributes:
label: NetBox Version
description: What version of NetBox are you currently running?
placeholder: v3.7.3
placeholder: v3.7.4
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.7.3
placeholder: v3.7.4
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 @@ -84,4 +84,4 @@ jobs:
run: coverage run --source="netbox/" netbox/manage.py test netbox/ --parallel

- name: Show coverage report
run: coverage report --skip-covered --omit *migrations*
run: coverage report --skip-covered --omit '*/migrations/*,*/tests/*'
2 changes: 1 addition & 1 deletion base_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ markdown-include
mkdocs-material

# Introspection for embedded code
# https://github.com/mkdocstrings/mkdocstrings/blob/master/CHANGELOG.md
# https://github.com/mkdocstrings/mkdocstrings/blob/main/CHANGELOG.md
mkdocstrings[python-legacy]

# Library for manipulating IP prefixes and addresses
Expand Down
3 changes: 3 additions & 0 deletions contrib/generated_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,10 @@
"8gfc-sfpp",
"16gfc-sfpp",
"32gfc-sfp28",
"32gfc-sfpp",
"64gfc-qsfpp",
"64gfc-sfpdd",
"64gfc-sfpp",
"128gfc-qsfp28",
"infiniband-sdr",
"infiniband-ddr",
Expand Down
3 changes: 1 addition & 2 deletions docs/installation/1-postgresql.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ This section entails the installation and configuration of a local PostgreSQL da
Once PostgreSQL has been installed, start the service and enable it to run at boot:

```no-highlight
sudo systemctl start postgresql
sudo systemctl enable postgresql
sudo systemctl enable --now postgresql
```

Before continuing, verify that you have installed PostgreSQL 12 or later:
Expand Down
3 changes: 1 addition & 2 deletions docs/installation/2-redis.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@

```no-highlight
sudo yum install -y redis
sudo systemctl start redis
sudo systemctl enable redis
sudo systemctl enable --now redis
```

Before continuing, verify that your installed version of Redis is at least v4.0:
Expand Down
3 changes: 1 addition & 2 deletions docs/installation/4-gunicorn.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ sudo systemctl daemon-reload
Then, start the `netbox` and `netbox-rq` services and enable them to initiate at boot time:

```no-highlight
sudo systemctl start netbox netbox-rq
sudo systemctl enable netbox netbox-rq
sudo systemctl enable --now netbox netbox-rq
```

You can use the command `systemctl status netbox` to verify that the WSGI service is running:
Expand Down
27 changes: 26 additions & 1 deletion docs/release-notes/version-3.7.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
# NetBox v3.7

## v3.7.4 (FUTURE)
## v3.7.5 (FUTURE)

---

## v3.7.4 (2024-03-13)

### Enhancements

* [#14206](https://github.com/netbox-community/netbox/issues/14206) - Add additional FibreChannel SFP+ interface types
* [#14366](https://github.com/netbox-community/netbox/issues/14366) - Enable custom links for config contexts & templates
* [#15291](https://github.com/netbox-community/netbox/issues/15291) - Add tunnel termination buttons to VM interfaces table
* [#15297](https://github.com/netbox-community/netbox/issues/15297) - Linkify platform column in device & virtual machine tables

### Bug Fixes

* [#13722](https://github.com/netbox-community/netbox/issues/13722) - Fix range expansion for comma-separated numerical values
* [#14832](https://github.com/netbox-community/netbox/issues/14832) - Enable querying IP addresses for an FHRP group via GraphQL
* [#15220](https://github.com/netbox-community/netbox/issues/15220) - Fix validation check when bulk editing the mask length of IP addresses
* [#15232](https://github.com/netbox-community/netbox/issues/15232) - Permit user with sufficient permissions to assign an inventory item to a device type
* [#15241](https://github.com/netbox-community/netbox/issues/15241) - Restore missing `display` field on VirtualDisk serialization in REST API
* [#15243](https://github.com/netbox-community/netbox/issues/15243) - Correct representation of installed module when listing module bays using REST API brief mode
* [#15316](https://github.com/netbox-community/netbox/issues/15316) - Fix selection of 3DES encryption for IKE & IPSec proposals
* [#15322](https://github.com/netbox-community/netbox/issues/15322) - Add description field to YAML export for device & module types
* [#15336](https://github.com/netbox-community/netbox/issues/15336) - Correct label for recurring scheduled jobs
* [#15347](https://github.com/netbox-community/netbox/issues/15347) - Fix querying virtual machine contacts via GraphQL
* [#15356](https://github.com/netbox-community/netbox/issues/15356) - Fix assignment of front & rear images to device types via REST API

---

Expand Down
12 changes: 10 additions & 2 deletions netbox/dcim/api/nested_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,14 @@ class Meta:
fields = ['id', 'url', 'display', 'name']


class ModuleBayNestedModuleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')

class Meta:
model = models.Module
fields = ['id', 'url', 'display', 'serial']


class NestedModuleSerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
device = NestedDeviceSerializer(read_only=True)
Expand Down Expand Up @@ -392,11 +400,11 @@ class Meta:

class NestedModuleBaySerializer(WritableNestedSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebay-detail')
module = NestedModuleSerializer(required=False, read_only=True, allow_null=True)
installed_module = ModuleBayNestedModuleSerializer(required=False, allow_null=True)

class Meta:
model = models.ModuleBay
fields = ['id', 'url', 'display', 'module', 'name']
fields = ['id', 'url', 'display', 'installed_module', 'name']


class NestedDeviceBaySerializer(WritableNestedSerializer):
Expand Down
4 changes: 2 additions & 2 deletions netbox/dcim/api/serializers_/devicetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False, allow_null=True)
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False, allow_null=True)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
front_image = serializers.URLField(allow_null=True, required=False)
rear_image = serializers.URLField(allow_null=True, required=False)
front_image = serializers.ImageField(required=False, allow_null=True)
rear_image = serializers.ImageField(required=False, allow_null=True)

# Counter fields
console_port_template_count = serializers.IntegerField(read_only=True)
Expand Down
6 changes: 6 additions & 0 deletions netbox/dcim/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -889,7 +889,10 @@ class InterfaceTypeChoices(ChoiceSet):
TYPE_8GFC_SFP_PLUS = '8gfc-sfpp'
TYPE_16GFC_SFP_PLUS = '16gfc-sfpp'
TYPE_32GFC_SFP28 = '32gfc-sfp28'
TYPE_32GFC_SFP_PLUS = '32gfc-sfpp'
TYPE_64GFC_QSFP_PLUS = '64gfc-qsfpp'
TYPE_64GFC_SFP_DD = '64gfc-sfpdd'
TYPE_64GFC_SFP_PLUS = '64gfc-sfpp'
TYPE_128GFC_QSFP28 = '128gfc-qsfp28'

# InfiniBand
Expand Down Expand Up @@ -1058,7 +1061,10 @@ class InterfaceTypeChoices(ChoiceSet):
(TYPE_8GFC_SFP_PLUS, 'SFP+ (8GFC)'),
(TYPE_16GFC_SFP_PLUS, 'SFP+ (16GFC)'),
(TYPE_32GFC_SFP28, 'SFP28 (32GFC)'),
(TYPE_32GFC_SFP_PLUS, 'SFP+ (32GFC)'),
(TYPE_64GFC_QSFP_PLUS, 'QSFP+ (64GFC)'),
(TYPE_64GFC_SFP_DD, 'SFP-DD (64GFC)'),
(TYPE_64GFC_SFP_PLUS, 'SFP+ (64GFC)'),
(TYPE_128GFC_QSFP28, 'QSFP28 (128GFC)'),
)
),
Expand Down
6 changes: 4 additions & 2 deletions netbox/dcim/models/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,16 @@ def to_yaml(self):
'manufacturer': self.manufacturer.name,
'model': self.model,
'slug': self.slug,
'description': self.description,
'default_platform': self.default_platform.name if self.default_platform else None,
'part_number': self.part_number,
'u_height': float(self.u_height),
'is_full_depth': self.is_full_depth,
'subdevice_role': self.subdevice_role,
'airflow': self.airflow,
'comments': self.comments,
'weight': float(self.weight) if self.weight is not None else None,
'weight_unit': self.weight_unit,
'comments': self.comments,
}

# Component templates
Expand Down Expand Up @@ -415,9 +416,10 @@ def to_yaml(self):
'manufacturer': self.manufacturer.name,
'model': self.model,
'part_number': self.part_number,
'comments': self.comments,
'description': self.description,
'weight': float(self.weight) if self.weight is not None else None,
'weight_unit': self.weight_unit,
'comments': self.comments,
}

# Component templates
Expand Down
6 changes: 5 additions & 1 deletion netbox/dcim/tables/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
linkify=True,
verbose_name=_('Type')
)
platform = tables.Column(
linkify=True,
verbose_name=_('Platform')
)
primary_ip = tables.Column(
linkify=True,
order_by=('primary_ip4', 'primary_ip6'),
Expand Down Expand Up @@ -294,7 +298,7 @@ class Meta(NetBoxTable.Meta):
model = models.Device
fields = (
'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'role', 'manufacturer', 'device_type',
'platform', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'parent_device',
'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'parent_device',
'device_bay_position', 'position', 'face', 'latitude', 'longitude', 'airflow', 'primary_ip', 'primary_ip4',
'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description',
'config_template', 'comments', 'contacts', 'tags', 'created', 'last_updated',
Expand Down
2 changes: 1 addition & 1 deletion netbox/dcim/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,7 @@ class DeviceTypeInventoryItemsView(DeviceTypeComponentsView):
tab = ViewTab(
label=_('Inventory Items'),
badge=lambda obj: obj.inventory_item_template_count,
permission='dcim.view_invenotryitemtemplate',
permission='dcim.view_inventoryitemtemplate',
weight=590,
hide_if_empty=True
)
Expand Down
1 change: 1 addition & 0 deletions netbox/extras/graphql/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
__all__ = (
'ChangelogMixin',
'ConfigContextMixin',
'ContactsMixin',
'CustomFieldsMixin',
'ImageAttachmentsMixin',
'JournalEntriesMixin',
Expand Down
6 changes: 3 additions & 3 deletions netbox/extras/models/configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from netbox.config import get_config
from netbox.registry import registry
from netbox.models import ChangeLoggedModel
from netbox.models.features import CloningMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin
from netbox.models.features import CloningMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin
from utilities.jinja2 import ConfigTemplateLoader
from utilities.utils import deepmerge

Expand All @@ -26,7 +26,7 @@
# Config contexts
#

class ConfigContext(SyncedDataMixin, CloningMixin, ChangeLoggedModel):
class ConfigContext(SyncedDataMixin, CloningMixin, CustomLinksMixin, ChangeLoggedModel):
"""
A ConfigContext represents a set of arbitrary data available to any Device or VirtualMachine matching its assigned
qualifiers (region, site, etc.). For example, the data stored in a ConfigContext assigned to site A and tenant B
Expand Down Expand Up @@ -210,7 +210,7 @@ def clean(self):
# Config templates
#

class ConfigTemplate(SyncedDataMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel):
class ConfigTemplate(SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel):
name = models.CharField(
verbose_name=_('name'),
max_length=100
Expand Down
14 changes: 0 additions & 14 deletions netbox/ipam/forms/model_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,20 +373,6 @@ def clean(self):
'primary_for_parent', _("Only IP addresses assigned to an interface can be designated as primary IPs.")
)

# Do not allow assigning a network ID or broadcast address to an interface.
if interface and (address := self.cleaned_data.get('address')):
if address.ip == address.network:
msg = _("{ip} is a network ID, which may not be assigned to an interface.").format(ip=address.ip)
if address.version == 4 and address.prefixlen not in (31, 32):
raise ValidationError(msg)
if address.version == 6 and address.prefixlen not in (127, 128):
raise ValidationError(msg)
if address.version == 4 and address.ip == address.broadcast and address.prefixlen not in (31, 32):
msg = _("{ip} is a broadcast address, which may not be assigned to an interface.").format(
ip=address.ip
)
raise ValidationError(msg)

def save(self, *args, **kwargs):
ipaddress = super().save(*args, **kwargs)

Expand Down
3 changes: 2 additions & 1 deletion netbox/ipam/graphql/types.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import graphene

from ipam import filtersets, models
from .mixins import IPAddressesMixin
from netbox.graphql.scalars import BigInt
from netbox.graphql.types import BaseObjectType, OrganizationalObjectType, NetBoxObjectType

Expand Down Expand Up @@ -71,7 +72,7 @@ class Meta:
filterset_class = filtersets.AggregateFilterSet


class FHRPGroupType(NetBoxObjectType):
class FHRPGroupType(NetBoxObjectType, IPAddressesMixin):

class Meta:
model = models.FHRPGroup
Expand Down
19 changes: 19 additions & 0 deletions netbox/ipam/models/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,25 @@ def clean(self):
'address': _("Cannot create IP address with /0 mask.")
})

# Do not allow assigning a network ID or broadcast address to an interface.
if self.assigned_object:
if self.address.ip == self.address.network:
msg = _("{ip} is a network ID, which may not be assigned to an interface.").format(
ip=self.address.ip
)
if self.address.version == 4 and self.address.prefixlen not in (31, 32):
raise ValidationError(msg)
if self.address.version == 6 and self.address.prefixlen not in (127, 128):
raise ValidationError(msg)
if (
self.address.version == 4 and self.address.ip == self.address.broadcast and
self.address.prefixlen not in (31, 32)
):
msg = _("{ip} is a broadcast address, which may not be assigned to an interface.").format(
ip=self.address.ip
)
raise ValidationError(msg)

# Enforce unique IP space (if applicable)
if (self.vrf is None and get_config().ENFORCE_GLOBAL_UNIQUE) or (self.vrf and self.vrf.enforce_unique):
duplicate_ips = self.get_duplicates()
Expand Down
2 changes: 1 addition & 1 deletion netbox/templates/core/job.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ <h5 class="card-header">{% trans "Scheduling" %}</h5>
<td>
{{ object.scheduled|annotated_date|placeholder }}
{% if object.interval %}
({% blocktrans with interval=object.interval %}every {{ interval }} seconds{% endblocktrans %})
({% blocktrans with interval=object.interval %}every {{ interval }} minutes{% endblocktrans %})
{% endif %}
</td>
</tr>
Expand Down
Loading

0 comments on commit 78bd7de

Please sign in to comment.