From 062329f56e6a23c9164ed56bc4aa762e7d111fbc Mon Sep 17 00:00:00 2001 From: Matthew Jones Date: Fri, 20 Apr 2018 15:30:13 -0400 Subject: [PATCH] Protect isolated and control groups from api deletion Isolated and Control groups are managed strictly from the standalone setup playbook installer and should not be directly managable from the api. Especially true since you can't assign or create isolated groups from within the API itself. In the future this may change but allowing this in the API could leave the system in a bad state. --- awx/api/views.py | 8 ++++++++ .../tests/functional/api/test_instance_group.py | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/awx/api/views.py b/awx/api/views.py index dd2174f7da..5e080ccea9 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -671,6 +671,14 @@ class InstanceGroupDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAP serializer_class = InstanceGroupSerializer permission_classes = (InstanceGroupTowerPermission,) + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.controller is not None: + raise PermissionDenied(detail=_("Isolated Groups can not be removed from the API")) + if instance.controlled_groups.count(): + raise PermissionDenied(detail=_("Instance Groups acting as a controller for an Isolated Group can not be removed from the API")) + return super(InstanceGroupDetail, self).destroy(request, *args, **kwargs) + class InstanceGroupUnifiedJobsList(SubListAPIView): diff --git a/awx/main/tests/functional/api/test_instance_group.py b/awx/main/tests/functional/api/test_instance_group.py index 0488453fcc..3dfd554f11 100644 --- a/awx/main/tests/functional/api/test_instance_group.py +++ b/awx/main/tests/functional/api/test_instance_group.py @@ -21,6 +21,13 @@ def instance_group(job_factory): return ig +@pytest.fixture +def isolated_instance_group(instance_group): + ig = InstanceGroup(name="iso", controller=instance_group) + ig.save() + return ig + + @pytest.fixture def create_job_factory(job_factory, instance_group): def fn(status='running'): @@ -91,3 +98,11 @@ def test_modify_delete_tower_instance_group_prevented(delete, options, tower_ins assert 'DELETE' not in resp.data['actions'] assert 'GET' in resp.data['actions'] assert 'PUT' in resp.data['actions'] + + +@pytest.mark.django_db +def test_prevent_delete_iso_and_control_groups(delete, isolated_instance_group, admin): + iso_url = reverse("api:instance_group_detail", kwargs={'pk': isolated_instance_group.pk}) + controller_url = reverse("api:instance_group_detail", kwargs={'pk': isolated_instance_group.controller.pk}) + delete(iso_url, None, admin, expect=403) + delete(controller_url, None, admin, expect=403)