mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 09:16:10 -06:00
Add config_template field to Device
This commit is contained in:
parent
f5e09c6f48
commit
8681e6d823
@ -9,6 +9,7 @@ from timezone_field.rest_framework import TimeZoneSerializerField
|
|||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
|
from extras.api.nested_serializers import NestedConfigTemplateSerializer
|
||||||
from ipam.api.nested_serializers import (
|
from ipam.api.nested_serializers import (
|
||||||
NestedASNSerializer, NestedIPAddressSerializer, NestedL2VPNTerminationSerializer, NestedVLANSerializer,
|
NestedASNSerializer, NestedIPAddressSerializer, NestedL2VPNTerminationSerializer, NestedVLANSerializer,
|
||||||
NestedVRFSerializer,
|
NestedVRFSerializer,
|
||||||
@ -651,6 +652,7 @@ class DeviceSerializer(NetBoxModelSerializer):
|
|||||||
cluster = NestedClusterSerializer(required=False, allow_null=True)
|
cluster = NestedClusterSerializer(required=False, allow_null=True)
|
||||||
virtual_chassis = NestedVirtualChassisSerializer(required=False, allow_null=True, default=None)
|
virtual_chassis = NestedVirtualChassisSerializer(required=False, allow_null=True, default=None)
|
||||||
vc_position = serializers.IntegerField(allow_null=True, max_value=255, min_value=0, default=None)
|
vc_position = serializers.IntegerField(allow_null=True, max_value=255, min_value=0, default=None)
|
||||||
|
config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
@ -658,7 +660,7 @@ class DeviceSerializer(NetBoxModelSerializer):
|
|||||||
'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
|
'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
|
||||||
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip',
|
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip',
|
||||||
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description',
|
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description',
|
||||||
'comments', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
|
'comments', 'config_template', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
@swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
|
@swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
|
||||||
|
@ -3,6 +3,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from extras.filtersets import LocalConfigContextFilterSet
|
from extras.filtersets import LocalConfigContextFilterSet
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import ASN, L2VPN, IPAddress, VRF
|
from ipam.models import ASN, L2VPN, IPAddress, VRF
|
||||||
from netbox.filtersets import (
|
from netbox.filtersets import (
|
||||||
BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet,
|
BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet,
|
||||||
@ -936,6 +937,10 @@ class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilter
|
|||||||
method='_virtual_chassis_member',
|
method='_virtual_chassis_member',
|
||||||
label=_('Is a virtual chassis member')
|
label=_('Is a virtual chassis member')
|
||||||
)
|
)
|
||||||
|
config_template_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
label=_('Config template (ID)'),
|
||||||
|
)
|
||||||
console_ports = django_filters.BooleanFilter(
|
console_ports = django_filters.BooleanFilter(
|
||||||
method='_console_ports',
|
method='_console_ports',
|
||||||
label=_('Has console ports'),
|
label=_('Has console ports'),
|
||||||
|
@ -6,6 +6,7 @@ from timezone_field import TimeZoneFormField
|
|||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import ASN, VLAN, VLANGroup, VRF
|
from ipam.models import ASN, VLAN, VLANGroup, VRF
|
||||||
from netbox.forms import NetBoxModelBulkEditForm
|
from netbox.forms import NetBoxModelBulkEditForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
@ -540,6 +541,10 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
max_length=200,
|
max_length=200,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
config_template = DynamicModelChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
comments = CommentField(
|
comments = CommentField(
|
||||||
widget=forms.Textarea,
|
widget=forms.Textarea,
|
||||||
label='Comments'
|
label='Comments'
|
||||||
@ -550,6 +555,7 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
('Device', ('device_role', 'status', 'tenant', 'platform', 'description')),
|
('Device', ('device_role', 'status', 'tenant', 'platform', 'description')),
|
||||||
('Location', ('site', 'location')),
|
('Location', ('site', 'location')),
|
||||||
('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')),
|
('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')),
|
||||||
|
('Configuration', ('config_template',)),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'location', 'tenant', 'platform', 'serial', 'airflow', 'description', 'comments',
|
'location', 'tenant', 'platform', 'serial', 'airflow', 'description', 'comments',
|
||||||
|
@ -8,6 +8,7 @@ from django.utils.translation import gettext as _
|
|||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import VRF
|
from ipam.models import VRF
|
||||||
from netbox.forms import NetBoxModelImportForm
|
from netbox.forms import NetBoxModelImportForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
@ -434,12 +435,17 @@ class DeviceImportForm(BaseDeviceImportForm):
|
|||||||
required=False,
|
required=False,
|
||||||
help_text=_('Airflow direction')
|
help_text=_('Airflow direction')
|
||||||
)
|
)
|
||||||
|
config_template = CSVModelChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
help_text=_('Config template')
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(BaseDeviceImportForm.Meta):
|
class Meta(BaseDeviceImportForm.Meta):
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
||||||
'site', 'location', 'rack', 'position', 'face', 'parent', 'device_bay', 'airflow', 'virtual_chassis',
|
'site', 'location', 'rack', 'position', 'face', 'parent', 'device_bay', 'airflow', 'virtual_chassis',
|
||||||
'vc_position', 'vc_priority', 'cluster', 'description', 'comments', 'tags',
|
'vc_position', 'vc_priority', 'cluster', 'description', 'config_template', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
|
@ -6,6 +6,7 @@ from dcim.choices import *
|
|||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
from extras.forms import LocalConfigContextFilterForm
|
from extras.forms import LocalConfigContextFilterForm
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import ASN, L2VPN, VRF
|
from ipam.models import ASN, L2VPN, VRF
|
||||||
from netbox.forms import NetBoxModelFilterSetForm
|
from netbox.forms import NetBoxModelFilterSetForm
|
||||||
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
|
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
|
||||||
@ -598,7 +599,7 @@ class DeviceFilterForm(
|
|||||||
('Components', (
|
('Components', (
|
||||||
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports',
|
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports',
|
||||||
)),
|
)),
|
||||||
('Miscellaneous', ('has_primary_ip', 'virtual_chassis_member', 'local_context_data'))
|
('Miscellaneous', ('has_primary_ip', 'virtual_chassis_member', 'config_template_id', 'local_context_data'))
|
||||||
)
|
)
|
||||||
region_id = DynamicModelMultipleChoiceField(
|
region_id = DynamicModelMultipleChoiceField(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
@ -680,6 +681,11 @@ class DeviceFilterForm(
|
|||||||
required=False,
|
required=False,
|
||||||
label='MAC address'
|
label='MAC address'
|
||||||
)
|
)
|
||||||
|
config_template_id = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
required=False,
|
||||||
|
label=_('Config template')
|
||||||
|
)
|
||||||
has_primary_ip = forms.NullBooleanField(
|
has_primary_ip = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has a primary IP',
|
label='Has a primary IP',
|
||||||
|
@ -7,6 +7,7 @@ from timezone_field import TimeZoneFormField
|
|||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VRF
|
from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VRF
|
||||||
from netbox.forms import NetBoxModelForm
|
from netbox.forms import NetBoxModelForm
|
||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
@ -565,6 +566,10 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
|
|||||||
label=_('Priority'),
|
label=_('Priority'),
|
||||||
help_text=_("The priority of the device in the virtual chassis")
|
help_text=_("The priority of the device in the virtual chassis")
|
||||||
)
|
)
|
||||||
|
config_template = DynamicModelChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
@ -572,7 +577,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
|
|||||||
'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'rack',
|
'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'rack',
|
||||||
'location', 'position', 'face', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6',
|
'location', 'position', 'face', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6',
|
||||||
'cluster_group', 'cluster', 'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority',
|
'cluster_group', 'cluster', 'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority',
|
||||||
'description', 'comments', 'tags', 'local_context_data'
|
'description', 'config_template', 'comments', 'tags', 'local_context_data'
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'device_role': _("The function this device serves"),
|
'device_role': _("The function this device serves"),
|
||||||
|
20
netbox/dcim/migrations/0169_device_configtemplate.py
Normal file
20
netbox/dcim/migrations/0169_device_configtemplate.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 4.1.6 on 2023-02-10 14:32
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('extras', '0086_configtemplate'),
|
||||||
|
('dcim', '0168_interface_template_enabled'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='config_template',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='devices', to='extras.configtemplate'),
|
||||||
|
),
|
||||||
|
]
|
@ -590,6 +590,13 @@ class Device(PrimaryModel, ConfigContextModel):
|
|||||||
null=True,
|
null=True,
|
||||||
validators=[MaxValueValidator(255)]
|
validators=[MaxValueValidator(255)]
|
||||||
)
|
)
|
||||||
|
config_template = models.ForeignKey(
|
||||||
|
to='extras.ConfigTemplate',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name='devices',
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
contacts = GenericRelation(
|
contacts = GenericRelation(
|
||||||
|
@ -203,6 +203,9 @@ class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
|||||||
vc_priority = tables.Column(
|
vc_priority = tables.Column(
|
||||||
verbose_name='VC Priority'
|
verbose_name='VC Priority'
|
||||||
)
|
)
|
||||||
|
config_template = tables.Column(
|
||||||
|
linkify=True
|
||||||
|
)
|
||||||
comments = columns.MarkdownColumn()
|
comments = columns.MarkdownColumn()
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:device_list'
|
url_name='dcim:device_list'
|
||||||
@ -214,7 +217,7 @@ class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
|||||||
'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'device_role', 'manufacturer', 'device_type',
|
'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'device_role', 'manufacturer', 'device_type',
|
||||||
'platform', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'position', 'face',
|
'platform', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'position', 'face',
|
||||||
'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position',
|
'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position',
|
||||||
'vc_priority', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
'vc_priority', 'description', 'config_template', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'name', 'status', 'tenant', 'site', 'location', 'rack', 'device_role', 'manufacturer', 'device_type',
|
'pk', 'name', 'status', 'tenant', 'site', 'location', 'rack', 'device_role', 'manufacturer', 'device_type',
|
||||||
|
@ -1997,6 +1997,32 @@ class DeviceInventoryView(DeviceComponentsView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(Device, 'render-config')
|
||||||
|
class DeviceRenderConfigView(generic.ObjectView):
|
||||||
|
queryset = Device.objects.all()
|
||||||
|
template_name = 'dcim/device/render_config.html'
|
||||||
|
tab = ViewTab(
|
||||||
|
label=_('Render Config'),
|
||||||
|
permission='extras.view_configtemplate',
|
||||||
|
weight=2000
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_extra_context(self, request, instance):
|
||||||
|
context_data = {
|
||||||
|
'device': instance,
|
||||||
|
}
|
||||||
|
context_data.update(**instance.get_config_context())
|
||||||
|
if instance.config_template:
|
||||||
|
rendered_config = instance.config_template.render(context=context_data)
|
||||||
|
else:
|
||||||
|
rendered_config = None
|
||||||
|
|
||||||
|
return {
|
||||||
|
'context_data': context_data,
|
||||||
|
'rendered_config': rendered_config,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(Device, 'configcontext', path='config-context')
|
@register_model_view(Device, 'configcontext', path='config-context')
|
||||||
class DeviceConfigContextView(ObjectConfigContextView):
|
class DeviceConfigContextView(ObjectConfigContextView):
|
||||||
queryset = Device.objects.annotate_config_context_data()
|
queryset = Device.objects.annotate_config_context_data()
|
||||||
@ -2004,7 +2030,7 @@ class DeviceConfigContextView(ObjectConfigContextView):
|
|||||||
tab = ViewTab(
|
tab = ViewTab(
|
||||||
label=_('Config Context'),
|
label=_('Config Context'),
|
||||||
permission='extras.view_configcontext',
|
permission='extras.view_configcontext',
|
||||||
weight=2000
|
weight=2100
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from users.api.nested_serializers import NestedUserSerializer
|
|||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'NestedConfigContextSerializer',
|
'NestedConfigContextSerializer',
|
||||||
|
'NestedConfigTemplateSerializer',
|
||||||
'NestedCustomFieldSerializer',
|
'NestedCustomFieldSerializer',
|
||||||
'NestedCustomLinkSerializer',
|
'NestedCustomLinkSerializer',
|
||||||
'NestedExportTemplateSerializer',
|
'NestedExportTemplateSerializer',
|
||||||
@ -51,6 +52,14 @@ class NestedConfigContextSerializer(WritableNestedSerializer):
|
|||||||
fields = ['id', 'url', 'display', 'name']
|
fields = ['id', 'url', 'display', 'name']
|
||||||
|
|
||||||
|
|
||||||
|
class NestedConfigTemplateSerializer(WritableNestedSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:configtemplate-detail')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.ConfigTemplate
|
||||||
|
fields = ['id', 'url', 'display', 'name']
|
||||||
|
|
||||||
|
|
||||||
class NestedExportTemplateSerializer(WritableNestedSerializer):
|
class NestedExportTemplateSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:exporttemplate-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:exporttemplate-detail')
|
||||||
|
|
||||||
|
@ -9,9 +9,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-12 col-xl-6">
|
<div class="col col-12 col-xl-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">Device</h5>
|
||||||
Device
|
|
||||||
</h5>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<table class="table table-hover attr-table">
|
<table class="table table-hover attr-table">
|
||||||
<tr>
|
<tr>
|
||||||
@ -111,6 +109,10 @@
|
|||||||
<th scope="row">Asset Tag</th>
|
<th scope="row">Asset Tag</th>
|
||||||
<td class="font-monospace">{{ object.asset_tag|placeholder }}</td>
|
<td class="font-monospace">{{ object.asset_tag|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Config Template</th>
|
||||||
|
<td>{{ object.config_template|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
47
netbox/templates/dcim/device/render_config.html
Normal file
47
netbox/templates/dcim/device/render_config.html
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{% extends 'dcim/device/base.html' %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}{{ object }} - Config{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-5">
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header">Config Template</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Config Template</th>
|
||||||
|
<td>{{ object.config_template|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Data Source</th>
|
||||||
|
<td>{{ object.config_template.data_file.source|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Data File</th>
|
||||||
|
<td>{{ object.config_template.data_file|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-7">
|
||||||
|
<div class="card">
|
||||||
|
<h5 class="card-header">Context Data</h5>
|
||||||
|
<pre class="card-body">{{ context_data|pprint }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<div class="card">
|
||||||
|
{% if rendered_config %}
|
||||||
|
<pre class="card-body">{{ rendered_config }}</pre>
|
||||||
|
{% else %}
|
||||||
|
<div class="card-body text-muted">No configuration template found</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -65,6 +65,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% render_field form.status %}
|
{% render_field form.status %}
|
||||||
{% render_field form.platform %}
|
{% render_field form.platform %}
|
||||||
|
{% render_field form.config_template %}
|
||||||
{% if object.pk %}
|
{% if object.pk %}
|
||||||
{% render_field form.primary_ip4 %}
|
{% render_field form.primary_ip4 %}
|
||||||
{% render_field form.primary_ip6 %}
|
{% render_field form.primary_ip6 %}
|
||||||
|
Loading…
Reference in New Issue
Block a user