diff --git a/awx/api/views/inventory.py b/awx/api/views/inventory.py index 453f9c6072..4085cf9bff 100644 --- a/awx/api/views/inventory.py +++ b/awx/api/views/inventory.py @@ -14,6 +14,7 @@ from django.utils.translation import gettext_lazy as _ from rest_framework.exceptions import PermissionDenied from rest_framework.response import Response from rest_framework import status +from rest_framework import serializers # AWX from awx.main.models import ActivityStream, Inventory, JobTemplate, Role, User, InstanceGroup, InventoryUpdateEvent, InventoryUpdate @@ -115,14 +116,9 @@ class InventoryInputInventoriesList(SubListAttachDetachAPIView): parent_model = Inventory relationship = 'input_inventories' - # Specifically overriding the post method on this view to disallow constructed inventories as input inventories - def post(self, request, *args, **kwargs): - obj = Inventory.objects.get(id=request.data.get('id')) - if obj.kind == 'constructed': - return Response( - dict(error=_('You cannot add a constructed inventory to another constructed inventory.')), status=status.HTTP_405_METHOD_NOT_ALLOWED - ) - return super(InventoryInputInventoriesList, self).post(request, *args, **kwargs) + def is_valid_relation(self, parent, sub, created=False): + if sub.kind == 'constructed': + raise serializers.ValidationError({'error': 'You cannot add a constructed inventory to another constructed inventory.'}) class InventoryActivityStreamList(SubListAPIView): diff --git a/awx/main/tests/functional/test_inventory_input_constructed.py b/awx/main/tests/functional/test_inventory_input_constructed.py index e677d46f46..ea1efb7d64 100644 --- a/awx/main/tests/functional/test_inventory_input_constructed.py +++ b/awx/main/tests/functional/test_inventory_input_constructed.py @@ -8,26 +8,35 @@ def constructed_inventory(organization): """ creates a new constructed inventory source """ - return Inventory.objects.create(name='dummy2', kind='constructed', organization=organization) + + def factory(name, org=organization): + try: + inv = Inventory.objects.get(name=name, organization=org, kind='constructed') + except Inventory.DoesNotExist: + inv = Inventory.objects.create(name=name, organization=org, kind='constructed') + return inv + + return factory @pytest.mark.django_db -def test_constructed_inventory_post(post, organization, admin_user): - inventory1 = Inventory.objects.create(name='dummy1', kind='constructed', organization=organization) - inventory2 = Inventory.objects.create(name='dummy2', kind='constructed', organization=organization) +def test_constructed_inventory_post(post, admin_user, constructed_inventory): + inv1 = constructed_inventory(name='dummy1') + inv2 = constructed_inventory(name='dummy2') resp = post( - url=reverse('api:inventory_input_inventories', kwargs={'pk': inventory1.pk}), - data={'id': inventory2.pk}, + url=reverse('api:inventory_input_inventories', kwargs={'pk': inv1.pk}), + data={'id': inv2.pk}, user=admin_user, - expect=405, + expect=400, ) - assert resp.status_code == 405 + assert resp.status_code == 400 @pytest.mark.django_db def test_add_constructed_inventory_source(post, admin_user, constructed_inventory): + inv1 = constructed_inventory(name='dummy1') resp = post( - url=reverse('api:inventory_inventory_sources_list', kwargs={'pk': constructed_inventory.pk}), + url=reverse('api:inventory_inventory_sources_list', kwargs={'pk': inv1.pk}), data={'name': 'dummy1', 'source': 'constructed'}, user=admin_user, expect=400, @@ -37,8 +46,9 @@ def test_add_constructed_inventory_source(post, admin_user, constructed_inventor @pytest.mark.django_db def test_add_constructed_inventory_host(post, admin_user, constructed_inventory): + inv1 = constructed_inventory(name='dummy1') resp = post( - url=reverse('api:inventory_hosts_list', kwargs={'pk': constructed_inventory.pk}), + url=reverse('api:inventory_hosts_list', kwargs={'pk': inv1.pk}), data={'name': 'dummy1'}, user=admin_user, expect=400, @@ -48,8 +58,9 @@ def test_add_constructed_inventory_host(post, admin_user, constructed_inventory) @pytest.mark.django_db def test_add_constructed_inventory_group(post, admin_user, constructed_inventory): + inv1 = constructed_inventory(name='dummy1') resp = post( - reverse('api:inventory_groups_list', kwargs={'pk': constructed_inventory.pk}), + reverse('api:inventory_groups_list', kwargs={'pk': inv1.pk}), data={'name': 'group-test'}, user=admin_user, expect=400, @@ -58,12 +69,11 @@ def test_add_constructed_inventory_group(post, admin_user, constructed_inventory @pytest.mark.django_db -def test_edit_constructed_inventory_source(patch, admin_user, inventory): - inventory.inventory_sources.create(name="dummysrc", source="constructed") - inv_id = inventory.inventory_sources.get(name='dummysrc').id +def test_edit_constructed_inventory_source(patch, admin_user, inventory_source_factory): + inv_src = inventory_source_factory(name='dummy1', source='constructed') resp = patch( - reverse('api:inventory_source_detail', kwargs={'pk': inv_id}), - data={'description': inventory.name}, + reverse('api:inventory_source_detail', kwargs={'pk': inv_src.id}), + data={'description': inv_src.name}, user=admin_user, expect=400, )