1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

Adding initial instance group policies

and policy evaluation planner
This commit is contained in:
Matthew Jones 2017-11-14 13:49:06 -05:00
parent c819560d39
commit 56abfa732e
No known key found for this signature in database
GPG Key ID: 76A4C17A97590C1C
5 changed files with 94 additions and 3 deletions

View File

@ -4011,7 +4011,8 @@ class InstanceGroupSerializer(BaseSerializer):
model = InstanceGroup
fields = ("id", "type", "url", "related", "name", "created", "modified",
"capacity", "committed_capacity", "consumed_capacity",
"percent_capacity_remaining", "jobs_running", "instances", "controller")
"percent_capacity_remaining", "jobs_running", "instances", "controller",
"policy_instance_percentage", "policy_instance_minimum")
def get_related(self, obj):
res = super(InstanceGroupSerializer, self).get_related(obj)

View File

@ -17,6 +17,10 @@ class Command(BaseCommand):
help='Comma-Delimited Hosts to add to the Queue')
parser.add_argument('--controller', dest='controller', type=str,
default='', help='The controlling group (makes this an isolated group)')
parser.add_argument('--instance_percent', dest='instance_percent', type=int, default=0,
help='The percentage of active instances that will be assigned to this group'),
parser.add_argument('--instance_minimum', dest='instance_minimum', type=int, default=0,
help='The minimum number of instance that will be retained for this group from available instances')
def handle(self, **options):
queuename = options.get('queuename')
@ -38,7 +42,9 @@ class Command(BaseCommand):
changed = True
else:
print("Creating instance group {}".format(queuename))
ig = InstanceGroup(name=queuename)
ig = InstanceGroup(name=queuename,
policy_instance_percentage=options.get('instance_percent'),
policy_instance_minimum=options.get('instance_minimum'))
if control_ig:
ig.controller = control_ig
ig.save()
@ -60,5 +66,7 @@ class Command(BaseCommand):
sys.exit(1)
else:
print("Instance already registered {}".format(instance[0].hostname))
ig.policy_instance_list = instance_list
ig.save()
if changed:
print('(changed: True)')

View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import awx.main.fields
class Migration(migrations.Migration):
dependencies = [
('main', '0008_v320_drop_v1_credential_fields'),
]
operations = [
migrations.AddField(
model_name='instancegroup',
name='policy_instance_list',
field=awx.main.fields.JSONField(default=[], help_text='List of exact-match Instances that will always be automatically assigned to this group', blank=True),
),
migrations.AddField(
model_name='instancegroup',
name='policy_instance_minimum',
field=models.IntegerField(default=0, help_text='Static minimum number of Instances to automatically assign to this group'),
),
migrations.AddField(
model_name='instancegroup',
name='policy_instance_percentage',
field=models.IntegerField(default=0, help_text='Percentage of Instances to automatically assign to this group'),
),
]

View File

@ -12,6 +12,7 @@ from solo.models import SingletonModel
from awx.api.versioning import reverse
from awx.main.managers import InstanceManager, InstanceGroupManager
from awx.main.fields import JSONField
from awx.main.models.inventory import InventoryUpdate
from awx.main.models.jobs import Job
from awx.main.models.projects import ProjectUpdate
@ -88,6 +89,19 @@ class InstanceGroup(models.Model):
default=None,
null=True
)
policy_instance_percentage = models.IntegerField(
default=0,
help_text=_("Percentage of Instances to automatically assign to this group")
)
policy_instance_minimum = models.IntegerField(
default=0,
help_text=_("Static minimum number of Instances to automatically assign to this group")
)
policy_instance_list = JSONField(
default=[],
blank=True,
help_text=_("List of exact-match Instances that will always be automatically assigned to this group")
)
def get_absolute_url(self, request=None):
return reverse('api:instance_group_detail', kwargs={'pk': self.pk}, request=request)

View File

@ -2,7 +2,8 @@
# All Rights Reserved.
# Python
from collections import OrderedDict
import codecs
from collections import OrderedDict, namedtuple
import ConfigParser
import cStringIO
import functools
@ -131,6 +132,43 @@ def inform_cluster_of_shutdown(*args, **kwargs):
logger.exception('Encountered problem with normal shutdown signal.')
@shared_task(bind=True, queue='tower', base=LogErrorsTask)
def apply_cluster_membership_policies(self):
considered_instances = Instance.objects.all().order_by('id').only('id')
total_instances = considered_instances.count()
actual_groups = []
actual_instances = []
Group = namedtuple('Group', ['obj', 'instances'])
Instance = namedtuple('Instance', ['obj', 'groups'])
# Process policy instance list first, these will represent manually managed instances
# that will not go through automatic policy determination
for ig in InstanceGroup.objects.all():
group_actual = Group(obj=ig, instances=[])
for i in ig.policy_instance_list:
group_actual.instances.append(i)
if i in considered_instances:
considered_instances.remove(i)
actual_groups.append(group_actual)
# Process Instance minimum policies next, since it represents a concrete lower bound to the
# number of instances to make available to instance groups
for i in considered_instances:
instance_actual = Instance(obj=i, groups=[])
for g in sorted(actual_groups, cmp=lambda x,y: len(x.instances) - len(y.instances)):
if len(g.instances) < g.obj.policy_instance_minimum:
g.instances.append(instance_actual.obj.id)
instance_actual.groups.append(g.obj.id)
break
actual_instances.append(instance_actual)
# Finally process instance policy percentages
for i in sorted(actual_instances, cmp=lambda x,y: len(x.groups) - len(y.groups)):
for g in sorted(actual_groups, cmp=lambda x,y: len(x.instances) - len(y.instances)):
if 100 * float(len(g.instances)) / total_instances < g.obj.policy_instance_percentage:
g.instances.append(i.obj.id)
i.groups.append(g.obj.id)
break
# Next step
@shared_task(queue='tower_broadcast_all', bind=True, base=LogErrorsTask)
def handle_setting_changes(self, setting_keys):
orig_len = len(setting_keys)