mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-24 08:25:17 -06:00
adds config template to vm model #12461
This commit is contained in:
parent
ff59845821
commit
1471aff91f
@ -43,6 +43,10 @@
|
|||||||
{{ object.tenant|linkify|placeholder }}
|
{{ object.tenant|linkify|placeholder }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Config Template</th>
|
||||||
|
<td>{{ object.config_template|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans "Primary IPv4" %}</th>
|
<th scope="row">{% trans "Primary IPv4" %}</th>
|
||||||
<td>
|
<td>
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
{% extends 'virtualization/virtualmachine/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>{{ config_template|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Data Source</th>
|
||||||
|
<td>{{ config_template.data_file.source|linkify|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Data File</th>
|
||||||
|
<td>{{ 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 config_template %}
|
||||||
|
<pre class="card-body">{{ rendered_config }}</pre>
|
||||||
|
{% else %}
|
||||||
|
<div class="card-body text-muted">No configuration template found</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
@ -5,6 +5,7 @@ from dcim.api.nested_serializers import (
|
|||||||
NestedDeviceSerializer, NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer,
|
NestedDeviceSerializer, NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer,
|
||||||
)
|
)
|
||||||
from dcim.choices import InterfaceModeChoices
|
from dcim.choices import InterfaceModeChoices
|
||||||
|
from extras.api.nested_serializers import NestedConfigTemplateSerializer
|
||||||
from ipam.api.nested_serializers import (
|
from ipam.api.nested_serializers import (
|
||||||
NestedIPAddressSerializer, NestedL2VPNTerminationSerializer, NestedVLANSerializer, NestedVRFSerializer,
|
NestedIPAddressSerializer, NestedL2VPNTerminationSerializer, NestedVLANSerializer, NestedVRFSerializer,
|
||||||
)
|
)
|
||||||
@ -79,6 +80,7 @@ class VirtualMachineSerializer(NetBoxModelSerializer):
|
|||||||
primary_ip = NestedIPAddressSerializer(read_only=True)
|
primary_ip = NestedIPAddressSerializer(read_only=True)
|
||||||
primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
|
primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
|
||||||
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
|
primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
|
||||||
|
config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
|
||||||
|
|
||||||
# Counter fields
|
# Counter fields
|
||||||
interface_count = serializers.IntegerField(read_only=True)
|
interface_count = serializers.IntegerField(read_only=True)
|
||||||
@ -88,7 +90,8 @@ class VirtualMachineSerializer(NetBoxModelSerializer):
|
|||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'platform',
|
'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'platform',
|
||||||
'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments',
|
'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments',
|
||||||
'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', 'interface_count',
|
'config_template', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
|
'interface_count',
|
||||||
]
|
]
|
||||||
validators = []
|
validators = []
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from django.utils.translation import gettext as _
|
|||||||
from dcim.filtersets import CommonInterfaceFilterSet
|
from dcim.filtersets import CommonInterfaceFilterSet
|
||||||
from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
|
from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
|
||||||
from extras.filtersets import LocalConfigContextFilterSet
|
from extras.filtersets import LocalConfigContextFilterSet
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from netbox.filtersets import OrganizationalModelFilterSet, NetBoxModelFilterSet
|
from netbox.filtersets import OrganizationalModelFilterSet, NetBoxModelFilterSet
|
||||||
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
|
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
|
||||||
from utilities.filters import MultiValueCharFilter, MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter
|
from utilities.filters import MultiValueCharFilter, MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter
|
||||||
@ -228,6 +229,10 @@ class VirtualMachineFilterSet(
|
|||||||
method='_has_primary_ip',
|
method='_has_primary_ip',
|
||||||
label=_('Has a primary IP'),
|
label=_('Has a primary IP'),
|
||||||
)
|
)
|
||||||
|
config_template_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
label=_('Config template (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
|
@ -4,6 +4,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
from dcim.choices import InterfaceModeChoices
|
from dcim.choices import InterfaceModeChoices
|
||||||
from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
|
from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
|
||||||
from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
|
from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import VLAN, VLANGroup, VRF
|
from ipam.models import VLAN, VLANGroup, VRF
|
||||||
from netbox.forms import NetBoxModelBulkEditForm
|
from netbox.forms import NetBoxModelBulkEditForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
@ -174,12 +175,17 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
max_length=200,
|
max_length=200,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
config_template = DynamicModelChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('site', 'cluster', 'device', 'status', 'role', 'tenant', 'platform', 'description')),
|
(None, ('site', 'cluster', 'device', 'status', 'role', 'tenant', 'platform', 'description')),
|
||||||
(_('Resources'), ('vcpus', 'memory', 'disk'))
|
(_('Resources'), ('vcpus', 'memory', 'disk')),
|
||||||
|
('Configuration', ('config_template',)),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'site', 'cluster', 'device', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'description', 'comments',
|
'site', 'cluster', 'device', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'description', 'comments',
|
||||||
|
@ -2,6 +2,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from dcim.choices import InterfaceModeChoices
|
from dcim.choices import InterfaceModeChoices
|
||||||
from dcim.models import Device, DeviceRole, Platform, Site
|
from dcim.models import Device, DeviceRole, Platform, Site
|
||||||
|
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
|
||||||
@ -123,12 +124,18 @@ class VirtualMachineImportForm(NetBoxModelImportForm):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
help_text=_('Assigned platform')
|
help_text=_('Assigned platform')
|
||||||
)
|
)
|
||||||
|
config_template = CSVModelChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
required=False,
|
||||||
|
help_text=_('Config template')
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
fields = (
|
fields = (
|
||||||
'name', 'status', 'role', 'site', 'cluster', 'device', 'tenant', 'platform', 'vcpus', 'memory', 'disk',
|
'name', 'status', 'role', 'site', 'cluster', 'device', 'tenant', 'platform', 'vcpus', 'memory', 'disk',
|
||||||
'description', 'comments', 'tags',
|
'description', 'config_template', 'comments', 'tags',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
|
from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
|
||||||
from extras.forms import LocalConfigContextFilterForm
|
from extras.forms import LocalConfigContextFilterForm
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import L2VPN, VRF
|
from ipam.models import L2VPN, VRF
|
||||||
from netbox.forms import NetBoxModelFilterSetForm
|
from netbox.forms import NetBoxModelFilterSetForm
|
||||||
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
|
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
|
||||||
@ -93,7 +94,7 @@ class VirtualMachineFilterForm(
|
|||||||
(None, ('q', 'filter_id', 'tag')),
|
(None, ('q', 'filter_id', 'tag')),
|
||||||
(_('Cluster'), ('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id')),
|
(_('Cluster'), ('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id')),
|
||||||
(_('Location'), ('region_id', 'site_group_id', 'site_id')),
|
(_('Location'), ('region_id', 'site_group_id', 'site_id')),
|
||||||
(_('Attributes'), ('status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'local_context_data')),
|
(_('Attributes'), ('status', 'role_id', 'platform_id', 'mac_address', 'has_primary_ip', 'config_template_id', 'local_context_data')),
|
||||||
(_('Tenant'), ('tenant_group_id', 'tenant_id')),
|
(_('Tenant'), ('tenant_group_id', 'tenant_id')),
|
||||||
(_('Contacts'), ('contact', 'contact_role', 'contact_group')),
|
(_('Contacts'), ('contact', 'contact_role', 'contact_group')),
|
||||||
)
|
)
|
||||||
@ -170,6 +171,11 @@ class VirtualMachineFilterForm(
|
|||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
config_template_id = DynamicModelMultipleChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
required=False,
|
||||||
|
label=_('Config template')
|
||||||
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from dcim.forms.common import InterfaceCommonForm
|
from dcim.forms.common import InterfaceCommonForm
|
||||||
from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site, SiteGroup
|
from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site, SiteGroup
|
||||||
|
from extras.models import ConfigTemplate
|
||||||
from ipam.models import IPAddress, VLAN, VLANGroup, VRF
|
from ipam.models import IPAddress, VLAN, VLANGroup, VRF
|
||||||
from netbox.forms import NetBoxModelForm
|
from netbox.forms import NetBoxModelForm
|
||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
@ -205,13 +206,17 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label=''
|
label=''
|
||||||
)
|
)
|
||||||
|
config_template = DynamicModelChoiceField(
|
||||||
|
queryset=ConfigTemplate.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(_('Virtual Machine'), ('name', 'role', 'status', 'description', 'tags')),
|
(_('Virtual Machine'), ('name', 'role', 'status', 'description', 'tags')),
|
||||||
(_('Site/Cluster'), ('site', 'cluster', 'device')),
|
(_('Site/Cluster'), ('site', 'cluster', 'device')),
|
||||||
(_('Tenancy'), ('tenant_group', 'tenant')),
|
(_('Tenancy'), ('tenant_group', 'tenant')),
|
||||||
(_('Management'), ('platform', 'primary_ip4', 'primary_ip6')),
|
(_('Management'), ('platform', 'primary_ip4', 'primary_ip6', 'config_template')),
|
||||||
(_('Resources'), ('vcpus', 'memory', 'disk')),
|
(_('Resources'), ('vcpus', 'memory', 'disk')),
|
||||||
(_('Config Context'), ('local_context_data',)),
|
(_('Config Context'), ('local_context_data',)),
|
||||||
)
|
)
|
||||||
@ -220,7 +225,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
|
|||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant_group', 'tenant', 'platform', 'primary_ip4',
|
'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant_group', 'tenant', 'platform', 'primary_ip4',
|
||||||
'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments', 'tags', 'local_context_data',
|
'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments', 'tags', 'local_context_data', 'config_template',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 4.1.10 on 2023-08-11 17:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('extras', '0098_webhook_custom_field_data_webhook_tags'),
|
||||||
|
('virtualization', '0035_virtualmachine_interface_count'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='virtualmachine',
|
||||||
|
name='config_template',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='virtual_machines', to='extras.configtemplate'),
|
||||||
|
),
|
||||||
|
]
|
@ -123,6 +123,13 @@ class VirtualMachine(ContactsMixin, PrimaryModel, ConfigContextModel):
|
|||||||
null=True,
|
null=True,
|
||||||
verbose_name=_('disk (GB)')
|
verbose_name=_('disk (GB)')
|
||||||
)
|
)
|
||||||
|
config_template = models.ForeignKey(
|
||||||
|
to='extras.ConfigTemplate',
|
||||||
|
on_delete=models.PROTECT,
|
||||||
|
related_name='virtual_machines',
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
# Counter fields
|
# Counter fields
|
||||||
interface_count = CounterCacheField(
|
interface_count = CounterCacheField(
|
||||||
@ -234,6 +241,17 @@ class VirtualMachine(ContactsMixin, PrimaryModel, ConfigContextModel):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_config_template(self):
|
||||||
|
"""
|
||||||
|
Return the appropriate ConfigTemplate (if any) for this Device.
|
||||||
|
"""
|
||||||
|
if self.config_template:
|
||||||
|
return self.config_template
|
||||||
|
if self.role.config_template:
|
||||||
|
return self.role.config_template
|
||||||
|
if self.platform and self.platform.config_template:
|
||||||
|
return self.platform.config_template
|
||||||
|
|
||||||
|
|
||||||
class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
||||||
virtual_machine = models.ForeignKey(
|
virtual_machine = models.ForeignKey(
|
||||||
|
@ -84,13 +84,16 @@ class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable)
|
|||||||
interface_count = tables.Column(
|
interface_count = tables.Column(
|
||||||
verbose_name=_('Interfaces')
|
verbose_name=_('Interfaces')
|
||||||
)
|
)
|
||||||
|
config_template = tables.Column(
|
||||||
|
linkify=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'tenant_group', 'platform',
|
'pk', 'id', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'tenant_group', 'platform',
|
||||||
'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'description', 'comments',
|
'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'description', 'comments',
|
||||||
'contacts', 'tags', 'created', 'last_updated',
|
'contacts', 'config_template', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip',
|
'pk', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip',
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import traceback
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
@ -6,6 +7,7 @@ from django.db.models import Prefetch, Sum
|
|||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
from jinja2.exceptions import TemplateError
|
||||||
|
|
||||||
from dcim.filtersets import DeviceFilterSet
|
from dcim.filtersets import DeviceFilterSet
|
||||||
from dcim.models import Device
|
from dcim.models import Device
|
||||||
@ -378,6 +380,39 @@ class VirtualMachineInterfacesView(generic.ObjectChildrenView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(VirtualMachine, 'render-config')
|
||||||
|
class VirtualMachineRenderConfigView(generic.ObjectView):
|
||||||
|
queryset = VirtualMachine.objects.all()
|
||||||
|
template_name = 'virtualization/virtualmachine/render_config.html'
|
||||||
|
tab = ViewTab(
|
||||||
|
label=_('Render Config'),
|
||||||
|
permission='extras.view_configtemplate',
|
||||||
|
weight=2000
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_extra_context(self, request, instance):
|
||||||
|
# Compile context data
|
||||||
|
context_data = {
|
||||||
|
'virtualmachine': instance,
|
||||||
|
}
|
||||||
|
context_data.update(**instance.get_config_context())
|
||||||
|
|
||||||
|
# Render the config template
|
||||||
|
rendered_config = None
|
||||||
|
if config_template := instance.get_config_template():
|
||||||
|
try:
|
||||||
|
rendered_config = config_template.render(context=context_data)
|
||||||
|
except TemplateError as e:
|
||||||
|
messages.error(request, f"An error occurred while rendering the template: {e}")
|
||||||
|
rendered_config = traceback.format_exc()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'config_template': config_template,
|
||||||
|
'context_data': context_data,
|
||||||
|
'rendered_config': rendered_config,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(VirtualMachine, 'configcontext', path='config-context')
|
@register_model_view(VirtualMachine, 'configcontext', path='config-context')
|
||||||
class VirtualMachineConfigContextView(ObjectConfigContextView):
|
class VirtualMachineConfigContextView(ObjectConfigContextView):
|
||||||
queryset = VirtualMachine.objects.annotate_config_context_data()
|
queryset = VirtualMachine.objects.annotate_config_context_data()
|
||||||
@ -385,7 +420,7 @@ class VirtualMachineConfigContextView(ObjectConfigContextView):
|
|||||||
tab = ViewTab(
|
tab = ViewTab(
|
||||||
label=_('Config Context'),
|
label=_('Config Context'),
|
||||||
permission='extras.view_configcontext',
|
permission='extras.view_configcontext',
|
||||||
weight=2000
|
weight=2100
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user