refactor(config_management): move config_group_hosts to related table
ref: #353
This commit is contained in:
@ -74,6 +74,7 @@ class ConfigGroupsSerializer(ConfigGroupsSerializerBase):
|
||||
'parent',
|
||||
'name',
|
||||
'config',
|
||||
'hosts',
|
||||
'url',
|
||||
]
|
||||
read_only_fields = [
|
||||
|
@ -4,7 +4,7 @@ from rest_framework import serializers
|
||||
|
||||
from api.serializers.config import ParentGroupSerializer
|
||||
|
||||
from config_management.models.groups import ConfigGroupHosts
|
||||
from config_management.models.groups import ConfigGroups
|
||||
|
||||
from itam.models.device import Device
|
||||
|
||||
@ -12,15 +12,13 @@ from itam.models.device import Device
|
||||
|
||||
class DeviceConfigGroupsSerializer(serializers.ModelSerializer):
|
||||
|
||||
name = serializers.CharField(source='group.name', read_only=True)
|
||||
|
||||
url = serializers.HyperlinkedIdentityField(
|
||||
view_name="API:_api_config_group", format="html"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = ConfigGroupHosts
|
||||
model = ConfigGroups
|
||||
|
||||
fields = [
|
||||
'id',
|
||||
@ -43,7 +41,7 @@ class DeviceSerializer(serializers.ModelSerializer):
|
||||
|
||||
config = serializers.SerializerMethodField('get_device_config')
|
||||
|
||||
groups = DeviceConfigGroupsSerializer(source='configgrouphosts_set', many=True, read_only=True)
|
||||
groups = DeviceConfigGroupsSerializer(source='configgroups_set', many=True, read_only=True)
|
||||
|
||||
def get_device_config(self, device):
|
||||
|
||||
|
@ -1,21 +0,0 @@
|
||||
from itam.models.device import Device
|
||||
|
||||
from config_management.models.groups import ConfigGroups, ConfigGroupHosts
|
||||
|
||||
from core.forms.common import CommonModelForm
|
||||
|
||||
|
||||
|
||||
class ConfigGroupHostsForm(CommonModelForm):
|
||||
|
||||
__name__ = 'asdsa'
|
||||
|
||||
class Meta:
|
||||
|
||||
fields = [
|
||||
'host'
|
||||
]
|
||||
|
||||
model = ConfigGroupHosts
|
||||
|
||||
prefix = 'config_group_hosts'
|
@ -0,0 +1,75 @@
|
||||
# Generated by Django 5.1.2 on 2024-10-16 06:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def migrate_to_configgroups_hosts(apps, schema_editor):
|
||||
|
||||
if schema_editor.connection.alias != "default":
|
||||
|
||||
return
|
||||
|
||||
print('')
|
||||
|
||||
ConfigGroups = apps.get_model('config_management', 'ConfigGroups')
|
||||
ConfigGroupHosts = apps.get_model('config_management', 'ConfigGroupHosts')
|
||||
|
||||
current_data = ConfigGroupHosts.objects.all()
|
||||
|
||||
for host in current_data:
|
||||
|
||||
print(f'Begin migrating host {host.host} in group {host.group}:')
|
||||
|
||||
config_group = ConfigGroups.objects.get(pk = host.group.id)
|
||||
|
||||
print(f' migrate {host.host} in group {config_group}')
|
||||
|
||||
config_group.hosts.add( host.host )
|
||||
|
||||
try:
|
||||
|
||||
was_migrated = ConfigGroups.objects.get(pk = host.group.id)
|
||||
|
||||
if host.host in was_migrated.hosts.all():
|
||||
|
||||
print(f' successfully migrated {host.id} {host.host} to new table')
|
||||
|
||||
ConfigGroupHosts.objects.get(pk = host.id).delete()
|
||||
|
||||
try:
|
||||
|
||||
ConfigGroupHosts.objects.get(pk = host.id)
|
||||
|
||||
print(f' Error Failed to remove old data for host {host.host}')
|
||||
|
||||
except ConfigGroupHosts.DoesNotExist:
|
||||
|
||||
print(f' Old data removed')
|
||||
|
||||
except ConfigGroupHosts.DoesNotExist:
|
||||
|
||||
print(f' Error, {host.host} was not migrated to new table')
|
||||
|
||||
|
||||
old_data = ConfigGroupHosts.objects.all()
|
||||
|
||||
if len(old_data) == 0:
|
||||
|
||||
print(f'Successfully migrated data to new table, removing old table')
|
||||
|
||||
migrations.DeleteModel("ConfigGroupHosts")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('config_management', '0007_configgroups_hosts'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(migrate_to_configgroups_hosts),
|
||||
]
|
@ -95,6 +95,13 @@ class ConfigGroups(GroupsCommonFields, SaveHistory):
|
||||
verbose_name = 'Configuration'
|
||||
)
|
||||
|
||||
hosts = models.ManyToManyField(
|
||||
to = Device,
|
||||
blank = True,
|
||||
help_text = 'Hosts that are part of this group',
|
||||
verbose_name = 'Hosts'
|
||||
)
|
||||
|
||||
|
||||
page_layout: dict = [
|
||||
{
|
||||
|
@ -4,11 +4,9 @@ from rest_framework.reverse import reverse
|
||||
|
||||
from access.serializers.organization import OrganizationBaseSerializer
|
||||
|
||||
from app.serializers.user import UserBaseSerializer
|
||||
|
||||
from config_management.models.groups import ConfigGroups
|
||||
|
||||
|
||||
from api.v2.serializers.itam.device import DeviceModelBaseSerializer
|
||||
|
||||
class ConfigGroupBaseSerializer(serializers.ModelSerializer):
|
||||
|
||||
@ -94,6 +92,7 @@ class ConfigGroupModelSerializer(ConfigGroupBaseSerializer):
|
||||
'name',
|
||||
'model_notes',
|
||||
'config',
|
||||
'hosts',
|
||||
'is_global',
|
||||
'created',
|
||||
'modified',
|
||||
@ -163,6 +162,8 @@ class ConfigGroupModelSerializer(ConfigGroupBaseSerializer):
|
||||
|
||||
class ConfigGroupViewSerializer(ConfigGroupModelSerializer):
|
||||
|
||||
hosts = DeviceModelBaseSerializer(read_only = True, many = True)
|
||||
|
||||
parent = ConfigGroupBaseSerializer( read_only = True )
|
||||
|
||||
organization = OrganizationBaseSerializer( many=False, read_only=True )
|
||||
|
@ -48,20 +48,18 @@
|
||||
|
||||
{% include 'content/section.html.j2' with tab=form.tabs.hosts %}
|
||||
|
||||
<input type="button" value="Add Host" onclick="window.location='{% url 'Config Management:_group_add_host' group.id %}';">
|
||||
|
||||
<table class="data">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Organization</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if config_group_hosts %}
|
||||
{% for host in config_group_hosts %}
|
||||
{% if group.hosts %}
|
||||
{% for host in group.hosts.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=host.host.id %}">{{ host.host }}</a></td>
|
||||
<td>{{ host.host.organization }}</td>
|
||||
<td><a href="{% url 'Config Management:_group_delete_host' group_id=group.id pk=host.id %}">Delete</a></td>
|
||||
<td><a href="{% url 'ITAM:_device_view' pk=host.id %}">{{ host }}</a></td>
|
||||
<td>{{ host.organization }}</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
|
@ -1,10 +1,8 @@
|
||||
from django.urls import path
|
||||
|
||||
from config_management.views.groups import groups
|
||||
from config_management.views.groups.groups import GroupHostAdd, GroupHostDelete
|
||||
|
||||
from config_management.views.groups import software
|
||||
# from config_management.views.groups.software import GroupSoftwareAdd, GroupSoftwareChange, GroupSoftwareDelete
|
||||
|
||||
app_name = "Config Management"
|
||||
|
||||
@ -21,7 +19,4 @@ urlpatterns = [
|
||||
path("group/<int:group_id>/software/<int:pk>", software.Change.as_view(), name="_group_software_change"),
|
||||
path("group/<int:group_id>/software/<int:pk>/delete", software.Delete.as_view(), name="_group_software_delete"),
|
||||
|
||||
path('group/<int:pk>/host', GroupHostAdd.as_view(), name='_group_add_host'),
|
||||
path('group/<int:group_id>/host/<int:pk>/delete', GroupHostDelete.as_view(), name='_group_delete_host'),
|
||||
|
||||
]
|
||||
|
@ -13,9 +13,8 @@ from itam.models.device import Device
|
||||
|
||||
from settings.models.user_settings import UserSettings
|
||||
|
||||
from config_management.forms.group_hosts import ConfigGroupHostsForm
|
||||
from config_management.forms.group.group import ConfigGroupForm, DetailForm
|
||||
from config_management.models.groups import ConfigGroups, ConfigGroupHosts, ConfigGroupSoftware
|
||||
from config_management.models.groups import ConfigGroups, ConfigGroupSoftware
|
||||
|
||||
|
||||
|
||||
@ -158,7 +157,6 @@ class View(ChangeView):
|
||||
|
||||
context['config'] = json.dumps(json.loads(self.object.render_config()), indent=4, sort_keys=True)
|
||||
|
||||
context['config_group_hosts'] = ConfigGroupHosts.objects.filter(group_id = self.kwargs['pk']).order_by('-host')
|
||||
|
||||
context['tickets'] = TicketLinkedItem.objects.filter(
|
||||
item = int(self.kwargs['pk']),
|
||||
@ -245,83 +243,3 @@ class Delete(DeleteView):
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Config Management:Groups')
|
||||
|
||||
|
||||
|
||||
class GroupHostAdd(AddView):
|
||||
|
||||
model = ConfigGroupHosts
|
||||
|
||||
parent_model = ConfigGroups
|
||||
|
||||
permission_required = [
|
||||
'config_management.add_configgrouphosts',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
form_class = ConfigGroupHostsForm
|
||||
|
||||
|
||||
def form_valid(self, form):
|
||||
|
||||
form.instance.group_id = self.kwargs['pk']
|
||||
|
||||
form.instance.organization = self.parent_model.objects.get(pk=form.instance.group_id).organization
|
||||
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'Add Host to Group'
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_form(self, form_class=None):
|
||||
|
||||
form_class = super().get_form(form_class=None)
|
||||
|
||||
group = ConfigGroups.objects.get(pk=self.kwargs['pk'])
|
||||
|
||||
exsting_group_hosts = ConfigGroupHosts.objects.filter(group=group)
|
||||
|
||||
form_class.fields["host"].queryset = form_class.fields["host"].queryset.filter(
|
||||
).exclude(
|
||||
id__in=exsting_group_hosts.values_list('host', flat=True)
|
||||
)
|
||||
|
||||
|
||||
return form_class
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Config Management:_group_view', args=[self.kwargs['pk'],])
|
||||
|
||||
|
||||
|
||||
class GroupHostDelete(DeleteView):
|
||||
|
||||
model = ConfigGroupHosts
|
||||
|
||||
permission_required = [
|
||||
'config_management.delete_configgrouphosts',
|
||||
]
|
||||
|
||||
template_name = 'form.html.j2'
|
||||
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context['content_title'] = 'Delete ' + self.object.host.name
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
|
||||
return reverse('Config Management:_group_view', args=[self.kwargs['group_id'],])
|
||||
|
@ -196,17 +196,17 @@
|
||||
<th>Added</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
{% if config_groups %}
|
||||
{% for group in config_groups %}
|
||||
{% if device.configgroups_set %}
|
||||
{% for group in device.configgroups_set.all %}
|
||||
<tr>
|
||||
<td><a href="{% url 'Config Management:_group_view' pk=group.group.id %}">{{ group.group }}</a></td>
|
||||
<td><a href="{% url 'Config Management:_group_view' pk=group.id %}">{{ group }}</a></td>
|
||||
<td>{{ group.created }}</td>
|
||||
<td><a href="{% url 'Config Management:_group_delete_host' group_id=group.group.id pk=group.id %}">Delete</a></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="3">Nothing Found</td>
|
||||
<td colspan="3">Nothing Found.</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
@ -374,24 +374,6 @@ class DeviceAPI(TestCase):
|
||||
assert type(self.api_data['modified']) is str
|
||||
|
||||
|
||||
def test_api_field_exists_groups(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
groups field must exist
|
||||
"""
|
||||
|
||||
assert 'groups' in self.api_data
|
||||
|
||||
|
||||
def test_api_field_type_groups(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
groups field must be list
|
||||
"""
|
||||
|
||||
assert type(self.api_data['groups']) is list
|
||||
|
||||
|
||||
def test_api_field_exists_organization(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
@ -428,63 +410,6 @@ class DeviceAPI(TestCase):
|
||||
assert type(self.api_data['url']) is Hyperlink
|
||||
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_groups_id(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
groups.id field must exist
|
||||
"""
|
||||
|
||||
assert 'id' in self.api_data['groups'][0]
|
||||
|
||||
|
||||
def test_api_field_type_groups_id(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
groups.id field must be int
|
||||
"""
|
||||
|
||||
assert type(self.api_data['groups'][0]['id']) is int
|
||||
|
||||
|
||||
def test_api_field_exists_groups_name(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
groups.name field must exist
|
||||
"""
|
||||
|
||||
assert 'name' in self.api_data['groups'][0]
|
||||
|
||||
|
||||
def test_api_field_type_groups_name(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
groups.name field must be str
|
||||
"""
|
||||
|
||||
assert type(self.api_data['groups'][0]['name']) is str
|
||||
|
||||
|
||||
def test_api_field_exists_groups_url(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
groups.url field must exist
|
||||
"""
|
||||
|
||||
assert 'url' in self.api_data['groups'][0]
|
||||
|
||||
|
||||
def test_api_field_type_groups_url(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
groups.url field must be str
|
||||
"""
|
||||
|
||||
assert type(self.api_data['groups'][0]['url']) is Hyperlink
|
||||
|
||||
|
||||
|
||||
def test_api_create_device_existing_uuid_matches_status_200(self):
|
||||
"""Creation of existing device
|
||||
|
||||
|
@ -8,9 +8,6 @@ from django.utils.decorators import method_decorator
|
||||
|
||||
from access.models import Organization
|
||||
|
||||
from config_management.models.groups import ConfigGroupHosts
|
||||
|
||||
|
||||
from ..models.device import Device, DeviceSoftware, DeviceOperatingSystem
|
||||
from ..models.software import Software
|
||||
|
||||
@ -143,7 +140,6 @@ class View(ChangeView):
|
||||
config = self.object.get_configuration
|
||||
context['config'] = json.dumps(config, indent=4, sort_keys=True)
|
||||
|
||||
context['config_groups'] = ConfigGroupHosts.objects.filter(host = self.object.id)
|
||||
|
||||
context['model_pk'] = self.kwargs['pk']
|
||||
context['model_name'] = self.model._meta.verbose_name.replace(' ', '')
|
||||
|
Reference in New Issue
Block a user