Allow setting default execution group pod spec

This will allow us to control the default container group created via settings, meaning
we could set this in the operator and the default container group would get created with it applied.

We need this for https://github.com/ansible/awx-operator/issues/242

Deepmerge the default podspec and the override

With out this, providing the `spec` for the podspec would override everything
contained, which ends up including the container used, which is not desired

Also, use the same deepmerge function def, as the code seems to be copypasted from
the utils
This commit is contained in:
Elijah DeLee
2021-11-29 14:30:19 -05:00
parent cdf14158b4
commit e10030b73d
5 changed files with 18 additions and 22 deletions

View File

@@ -17,13 +17,14 @@ class InstanceNotFound(Exception):
class RegisterQueue: class RegisterQueue:
def __init__(self, queuename, instance_percent, inst_min, hostname_list, is_container_group=None): def __init__(self, queuename, instance_percent, inst_min, hostname_list, is_container_group=None, pod_spec_override=None):
self.instance_not_found_err = None self.instance_not_found_err = None
self.queuename = queuename self.queuename = queuename
self.instance_percent = instance_percent self.instance_percent = instance_percent
self.instance_min = inst_min self.instance_min = inst_min
self.hostname_list = hostname_list self.hostname_list = hostname_list
self.is_container_group = is_container_group self.is_container_group = is_container_group
self.pod_spec_override = pod_spec_override
def get_create_update_instance_group(self): def get_create_update_instance_group(self):
created = False created = False
@@ -40,6 +41,10 @@ class RegisterQueue:
ig.is_container_group = self.is_container_group ig.is_container_group = self.is_container_group
changed = True changed = True
if self.pod_spec_override and (ig.pod_spec_override != self.pod_spec_override):
ig.pod_spec_override = self.pod_spec_override
changed = True
if changed: if changed:
ig.save() ig.save()

View File

@@ -179,7 +179,9 @@ class InstanceManager(models.Manager):
else: else:
registered = self.register(ip_address=pod_ip, uuid=settings.SYSTEM_UUID) registered = self.register(ip_address=pod_ip, uuid=settings.SYSTEM_UUID)
RegisterQueue(settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME, 100, 0, [], is_container_group=False).register() RegisterQueue(settings.DEFAULT_CONTROL_PLANE_QUEUE_NAME, 100, 0, [], is_container_group=False).register()
RegisterQueue(settings.DEFAULT_EXECUTION_QUEUE_NAME, 100, 0, [], is_container_group=True).register() RegisterQueue(
settings.DEFAULT_EXECUTION_QUEUE_NAME, 100, 0, [], is_container_group=True, pod_spec_override=settings.DEFAULT_EXECUTION_QUEUE_POD_SPEC_OVERRIDE
).register()
return registered return registered
else: else:
return (False, self.me()) return (False, self.me())

View File

@@ -9,29 +9,12 @@ from kubernetes import client, config
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from awx.main.utils.common import parse_yaml_or_json from awx.main.utils.common import parse_yaml_or_json, deepmerge
from awx.main.utils.execution_environments import get_default_pod_spec from awx.main.utils.execution_environments import get_default_pod_spec
logger = logging.getLogger('awx.main.scheduler') logger = logging.getLogger('awx.main.scheduler')
def deepmerge(a, b):
"""
Merge dict structures and return the result.
>>> a = {'first': {'all_rows': {'pass': 'dog', 'number': '1'}}}
>>> b = {'first': {'all_rows': {'fail': 'cat', 'number': '5'}}}
>>> import pprint; pprint.pprint(deepmerge(a, b))
{'first': {'all_rows': {'fail': 'cat', 'number': '5', 'pass': 'dog'}}}
"""
if isinstance(a, dict) and isinstance(b, dict):
return dict([(k, deepmerge(a.get(k), b.get(k))) for k in set(a.keys()).union(b.keys())])
elif b is None:
return a
else:
return b
class PodManager(object): class PodManager(object):
def __init__(self, task=None): def __init__(self, task=None):
self.task = task self.task = task
@@ -183,7 +166,7 @@ class PodManager(object):
pod_spec_override = {} pod_spec_override = {}
if self.task and self.task.instance_group.pod_spec_override: if self.task and self.task.instance_group.pod_spec_override:
pod_spec_override = parse_yaml_or_json(self.task.instance_group.pod_spec_override) pod_spec_override = parse_yaml_or_json(self.task.instance_group.pod_spec_override)
pod_spec = {**default_pod_spec, **pod_spec_override} pod_spec = deepmerge(default_pod_spec, pod_spec_override)
if self.task: if self.task:
pod_spec['metadata'] = deepmerge( pod_spec['metadata'] = deepmerge(

View File

@@ -3286,7 +3286,11 @@ class AWXReceptorJob:
pod_spec_override = {} pod_spec_override = {}
if self.task and self.task.instance.instance_group.pod_spec_override: if self.task and self.task.instance.instance_group.pod_spec_override:
pod_spec_override = parse_yaml_or_json(self.task.instance.instance_group.pod_spec_override) pod_spec_override = parse_yaml_or_json(self.task.instance.instance_group.pod_spec_override)
pod_spec = {**default_pod_spec, **pod_spec_override} # According to the deepmerge docstring, the second dictionary will override when
# they share keys, which is the desired behavior.
# This allows user to only provide elements they want to override, and for us to still provide any
# defaults they don't want to change
pod_spec = deepmerge(default_pod_spec, pod_spec_override)
pod_spec['spec']['containers'][0]['image'] = ee.image pod_spec['spec']['containers'][0]['image'] = ee.image
pod_spec['spec']['containers'][0]['args'] = ['ansible-runner', 'worker', '--private-data-dir=/runner'] pod_spec['spec']['containers'][0]['args'] = ['ansible-runner', 'worker', '--private-data-dir=/runner']

View File

@@ -986,5 +986,7 @@ DJANGO_GUID = {'GUID_HEADER_NAME': 'X-API-Request-Id'}
# Name of the default task queue # Name of the default task queue
DEFAULT_EXECUTION_QUEUE_NAME = 'default' DEFAULT_EXECUTION_QUEUE_NAME = 'default'
# pod spec used when the default execution queue is a container group, e.g. when deploying on k8s/ocp with the operator
DEFAULT_EXECUTION_QUEUE_POD_SPEC_OVERRIDE = ''
# Name of the default controlplane queue # Name of the default controlplane queue
DEFAULT_CONTROL_PLANE_QUEUE_NAME = 'controlplane' DEFAULT_CONTROL_PLANE_QUEUE_NAME = 'controlplane'