Fixing item loop when undefined variable errors occur because of missing attributes
Fixes a case where the variable 'foo' may exist, but the with_items loop was used on something like 'foo.results', where 'results' was not a valid attribute of 'foo'. Prior to this patch, conditionals were not evaluated until later, meaning there was no opportunity to allow a test to skip the task or item based on it being undefined.
This commit is contained in:
parent
b4f84c5d9a
commit
2eda9a3a47
3 changed files with 56 additions and 3 deletions
|
@ -663,9 +663,24 @@ class Runner(object):
|
||||||
if os.path.exists(filesdir):
|
if os.path.exists(filesdir):
|
||||||
basedir = filesdir
|
basedir = filesdir
|
||||||
|
|
||||||
items_terms = self.module_vars.get('items_lookup_terms', '')
|
try:
|
||||||
items_terms = template.template(basedir, items_terms, inject)
|
items_terms = self.module_vars.get('items_lookup_terms', '')
|
||||||
items = utils.plugins.lookup_loader.get(items_plugin, runner=self, basedir=basedir).run(items_terms, inject=inject)
|
items_terms = template.template(basedir, items_terms, inject)
|
||||||
|
items = utils.plugins.lookup_loader.get(items_plugin, runner=self, basedir=basedir).run(items_terms, inject=inject)
|
||||||
|
except errors.AnsibleUndefinedVariable, e:
|
||||||
|
if 'has no attribute' in str(e):
|
||||||
|
# the undefined variable was an attribute of a variable that does
|
||||||
|
# exist, so try and run this through the conditional check to see
|
||||||
|
# if the user wanted to skip something on being undefined
|
||||||
|
if utils.check_conditional(self.conditional, self.basedir, inject, fail_on_undefined=True):
|
||||||
|
# the conditional check passed, so we have to fail here
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
# the conditional failed, so we skip this task
|
||||||
|
result = utils.jsonify(dict(changed=False, skipped=True))
|
||||||
|
self.callbacks.on_skipped(host, None)
|
||||||
|
return ReturnData(host=host, result=result)
|
||||||
|
|
||||||
# strip out any jinja2 template syntax within
|
# strip out any jinja2 template syntax within
|
||||||
# the data returned by the lookup plugin
|
# the data returned by the lookup plugin
|
||||||
items = utils._clean_data_struct(items, from_remote=True)
|
items = utils._clean_data_struct(items, from_remote=True)
|
||||||
|
|
|
@ -267,3 +267,28 @@
|
||||||
that:
|
that:
|
||||||
- "result.changed"
|
- "result.changed"
|
||||||
|
|
||||||
|
- name: test a with_items loop using a variable with a missing attribute
|
||||||
|
debug: var=item
|
||||||
|
with_items: foo.results
|
||||||
|
when: foo is defined and 'results' in foo
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: assert the task was skipped
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "'skipped' in result"
|
||||||
|
- result.skipped
|
||||||
|
|
||||||
|
- name: test a with_items loop skipping a single item
|
||||||
|
debug: var=item
|
||||||
|
with_items: items.results
|
||||||
|
when: item != 'b'
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- debug: var=result
|
||||||
|
|
||||||
|
- name: assert only a single item was skipped
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.results|length == 3
|
||||||
|
- result.results[1].skipped
|
||||||
|
|
13
test/integration/roles/test_conditionals/vars/main.yml
Normal file
13
test/integration/roles/test_conditionals/vars/main.yml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
# foo is a dictionary that will be used to check that
|
||||||
|
# a conditional passes a with_items loop on a variable
|
||||||
|
# with a missing attribute (ie. foo.results)
|
||||||
|
foo:
|
||||||
|
bar: a
|
||||||
|
|
||||||
|
items:
|
||||||
|
results:
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
- c
|
||||||
|
|
Loading…
Reference in a new issue