mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 04:22:01 -06:00
Closes #7769: Enable assignment of IP addresses to an existing FHRP group
This commit is contained in:
parent
34f24de3e4
commit
83b2102705
@ -3,6 +3,7 @@
|
||||
### Enhancements
|
||||
|
||||
* [#7619](https://github.com/netbox-community/netbox/issues/7619) - Permit custom validation rules to be defined as plain data or dotted path to class
|
||||
* [#7769](https://github.com/netbox-community/netbox/issues/7769) - Enable assignment of IP addresses to an existing FHRP group
|
||||
* [#7775](https://github.com/netbox-community/netbox/issues/7775) - Enable dynamic config for `CHANGELOG_RETENTION`, `CUSTOM_VALIDATORS`, and `GRAPHQL_ENABLED`
|
||||
|
||||
### Bug Fixes
|
||||
|
@ -321,6 +321,11 @@ class IPAddressForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
'virtual_machine_id': '$virtual_machine'
|
||||
}
|
||||
)
|
||||
fhrpgroup = DynamicModelChoiceField(
|
||||
queryset=FHRPGroup.objects.all(),
|
||||
required=False,
|
||||
label='FHRP Group'
|
||||
)
|
||||
vrf = DynamicModelChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
@ -428,6 +433,8 @@ class IPAddressForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
initial['interface'] = instance.assigned_object
|
||||
elif type(instance.assigned_object) is VMInterface:
|
||||
initial['vminterface'] = instance.assigned_object
|
||||
elif type(instance.assigned_object) is FHRPGroup:
|
||||
initial['fhrpgroup'] = instance.assigned_object
|
||||
if instance.nat_inside:
|
||||
nat_inside_parent = instance.nat_inside.assigned_object
|
||||
if type(nat_inside_parent) is Interface:
|
||||
@ -454,10 +461,13 @@ class IPAddressForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
# Cannot select both a device interface and a VM interface
|
||||
if self.cleaned_data.get('interface') and self.cleaned_data.get('vminterface'):
|
||||
raise forms.ValidationError("Cannot select both a device interface and a virtual machine interface")
|
||||
self.instance.assigned_object = self.cleaned_data.get('interface') or self.cleaned_data.get('vminterface')
|
||||
# Handle object assignment
|
||||
if self.cleaned_data['interface']:
|
||||
self.instance.assigned_object = self.cleaned_data['interface']
|
||||
elif self.cleaned_data['vminterface']:
|
||||
self.instance.assigned_object = self.cleaned_data['vminterface']
|
||||
elif self.cleaned_data['fhrpgroup']:
|
||||
self.instance.assigned_object = self.cleaned_data['fhrpgroup']
|
||||
|
||||
# Primary IP assignment is only available if an interface has been assigned.
|
||||
interface = self.cleaned_data.get('interface') or self.cleaned_data.get('vminterface')
|
||||
@ -471,7 +481,7 @@ class IPAddressForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
|
||||
# Assign/clear this IPAddress as the primary for the associated Device/VirtualMachine.
|
||||
interface = self.instance.assigned_object
|
||||
if interface:
|
||||
if type(interface) in (Interface, VMInterface):
|
||||
parent = interface.parent_object
|
||||
if self.cleaned_data['primary_for_parent']:
|
||||
if ipaddress.address.version == 4:
|
||||
|
@ -47,7 +47,7 @@ class FHRPGroup(PrimaryModel):
|
||||
to='ipam.IPAddress',
|
||||
content_type_field='assigned_object_type',
|
||||
object_id_field='assigned_object_id',
|
||||
related_query_name='fhrp_group'
|
||||
related_query_name='fhrpgroup'
|
||||
)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
@ -739,6 +739,12 @@ class IPAddressEditView(generic.ObjectEditView):
|
||||
except (ValueError, VMInterface.DoesNotExist):
|
||||
pass
|
||||
|
||||
elif 'fhrpgroup' in request.GET:
|
||||
try:
|
||||
obj.assigned_object = FHRPGroup.objects.get(pk=request.GET['fhrpgroup'])
|
||||
except (ValueError, FHRPGroup.DoesNotExist):
|
||||
pass
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
|
@ -68,6 +68,13 @@
|
||||
<div class="text-muted">None</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if perms.ipam.add_ipaddress %}
|
||||
<div class="card-footer text-end">
|
||||
<a href="{% url 'ipam:ipaddress_add' %}?fhrpgroup={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-sm btn-primary">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add IP Address
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card">
|
||||
<h5 class="card-header">Members</h5>
|
||||
|
@ -33,51 +33,41 @@
|
||||
<div class="row mb-2">
|
||||
<h5 class="offset-sm-3">Interface Assignment</h5>
|
||||
</div>
|
||||
{% with vm_tab_active=form.initial.vminterface %}
|
||||
<div class="row mb-2">
|
||||
<div class="offset-sm-3">
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation" class="nav-item">
|
||||
<button
|
||||
role="tab"
|
||||
type="button"
|
||||
id="device_tab"
|
||||
data-bs-toggle="tab"
|
||||
aria-controls="device"
|
||||
data-bs-target="#device"
|
||||
class="nav-link {% if not vm_tab_active %}active{% endif %}"
|
||||
>
|
||||
Device
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button
|
||||
role="tab"
|
||||
type="button"
|
||||
id="vm_tab"
|
||||
data-bs-toggle="tab"
|
||||
aria-controls="vm"
|
||||
data-bs-target="#vm"
|
||||
class="nav-link {% if vm_tab_active %}active{% endif %}"
|
||||
>
|
||||
Virtual Machine
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="row mb-2">
|
||||
<div class="offset-sm-3">
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link {% if not form.initial.vminterface and not form.initial.fhrpgroup %}active{% endif %}">
|
||||
Device
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="vm_tab" data-bs-toggle="tab" aria-controls="vm" data-bs-target="#vm" class="nav-link {% if form.initial.vminterface %}active{% endif %}">
|
||||
Virtual Machine
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="fhrpgroup_tab" data-bs-toggle="tab" aria-controls="fhrpgroup" data-bs-target="#fhrpgroup" class="nav-link {% if form.initial.fhrpgroup %}active{% endif %}">
|
||||
FHRP Group
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content p-0 border-0">
|
||||
<div class="tab-pane {% if not vm_tab_active %}active{% endif %}" id="device" role="tabpanel" aria-labeled-by="device_tab">
|
||||
{% render_field form.device %}
|
||||
{% render_field form.interface %}
|
||||
</div>
|
||||
<div class="tab-pane {% if vm_tab_active %}active{% endif %}" id="vm" role="tabpanel" aria-labeled-by="vm_tab">
|
||||
{% render_field form.virtual_machine %}
|
||||
{% render_field form.vminterface %}
|
||||
</div>
|
||||
{% render_field form.primary_for_parent %}
|
||||
</div>
|
||||
<div class="tab-content p-0 border-0">
|
||||
<div class="tab-pane {% if not form.initial.vminterface and not form.initial.fhrpgroup %}active{% endif %}" id="device" role="tabpanel" aria-labeled-by="device_tab">
|
||||
{% render_field form.device %}
|
||||
{% render_field form.interface %}
|
||||
</div>
|
||||
{% endwith %}
|
||||
<div class="tab-pane {% if form.initial.vminterface %}active{% endif %}" id="vm" role="tabpanel" aria-labeled-by="vm_tab">
|
||||
{% render_field form.virtual_machine %}
|
||||
{% render_field form.vminterface %}
|
||||
</div>
|
||||
<div class="tab-pane {% if form.initial.fhrpgroup %}active{% endif %}" id="fhrpgroup" role="tabpanel" aria-labeled-by="fhrpgroup_tab">
|
||||
{% render_field form.fhrpgroup %}
|
||||
</div>
|
||||
{% render_field form.primary_for_parent %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field-group my-5">
|
||||
|
Loading…
Reference in New Issue
Block a user