mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-23 12:08:43 -06:00
4867 multiple mac addresses (#17902)
* Create MACAddress model and migrations to convert existing .mac_address fields to standalone objects * Add migrations * All views/filtering working and documentation done; no unit tests yet * Redo migrations following VLAN Translation * Remove mac_address filter fields and add table columns for device/vm * Remove unnecessary "bulk rename" * Fix filterset tests for Device * Fix filterset tests for Interface * Fix tests on single-object forms * Fix serializer tests * Fix filterset tests for VMInterface * Fix filterset tests for Device and VirtualMachine * Move new field check into lookup_map iteration * Fix general MACAddress filter tests * Add GraphQL types/filters/schema * Fix bulk edit/create tests (bulk editing Interfaces will be unsupported because of inheritance from ComponentBulkEditForm) * Make mac_address read_only on InterfaceSerializer/VMInterfaceSerializer * Undo unrelated work * Cleanup unused IPAddress derived stuff * API endpoints * Add serializer objects to interface serializers * Clean up unnecessary bulk create forms/views/routes * Add SearchIndex and adjust indexable fields for Interface and VMInterface * Reorganize MACAddress classes out of association with DeviceComponents * Move MACAddressSerializer * Enforce saving only a single is_primary MACAddress per interface/vminterface * Perform is_primary validation on MACAddress model and just check if one already exists for the interface * Remove form-level validation * Fix check for current is_primary setting when reassigning * Model cleanup * Documentation notes and cleanup * Simplify serializer and add ip_addresses * Add to VMInterfaceSerializer too * Style cleanup * Standardize "MAC Address" instead of "MAC" * Remove unused views * Add is_primary field for bulk edit * HTML cleanup and add copy-to-clipboard button * Remove mac_address from Interface and VMInterface bulk-edit forms * Add device and VM filtering * Use combined assigned_object_parent in table to match structure of IPAddressTable * Add GFK fields to MACAddressSerializer * Reorganize "Addressing" sections to remove from proximity to "Device Components" and related groupings * Clean up migrations * Misc cleanup * Add filterset test * Remove mac_address field from interface forms * Designate primary MAC address via a ForeignKey on the interface models * Add serializer fields for primary_mac_address * Update docs --------- Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
@@ -123,11 +123,24 @@
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "MAC Address" %}</th>
|
||||
<td><span class="font-monospace">{{ object.mac_address|placeholder }}</span></td>
|
||||
<td>
|
||||
{% if object.mac_address %}
|
||||
<span class="font-monospace">{{ object.mac_address }}</span>
|
||||
<span class="badge text-bg-primary">{% trans "Primary" %}</span>
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "WWN" %}</th>
|
||||
<td><span class="font-monospace">{{ object.wwn|placeholder }}</span></td>
|
||||
<td>
|
||||
{% if object.wwn %}
|
||||
<span class="font-monospace">{{ object.wwn }}</span>
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "VRF" %}</th>
|
||||
@@ -350,7 +363,23 @@
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% htmx_table 'ipam:ipaddress_list' interface_id=object.pk %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h2 class="card-header">
|
||||
{% trans "MAC Addresses" %}
|
||||
{% if perms.dcim.add_macaddress %}
|
||||
<div class="card-actions">
|
||||
<a href="{% url 'dcim:macaddress_add' %}?device={{ object.device.pk }}&interface={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-ghost-primary btn-sm">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add MAC Address" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% htmx_table 'dcim:macaddress_list' interface_id=object.pk %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
55
netbox/templates/dcim/macaddress.html
Normal file
55
netbox/templates/dcim/macaddress.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{% extends 'generic/object.html' %}
|
||||
{% load helpers %}
|
||||
{% load plugins %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "MAC Address" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "MAC Address" %}</th>
|
||||
<td>
|
||||
<span id="macaddress_{{ object.pk }}">{{ object.mac_address|placeholder }}</span>
|
||||
{% copy_content object.pk prefix="macaddress_" %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Assignment" %}</th>
|
||||
<td>
|
||||
{% if object.assigned_object %}
|
||||
{{ object.assigned_object.parent_object|linkify }} /
|
||||
{{ object.assigned_object|linkify }}
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Primary for interface" %}</th>
|
||||
<td>{% checkmark object.is_primary %}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/comments.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -14,73 +14,85 @@
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Interface" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Virtual Machine" %}</th>
|
||||
<td>{{ object.virtual_machine|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Enabled" %}</th>
|
||||
<td>
|
||||
{% if object.enabled %}
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span>
|
||||
{% else %}
|
||||
<span class="text-danger"><i class="mdi mdi-close"></i></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Parent" %}</th>
|
||||
<td>{{ object.parent|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Bridge" %}</th>
|
||||
<td>{{ object.bridge|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "VRF" %}</th>
|
||||
<td>{{ object.vrf|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "MTU" %}</th>
|
||||
<td>{{ object.mtu|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "MAC Address" %}</th>
|
||||
<td><span class="font-monospace">{{ object.mac_address|placeholder }}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "802.1Q Mode" %}</th>
|
||||
<td>{{ object.get_mode_display|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Tunnel" %}</th>
|
||||
<td>{{ object.tunnel_termination.tunnel|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "VLAN Translation" %}</th>
|
||||
<td>{{ object.vlan_translation_policy|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% plugin_left_page object %}
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Interface" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Virtual Machine" %}</th>
|
||||
<td>{{ object.virtual_machine|linkify }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Name" %}</th>
|
||||
<td>{{ object.name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Enabled" %}</th>
|
||||
<td>
|
||||
{% if object.enabled %}
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span>
|
||||
{% else %}
|
||||
<span class="text-danger"><i class="mdi mdi-close"></i></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Parent" %}</th>
|
||||
<td>{{ object.parent|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Bridge" %}</th>
|
||||
<td>{{ object.bridge|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "MTU" %}</th>
|
||||
<td>{{ object.mtu|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "802.1Q Mode" %}</th>
|
||||
<td>{{ object.get_mode_display|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Tunnel" %}</th>
|
||||
<td>{{ object.tunnel_termination.tunnel|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
{% include 'ipam/inc/panels/fhrp_groups.html' %}
|
||||
{% plugin_right_page object %}
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
<div class="card">
|
||||
<h2 class="card-header">{% trans "Addressing" %}</h2>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "MAC Address" %}</th>
|
||||
<td>
|
||||
{% if object.mac_address %}
|
||||
<span class="font-monospace">{{ object.mac_address }}</span>
|
||||
<span class="badge text-bg-primary">{% trans "Primary" %}</span>
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "VRF" %}</th>
|
||||
<td>{{ object.vrf|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "VLAN Translation" %}</th>
|
||||
<td>{{ object.vlan_translation_policy|linkify|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'ipam/inc/panels/fhrp_groups.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
@@ -99,6 +111,24 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h2 class="card-header">
|
||||
{% trans "MAC Addresses" %}
|
||||
{% if perms.ipam.add_macaddress %}
|
||||
<div class="card-actions">
|
||||
<a href="{% url 'dcim:macaddress_add' %}?virtual_machine={{ object.device.pk }}&vminterface={{ object.pk }}&return_url={{ object.get_absolute_url }}"
|
||||
class="btn btn-ghost-primary btn-sm">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add MAC Address" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% htmx_table 'dcim:macaddress_list' vminterface_id=object.pk %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
{% include 'inc/panel_table.html' with table=vlan_table heading="VLANs" %}
|
||||
|
||||
Reference in New Issue
Block a user