mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Implemented a view for adding individual devices to an existing virtual chassis
This commit is contained in:
@ -22,9 +22,10 @@ from utilities.forms import (
|
|||||||
)
|
)
|
||||||
from virtualization.models import Cluster
|
from virtualization.models import Cluster
|
||||||
from .constants import (
|
from .constants import (
|
||||||
CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_CONNECTED, IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_ORDERING_CHOICES,
|
CONNECTION_STATUS_CHOICES, CONNECTION_STATUS_CONNECTED, IFACE_FF_CHOICES, IFACE_FF_LAG, IFACE_MODE_ACCESS,
|
||||||
RACK_FACE_CHOICES, RACK_TYPE_CHOICES, RACK_WIDTH_CHOICES, RACK_WIDTH_19IN, RACK_WIDTH_23IN, STATUS_CHOICES,
|
IFACE_MODE_CHOICES, IFACE_MODE_TAGGED_ALL, IFACE_ORDERING_CHOICES, RACK_FACE_CHOICES, RACK_TYPE_CHOICES,
|
||||||
SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT, SUBDEVICE_ROLE_CHOICES,
|
RACK_WIDTH_CHOICES, RACK_WIDTH_19IN, RACK_WIDTH_23IN, STATUS_CHOICES, SUBDEVICE_ROLE_CHILD, SUBDEVICE_ROLE_PARENT,
|
||||||
|
SUBDEVICE_ROLE_CHOICES,
|
||||||
)
|
)
|
||||||
from .formfields import MACAddressFormField
|
from .formfields import MACAddressFormField
|
||||||
from .models import (
|
from .models import (
|
||||||
@ -33,7 +34,6 @@ from .models import (
|
|||||||
Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RackReservation,
|
Platform, PowerOutlet, PowerOutletTemplate, PowerPort, PowerPortTemplate, Rack, RackGroup, RackReservation,
|
||||||
RackRole, Region, Site, VCMembership, VirtualChassis
|
RackRole, Region, Site, VCMembership, VirtualChassis
|
||||||
)
|
)
|
||||||
from .constants import *
|
|
||||||
|
|
||||||
DEVICE_BY_PK_RE = '{\d+\}'
|
DEVICE_BY_PK_RE = '{\d+\}'
|
||||||
|
|
||||||
@ -2253,3 +2253,42 @@ class VCMembershipForm(BootstrapMixin, forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VCMembership
|
model = VCMembership
|
||||||
fields = ['position', 'priority']
|
fields = ['position', 'priority']
|
||||||
|
|
||||||
|
|
||||||
|
class VCMembershipCreateForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm):
|
||||||
|
site = forms.ModelChoiceField(
|
||||||
|
queryset=Site.objects.all(),
|
||||||
|
label='Site',
|
||||||
|
required=False,
|
||||||
|
widget=forms.Select(
|
||||||
|
attrs={'filter-for': 'rack'}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
rack = ChainedModelChoiceField(
|
||||||
|
queryset=Rack.objects.all(),
|
||||||
|
chains=(
|
||||||
|
('site', 'site'),
|
||||||
|
),
|
||||||
|
label='Rack',
|
||||||
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url='/api/dcim/racks/?site_id={{site}}',
|
||||||
|
attrs={'filter-for': 'device', 'nullable': 'true'}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
device = ChainedModelChoiceField(
|
||||||
|
queryset=Device.objects.all(),
|
||||||
|
chains=(
|
||||||
|
('site', 'site'),
|
||||||
|
('rack', 'rack'),
|
||||||
|
),
|
||||||
|
label='Device',
|
||||||
|
widget=APISelect(
|
||||||
|
api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}',
|
||||||
|
display_field='display_name'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = VCMembership
|
||||||
|
fields = ['site', 'rack', 'device', 'position', 'priority']
|
||||||
|
@ -216,6 +216,7 @@ urlpatterns = [
|
|||||||
url(r'^virtual-chassis/add/$', views.VirtualChassisCreateView.as_view(), name='virtualchassis_add'),
|
url(r'^virtual-chassis/add/$', views.VirtualChassisCreateView.as_view(), name='virtualchassis_add'),
|
||||||
url(r'^virtual-chassis/(?P<pk>\d+)/edit/$', views.VirtualChassisEditView.as_view(), name='virtualchassis_edit'),
|
url(r'^virtual-chassis/(?P<pk>\d+)/edit/$', views.VirtualChassisEditView.as_view(), name='virtualchassis_edit'),
|
||||||
url(r'^virtual-chassis/(?P<pk>\d+)/delete/$', views.VirtualChassisDeleteView.as_view(), name='virtualchassis_delete'),
|
url(r'^virtual-chassis/(?P<pk>\d+)/delete/$', views.VirtualChassisDeleteView.as_view(), name='virtualchassis_delete'),
|
||||||
|
url(r'^virtual-chassis/(?P<pk>\d+)/add-member/$', views.VirtualChassisAddMemberView.as_view(), name='virtualchassis_add_member'),
|
||||||
|
|
||||||
# VC memberships
|
# VC memberships
|
||||||
url(r'^vc-memberships/(?P<pk>\d+)/edit/$', views.VCMembershipEditView.as_view(), name='vcmembership_edit'),
|
url(r'^vc-memberships/(?P<pk>\d+)/edit/$', views.VCMembershipEditView.as_view(), name='vcmembership_edit'),
|
||||||
|
@ -2099,6 +2099,59 @@ class VirtualChassisDeleteView(PermissionRequiredMixin, ObjectDeleteView):
|
|||||||
default_return_url = 'dcim:device_list'
|
default_return_url = 'dcim:device_list'
|
||||||
|
|
||||||
|
|
||||||
|
class VirtualChassisAddMemberView(GetReturnURLMixin, View):
|
||||||
|
"""
|
||||||
|
Create a new VCMembership tying a Device to the VirtualChassis.
|
||||||
|
"""
|
||||||
|
template_name = 'utilities/obj_edit.html'
|
||||||
|
|
||||||
|
def get(self, request, pk):
|
||||||
|
|
||||||
|
virtual_chassis = get_object_or_404(VirtualChassis, pk=pk)
|
||||||
|
obj = VCMembership(virtual_chassis=virtual_chassis)
|
||||||
|
|
||||||
|
initial_data = {k: request.GET[k] for k in request.GET}
|
||||||
|
form = forms.VCMembershipCreateForm(instance=obj, initial=initial_data)
|
||||||
|
|
||||||
|
return render(request, self.template_name, {
|
||||||
|
'obj': obj,
|
||||||
|
'obj_type': VCMembership._meta.verbose_name,
|
||||||
|
'form': form,
|
||||||
|
'return_url': self.get_return_url(request, obj),
|
||||||
|
})
|
||||||
|
|
||||||
|
def post(self, request, pk):
|
||||||
|
|
||||||
|
virtual_chassis = get_object_or_404(VirtualChassis, pk=pk)
|
||||||
|
obj = VCMembership(virtual_chassis=virtual_chassis)
|
||||||
|
|
||||||
|
form = forms.VCMembershipCreateForm(request.POST, instance=obj)
|
||||||
|
|
||||||
|
if form.is_valid():
|
||||||
|
|
||||||
|
obj = form.save()
|
||||||
|
|
||||||
|
msg = 'Added member <a href="{}">{}</a>'.format(obj.device.get_absolute_url(), escape(obj.device))
|
||||||
|
messages.success(request, mark_safe(msg))
|
||||||
|
UserAction.objects.log_create(request.user, obj, msg)
|
||||||
|
|
||||||
|
if '_addanother' in request.POST:
|
||||||
|
return redirect(request.get_full_path())
|
||||||
|
|
||||||
|
return_url = form.cleaned_data.get('return_url')
|
||||||
|
if return_url is not None and is_safe_url(url=return_url, host=request.get_host()):
|
||||||
|
return redirect(return_url)
|
||||||
|
else:
|
||||||
|
return redirect(self.get_return_url(request, obj))
|
||||||
|
|
||||||
|
return render(request, self.template_name, {
|
||||||
|
'obj': obj,
|
||||||
|
'obj_type': VCMembership._meta.verbose_name,
|
||||||
|
'form': form,
|
||||||
|
'return_url': self.get_return_url(request, obj),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# VC memberships
|
# VC memberships
|
||||||
#
|
#
|
||||||
|
@ -122,6 +122,11 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
<div class="panel-footer text-right">
|
<div class="panel-footer text-right">
|
||||||
|
{% if perms.dcim.add_vcmembership %}
|
||||||
|
<a href="{% url 'dcim:virtualchassis_add_member' pk=device.virtual_chassis.pk %}?site={{ device.site.pk }}&rack={{ device.rack.pk }}&return_url={{ device.get_absolute_url }}" class="btn btn-primary btn-xs">
|
||||||
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Member
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
{% if perms.dcim.change_virtualchassis %}
|
{% if perms.dcim.change_virtualchassis %}
|
||||||
<a href="{% url 'dcim:virtualchassis_edit' pk=device.virtual_chassis.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
|
<a href="{% url 'dcim:virtualchassis_edit' pk=device.virtual_chassis.pk %}?return_url={{ device.get_absolute_url }}" class="btn btn-warning btn-xs">
|
||||||
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit Virtual Chassis
|
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> Edit Virtual Chassis
|
||||||
|
Reference in New Issue
Block a user