mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 01:47:35 -02:30
Merge pull request #1154 from chrismeyersfsu/enhancement-tower_in_all_groups
add all instances to special tower instance group
This commit is contained in:
@@ -231,10 +231,7 @@ class IsSuperUser(permissions.BasePermission):
|
|||||||
|
|
||||||
class InstanceGroupTowerPermission(ModelAccessPermission):
|
class InstanceGroupTowerPermission(ModelAccessPermission):
|
||||||
def has_object_permission(self, request, view, obj):
|
def has_object_permission(self, request, view, obj):
|
||||||
if request.method == 'DELETE' and obj.name == "tower":
|
if request.method not in permissions.SAFE_METHODS and obj.name == "tower":
|
||||||
return False
|
|
||||||
if request.method in ['PATCH', 'PUT'] and obj.name == 'tower' and \
|
|
||||||
request and request.data and request.data.get('name', '') != 'tower':
|
|
||||||
return False
|
return False
|
||||||
return super(InstanceGroupTowerPermission, self).has_object_permission(request, view, obj)
|
return super(InstanceGroupTowerPermission, self).has_object_permission(request, view, obj)
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,9 @@ class InstanceManager(models.Manager):
|
|||||||
# NOTE: TODO: Likely to repurpose this once standalone ramparts are a thing
|
# NOTE: TODO: Likely to repurpose this once standalone ramparts are a thing
|
||||||
return "tower"
|
return "tower"
|
||||||
|
|
||||||
|
def all_non_isolated(self):
|
||||||
|
return self.filter(rampart_groups__controller__isnull=True).distinct()
|
||||||
|
|
||||||
|
|
||||||
class InstanceGroupManager(models.Manager):
|
class InstanceGroupManager(models.Manager):
|
||||||
"""A custom manager class for the Instance model.
|
"""A custom manager class for the Instance model.
|
||||||
|
|||||||
@@ -163,6 +163,10 @@ class InstanceGroup(models.Model, RelatedJobsMixin):
|
|||||||
def _get_related_jobs(self):
|
def _get_related_jobs(self):
|
||||||
return UnifiedJob.objects.filter(instance_group=self)
|
return UnifiedJob.objects.filter(instance_group=self)
|
||||||
|
|
||||||
|
def add_all_non_iso_instances(self):
|
||||||
|
self.instances = Instance.objects.all_non_isolated()
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
app_label = 'main'
|
app_label = 'main'
|
||||||
|
|||||||
@@ -143,9 +143,13 @@ def apply_cluster_membership_policies(self):
|
|||||||
actual_instances = []
|
actual_instances = []
|
||||||
Group = namedtuple('Group', ['obj', 'instances'])
|
Group = namedtuple('Group', ['obj', 'instances'])
|
||||||
Node = namedtuple('Instance', ['obj', 'groups'])
|
Node = namedtuple('Instance', ['obj', 'groups'])
|
||||||
|
|
||||||
|
# Add every instnace to the special 'tower' group
|
||||||
|
InstanceGroup.objects.get(name='tower').add_all_non_iso_instances()
|
||||||
|
|
||||||
# Process policy instance list first, these will represent manually managed instances
|
# Process policy instance list first, these will represent manually managed instances
|
||||||
# that will not go through automatic policy determination
|
# that will not go through automatic policy determination
|
||||||
for ig in InstanceGroup.objects.all():
|
for ig in InstanceGroup.objects.exclude(name='tower'):
|
||||||
logger.info(six.text_type("Considering group {}").format(ig.name))
|
logger.info(six.text_type("Considering group {}").format(ig.name))
|
||||||
ig.instances.clear()
|
ig.instances.clear()
|
||||||
group_actual = Group(obj=ig, instances=[])
|
group_actual = Group(obj=ig, instances=[])
|
||||||
@@ -312,7 +316,7 @@ def purge_old_stdout_files(self):
|
|||||||
def cluster_node_heartbeat(self):
|
def cluster_node_heartbeat(self):
|
||||||
logger.debug("Cluster node heartbeat task.")
|
logger.debug("Cluster node heartbeat task.")
|
||||||
nowtime = now()
|
nowtime = now()
|
||||||
instance_list = list(Instance.objects.filter(rampart_groups__controller__isnull=True).distinct())
|
instance_list = list(Instance.objects.all_non_isolated())
|
||||||
this_inst = None
|
this_inst = None
|
||||||
lost_instances = []
|
lost_instances = []
|
||||||
|
|
||||||
|
|||||||
@@ -80,12 +80,20 @@ def test_delete_instance_group_jobs_running(delete, instance_group_jobs_running,
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_delete_tower_instance_group_prevented(delete, options, tower_instance_group, user):
|
def test_modify_delete_tower_instance_group_prevented(delete, options, tower_instance_group, user, patch, put):
|
||||||
url = reverse("api:instance_group_detail", kwargs={'pk': tower_instance_group.pk})
|
url = reverse("api:instance_group_detail", kwargs={'pk': tower_instance_group.pk})
|
||||||
super_user = user('bob', True)
|
super_user = user('bob', True)
|
||||||
|
|
||||||
|
# DELETE tower group not allowed
|
||||||
delete(url, None, super_user, expect=403)
|
delete(url, None, super_user, expect=403)
|
||||||
|
|
||||||
|
# OPTIONS should just be "GET"
|
||||||
resp = options(url, None, super_user, expect=200)
|
resp = options(url, None, super_user, expect=200)
|
||||||
actions = ['GET', 'PUT',]
|
assert len(resp.data['actions'].keys()) == 1
|
||||||
assert 'DELETE' not in resp.data['actions']
|
assert 'GET' in resp.data['actions']
|
||||||
for action in actions:
|
|
||||||
assert action in resp.data['actions']
|
# Updating tower group fields not allowed
|
||||||
|
patch(url, {'name': 'foobar'}, super_user, expect=403)
|
||||||
|
patch(url, {'policy_instance_percentage': 40}, super_user, expect=403)
|
||||||
|
put(url, {'name': 'foobar'}, super_user, expect=403)
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ def test_instance_group_basic_policies(instance_factory, instance_group_factory)
|
|||||||
i2 = instance_factory("i2")
|
i2 = instance_factory("i2")
|
||||||
i3 = instance_factory("i3")
|
i3 = instance_factory("i3")
|
||||||
i4 = instance_factory("i4")
|
i4 = instance_factory("i4")
|
||||||
|
instance_group_factory("tower")
|
||||||
ig0 = instance_group_factory("ig0")
|
ig0 = instance_group_factory("ig0")
|
||||||
ig1 = instance_group_factory("ig1", minimum=2)
|
ig1 = instance_group_factory("ig1", minimum=2)
|
||||||
ig2 = instance_group_factory("ig2", percentage=50)
|
ig2 = instance_group_factory("ig2", percentage=50)
|
||||||
|
|||||||
@@ -31,15 +31,32 @@ def test_instance_dup(org_admin, organization, project, instance_factory, instan
|
|||||||
assert api_num_instances_oa == (actual_num_instances - 1)
|
assert api_num_instances_oa == (actual_num_instances - 1)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
@mock.patch('awx.main.tasks.handle_ha_toplogy_changes', return_value=None)
|
||||||
|
def test_policy_instance_tower_group(mock, instance_factory, instance_group_factory):
|
||||||
|
instance_factory("i1")
|
||||||
|
instance_factory("i2")
|
||||||
|
instance_factory("i3")
|
||||||
|
ig_t = instance_group_factory("tower")
|
||||||
|
instance_group_factory("ig1", percentage=25)
|
||||||
|
instance_group_factory("ig2", percentage=25)
|
||||||
|
instance_group_factory("ig3", percentage=25)
|
||||||
|
instance_group_factory("ig4", percentage=25)
|
||||||
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 3
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
@mock.patch('awx.main.tasks.handle_ha_toplogy_changes', return_value=None)
|
@mock.patch('awx.main.tasks.handle_ha_toplogy_changes', return_value=None)
|
||||||
def test_policy_instance_few_instances(mock, instance_factory, instance_group_factory):
|
def test_policy_instance_few_instances(mock, instance_factory, instance_group_factory):
|
||||||
i1 = instance_factory("i1")
|
i1 = instance_factory("i1")
|
||||||
|
ig_t = instance_group_factory("tower")
|
||||||
ig_1 = instance_group_factory("ig1", percentage=25)
|
ig_1 = instance_group_factory("ig1", percentage=25)
|
||||||
ig_2 = instance_group_factory("ig2", percentage=25)
|
ig_2 = instance_group_factory("ig2", percentage=25)
|
||||||
ig_3 = instance_group_factory("ig3", percentage=25)
|
ig_3 = instance_group_factory("ig3", percentage=25)
|
||||||
ig_4 = instance_group_factory("ig4", percentage=25)
|
ig_4 = instance_group_factory("ig4", percentage=25)
|
||||||
apply_cluster_membership_policies()
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 1
|
||||||
assert len(ig_1.instances.all()) == 1
|
assert len(ig_1.instances.all()) == 1
|
||||||
assert i1 in ig_1.instances.all()
|
assert i1 in ig_1.instances.all()
|
||||||
assert len(ig_2.instances.all()) == 1
|
assert len(ig_2.instances.all()) == 1
|
||||||
@@ -50,6 +67,7 @@ def test_policy_instance_few_instances(mock, instance_factory, instance_group_fa
|
|||||||
assert i1 in ig_4.instances.all()
|
assert i1 in ig_4.instances.all()
|
||||||
i2 = instance_factory("i2")
|
i2 = instance_factory("i2")
|
||||||
apply_cluster_membership_policies()
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 2
|
||||||
assert len(ig_1.instances.all()) == 1
|
assert len(ig_1.instances.all()) == 1
|
||||||
assert i1 in ig_1.instances.all()
|
assert i1 in ig_1.instances.all()
|
||||||
assert len(ig_2.instances.all()) == 1
|
assert len(ig_2.instances.all()) == 1
|
||||||
@@ -66,11 +84,13 @@ def test_policy_instance_distribution_uneven(mock, instance_factory, instance_gr
|
|||||||
i1 = instance_factory("i1")
|
i1 = instance_factory("i1")
|
||||||
i2 = instance_factory("i2")
|
i2 = instance_factory("i2")
|
||||||
i3 = instance_factory("i3")
|
i3 = instance_factory("i3")
|
||||||
|
ig_t = instance_group_factory("tower")
|
||||||
ig_1 = instance_group_factory("ig1", percentage=25)
|
ig_1 = instance_group_factory("ig1", percentage=25)
|
||||||
ig_2 = instance_group_factory("ig2", percentage=25)
|
ig_2 = instance_group_factory("ig2", percentage=25)
|
||||||
ig_3 = instance_group_factory("ig3", percentage=25)
|
ig_3 = instance_group_factory("ig3", percentage=25)
|
||||||
ig_4 = instance_group_factory("ig4", percentage=25)
|
ig_4 = instance_group_factory("ig4", percentage=25)
|
||||||
apply_cluster_membership_policies()
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 3
|
||||||
assert len(ig_1.instances.all()) == 1
|
assert len(ig_1.instances.all()) == 1
|
||||||
assert i1 in ig_1.instances.all()
|
assert i1 in ig_1.instances.all()
|
||||||
assert len(ig_2.instances.all()) == 1
|
assert len(ig_2.instances.all()) == 1
|
||||||
@@ -88,11 +108,13 @@ def test_policy_instance_distribution_even(mock, instance_factory, instance_grou
|
|||||||
i2 = instance_factory("i2")
|
i2 = instance_factory("i2")
|
||||||
i3 = instance_factory("i3")
|
i3 = instance_factory("i3")
|
||||||
i4 = instance_factory("i4")
|
i4 = instance_factory("i4")
|
||||||
|
ig_t = instance_group_factory("tower")
|
||||||
ig_1 = instance_group_factory("ig1", percentage=25)
|
ig_1 = instance_group_factory("ig1", percentage=25)
|
||||||
ig_2 = instance_group_factory("ig2", percentage=25)
|
ig_2 = instance_group_factory("ig2", percentage=25)
|
||||||
ig_3 = instance_group_factory("ig3", percentage=25)
|
ig_3 = instance_group_factory("ig3", percentage=25)
|
||||||
ig_4 = instance_group_factory("ig4", percentage=25)
|
ig_4 = instance_group_factory("ig4", percentage=25)
|
||||||
apply_cluster_membership_policies()
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 4
|
||||||
assert len(ig_1.instances.all()) == 1
|
assert len(ig_1.instances.all()) == 1
|
||||||
assert i1 in ig_1.instances.all()
|
assert i1 in ig_1.instances.all()
|
||||||
assert len(ig_2.instances.all()) == 1
|
assert len(ig_2.instances.all()) == 1
|
||||||
@@ -104,6 +126,7 @@ def test_policy_instance_distribution_even(mock, instance_factory, instance_grou
|
|||||||
ig_1.policy_instance_minimum = 2
|
ig_1.policy_instance_minimum = 2
|
||||||
ig_1.save()
|
ig_1.save()
|
||||||
apply_cluster_membership_policies()
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 4
|
||||||
assert len(ig_1.instances.all()) == 2
|
assert len(ig_1.instances.all()) == 2
|
||||||
assert i1 in ig_1.instances.all()
|
assert i1 in ig_1.instances.all()
|
||||||
assert i2 in ig_1.instances.all()
|
assert i2 in ig_1.instances.all()
|
||||||
@@ -122,11 +145,13 @@ def test_policy_instance_distribution_simultaneous(mock, instance_factory, insta
|
|||||||
i2 = instance_factory("i2")
|
i2 = instance_factory("i2")
|
||||||
i3 = instance_factory("i3")
|
i3 = instance_factory("i3")
|
||||||
i4 = instance_factory("i4")
|
i4 = instance_factory("i4")
|
||||||
|
ig_t = instance_group_factory("tower")
|
||||||
ig_1 = instance_group_factory("ig1", percentage=25, minimum=2)
|
ig_1 = instance_group_factory("ig1", percentage=25, minimum=2)
|
||||||
ig_2 = instance_group_factory("ig2", percentage=25)
|
ig_2 = instance_group_factory("ig2", percentage=25)
|
||||||
ig_3 = instance_group_factory("ig3", percentage=25)
|
ig_3 = instance_group_factory("ig3", percentage=25)
|
||||||
ig_4 = instance_group_factory("ig4", percentage=25)
|
ig_4 = instance_group_factory("ig4", percentage=25)
|
||||||
apply_cluster_membership_policies()
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 4
|
||||||
assert len(ig_1.instances.all()) == 2
|
assert len(ig_1.instances.all()) == 2
|
||||||
assert i1 in ig_1.instances.all()
|
assert i1 in ig_1.instances.all()
|
||||||
assert i2 in ig_1.instances.all()
|
assert i2 in ig_1.instances.all()
|
||||||
@@ -143,11 +168,13 @@ def test_policy_instance_distribution_simultaneous(mock, instance_factory, insta
|
|||||||
def test_policy_instance_list_manually_managed(mock, instance_factory, instance_group_factory):
|
def test_policy_instance_list_manually_managed(mock, instance_factory, instance_group_factory):
|
||||||
i1 = instance_factory("i1")
|
i1 = instance_factory("i1")
|
||||||
i2 = instance_factory("i2")
|
i2 = instance_factory("i2")
|
||||||
|
ig_t = instance_group_factory("tower")
|
||||||
ig_1 = instance_group_factory("ig1", percentage=100, minimum=2)
|
ig_1 = instance_group_factory("ig1", percentage=100, minimum=2)
|
||||||
ig_2 = instance_group_factory("ig2")
|
ig_2 = instance_group_factory("ig2")
|
||||||
ig_2.policy_instance_list = [i2.hostname]
|
ig_2.policy_instance_list = [i2.hostname]
|
||||||
ig_2.save()
|
ig_2.save()
|
||||||
apply_cluster_membership_policies()
|
apply_cluster_membership_policies()
|
||||||
|
assert len(ig_t.instances.all()) == 2
|
||||||
assert len(ig_1.instances.all()) == 1
|
assert len(ig_1.instances.all()) == 1
|
||||||
assert i1 in ig_1.instances.all()
|
assert i1 in ig_1.instances.all()
|
||||||
assert i2 not in ig_1.instances.all()
|
assert i2 not in ig_1.instances.all()
|
||||||
|
|||||||
Reference in New Issue
Block a user