Make the necessary changes to the models

- remove InstanceGroup.controller
- remove Instance.last_isolated_check
- remove .is_isolated and .is_controller methods/properties
- remove .choose_online_controller_node() method
- remove .supports_isolation() and replace with .can_run_containerized
- simplify .can_run_containerized
This commit is contained in:
Jeff Bradberry
2021-04-21 11:03:38 -04:00
parent 6a599695db
commit 1819a7963a
6 changed files with 39 additions and 85 deletions

View File

@@ -0,0 +1,26 @@
# Generated by Django 2.2.16 on 2021-04-21 15:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0138_custom_inventory_scripts_removal'),
]
operations = [
migrations.RemoveField(
model_name='instance',
name='last_isolated_check',
),
migrations.RemoveField(
model_name='instancegroup',
name='controller',
),
migrations.AlterField(
model_name='unifiedjob',
name='controller_node',
field=models.TextField(blank=True, default='', editable=False, help_text='The instance that managed the execution environment.'),
),
]

View File

@@ -146,10 +146,6 @@ class AdHocCommand(UnifiedJob, JobNotificationMixin):
return RunAdHocCommand return RunAdHocCommand
@classmethod
def supports_isolation(cls):
return True
@property @property
def is_container_group_task(self): def is_container_group_task(self):
return bool(self.instance_group and self.instance_group.is_container_group) return bool(self.instance_group and self.instance_group.is_container_group)

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2015 Ansible, Inc. # Copyright (c) 2015 Ansible, Inc.
# All Rights Reserved. # All Rights Reserved.
import random
from decimal import Decimal from decimal import Decimal
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
@@ -63,10 +62,6 @@ class Instance(HasPolicyEditsMixin, BaseModel):
) )
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True) modified = models.DateTimeField(auto_now=True)
last_isolated_check = models.DateTimeField(
null=True,
editable=False,
)
version = models.CharField(max_length=120, blank=True) version = models.CharField(max_length=120, blank=True)
capacity = models.PositiveIntegerField( capacity = models.PositiveIntegerField(
default=100, default=100,
@@ -128,20 +123,12 @@ class Instance(HasPolicyEditsMixin, BaseModel):
def jobs_total(self): def jobs_total(self):
return UnifiedJob.objects.filter(execution_node=self.hostname).count() return UnifiedJob.objects.filter(execution_node=self.hostname).count()
def is_lost(self, ref_time=None, isolated=False): def is_lost(self, ref_time=None):
if ref_time is None: if ref_time is None:
ref_time = now() ref_time = now()
grace_period = 120 grace_period = 120
if isolated:
grace_period = settings.AWX_ISOLATED_PERIODIC_CHECK * 2
return self.modified < ref_time - timedelta(seconds=grace_period) return self.modified < ref_time - timedelta(seconds=grace_period)
def is_controller(self):
return Instance.objects.filter(rampart_groups__controller__instances=self).exists()
def is_isolated(self):
return self.rampart_groups.filter(controller__isnull=False).exists()
def refresh_capacity(self): def refresh_capacity(self):
if settings.IS_K8S: if settings.IS_K8S:
self.capacity = self.cpu = self.memory = self.cpu_capacity = self.mem_capacity = 0 # noqa self.capacity = self.cpu = self.memory = self.cpu_capacity = self.mem_capacity = 0 # noqa
@@ -185,15 +172,6 @@ class InstanceGroup(HasPolicyEditsMixin, BaseModel, RelatedJobsMixin):
editable=False, editable=False,
help_text=_('Instances that are members of this InstanceGroup'), help_text=_('Instances that are members of this InstanceGroup'),
) )
controller = models.ForeignKey(
'InstanceGroup',
related_name='controlled_groups',
help_text=_('Instance Group to remotely control this group.'),
editable=False,
default=None,
null=True,
on_delete=models.CASCADE,
)
is_container_group = models.BooleanField(default=False) is_container_group = models.BooleanField(default=False)
credential = models.ForeignKey( credential = models.ForeignKey(
'Credential', 'Credential',
@@ -215,7 +193,7 @@ class InstanceGroup(HasPolicyEditsMixin, BaseModel, RelatedJobsMixin):
default=[], blank=True, help_text=_("List of exact-match Instances that will always be automatically assigned to this group") default=[], blank=True, help_text=_("List of exact-match Instances that will always be automatically assigned to this group")
) )
POLICY_FIELDS = frozenset(('policy_instance_list', 'policy_instance_minimum', 'policy_instance_percentage', 'controller')) POLICY_FIELDS = frozenset(('policy_instance_list', 'policy_instance_minimum', 'policy_instance_percentage'))
def get_absolute_url(self, request=None): def get_absolute_url(self, request=None):
return reverse('api:instance_group_detail', kwargs={'pk': self.pk}, request=request) return reverse('api:instance_group_detail', kwargs={'pk': self.pk}, request=request)
@@ -232,14 +210,6 @@ class InstanceGroup(HasPolicyEditsMixin, BaseModel, RelatedJobsMixin):
def jobs_total(self): def jobs_total(self):
return UnifiedJob.objects.filter(instance_group=self).count() return UnifiedJob.objects.filter(instance_group=self).count()
@property
def is_controller(self):
return self.controlled_groups.exists()
@property
def is_isolated(self):
return bool(self.controller)
''' '''
RelatedJobsMixin RelatedJobsMixin
''' '''
@@ -271,9 +241,6 @@ class InstanceGroup(HasPolicyEditsMixin, BaseModel, RelatedJobsMixin):
largest_instance = i largest_instance = i
return largest_instance return largest_instance
def choose_online_controller_node(self):
return random.choice(list(self.controller.instances.filter(capacity__gt=0, enabled=True).values_list('hostname', flat=True)))
def set_default_policy_fields(self): def set_default_policy_fields(self):
self.policy_instance_list = [] self.policy_instance_list = []
self.policy_instance_minimum = 0 self.policy_instance_minimum = 0

View File

@@ -587,10 +587,6 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
return RunJob return RunJob
@classmethod
def supports_isolation(cls):
return True
def _global_timeout_setting(self): def _global_timeout_setting(self):
return 'DEFAULT_JOB_TIMEOUT' return 'DEFAULT_JOB_TIMEOUT'
@@ -759,7 +755,7 @@ class Job(UnifiedJob, JobOptions, SurveyJobMixin, JobNotificationMixin, TaskMana
@property @property
def can_run_containerized(self): def can_run_containerized(self):
return any([ig for ig in self.preferred_instance_groups if ig.is_container_group]) return True
@property @property
def is_container_group_task(self): def is_container_group_task(self):

View File

@@ -588,7 +588,7 @@ class UnifiedJob(
blank=True, blank=True,
default='', default='',
editable=False, editable=False,
help_text=_("The instance that managed the isolated execution environment."), help_text=_("The instance that managed the execution environment."),
) )
notifications = models.ManyToManyField( notifications = models.ManyToManyField(
'Notification', 'Notification',
@@ -737,10 +737,6 @@ class UnifiedJob(
def _get_task_class(cls): def _get_task_class(cls):
raise NotImplementedError # Implement in subclasses. raise NotImplementedError # Implement in subclasses.
@classmethod
def supports_isolation(cls):
return False
@property @property
def can_run_containerized(self): def can_run_containerized(self):
return False return False
@@ -1402,12 +1398,11 @@ class UnifiedJob(
@property @property
def preferred_instance_groups(self): def preferred_instance_groups(self):
""" """
Return Instance/Rampart Groups preferred by this unified job templates Return Instance/Rampart Groups preferred by this unified job template
""" """
if not self.unified_job_template: if not self.unified_job_template:
return [] return []
template_groups = [x for x in self.unified_job_template.instance_groups.all()] return list(self.unified_job_template.instance_groups.all())
return template_groups
@property @property
def global_instance_groups(self): def global_instance_groups(self):
@@ -1467,9 +1462,6 @@ class UnifiedJob(
def get_queue_name(self): def get_queue_name(self):
return self.controller_node or self.execution_node or get_local_queuename() return self.controller_node or self.execution_node or get_local_queuename()
def is_isolated(self):
return bool(self.controller_node)
@property @property
def is_container_group_task(self): def is_container_group_task(self):
return False return False

View File

@@ -6,7 +6,6 @@ from datetime import timedelta
import logging import logging
import uuid import uuid
import json import json
import random
from types import SimpleNamespace from types import SimpleNamespace
# Django # Django
@@ -253,14 +252,6 @@ class TaskManager:
} }
dependencies = [{'type': get_type_for_model(type(t)), 'id': t.id} for t in dependent_tasks] dependencies = [{'type': get_type_for_model(type(t)), 'id': t.id} for t in dependent_tasks]
controller_node = None
if task.supports_isolation() and rampart_group.controller_id:
try:
controller_node = rampart_group.choose_online_controller_node()
except IndexError:
logger.debug("No controllers available in group {} to run {}".format(rampart_group.name, task.log_format))
return
task.status = 'waiting' task.status = 'waiting'
(start_status, opts) = task.pre_start() (start_status, opts) = task.pre_start()
@@ -277,38 +268,24 @@ class TaskManager:
task.send_notification_templates('running') task.send_notification_templates('running')
logger.debug('Transitioning %s to running status.', task.log_format) logger.debug('Transitioning %s to running status.', task.log_format)
schedule_task_manager() schedule_task_manager()
elif not task.supports_isolation() and rampart_group.controller_id:
# non-Ansible jobs on isolated instances run on controller
task.instance_group = rampart_group.controller
task.execution_node = random.choice(list(rampart_group.controller.instances.all().values_list('hostname', flat=True)))
logger.debug('Submitting isolated {} to queue {} on node {}.'.format(task.log_format, task.instance_group.name, task.execution_node))
elif controller_node:
task.instance_group = rampart_group
task.execution_node = instance.hostname
task.controller_node = controller_node
logger.debug('Submitting isolated {} to queue {} controlled by {}.'.format(task.log_format, task.execution_node, controller_node))
elif rampart_group.is_container_group: elif rampart_group.is_container_group:
# find one real, non-containerized instance with capacity to # find one real, non-containerized instance with capacity to
# act as the controller for k8s API interaction # act as the controller for k8s API interaction
match = None match = None
for group in InstanceGroup.objects.all(): for group in InstanceGroup.objects.filter(is_container_group=False):
if group.is_container_group or group.controller_id:
continue
match = group.fit_task_to_most_remaining_capacity_instance(task, group.instances.all()) match = group.fit_task_to_most_remaining_capacity_instance(task, group.instances.all())
if match: if match:
break break
task.instance_group = rampart_group task.instance_group = rampart_group
if match is None: if match is None:
logger.warn('No available capacity to run containerized <{}>.'.format(task.log_format)) logger.warn('No available capacity to run containerized <{}>.'.format(task.log_format))
elif task.can_run_containerized and any(ig.is_container_group for ig in task.preferred_instance_groups):
task.controller_node = match.hostname
else: else:
if task.supports_isolation(): # project updates and inventory updates don't *actually* run in pods, so
task.controller_node = match.hostname # just pick *any* non-containerized host and use it as the execution node
else: task.execution_node = match.hostname
# project updates and inventory updates don't *actually* run in pods, logger.debug('Submitting containerized {} to queue {}.'.format(task.log_format, task.execution_node))
# so just pick *any* non-isolated, non-containerized host and use it
# as the execution node
task.execution_node = match.hostname
logger.debug('Submitting containerized {} to queue {}.'.format(task.log_format, task.execution_node))
else: else:
task.instance_group = rampart_group task.instance_group = rampart_group
if instance is not None: if instance is not None: