mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 18:09:57 -03:30
Merge pull request #10929 from ansible/validate-control-only-nodes
Validate that control-only Instance nodes cannot change IG membership
This commit is contained in:
commit
81fe39f060
@ -402,6 +402,11 @@ class InstanceInstanceGroupsList(InstanceGroupMembershipMixin, SubListCreateAtta
|
||||
parent_model = models.Instance
|
||||
relationship = 'rampart_groups'
|
||||
|
||||
def is_valid_relation(self, parent, sub, created=False):
|
||||
if parent.node_type == 'control':
|
||||
return {'msg': _(f"Cannot change instance group membership of control-only node: {parent.hostname}.")}
|
||||
return None
|
||||
|
||||
|
||||
class InstanceGroupList(ListCreateAPIView):
|
||||
|
||||
@ -444,6 +449,11 @@ class InstanceGroupInstanceList(InstanceGroupMembershipMixin, SubListAttachDetac
|
||||
relationship = "instances"
|
||||
search_fields = ('hostname',)
|
||||
|
||||
def is_valid_relation(self, parent, sub, created=False):
|
||||
if sub.node_type == 'control':
|
||||
return {'msg': _(f"Cannot change instance group membership of control-only node: {sub.hostname}.")}
|
||||
return None
|
||||
|
||||
|
||||
class ScheduleList(ListCreateAPIView):
|
||||
|
||||
|
||||
@ -68,13 +68,23 @@ class InstanceGroupMembershipMixin(object):
|
||||
membership.
|
||||
"""
|
||||
|
||||
def attach_validate(self, request):
|
||||
parent = self.get_parent_object()
|
||||
sub_id, res = super().attach_validate(request)
|
||||
if res: # handle an error
|
||||
return sub_id, res
|
||||
sub = get_object_or_400(self.model, pk=sub_id)
|
||||
attach_errors = self.is_valid_relation(parent, sub)
|
||||
if attach_errors:
|
||||
return sub_id, Response(attach_errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
return sub_id, res
|
||||
|
||||
def attach(self, request, *args, **kwargs):
|
||||
response = super(InstanceGroupMembershipMixin, self).attach(request, *args, **kwargs)
|
||||
sub_id, res = self.attach_validate(request)
|
||||
if status.is_success(response.status_code):
|
||||
if self.parent_model is Instance:
|
||||
ig_obj = get_object_or_400(self.model, pk=sub_id)
|
||||
inst_name = ig_obj.hostname
|
||||
inst_name = self.get_parent_object().hostname
|
||||
else:
|
||||
inst_name = get_object_or_400(self.model, pk=sub_id).hostname
|
||||
with transaction.atomic():
|
||||
@ -91,11 +101,12 @@ class InstanceGroupMembershipMixin(object):
|
||||
return response
|
||||
|
||||
def unattach_validate(self, request):
|
||||
parent = self.get_parent_object()
|
||||
(sub_id, res) = super(InstanceGroupMembershipMixin, self).unattach_validate(request)
|
||||
if res:
|
||||
return (sub_id, res)
|
||||
sub = get_object_or_400(self.model, pk=sub_id)
|
||||
attach_errors = self.is_valid_relation(None, sub)
|
||||
attach_errors = self.is_valid_relation(parent, sub)
|
||||
if attach_errors:
|
||||
return (sub_id, Response(attach_errors, status=status.HTTP_400_BAD_REQUEST))
|
||||
return (sub_id, res)
|
||||
|
||||
@ -23,6 +23,14 @@ def instance():
|
||||
return Instance.objects.create(hostname='instance')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def node_type_instance():
|
||||
def fn(hostname, node_type):
|
||||
return Instance.objects.create(hostname=hostname, node_type=node_type)
|
||||
|
||||
return fn
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def instance_group(job_factory):
|
||||
ig = InstanceGroup(name="east")
|
||||
@ -198,3 +206,41 @@ def test_containerized_group_default_fields(instance_group, kube_credential):
|
||||
assert ig.policy_instance_list == []
|
||||
assert ig.policy_instance_minimum == 0
|
||||
assert ig.policy_instance_percentage == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('node_type', ['control', 'hybrid', 'execution'])
|
||||
def test_instance_attach_to_instance_group(post, instance_group, node_type_instance, admin, node_type):
|
||||
instance = node_type_instance(hostname=node_type, node_type=node_type)
|
||||
|
||||
url = reverse(f'api:instance_group_instance_list', kwargs={'pk': instance_group.pk})
|
||||
post(url, {'associate': True, 'id': instance.id}, admin, expect=204 if node_type != 'control' else 400)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('node_type', ['control', 'hybrid', 'execution'])
|
||||
def test_instance_unattach_from_instance_group(post, instance_group, node_type_instance, admin, node_type):
|
||||
instance = node_type_instance(hostname=node_type, node_type=node_type)
|
||||
instance_group.instances.add(instance)
|
||||
|
||||
url = reverse(f'api:instance_group_instance_list', kwargs={'pk': instance_group.pk})
|
||||
post(url, {'disassociate': True, 'id': instance.id}, admin, expect=204 if node_type != 'control' else 400)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('node_type', ['control', 'hybrid', 'execution'])
|
||||
def test_instance_group_attach_to_instance(post, instance_group, node_type_instance, admin, node_type):
|
||||
instance = node_type_instance(hostname=node_type, node_type=node_type)
|
||||
|
||||
url = reverse(f'api:instance_instance_groups_list', kwargs={'pk': instance.pk})
|
||||
post(url, {'associate': True, 'id': instance_group.id}, admin, expect=204 if node_type != 'control' else 400)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('node_type', ['control', 'hybrid', 'execution'])
|
||||
def test_instance_group_unattach_from_instance(post, instance_group, node_type_instance, admin, node_type):
|
||||
instance = node_type_instance(hostname=node_type, node_type=node_type)
|
||||
instance_group.instances.add(instance)
|
||||
|
||||
url = reverse(f'api:instance_instance_groups_list', kwargs={'pk': instance.pk})
|
||||
post(url, {'disassociate': True, 'id': instance_group.id}, admin, expect=204 if node_type != 'control' else 400)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user