Make Ansible variable freezing more efficient
We currently iterate over every job/host/etc variable in the freeze playbook. The reason is because if any value in any variable is Undefined according to jinja, the Ansible combine filter throws an error. What we want to do in Zuul is merge any variable we can, but if any is undefined, we skip it. Thus, the process of combining the variables one at a time in a task and ignoring errors. This process can be slow, especially if we have start with a large amount of data in one of the early variables. The combine filter needs to reprocess the large data repeatedly for each additional variable. To improve the process, we create a new action plugin, "zuul_freeze" which takes a list of variables we want to freeze, then templates them one at a time and stores the result in a cacheable fact. This is the essence of what we were trying to accomplish with the combine filter. Change-Id: Ie41f404762daa1b1a5ae47f6ec1aa1954ad36a39
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
vars:
|
||||
latesub: "{{ latefact | default('undefined') }}"
|
||||
jobvar: "{{ base_secret.secret | default('undefined') }}"
|
||||
# Make sure we have a top level variable that is undefined to
|
||||
# ensure that it doesn't cause all values to be omitted.
|
||||
undefvar: "{{ undefinedvar }}"
|
||||
run: playbooks/testjob-run.yaml
|
||||
|
||||
- job:
|
||||
|
||||
1
zuul/ansible/6/action/zuul_freeze.py
Symbolic link
1
zuul/ansible/6/action/zuul_freeze.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../../base/action/zuul_freeze.py
|
||||
1
zuul/ansible/8/action/zuul_freeze.py
Symbolic link
1
zuul/ansible/8/action/zuul_freeze.py
Symbolic link
@@ -0,0 +1 @@
|
||||
../../base/action/zuul_freeze.py
|
||||
53
zuul/ansible/base/action/zuul_freeze.py
Normal file
53
zuul/ansible/base/action/zuul_freeze.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# Copyright (C) 2023 Acme Gating, LLC
|
||||
#
|
||||
# This module is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This software is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.template import recursive_check_defined
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
"""This module accepts one parameter:
|
||||
|
||||
_zuul_freeze_vars is a list of variable names to template.
|
||||
|
||||
It stores the templated variables in a cacheable fact named
|
||||
_zuul_frozen.
|
||||
|
||||
If any variable is undefined or recursively references any
|
||||
undefined variables, it is omitted from the result.
|
||||
|
||||
"""
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
results = super(ActionModule, self).run(tmp, task_vars)
|
||||
del tmp # tmp no longer has any effect
|
||||
|
||||
varlist = self._task.args.get('_zuul_freeze_vars')
|
||||
ret = {}
|
||||
for var in varlist:
|
||||
try:
|
||||
# Template the variable (convert_bare means treat a
|
||||
# bare variable name as {{ var }}.
|
||||
value = self._templar.template(var, convert_bare=True)
|
||||
recursive_check_defined(value)
|
||||
ret[var] = value
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
results['ansible_facts'] = {'_zuul_frozen': ret}
|
||||
results['_ansible_facts_cacheable'] = True
|
||||
|
||||
return results
|
||||
@@ -3060,21 +3060,11 @@ class AnsibleJob(object):
|
||||
}
|
||||
for host in self.host_list + [localhost]:
|
||||
tasks = [{
|
||||
'set_fact': {
|
||||
'_zuul_frozen': {},
|
||||
'cacheable': True,
|
||||
'zuul_freeze': {
|
||||
'_zuul_freeze_vars': list(
|
||||
self.original_hostvars[host['name']].keys()),
|
||||
},
|
||||
}]
|
||||
for var in self.original_hostvars[host['name']].keys():
|
||||
val = "{{ _zuul_frozen | combine({'%s': %s}) }}" % (var, var)
|
||||
task = {
|
||||
'set_fact': {
|
||||
'_zuul_frozen': val,
|
||||
'cacheable': True,
|
||||
},
|
||||
'ignore_errors': True,
|
||||
}
|
||||
tasks.append(task)
|
||||
play = {
|
||||
'hosts': host['name'],
|
||||
'tasks': tasks,
|
||||
|
||||
Reference in New Issue
Block a user