Added inventory tree view for AC-360.

This commit is contained in:
Chris Church 2013-08-26 12:57:41 -04:00
parent e343c9386d
commit 2bb5374685
14 changed files with 88 additions and 10 deletions

View File

@ -216,6 +216,11 @@ class Inventory(CommonModel):
self.has_active_failures = has_active_failures
self.save()
@property
def root_groups(self):
group_pks = self.groups.values_list('pk', flat=True)
return self.groups.exclude(parents__pk__in=group_pks).distinct()
class Host(CommonModelNameNotUnique):
'''
A managed node

View File

@ -263,6 +263,7 @@ class InventorySerializer(BaseSerializerWithVariables):
root_groups = reverse('main:inventory_root_groups_list', args=(obj.pk,)),
variable_data = reverse('main:inventory_variable_data', args=(obj.pk,)),
script = reverse('main:inventory_script_view', args=(obj.pk,)),
tree = reverse('main:inventory_tree_view', args=(obj.pk,)),
organization = reverse('main:organization_detail', args=(obj.organization.pk,)),
))
return res
@ -315,6 +316,19 @@ class GroupSerializer(BaseSerializerWithVariables):
))
return res
class GroupTreeSerializer(GroupSerializer):
children = serializers.SerializerMethodField('get_children')
class Meta:
model = Group
fields = BASE_FIELDS + ('inventory', 'variables', 'has_active_failures',
'children')
def get_children(self, obj):
children_qs = obj.children.filter(active=True)
return GroupTreeSerializer(children_qs, many=True).data
class BaseVariableDataSerializer(BaseSerializer):
def to_native(self, obj):

View File

@ -0,0 +1 @@
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}

View File

@ -1,3 +1,3 @@
{{ docstring }}
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}
{% include "main/_new_in_awx.md" %}

View File

@ -0,0 +1,15 @@
# Group Tree for this {{ model_verbose_name|title }}:
Make a GET request to this resource to retrieve a hierarchical view of groups
associated with the selected {{ model_verbose_name }}.
The resulting data structure contains a list of root groups, with each group
also containing a list of its children.
## Results
Each group data structure includes the following fields:
{% include "main/_result_fields_common.md" %}
{% include "main/_new_in_awx.md" %}

View File

@ -5,4 +5,4 @@ Make a GET request to this resource to retrieve the list of
{% include "main/_list_common.md" %}
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}
{% include "main/_new_in_awx.md" %}

View File

@ -9,4 +9,4 @@ fields to create a new {{ model_verbose_name }}:
{% include "main/_result_fields_common.md" %}
{% endwith %}
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}
{% include "main/_new_in_awx.md" %}

View File

@ -5,5 +5,5 @@ record containing the following fields:
{% include "main/_result_fields_common.md" %}
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}
{% include "main/_new_in_awx.md" %}

View File

@ -17,4 +17,4 @@ For a PATCH request, include only the fields that are being modified.
Make a DELETE request to this resource to delete this {{ model_verbose_name }}.
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}
{% include "main/_new_in_awx.md" %}

View File

@ -6,4 +6,4 @@ Make a GET request to this resource to retrieve a list of
{% include "main/_list_common.md" %}
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}
{% include "main/_new_in_awx.md" %}

View File

@ -36,4 +36,4 @@ remove the {{ model_verbose_name }} from this {{ parent_model_verbose_name }}
without deleting the {{ model_verbose_name }}.
{% endif %}
{% if new_in_13 %}> _New in AWX 1.3_{% endif %}
{% include "main/_new_in_awx.md" %}

View File

@ -663,6 +663,31 @@ class InventoryTest(BaseTest):
# on a group resource, I can see related resources for variables, inventories, and children
# and these work
def test_get_inventory_tree(self):
# Group A is parent of B, B is parent of C, C is parent of D.
g_a = self.inventory_a.groups.create(name='A')
g_b = self.inventory_a.groups.create(name='B')
g_b.parents.add(g_a)
g_c = self.inventory_a.groups.create(name='C')
g_c.parents.add(g_b)
g_d = self.inventory_a.groups.create(name='D')
g_d.parents.add(g_c)
url = reverse('main:inventory_tree_view', args=(self.inventory_a.pk,))
with self.current_user(self.super_django_user):
response = self.get(url, expect=200)
self.assertTrue(isinstance(response, list))
self.assertEqual(len(response), 1)
self.assertEqual(response[0]['id'], g_a.pk)
self.assertEqual(len(response[0]['children']), 1)
self.assertEqual(response[0]['children'][0]['id'], g_b.pk)
self.assertEqual(len(response[0]['children'][0]['children']), 1)
self.assertEqual(response[0]['children'][0]['children'][0]['id'], g_c.pk)
self.assertEqual(len(response[0]['children'][0]['children'][0]['children']), 1)
self.assertEqual(response[0]['children'][0]['children'][0]['children'][0]['id'], g_d.pk)
self.assertEqual(len(response[0]['children'][0]['children'][0]['children'][0]['children']), 0)
def test_migrate_children_when_group_removed(self):
# Group A is parent of B, B is parent of C, C is parent of D.
g_a = self.inventory_a.groups.create(name='A')

View File

@ -62,6 +62,7 @@ inventory_urls = patterns('awx.main.views',
url(r'^(?P<pk>[0-9]+)/root_groups/$', 'inventory_root_groups_list'),
url(r'^(?P<pk>[0-9]+)/variable_data/$', 'inventory_variable_data'),
url(r'^(?P<pk>[0-9]+)/script/$', 'inventory_script_view'),
url(r'^(?P<pk>[0-9]+)/tree/$', 'inventory_tree_view'),
)
host_urls = patterns('awx.main.views',

View File

@ -550,9 +550,7 @@ class InventoryRootGroupsList(SubListCreateAPIView):
parent = self.get_parent_object()
self.check_parent_access(parent)
qs = self.request.user.get_queryset(self.model)
all_pks = parent.groups.values_list('pk', flat=True)
sublist_qs = parent.groups.exclude(parents__pk__in=all_pks).distinct()
return qs & sublist_qs
return qs & parent.root_groups
class BaseVariableData(RetrieveUpdateAPIView):
@ -618,6 +616,25 @@ class InventoryScriptView(RetrieveAPIView):
return Response(data)
class InventoryTreeView(RetrieveAPIView):
model = Inventory
filter_backends = ()
new_in_13 = True
def retrieve(self, request, *args, **kwargs):
inventory = self.get_object()
groups_qs = inventory.root_groups.filter(active=True)
data = GroupTreeSerializer(groups_qs, many=True).data
return Response(data)
def get_description_context(self):
d = super(InventoryTreeView, self).get_description_context()
d.update({
'serializer_fields': GroupTreeSerializer().metadata(),
})
return d
class JobTemplateList(ListCreateAPIView):
model = JobTemplate