This commit is contained in:
jeremystretch 2022-11-15 11:24:36 -05:00
parent 640fd8045d
commit 6f8a7fdbe3
10 changed files with 82 additions and 43 deletions

View File

@ -37,7 +37,7 @@ router.register('inventory-item-templates', views.InventoryItemTemplateViewSet)
router.register('device-roles', views.DeviceRoleViewSet)
router.register('platforms', views.PlatformViewSet)
router.register('devices', views.DeviceViewSet)
router.register('vdcs', views.VirtualDeviceContextViewSet)
router.register('virtual-device-contexts', views.VirtualDeviceContextViewSet)
router.register('modules', views.ModuleViewSet)
# Device components

View File

@ -1407,12 +1407,12 @@ class PowerFeedPhaseChoices(ChoiceSet):
class VirtualDeviceContextStatusChoices(ChoiceSet):
key = 'VirtualDeviceContext.status'
STATUS_PLANNED = 'planned'
STATUS_ACTIVE = 'active'
STATUS_PLANNED = 'planned'
STATUS_OFFLINE = 'offline'
CHOICES = [
(STATUS_PLANNED, 'Planned', 'cyan'),
(STATUS_ACTIVE, 'Active', 'green'),
(STATUS_PLANNED, 'Planned', 'cyan'),
(STATUS_OFFLINE, 'Offline', 'red'),
]

View File

@ -1032,7 +1032,7 @@ class VirtualDeviceContextFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
class Meta:
model = VirtualDeviceContext
fields = ['id', 'device', 'name', ]
fields = ['id', 'device', 'name']
def search(self, queryset, name, value):
if not value.strip():

View File

@ -736,9 +736,8 @@ class VirtualDeviceContextFilterForm(
model = VirtualDeviceContext
fieldsets = (
(None, ('q', 'filter_id', 'tag')),
('Hardware', ('device', 'status', )),
('Attributes', ('device', 'status', 'has_primary_ip')),
('Tenant', ('tenant_group_id', 'tenant_id')),
('Miscellaneous', ('has_primary_ip',))
)
device = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),

View File

@ -1698,21 +1698,19 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm):
)
fieldsets = (
('Device', ('region', 'site_group', 'site', 'location', 'rack', 'device')),
('Virtual Device Context', ('name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tenant_group',
'tenant')),
(None, ('tags', ))
('Assigned Device', ('region', 'site_group', 'site', 'location', 'rack', 'device')),
('Virtual Device Context', ('name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tags')),
('Tenancy', ('tenant_group', 'tenant'))
)
class Meta:
model = VirtualDeviceContext
fields = [
'region', 'site_group', 'site', 'location', 'rack',
'device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant',
'comments', 'tags'
'region', 'site_group', 'site', 'location', 'rack', 'device', 'name', 'status', 'identifier',
'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant', 'comments', 'tags'
]
help_texts = {}
widgets = {
'status': StaticSelect(),
'primary_ip4': StaticSelect(),
'primary_ip6': StaticSelect(),
}

View File

@ -1113,7 +1113,7 @@ class VirtualDeviceContext(PrimaryModel):
choices=VirtualDeviceContextStatusChoices,
)
identifier = models.PositiveSmallIntegerField(
help_text='Unique identifier provided by the platform being virtualized (Example: Nexus VDC Identifier)',
help_text='Numeric identifier unique to the parent device',
blank=True,
null=True,
)
@ -1163,6 +1163,9 @@ class VirtualDeviceContext(PrimaryModel):
def get_absolute_url(self):
return reverse('dcim:virtualdevicecontext', kwargs={'pk': self.pk})
def get_status_color(self):
return VirtualDeviceContextStatusChoices.colors.get(self.status)
@property
def primary_ip(self):
if ConfigItem('PREFER_IPV4')() and self.primary_ip4:

View File

@ -184,12 +184,12 @@ urlpatterns = [
path('devices/<int:pk>/', include(get_model_urls('dcim', 'device'))),
# Virtual Device Context
path('vdcs/', views.VirtualDeviceContextListView.as_view(), name='virtualdevicecontext_list'),
path('vdcs/add/', views.VirtualDeviceContextEditView.as_view(), name='virtualdevicecontext_add'),
path('vdcs/import/', views.VirtualDeviceContextBulkImportView.as_view(), name='virtualdevicecontext_import'),
path('vdcs/edit/', views.VirtualDeviceContextBulkEditView.as_view(), name='virtualdevicecontext_bulk_edit'),
path('vdcs/delete/', views.VirtualDeviceContextBulkDeleteView.as_view(), name='virtualdevicecontext_bulk_delete'),
path('vdcs/<int:pk>/', include(get_model_urls('dcim', 'virtualdevicecontext'))),
path('virtual-device-contexts/', views.VirtualDeviceContextListView.as_view(), name='virtualdevicecontext_list'),
path('virtual-device-contexts/add/', views.VirtualDeviceContextEditView.as_view(), name='virtualdevicecontext_add'),
path('virtual-device-contexts/import/', views.VirtualDeviceContextBulkImportView.as_view(), name='virtualdevicecontext_import'),
path('virtual-device-contexts/edit/', views.VirtualDeviceContextBulkEditView.as_view(), name='virtualdevicecontext_bulk_edit'),
path('virtual-device-contexts/delete/', views.VirtualDeviceContextBulkDeleteView.as_view(), name='virtualdevicecontext_bulk_delete'),
path('virtual-device-contexts/<int:pk>/', include(get_model_urls('dcim', 'virtualdevicecontext'))),
# Modules
path('modules/', views.ModuleListView.as_view(), name='module_list'),

View File

@ -1837,11 +1837,14 @@ class DeviceView(generic.ObjectView):
else:
vc_members = []
# Services
services = Service.objects.restrict(request.user, 'view').filter(device=instance)
vdcs = VirtualDeviceContext.objects.restrict(request.user, 'view').filter(device=instance).prefetch_related(
'tenant'
)
return {
'services': services,
'vdcs': vdcs,
'vc_members': vc_members,
'svg_extra': f'highlight=id:{instance.pk}'
}

View File

@ -155,6 +155,38 @@
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/tags.html' %}
{% include 'inc/panels/comments.html' %}
<div class="card">
<h5 class="card-header">Virtual Device Contexts</h5>
<div class="card-body">
{% if vdcs %}
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Status</th>
<th>Identifier</th>
<th>Tenant</th>
</tr>
{% for vdc in vdcs %}
<tr>
<td>{{ vdc|linkify }}</td>
<td>{% badge vdc.get_status_display bg_color=vdc.get_status_color %}</td>
<td>{{ vdc.identifier|placeholder }}</td>
<td>{{ vdc.tenant|linkify|placeholder }}</td>
</tr>
{% endfor %}
</table>
{% else %}
<div class="text-muted">None</div>
{% endif %}
</div>
{% if perms.dcim.add_virtualdevicecontext %}
<div class="card-footer text-end noprint">
<a href="{% url 'dcim:virtualdevicecontext_add' %}?device={{ object.pk }}" class="btn btn-sm btn-primary">
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Create VDC
</a>
</div>
{% endif %}
</div>
{% plugin_left_page object %}
</div>
<div class="col col-12 col-xl-6">
@ -264,9 +296,7 @@
</div>
{% endif %}
<div class="card">
<h5 class="card-header">
Services
</h5>
<h5 class="card-header">Services</h5>
<div class="card-body">
{% if services %}
<table class="table table-hover">
@ -275,9 +305,7 @@
{% endfor %}
</table>
{% else %}
<div class="text-muted">
None
</div>
<div class="text-muted">None</div>
{% endif %}
</div>
{% if perms.ipam.add_service %}

View File

@ -28,7 +28,6 @@
<th scope="row">Identifier</th>
<td>{{ object.identifier|placeholder }}</td>
</tr>
</tr>
<tr>
<th scope="row">Primary IPv4</th>
<td>
@ -41,6 +40,15 @@
{{ object.primary_ip6|placeholder }}
</td>
</tr>
<tr>
<th scope="row">Tenant</th>
<td>
{% if object.tenant.group %}
{{ object.tenant.group|linkify }} /
{% endif %}
{{ object.tenant|linkify|placeholder }}
</td>
</tr>
</table>
</div>
</div>