@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-20 20:40
|
||||
# Generated by Django 5.0.7 on 2024-07-20 23:46
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
@ -14,4 +14,4 @@ def json_pretty(value):
|
||||
|
||||
return str('{}')
|
||||
|
||||
return json.dumps(json.loads(value), indent=4, sort_keys=True)
|
||||
return json.dumps(json.loads(value.replace("'", '"')), indent=4, sort_keys=True)
|
||||
|
@ -26,6 +26,10 @@ class ServiceForm(CommonModelForm):
|
||||
id=self.instance.pk
|
||||
)
|
||||
|
||||
self.fields['template'].queryset = self.fields['template'].queryset.exclude(
|
||||
id=self.instance.pk
|
||||
)
|
||||
|
||||
|
||||
def clean(self):
|
||||
|
||||
@ -33,16 +37,28 @@ class ServiceForm(CommonModelForm):
|
||||
|
||||
device = cleaned_data.get("device")
|
||||
cluster = cleaned_data.get("cluster")
|
||||
is_template = cleaned_data.get("is_template")
|
||||
template = cleaned_data.get("template")
|
||||
port = cleaned_data.get("port")
|
||||
|
||||
|
||||
if not device and not cluster:
|
||||
if not is_template and not template:
|
||||
|
||||
raise ValidationError('A Service must be assigned to either a "Cluster" or a "Device".')
|
||||
if not device and not cluster:
|
||||
|
||||
raise ValidationError('A Service must be assigned to either a "Cluster" or a "Device".')
|
||||
|
||||
|
||||
if device and cluster:
|
||||
if device and cluster:
|
||||
|
||||
raise ValidationError('A Service must only be assigned to either a "Cluster" or a "Device". Not both.')
|
||||
raise ValidationError('A Service must only be assigned to either a "Cluster" or a "Device". Not both.')
|
||||
|
||||
|
||||
if not port:
|
||||
|
||||
raise ValidationError('Port(s) must be assigned to a service.')
|
||||
|
||||
|
||||
|
||||
|
||||
return cleaned_data
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.0.7 on 2024-07-20 20:40
|
||||
# Generated by Django 5.0.7 on 2024-07-20 23:46
|
||||
|
||||
import access.fields
|
||||
import access.models
|
||||
@ -79,6 +79,7 @@ class Migration(migrations.Migration):
|
||||
('is_global', models.BooleanField(default=False)),
|
||||
('model_notes', models.TextField(blank=True, default=None, null=True, verbose_name='Notes')),
|
||||
('id', models.AutoField(primary_key=True, serialize=False, unique=True)),
|
||||
('is_template', models.BooleanField(default=False, help_text='Is this service to be used as a template', verbose_name='Template')),
|
||||
('name', models.CharField(help_text='Name of the Service', max_length=50, verbose_name='Name')),
|
||||
('config', models.JSONField(blank=True, default=None, help_text='Cluster Configuration', null=True, verbose_name='Configuration')),
|
||||
('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False)),
|
||||
@ -87,7 +88,8 @@ class Migration(migrations.Migration):
|
||||
('dependent_service', models.ManyToManyField(blank=True, default=None, help_text='Services that this service depends upon', to='itim.service', verbose_name='Dependent Services')),
|
||||
('device', models.ForeignKey(blank=True, default=None, help_text='Device the service is assigned to', null=True, on_delete=django.db.models.deletion.CASCADE, to='itam.device', verbose_name='Device')),
|
||||
('organization', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='access.organization', validators=[access.models.TenancyObject.validatate_organization_exists])),
|
||||
('port', models.ManyToManyField(help_text='Port the service is available on', to='itim.port', verbose_name='Port')),
|
||||
('port', models.ManyToManyField(blank=True, help_text='Port the service is available on', to='itim.port', verbose_name='Port')),
|
||||
('template', models.ForeignKey(blank=True, default=None, help_text='Template this service uses', null=True, on_delete=django.db.models.deletion.CASCADE, to='itim.service', verbose_name='Template')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Service',
|
||||
|
@ -93,6 +93,23 @@ class Service(TenancyObject):
|
||||
blank=False
|
||||
)
|
||||
|
||||
is_template = models.BooleanField(
|
||||
blank = False,
|
||||
default = False,
|
||||
help_text = 'Is this service to be used as a template',
|
||||
verbose_name = 'Template',
|
||||
)
|
||||
|
||||
template = models.ForeignKey(
|
||||
'self',
|
||||
blank = True,
|
||||
default = None,
|
||||
help_text = 'Template this service uses',
|
||||
null = True,
|
||||
on_delete = models.CASCADE,
|
||||
verbose_name = 'Template',
|
||||
)
|
||||
|
||||
name = models.CharField(
|
||||
blank = False,
|
||||
help_text = 'Name of the Service',
|
||||
@ -132,7 +149,7 @@ class Service(TenancyObject):
|
||||
|
||||
port = models.ManyToManyField(
|
||||
Port,
|
||||
blank = False,
|
||||
blank = True,
|
||||
help_text = 'Port the service is available on',
|
||||
verbose_name = 'Port',
|
||||
)
|
||||
@ -149,6 +166,27 @@ class Service(TenancyObject):
|
||||
|
||||
modified = AutoLastModifiedField()
|
||||
|
||||
@property
|
||||
def config_variables(self):
|
||||
|
||||
if self.is_template:
|
||||
|
||||
return self.config
|
||||
|
||||
if self.template:
|
||||
|
||||
template_config: dict = Service.objects.get(id=self.template.id).config
|
||||
|
||||
template_config.update(self.config)
|
||||
|
||||
return template_config
|
||||
|
||||
else:
|
||||
|
||||
return self.config
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
{% extends 'base.html.j2' %}
|
||||
|
||||
{% load json %}
|
||||
{% load markdown %}
|
||||
|
||||
{% block content %}
|
||||
@ -68,6 +69,7 @@
|
||||
</svg>Back to Services</button>
|
||||
|
||||
<button id="defaultOpen" class="tablinks" onclick="openCity(event, 'Details')">Details</button>
|
||||
<button class="tablinks" onclick="openCity(event, 'Rendered_Config')">Rendered Config</button>
|
||||
{% if perms.assistance.change_service %}
|
||||
<button class="tablinks" onclick="openCity(event, 'Notes')">Notes</button>
|
||||
{% endif %}
|
||||
@ -88,6 +90,19 @@
|
||||
<span>{{ form.name.value }}</span>
|
||||
</div>
|
||||
|
||||
{% if form.template.value or form.is_template.value %}
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.is_template.label }}</label>
|
||||
<span>
|
||||
{% if form.is_template.value %}
|
||||
{{ form.is_template.value }}
|
||||
{% else %}
|
||||
<a href="{% url 'ITIM:_service_view' item.template.pk %}">{{ item.template }}</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="detail-view-field">
|
||||
<label>{{ form.organization.label }}</label>
|
||||
<span>
|
||||
@ -157,12 +172,19 @@
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
{% if item.port.all %}
|
||||
{% if item.port.all and not item.template %}
|
||||
{% for port in item.port.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Settings:_port_view' item.pk %}">{{ port }}</a></td>
|
||||
<td>{{ port.description }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% elif not item.port.all and item.template %}
|
||||
{% for port in item.template.port.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Settings:_port_view' item.pk %}">{{ port }}</a></td>
|
||||
<td>{{ port.description }}</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
{% else %}
|
||||
<tr>
|
||||
@ -199,7 +221,7 @@
|
||||
<div style="display: block; width: 100%;">
|
||||
<h3>Service Config</h3>
|
||||
<br>
|
||||
<textarea cols="90" rows="30" readonly>{{ item.config }}</textarea>
|
||||
<textarea cols="90" rows="30" readonly>{{ item.config | json_pretty }}</textarea>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
@ -210,6 +232,17 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div id="Rendered_Config" class="tabcontent">
|
||||
<h3>
|
||||
Rendered Config
|
||||
</h3>
|
||||
|
||||
<div>
|
||||
<textarea cols="90" rows="30" readonly>{{ item.config_variables | json_pretty }}</textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% if perms.assistance.change_knowledgebase %}
|
||||
<div id="Notes" class="tabcontent">
|
||||
<h3>
|
||||
|
Reference in New Issue
Block a user