Merge branch 'main' into 18433-fix-macaddress-primary-for-interface

This commit is contained in:
Daniel Sheppard 2025-01-27 12:11:37 -06:00 committed by GitHub
commit ee5d7cfe31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 175 additions and 121 deletions

View File

@ -1,5 +1,6 @@
---
name: ✨ Feature Request
type: Feature
description: Propose a new NetBox feature or enhancement
labels: ["type: feature", "status: needs triage"]
body:

View File

@ -1,5 +1,6 @@
---
name: 🐛 Bug Report
type: Bug
description: Report a reproducible bug in the current release of NetBox
labels: ["type: bug", "status: needs triage"]
body:

View File

@ -1,5 +1,6 @@
---
name: 📖 Documentation Change
type: Documentation
description: Suggest an addition or modification to the NetBox documentation
labels: ["type: documentation", "status: needs triage"]
body:

View File

@ -1,5 +1,6 @@
---
name: 🌍 Translation
type: Translation
description: Request support for a new language in the user interface
labels: ["type: translation"]
body:

View File

@ -1,5 +1,6 @@
---
name: 🏡 Housekeeping
type: Housekeeping
description: A change pertaining to the codebase itself (developers only)
labels: ["type: housekeeping"]
body:

View File

@ -1,5 +1,6 @@
---
name: 🗑️ Deprecation
type: Deprecation
description: The removal of an existing feature or resource
labels: ["type: deprecation"]
body:

View File

@ -3,11 +3,15 @@ name: CI
on:
push:
paths-ignore:
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE.md'
- 'contrib/**'
- 'docs/**'
- 'netbox/translations/**'
pull_request:
paths-ignore:
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE.md'
- 'contrib/**'
- 'docs/**'
- 'netbox/translations/**'

View File

@ -46,7 +46,7 @@ Regions will always be listed alphabetically by name within each parent, and the
Like regions, site groups can be arranged in a recursive hierarchy for grouping sites. However, whereas regions are intended for geographic organization, site groups may be used for functional grouping. For example, you might classify sites as corporate, branch, or customer sites in addition to where they are physically located.
The use of both regions and site groups affords to independent but complementary dimensions across which sites can be organized.
The use of both regions and site groups affords two independent but complementary dimensions across which sites can be organized.
## Sites

View File

@ -62,6 +62,9 @@ GRANT CREATE ON SCHEMA public TO netbox;
!!! danger "Use a strong password"
**Do not use the password from the example.** Choose a strong, random password to ensure secure database authentication for your NetBox installation.
!!! danger "Use UTF8 encoding"
Make sure that your database uses `UTF8` encoding (the default for new installations). Especially do not use `SQL_ASCII` encoding, as it can lead to unpredictable and unrecoverable errors. Enter `\l` to check your encoding.
Once complete, enter `\q` to exit the PostgreSQL shell.
## Verify Service Status

View File

@ -1,4 +1,3 @@
# Generated by Django 5.0.9 on 2024-10-21 17:34
import django.db.models.deletion
from django.db import migrations, models
@ -16,7 +15,7 @@ def populate_denormalized_fields(apps, schema_editor):
termination._site_id = termination.site_id
# Note: Location cannot be set prior to migration
CircuitTermination.objects.bulk_update(terminations, ['_region', '_site_group', '_site'])
CircuitTermination.objects.bulk_update(terminations, ['_region', '_site_group', '_site'], batch_size=100)
class Migration(migrations.Migration):

View File

@ -53,10 +53,10 @@ class ScopedFilterSet(BaseFilterSet):
label=_('Site (slug)'),
)
location_id = TreeNodeMultipleChoiceFilter(
queryset=Location.objects.all(),
field_name='_location',
lookup_expr='in',
label=_('Location (ID)'),
queryset=Location.objects.all(),
field_name='_location',
lookup_expr='in',
label=_('Location (ID)'),
)
location = TreeNodeMultipleChoiceFilter(
queryset=Location.objects.all(),

View File

@ -1652,8 +1652,8 @@ class MACAddressFilterSet(NetBoxModelFilterSet):
if not value.strip():
return queryset
qs_filter = (
Q(mac_address__icontains=value) |
Q(description__icontains=value)
Q(mac_address__icontains=value) |
Q(description__icontains=value)
)
return queryset.filter(qs_filter)

View File

@ -1810,6 +1810,11 @@ class MACAddressForm(NetBoxModelForm):
super().__init__(*args, **kwargs)
if instance and instance.assigned_object and instance.assigned_object.primary_mac_address:
if instance.assigned_object.primary_mac_address.pk == instance.pk:
self.fields['interface'].disabled = True
self.fields['vminterface'].disabled = True
def clean(self):
super().clean()

View File

@ -15,6 +15,7 @@ from django.urls import reverse
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from core.models import ObjectType
from dcim.choices import *
from dcim.constants import *
from dcim.fields import MACAddressField
@ -1523,9 +1524,33 @@ class MACAddress(PrimaryModel):
def __str__(self):
return str(self.mac_address)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Denote the original assigned object (if any) for validation in clean()
self._original_assigned_object_id = self.__dict__.get('assigned_object_id')
self._original_assigned_object_type_id = self.__dict__.get('assigned_object_type_id')
@cached_property
def is_primary(self):
if self.assigned_object and hasattr(self.assigned_object, 'primary_mac_address'):
if self.assigned_object.primary_mac_address and self.assigned_object.primary_mac_address.pk == self.pk:
return True
return False
def clean(self, *args, **kwargs):
super().clean()
if self._original_assigned_object_id and self._original_assigned_object_type_id:
assigned_object = self.assigned_object
ct = ObjectType.objects.get_for_id(self._original_assigned_object_type_id)
original_assigned_object = ct.get_object_for_this_type(pk=self._original_assigned_object_id)
if original_assigned_object.primary_mac_address:
if not assigned_object:
raise ValidationError(
_("Cannot unassign MAC Address while it is designated as the primary MAC for an object")
)
elif original_assigned_object != assigned_object:
raise ValidationError(
_("Cannot reassign MAC Address while it is designated as the primary MAC for an object")
)

View File

@ -705,7 +705,7 @@ class DeviceInterfaceTable(InterfaceTable):
model = models.Interface
fields = (
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag',
'mgmt_only', 'mtu', 'mode', 'mac_address', 'wwn', 'rf_role', 'rf_channel', 'rf_channel_frequency',
'mgmt_only', 'mtu', 'mode', 'primary_mac_address', 'wwn', 'rf_role', 'rf_channel', 'rf_channel_frequency',
'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable', 'cable_color', 'wireless_link',
'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses',
'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'actions',

View File

@ -660,8 +660,8 @@ class CustomFieldAPITest(APITestCase):
CustomField(
type=CustomFieldTypeChoices.TYPE_BOOLEAN,
name='boolean_field',
default=False)
,
default=False
),
CustomField(
type=CustomFieldTypeChoices.TYPE_DATE,
name='date_field',

View File

@ -15,7 +15,7 @@ def populate_denormalized_fields(apps, schema_editor):
prefix._site_id = prefix.site_id
# Note: Location cannot be set prior to migration
Prefix.objects.bulk_update(prefixes, ['_region', '_site_group', '_site'])
Prefix.objects.bulk_update(prefixes, ['_region', '_site_group', '_site'], batch_size=100)
class Migration(migrations.Migration):

View File

@ -361,7 +361,7 @@ class VLANTranslationRule(NetBoxModel):
)
local_vid = models.PositiveSmallIntegerField(
verbose_name=_('Local VLAN ID'),
validators=(
validators=(
MinValueValidator(VLAN_VID_MIN),
MaxValueValidator(VLAN_VID_MAX)
),
@ -369,7 +369,7 @@ class VLANTranslationRule(NetBoxModel):
)
remote_vid = models.PositiveSmallIntegerField(
verbose_name=_('Remote VLAN ID'),
validators=(
validators=(
MinValueValidator(VLAN_VID_MIN),
MaxValueValidator(VLAN_VID_MAX)
),

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-01-18 05:01+0000\n"
"POT-Creation-Date: 2025-01-24 05:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -1402,7 +1402,7 @@ msgstr ""
#: netbox/dcim/models/device_components.py:1024
#: netbox/dcim/models/device_components.py:1095
#: netbox/dcim/models/device_components.py:1241
#: netbox/dcim/models/devices.py:477 netbox/dcim/models/racks.py:221
#: netbox/dcim/models/devices.py:478 netbox/dcim/models/racks.py:221
#: netbox/extras/models/tags.py:28
msgid "color"
msgstr ""
@ -1429,8 +1429,8 @@ msgstr ""
#: netbox/circuits/models/virtual_circuits.py:59 netbox/core/models/data.py:52
#: netbox/core/models/jobs.py:85 netbox/dcim/models/cables.py:49
#: netbox/dcim/models/device_components.py:1281
#: netbox/dcim/models/devices.py:644 netbox/dcim/models/devices.py:1176
#: netbox/dcim/models/devices.py:1403 netbox/dcim/models/power.py:94
#: netbox/dcim/models/devices.py:645 netbox/dcim/models/devices.py:1177
#: netbox/dcim/models/devices.py:1404 netbox/dcim/models/power.py:94
#: netbox/dcim/models/racks.py:288 netbox/dcim/models/sites.py:154
#: netbox/dcim/models/sites.py:270 netbox/ipam/models/ip.py:237
#: netbox/ipam/models/ip.py:508 netbox/ipam/models/ip.py:729
@ -1560,8 +1560,8 @@ msgstr ""
#: netbox/circuits/models/providers.py:98 netbox/core/models/data.py:39
#: netbox/core/models/jobs.py:46
#: netbox/dcim/models/device_component_templates.py:43
#: netbox/dcim/models/device_components.py:52 netbox/dcim/models/devices.py:588
#: netbox/dcim/models/devices.py:1335 netbox/dcim/models/devices.py:1398
#: netbox/dcim/models/device_components.py:52 netbox/dcim/models/devices.py:589
#: netbox/dcim/models/devices.py:1336 netbox/dcim/models/devices.py:1399
#: netbox/dcim/models/power.py:38 netbox/dcim/models/power.py:89
#: netbox/dcim/models/racks.py:257 netbox/dcim/models/sites.py:142
#: netbox/extras/models/configs.py:36 netbox/extras/models/configs.py:215
@ -1593,7 +1593,7 @@ msgstr ""
msgid "Full name of the provider"
msgstr ""
#: netbox/circuits/models/providers.py:28 netbox/dcim/models/devices.py:87
#: netbox/circuits/models/providers.py:28 netbox/dcim/models/devices.py:88
#: netbox/dcim/models/racks.py:137 netbox/dcim/models/sites.py:149
#: netbox/extras/models/models.py:506 netbox/ipam/models/asns.py:23
#: netbox/ipam/models/vlans.py:42 netbox/netbox/models/__init__.py:145
@ -3532,7 +3532,7 @@ msgstr ""
#: netbox/dcim/filtersets.py:1104 netbox/dcim/forms/filtersets.py:819
#: netbox/dcim/forms/filtersets.py:1390 netbox/dcim/forms/filtersets.py:1586
#: netbox/dcim/forms/filtersets.py:1591 netbox/dcim/forms/model_forms.py:1762
#: netbox/dcim/models/devices.py:1499 netbox/dcim/models/devices.py:1520
#: netbox/dcim/models/devices.py:1500 netbox/dcim/models/devices.py:1521
#: netbox/virtualization/filtersets.py:196
#: netbox/virtualization/filtersets.py:268
#: netbox/virtualization/forms/filtersets.py:177
@ -4125,7 +4125,7 @@ msgstr ""
msgid "Chassis"
msgstr ""
#: netbox/dcim/forms/bulk_edit.py:619 netbox/dcim/models/devices.py:482
#: netbox/dcim/forms/bulk_edit.py:619 netbox/dcim/models/devices.py:483
#: netbox/dcim/tables/devices.py:78
msgid "VM role"
msgstr ""
@ -5234,7 +5234,7 @@ msgstr ""
msgid "Device Role"
msgstr ""
#: netbox/dcim/forms/model_forms.py:500 netbox/dcim/models/devices.py:634
#: netbox/dcim/forms/model_forms.py:500 netbox/dcim/models/devices.py:635
msgid "The lowest-numbered unit occupied by the device"
msgstr ""
@ -5417,7 +5417,7 @@ msgstr ""
msgid "Virtual Machine"
msgstr ""
#: netbox/dcim/forms/model_forms.py:1822
#: netbox/dcim/forms/model_forms.py:1827
msgid "A MAC address can only be assigned to a single object."
msgstr ""
@ -6139,7 +6139,7 @@ msgid "module bays"
msgstr ""
#: netbox/dcim/models/device_components.py:1178
#: netbox/dcim/models/devices.py:1224
#: netbox/dcim/models/devices.py:1225
msgid "A module bay cannot belong to a module installed within it."
msgstr ""
@ -6175,14 +6175,14 @@ msgid "inventory item roles"
msgstr ""
#: netbox/dcim/models/device_components.py:1308
#: netbox/dcim/models/devices.py:597 netbox/dcim/models/devices.py:1184
#: netbox/dcim/models/devices.py:598 netbox/dcim/models/devices.py:1185
#: netbox/dcim/models/racks.py:304
#: netbox/virtualization/models/virtualmachines.py:126
msgid "serial number"
msgstr ""
#: netbox/dcim/models/device_components.py:1316
#: netbox/dcim/models/devices.py:605 netbox/dcim/models/devices.py:1191
#: netbox/dcim/models/devices.py:606 netbox/dcim/models/devices.py:1192
#: netbox/dcim/models/racks.py:311
msgid "asset tag"
msgstr ""
@ -6223,377 +6223,389 @@ msgstr ""
msgid "Cannot assign inventory item to component on another device"
msgstr ""
#: netbox/dcim/models/devices.py:58
#: netbox/dcim/models/devices.py:59
msgid "manufacturer"
msgstr ""
#: netbox/dcim/models/devices.py:59
#: netbox/dcim/models/devices.py:60
msgid "manufacturers"
msgstr ""
#: netbox/dcim/models/devices.py:83 netbox/dcim/models/devices.py:382
#: netbox/dcim/models/devices.py:84 netbox/dcim/models/devices.py:383
#: netbox/dcim/models/racks.py:133
msgid "model"
msgstr ""
#: netbox/dcim/models/devices.py:96
#: netbox/dcim/models/devices.py:97
msgid "default platform"
msgstr ""
#: netbox/dcim/models/devices.py:99 netbox/dcim/models/devices.py:386
#: netbox/dcim/models/devices.py:100 netbox/dcim/models/devices.py:387
msgid "part number"
msgstr ""
#: netbox/dcim/models/devices.py:102 netbox/dcim/models/devices.py:389
#: netbox/dcim/models/devices.py:103 netbox/dcim/models/devices.py:390
msgid "Discrete part number (optional)"
msgstr ""
#: netbox/dcim/models/devices.py:108 netbox/dcim/models/racks.py:53
#: netbox/dcim/models/devices.py:109 netbox/dcim/models/racks.py:53
msgid "height (U)"
msgstr ""
#: netbox/dcim/models/devices.py:112
#: netbox/dcim/models/devices.py:113
msgid "exclude from utilization"
msgstr ""
#: netbox/dcim/models/devices.py:113
#: netbox/dcim/models/devices.py:114
msgid "Devices of this type are excluded when calculating rack utilization."
msgstr ""
#: netbox/dcim/models/devices.py:117
#: netbox/dcim/models/devices.py:118
msgid "is full depth"
msgstr ""
#: netbox/dcim/models/devices.py:118
#: netbox/dcim/models/devices.py:119
msgid "Device consumes both front and rear rack faces."
msgstr ""
#: netbox/dcim/models/devices.py:125
#: netbox/dcim/models/devices.py:126
msgid "parent/child status"
msgstr ""
#: netbox/dcim/models/devices.py:126
#: netbox/dcim/models/devices.py:127
msgid ""
"Parent devices house child devices in device bays. Leave blank if this "
"device type is neither a parent nor a child."
msgstr ""
#: netbox/dcim/models/devices.py:130 netbox/dcim/models/devices.py:392
#: netbox/dcim/models/devices.py:650 netbox/dcim/models/racks.py:315
#: netbox/dcim/models/devices.py:131 netbox/dcim/models/devices.py:393
#: netbox/dcim/models/devices.py:651 netbox/dcim/models/racks.py:315
msgid "airflow"
msgstr ""
#: netbox/dcim/models/devices.py:207
#: netbox/dcim/models/devices.py:208
msgid "device type"
msgstr ""
#: netbox/dcim/models/devices.py:208
#: netbox/dcim/models/devices.py:209
msgid "device types"
msgstr ""
#: netbox/dcim/models/devices.py:290
#: netbox/dcim/models/devices.py:291
msgid "U height must be in increments of 0.5 rack units."
msgstr ""
#: netbox/dcim/models/devices.py:307
#: netbox/dcim/models/devices.py:308
#, python-brace-format
msgid ""
"Device {device} in rack {rack} does not have sufficient space to accommodate "
"a height of {height}U"
msgstr ""
#: netbox/dcim/models/devices.py:322
#: netbox/dcim/models/devices.py:323
#, python-brace-format
msgid ""
"Unable to set 0U height: Found <a href=\"{url}\">{racked_instance_count} "
"instances</a> already mounted within racks."
msgstr ""
#: netbox/dcim/models/devices.py:331
#: netbox/dcim/models/devices.py:332
msgid ""
"Must delete all device bay templates associated with this device before "
"declassifying it as a parent device."
msgstr ""
#: netbox/dcim/models/devices.py:337
#: netbox/dcim/models/devices.py:338
msgid "Child device types must be 0U."
msgstr ""
#: netbox/dcim/models/devices.py:412
#: netbox/dcim/models/devices.py:413
msgid "module type"
msgstr ""
#: netbox/dcim/models/devices.py:413
#: netbox/dcim/models/devices.py:414
msgid "module types"
msgstr ""
#: netbox/dcim/models/devices.py:483
#: netbox/dcim/models/devices.py:484
msgid "Virtual machines may be assigned to this role"
msgstr ""
#: netbox/dcim/models/devices.py:495
#: netbox/dcim/models/devices.py:496
msgid "device role"
msgstr ""
#: netbox/dcim/models/devices.py:496
#: netbox/dcim/models/devices.py:497
msgid "device roles"
msgstr ""
#: netbox/dcim/models/devices.py:510
#: netbox/dcim/models/devices.py:511
msgid "Optionally limit this platform to devices of a certain manufacturer"
msgstr ""
#: netbox/dcim/models/devices.py:522
#: netbox/dcim/models/devices.py:523
msgid "platform"
msgstr ""
#: netbox/dcim/models/devices.py:523
#: netbox/dcim/models/devices.py:524
msgid "platforms"
msgstr ""
#: netbox/dcim/models/devices.py:571
#: netbox/dcim/models/devices.py:572
msgid "The function this device serves"
msgstr ""
#: netbox/dcim/models/devices.py:598
#: netbox/dcim/models/devices.py:599
msgid "Chassis serial number, assigned by the manufacturer"
msgstr ""
#: netbox/dcim/models/devices.py:606 netbox/dcim/models/devices.py:1192
#: netbox/dcim/models/devices.py:607 netbox/dcim/models/devices.py:1193
msgid "A unique tag used to identify this device"
msgstr ""
#: netbox/dcim/models/devices.py:633
#: netbox/dcim/models/devices.py:634
msgid "position (U)"
msgstr ""
#: netbox/dcim/models/devices.py:641
#: netbox/dcim/models/devices.py:642
msgid "rack face"
msgstr ""
#: netbox/dcim/models/devices.py:662 netbox/dcim/models/devices.py:1419
#: netbox/dcim/models/devices.py:663 netbox/dcim/models/devices.py:1420
#: netbox/virtualization/models/virtualmachines.py:95
msgid "primary IPv4"
msgstr ""
#: netbox/dcim/models/devices.py:670 netbox/dcim/models/devices.py:1427
#: netbox/dcim/models/devices.py:671 netbox/dcim/models/devices.py:1428
#: netbox/virtualization/models/virtualmachines.py:103
msgid "primary IPv6"
msgstr ""
#: netbox/dcim/models/devices.py:678
#: netbox/dcim/models/devices.py:679
msgid "out-of-band IP"
msgstr ""
#: netbox/dcim/models/devices.py:695
#: netbox/dcim/models/devices.py:696
msgid "VC position"
msgstr ""
#: netbox/dcim/models/devices.py:698
#: netbox/dcim/models/devices.py:699
msgid "Virtual chassis position"
msgstr ""
#: netbox/dcim/models/devices.py:701
#: netbox/dcim/models/devices.py:702
msgid "VC priority"
msgstr ""
#: netbox/dcim/models/devices.py:705
#: netbox/dcim/models/devices.py:706
msgid "Virtual chassis master election priority"
msgstr ""
#: netbox/dcim/models/devices.py:708 netbox/dcim/models/sites.py:208
#: netbox/dcim/models/devices.py:709 netbox/dcim/models/sites.py:208
msgid "latitude"
msgstr ""
#: netbox/dcim/models/devices.py:713 netbox/dcim/models/devices.py:721
#: netbox/dcim/models/devices.py:714 netbox/dcim/models/devices.py:722
#: netbox/dcim/models/sites.py:213 netbox/dcim/models/sites.py:221
msgid "GPS coordinate in decimal format (xx.yyyyyy)"
msgstr ""
#: netbox/dcim/models/devices.py:716 netbox/dcim/models/sites.py:216
#: netbox/dcim/models/devices.py:717 netbox/dcim/models/sites.py:216
msgid "longitude"
msgstr ""
#: netbox/dcim/models/devices.py:789
#: netbox/dcim/models/devices.py:790
msgid "Device name must be unique per site."
msgstr ""
#: netbox/dcim/models/devices.py:800 netbox/ipam/models/services.py:71
#: netbox/dcim/models/devices.py:801 netbox/ipam/models/services.py:71
msgid "device"
msgstr ""
#: netbox/dcim/models/devices.py:801
#: netbox/dcim/models/devices.py:802
msgid "devices"
msgstr ""
#: netbox/dcim/models/devices.py:824
#: netbox/dcim/models/devices.py:825
#, python-brace-format
msgid "Rack {rack} does not belong to site {site}."
msgstr ""
#: netbox/dcim/models/devices.py:829
#: netbox/dcim/models/devices.py:830
#, python-brace-format
msgid "Location {location} does not belong to site {site}."
msgstr ""
#: netbox/dcim/models/devices.py:835
#: netbox/dcim/models/devices.py:836
#, python-brace-format
msgid "Rack {rack} does not belong to location {location}."
msgstr ""
#: netbox/dcim/models/devices.py:842
#: netbox/dcim/models/devices.py:843
msgid "Cannot select a rack face without assigning a rack."
msgstr ""
#: netbox/dcim/models/devices.py:846
#: netbox/dcim/models/devices.py:847
msgid "Cannot select a rack position without assigning a rack."
msgstr ""
#: netbox/dcim/models/devices.py:852
#: netbox/dcim/models/devices.py:853
msgid "Position must be in increments of 0.5 rack units."
msgstr ""
#: netbox/dcim/models/devices.py:856
#: netbox/dcim/models/devices.py:857
msgid "Must specify rack face when defining rack position."
msgstr ""
#: netbox/dcim/models/devices.py:864
#: netbox/dcim/models/devices.py:865
#, python-brace-format
msgid "A 0U device type ({device_type}) cannot be assigned to a rack position."
msgstr ""
#: netbox/dcim/models/devices.py:875
#: netbox/dcim/models/devices.py:876
msgid ""
"Child device types cannot be assigned to a rack face. This is an attribute "
"of the parent device."
msgstr ""
#: netbox/dcim/models/devices.py:882
#: netbox/dcim/models/devices.py:883
msgid ""
"Child device types cannot be assigned to a rack position. This is an "
"attribute of the parent device."
msgstr ""
#: netbox/dcim/models/devices.py:896
#: netbox/dcim/models/devices.py:897
#, python-brace-format
msgid ""
"U{position} is already occupied or does not have sufficient space to "
"accommodate this device type: {device_type} ({u_height}U)"
msgstr ""
#: netbox/dcim/models/devices.py:911
#: netbox/dcim/models/devices.py:912
#, python-brace-format
msgid "{ip} is not an IPv4 address."
msgstr ""
#: netbox/dcim/models/devices.py:923 netbox/dcim/models/devices.py:941
#: netbox/dcim/models/devices.py:924 netbox/dcim/models/devices.py:942
#, python-brace-format
msgid "The specified IP address ({ip}) is not assigned to this device."
msgstr ""
#: netbox/dcim/models/devices.py:929
#: netbox/dcim/models/devices.py:930
#, python-brace-format
msgid "{ip} is not an IPv6 address."
msgstr ""
#: netbox/dcim/models/devices.py:959
#: netbox/dcim/models/devices.py:960
#, python-brace-format
msgid ""
"The assigned platform is limited to {platform_manufacturer} device types, "
"but this device's type belongs to {devicetype_manufacturer}."
msgstr ""
#: netbox/dcim/models/devices.py:970
#: netbox/dcim/models/devices.py:971
#, python-brace-format
msgid "The assigned cluster belongs to a different site ({site})"
msgstr ""
#: netbox/dcim/models/devices.py:977
#: netbox/dcim/models/devices.py:978
#, python-brace-format
msgid "The assigned cluster belongs to a different location ({location})"
msgstr ""
#: netbox/dcim/models/devices.py:985
#: netbox/dcim/models/devices.py:986
msgid "A device assigned to a virtual chassis must have its position defined."
msgstr ""
#: netbox/dcim/models/devices.py:991
#: netbox/dcim/models/devices.py:992
#, python-brace-format
msgid ""
"Device cannot be removed from virtual chassis {virtual_chassis} because it "
"is currently designated as its master."
msgstr ""
#: netbox/dcim/models/devices.py:1199
#: netbox/dcim/models/devices.py:1200
msgid "module"
msgstr ""
#: netbox/dcim/models/devices.py:1200
#: netbox/dcim/models/devices.py:1201
msgid "modules"
msgstr ""
#: netbox/dcim/models/devices.py:1213
#: netbox/dcim/models/devices.py:1214
#, python-brace-format
msgid ""
"Module must be installed within a module bay belonging to the assigned "
"device ({device})."
msgstr ""
#: netbox/dcim/models/devices.py:1340
#: netbox/dcim/models/devices.py:1341
msgid "domain"
msgstr ""
#: netbox/dcim/models/devices.py:1353 netbox/dcim/models/devices.py:1354
#: netbox/dcim/models/devices.py:1354 netbox/dcim/models/devices.py:1355
msgid "virtual chassis"
msgstr ""
#: netbox/dcim/models/devices.py:1366
#: netbox/dcim/models/devices.py:1367
#, python-brace-format
msgid "The selected master ({master}) is not assigned to this virtual chassis."
msgstr ""
#: netbox/dcim/models/devices.py:1382
#: netbox/dcim/models/devices.py:1383
#, python-brace-format
msgid ""
"Unable to delete virtual chassis {self}. There are member interfaces which "
"form a cross-chassis LAG interfaces."
msgstr ""
#: netbox/dcim/models/devices.py:1408 netbox/vpn/models/l2vpn.py:37
#: netbox/dcim/models/devices.py:1409 netbox/vpn/models/l2vpn.py:37
msgid "identifier"
msgstr ""
#: netbox/dcim/models/devices.py:1409
#: netbox/dcim/models/devices.py:1410
msgid "Numeric identifier unique to the parent device"
msgstr ""
#: netbox/dcim/models/devices.py:1437 netbox/extras/models/customfields.py:225
#: netbox/dcim/models/devices.py:1438 netbox/extras/models/customfields.py:225
#: netbox/extras/models/models.py:107 netbox/extras/models/models.py:694
#: netbox/netbox/models/__init__.py:119
msgid "comments"
msgstr ""
#: netbox/dcim/models/devices.py:1453
#: netbox/dcim/models/devices.py:1454
msgid "virtual device context"
msgstr ""
#: netbox/dcim/models/devices.py:1454
#: netbox/dcim/models/devices.py:1455
msgid "virtual device contexts"
msgstr ""
#: netbox/dcim/models/devices.py:1483
#: netbox/dcim/models/devices.py:1484
#, python-brace-format
msgid "{ip} is not an IPv{family} address."
msgstr ""
#: netbox/dcim/models/devices.py:1489
#: netbox/dcim/models/devices.py:1490
msgid "Primary IP address must belong to an interface on the assigned device."
msgstr ""
#: netbox/dcim/models/devices.py:1521
#: netbox/dcim/models/devices.py:1522
msgid "MAC addresses"
msgstr ""
#: netbox/dcim/models/devices.py:1544
msgid ""
"Cannot unassign MAC Address while it is designated as the primary MAC for an "
"object"
msgstr ""
#: netbox/dcim/models/devices.py:1548
msgid ""
"Cannot reassign MAC Address while it is designated as the primary MAC for an "
"object"
msgstr ""
#: netbox/dcim/models/mixins.py:94
#, python-brace-format
msgid "Please select a {scope_type}."

View File

@ -150,8 +150,8 @@ class ClusterAddDevicesForm(forms.Form):
for scope_field in ['site', 'location']:
device_scope = getattr(device, scope_field)
if (
self.cluster.scope_type.model_class() == apps.get_model('dcim', scope_field)
and device_scope != self.cluster.scope
self.cluster.scope_type.model_class() == apps.get_model('dcim', scope_field) and
device_scope != self.cluster.scope
):
raise ValidationError({
'devices': _(

View File

@ -15,7 +15,7 @@ def populate_denormalized_fields(apps, schema_editor):
cluster._site_id = cluster.site_id
# Note: Location cannot be set prior to migration
Cluster.objects.bulk_update(clusters, ['_region', '_site_group', '_site'])
Cluster.objects.bulk_update(clusters, ['_region', '_site_group', '_site'], batch_size=100)
class Migration(migrations.Migration):

View File

@ -120,9 +120,9 @@ class VMInterfaceTable(BaseInterfaceTable):
class Meta(NetBoxTable.Meta):
model = VMInterface
fields = (
'pk', 'id', 'name', 'virtual_machine', 'enabled', 'mac_address', 'mtu', 'mode', 'description', 'tags',
'vrf', 'primary_mac_address', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan',
'tagged_vlans', 'qinq_svlan', 'created', 'last_updated',
'pk', 'id', 'name', 'virtual_machine', 'enabled', 'mtu', 'mode', 'description', 'tags', 'vrf',
'primary_mac_address', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans',
'qinq_svlan', 'created', 'last_updated',
)
default_columns = ('pk', 'name', 'virtual_machine', 'enabled', 'description')
@ -144,11 +144,11 @@ class VirtualMachineVMInterfaceTable(VMInterfaceTable):
class Meta(NetBoxTable.Meta):
model = VMInterface
fields = (
'pk', 'id', 'name', 'enabled', 'parent', 'bridge', 'mac_address', 'mtu', 'mode', 'description', 'tags',
'vrf', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'qinq_svlan',
'actions',
'pk', 'id', 'name', 'enabled', 'parent', 'bridge', 'primary_mac_address', 'mtu', 'mode', 'description',
'tags', 'vrf', 'l2vpn', 'tunnel', 'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans',
'qinq_svlan', 'actions',
)
default_columns = ('pk', 'name', 'enabled', 'mac_address', 'mtu', 'mode', 'description', 'ip_addresses')
default_columns = ('pk', 'name', 'enabled', 'primary_mac_address', 'mtu', 'mode', 'description', 'ip_addresses')
row_attrs = {
'data-name': lambda record: record.name,
'data-virtual': lambda record: "true",