Merge pull request #13520 from gamuniz/constructed_inventory_host_linkage

[constructed-inventory] Constructed inventory host linkage
This commit is contained in:
Gabriel Muniz
2023-02-03 12:09:43 -05:00
committed by GitHub
7 changed files with 15 additions and 14 deletions

View File

@@ -1702,8 +1702,8 @@ class InventorySerializer(LabelsListMixin, BaseSerializerWithVariables):
if obj.organization: if obj.organization:
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk}) res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
if obj.kind == 'constructed': if obj.kind == 'constructed':
res['source_inventories'] = self.reverse('api:inventory_source_inventories', kwargs={'pk': obj.pk}) res['input_inventories'] = self.reverse('api:inventory_input_inventories', kwargs={'pk': obj.pk})
res['url'] = self.reverse('api:constructed_inventory_detail', kwargs={'pk': obj.pk}) res['constructed_url'] = self.reverse('api:constructed_inventory_detail', kwargs={'pk': obj.pk})
return res return res
def to_representation(self, obj): def to_representation(self, obj):
@@ -1883,6 +1883,8 @@ class HostSerializer(BaseSerializerWithVariables):
ansible_facts=self.reverse('api:host_ansible_facts_detail', kwargs={'pk': obj.pk}), ansible_facts=self.reverse('api:host_ansible_facts_detail', kwargs={'pk': obj.pk}),
) )
) )
if obj.inventory.kind == 'constructed':
res['original_host'] = self.reverse('api:host_detail', kwargs={'pk': obj.instance_id})
if obj.inventory: if obj.inventory:
res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk}) res['inventory'] = self.reverse('api:inventory_detail', kwargs={'pk': obj.inventory.pk})
if obj.last_job: if obj.last_job:

View File

@@ -9,7 +9,7 @@ from awx.api.views.inventory import (
ConstructedInventoryDetail, ConstructedInventoryDetail,
ConstructedInventoryList, ConstructedInventoryList,
InventoryActivityStreamList, InventoryActivityStreamList,
InventorySourceInventoriesList, InventoryInputInventoriesList,
InventoryJobTemplateList, InventoryJobTemplateList,
InventoryAccessList, InventoryAccessList,
InventoryObjectRolesList, InventoryObjectRolesList,
@@ -40,7 +40,7 @@ urls = [
re_path(r'^(?P<pk>[0-9]+)/script/$', InventoryScriptView.as_view(), name='inventory_script_view'), re_path(r'^(?P<pk>[0-9]+)/script/$', InventoryScriptView.as_view(), name='inventory_script_view'),
re_path(r'^(?P<pk>[0-9]+)/tree/$', InventoryTreeView.as_view(), name='inventory_tree_view'), re_path(r'^(?P<pk>[0-9]+)/tree/$', InventoryTreeView.as_view(), name='inventory_tree_view'),
re_path(r'^(?P<pk>[0-9]+)/inventory_sources/$', InventoryInventorySourcesList.as_view(), name='inventory_inventory_sources_list'), re_path(r'^(?P<pk>[0-9]+)/inventory_sources/$', InventoryInventorySourcesList.as_view(), name='inventory_inventory_sources_list'),
re_path(r'^(?P<pk>[0-9]+)/source_inventories/$', InventorySourceInventoriesList.as_view(), name='inventory_source_inventories'), re_path(r'^(?P<pk>[0-9]+)/input_inventories/$', InventoryInputInventoriesList.as_view(), name='inventory_input_inventories'),
re_path(r'^(?P<pk>[0-9]+)/update_inventory_sources/$', InventoryInventorySourcesUpdate.as_view(), name='inventory_inventory_sources_update'), re_path(r'^(?P<pk>[0-9]+)/update_inventory_sources/$', InventoryInventorySourcesUpdate.as_view(), name='inventory_inventory_sources_update'),
re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', InventoryActivityStreamList.as_view(), name='inventory_activity_stream_list'), re_path(r'^(?P<pk>[0-9]+)/activity_stream/$', InventoryActivityStreamList.as_view(), name='inventory_activity_stream_list'),
re_path(r'^(?P<pk>[0-9]+)/job_templates/$', InventoryJobTemplateList.as_view(), name='inventory_job_template_list'), re_path(r'^(?P<pk>[0-9]+)/job_templates/$', InventoryJobTemplateList.as_view(), name='inventory_job_template_list'),

View File

@@ -98,12 +98,10 @@ class InventoryDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAPIVie
class ConstructedInventoryDetail(InventoryDetail): class ConstructedInventoryDetail(InventoryDetail):
serializer_class = ConstructedInventorySerializer serializer_class = ConstructedInventorySerializer
class ConstructedInventoryList(InventoryList): class ConstructedInventoryList(InventoryList):
serializer_class = ConstructedInventorySerializer serializer_class = ConstructedInventorySerializer
def get_queryset(self): def get_queryset(self):
@@ -111,11 +109,11 @@ class ConstructedInventoryList(InventoryList):
return r.filter(kind='constructed') return r.filter(kind='constructed')
class InventorySourceInventoriesList(SubListAttachDetachAPIView): class InventoryInputInventoriesList(SubListAttachDetachAPIView):
model = Inventory model = Inventory
serializer_class = InventorySerializer serializer_class = InventorySerializer
parent_model = Inventory parent_model = Inventory
relationship = 'source_inventories' relationship = 'input_inventories'
class InventoryActivityStreamList(SubListAPIView): class InventoryActivityStreamList(SubListAPIView):

View File

@@ -4,7 +4,6 @@ from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
dependencies = [ dependencies = [
('main', '0174_ensure_org_ee_admin_roles'), ('main', '0174_ensure_org_ee_admin_roles'),
] ]
@@ -12,7 +11,7 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.AddField( migrations.AddField(
model_name='inventory', model_name='inventory',
name='source_inventories', name='input_inventories',
field=models.ManyToManyField( field=models.ManyToManyField(
blank=True, blank=True,
help_text='Only valid for constructed inventories, this links to the inventories that will be used.', help_text='Only valid for constructed inventories, this links to the inventories that will be used.',

View File

@@ -140,7 +140,7 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
default=None, default=None,
help_text=_('Filter that will be applied to the hosts of this inventory.'), help_text=_('Filter that will be applied to the hosts of this inventory.'),
) )
source_inventories = models.ManyToManyField( input_inventories = models.ManyToManyField(
'Inventory', 'Inventory',
blank=True, blank=True,
related_name='destination_inventories', related_name='destination_inventories',

View File

@@ -320,7 +320,7 @@ class BaseTask(object):
for hostname, hv in script_data.get('_meta', {}).get('hostvars', {}).items(): for hostname, hv in script_data.get('_meta', {}).get('hostvars', {}).items():
# maintain a list of host_name --> host_id # maintain a list of host_name --> host_id
# so we can associate emitted events to Host objects # so we can associate emitted events to Host objects
self.runner_callback.host_map[hostname] = hv.pop('remote_tower_id', '') self.runner_callback.host_map[hostname] = hv.get('remote_tower_id', '')
file_content = '#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\nprint(%r)\n' % json.dumps(script_data) file_content = '#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\nprint(%r)\n' % json.dumps(script_data)
return self.write_private_data_file(private_data_dir, file_name, file_content, sub_dir='inventory', file_permissions=0o700) return self.write_private_data_file(private_data_dir, file_name, file_content, sub_dir='inventory', file_permissions=0o700)
@@ -1524,10 +1524,10 @@ class RunInventoryUpdate(SourceControlMixin, BaseTask):
# special case for constructed inventories, we pass source inventories from database # special case for constructed inventories, we pass source inventories from database
# these must come in order, and in order _before_ the constructed inventory itself # these must come in order, and in order _before_ the constructed inventory itself
if inventory_update.inventory.kind == 'constructed': if inventory_update.inventory.kind == 'constructed':
for source_inventory in inventory_update.inventory.source_inventories.all(): for input_inventory in inventory_update.inventory.input_inventories.all():
args.append('-i') args.append('-i')
script_params = dict(hostvars=True, towervars=True) script_params = dict(hostvars=True, towervars=True)
source_inv_path = self.write_inventory_file(source_inventory, private_data_dir, f'hosts_{source_inventory.id}', script_params) source_inv_path = self.write_inventory_file(input_inventory, private_data_dir, f'hosts_{input_inventory.id}', script_params)
args.append(to_container_path(source_inv_path, private_data_dir)) args.append(to_container_path(source_inv_path, private_data_dir))
# Add arguments for the source inventory file/script/thing # Add arguments for the source inventory file/script/thing

View File

@@ -747,6 +747,8 @@ SCM_EXCLUDE_EMPTY_GROUPS = False
# ---------------- # ----------------
# -- Constructed -- # -- Constructed --
# ---------------- # ----------------
CONSTRUCTED_INSTANCE_ID_VAR = 'remote_tower_id'
CONSTRUCTED_EXCLUDE_EMPTY_GROUPS = False CONSTRUCTED_EXCLUDE_EMPTY_GROUPS = False
# --------------------- # ---------------------