summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Fontein <felix@fontein.de>2020-12-07 16:59:04 +0100
committerGitHub <noreply@github.com>2020-12-07 09:59:04 -0600
commitaa471096de7b604f6304b02a5a1d2be6092ccb7e (patch)
treeb6bc051ca01bdaef17b9f1b313bbb41d79f2d7d8
parentf67b4e76954ecf44f15ee4f399ed85869f3ab32c (diff)
downloadansible-aa471096de7b604f6304b02a5a1d2be6092ccb7e.tar.gz
[2.9] Fix missing ansible.builtin FQCNs in hardcoded action names (#72458)
* Fix missing ansible.builtin FQCNs in hardcoded action names (#71824) * Make sure hard-coded action names also check for FQCN. * Use _add_internal_fqcn() to avoid hardcoded lists and typoes. (cherry picked from commit da60525610a384bb04833b1c6429d9db6a87ef64) ci_complete * Replace some more FQCNs. (cherry picked from commit 72302dd61168e17fe4d16fbb4429d48662d9f0c3) * Fix another case which was already fixed in stable-2.10.
-rw-r--r--changelogs/fragments/71824-action-fqcns.yml2
-rw-r--r--lib/ansible/cli/adhoc.py6
-rw-r--r--lib/ansible/cli/console.py2
-rw-r--r--lib/ansible/cli/playbook.py3
-rw-r--r--lib/ansible/constants.py30
-rw-r--r--lib/ansible/executor/task_executor.py8
-rw-r--r--lib/ansible/executor/task_result.py2
-rw-r--r--lib/ansible/parsing/mod_args.py9
-rw-r--r--lib/ansible/playbook/__init__.py10
-rw-r--r--lib/ansible/playbook/block.py5
-rw-r--r--lib/ansible/playbook/helpers.py18
-rw-r--r--lib/ansible/playbook/included_file.py5
-rw-r--r--lib/ansible/playbook/playbook_include.py3
-rw-r--r--lib/ansible/playbook/role_include.py5
-rw-r--r--lib/ansible/playbook/task.py10
-rw-r--r--lib/ansible/playbook/task_include.py8
-rw-r--r--lib/ansible/plugins/action/gather_facts.py2
-rw-r--r--lib/ansible/plugins/action/normal.py3
-rw-r--r--lib/ansible/plugins/callback/__init__.py2
-rw-r--r--lib/ansible/plugins/callback/junit.py3
-rw-r--r--lib/ansible/plugins/strategy/__init__.py9
-rw-r--r--lib/ansible/plugins/strategy/free.py2
-rw-r--r--lib/ansible/plugins/strategy/linear.py5
-rw-r--r--lib/ansible/utils/fqcn.py33
-rw-r--r--lib/ansible/vars/manager.py2
-rw-r--r--test/integration/targets/debug/main_fqcn.yml6
-rwxr-xr-xtest/integration/targets/debug/runme.sh6
-rwxr-xr-xtest/integration/targets/include_import/runme.sh8
-rw-r--r--test/integration/targets/include_import/test_copious_include_tasks_fqcn.yml44
-rw-r--r--test/integration/targets/include_import/test_grandparent_inheritance_fqcn.yml29
-rw-r--r--test/integration/targets/include_import/test_include_loop_fqcn.yml17
-rw-r--r--test/integration/targets/include_import/test_nested_tasks_fqcn.yml6
-rw-r--r--test/integration/targets/include_import/test_role_recursion_fqcn.yml7
-rw-r--r--test/integration/targets/include_vars/tasks/main.yml18
-rw-r--r--test/integration/targets/include_vars/vars/services/service_vars_fqcn.yml3
-rw-r--r--test/integration/targets/includes/roles/test_includes_free/tasks/inner_fqcn.yml2
-rw-r--r--test/integration/targets/includes/roles/test_includes_free/tasks/main.yml3
-rw-r--r--test/integration/targets/includes/test_include_free.yml1
-rwxr-xr-xtest/integration/targets/meta_tasks/runme.sh19
-rw-r--r--test/integration/targets/meta_tasks/test_end_host_all_fqcn.yml13
-rw-r--r--test/integration/targets/meta_tasks/test_end_host_fqcn.yml14
-rw-r--r--test/integration/targets/meta_tasks/test_end_play_fqcn.yml12
-rw-r--r--test/integration/targets/set_fact/incremental.yml16
-rw-r--r--test/integration/targets/set_fact/nowarn_clean_facts.yml3
-rw-r--r--test/integration/targets/set_fact/set_fact_bool_conv.yml15
-rw-r--r--test/integration/targets/set_fact/set_fact_bool_conv_jinja2_native.yml15
-rw-r--r--test/integration/targets/set_fact/set_fact_cached_1.yml155
-rw-r--r--test/integration/targets/set_fact/set_fact_cached_2.yml27
-rw-r--r--test/integration/targets/set_fact/set_fact_no_cache.yml18
49 files changed, 577 insertions, 67 deletions
diff --git a/changelogs/fragments/71824-action-fqcns.yml b/changelogs/fragments/71824-action-fqcns.yml
new file mode 100644
index 0000000000..e2c8729d7c
--- /dev/null
+++ b/changelogs/fragments/71824-action-fqcns.yml
@@ -0,0 +1,2 @@
+bugfixes:
+- "Adjust various hard-coded action names to also include their ``ansible.builtin.`` and ``ansible.legacy.`` prefixed version (https://github.com/ansible/ansible/issues/71817, https://github.com/ansible/ansible/issues/71818, https://github.com/ansible/ansible/pull/71824)."
diff --git a/lib/ansible/cli/adhoc.py b/lib/ansible/cli/adhoc.py
index 9d91b2934f..fd39f1a50a 100644
--- a/lib/ansible/cli/adhoc.py
+++ b/lib/ansible/cli/adhoc.py
@@ -64,12 +64,12 @@ class AdHocCLI(CLI):
return options
def _play_ds(self, pattern, async_val, poll):
- check_raw = context.CLIARGS['module_name'] in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
+ check_raw = context.CLIARGS['module_name'] in C.MODULE_REQUIRE_ARGS
mytask = {'action': {'module': context.CLIARGS['module_name'], 'args': parse_kv(context.CLIARGS['module_args'], check_raw=check_raw)}}
# avoid adding to tasks that don't support it, unless set, then give user an error
- if context.CLIARGS['module_name'] not in ('include_role', 'include_tasks') and any(frozenset((async_val, poll))):
+ if context.CLIARGS['module_name'] not in C._ACTION_ALL_INCLUDE_ROLE_TASKS and any(frozenset((async_val, poll))):
mytask['async_val'] = async_val
mytask['poll'] = poll
@@ -118,7 +118,7 @@ class AdHocCLI(CLI):
raise AnsibleOptionsError(err)
# Avoid modules that don't work with ad-hoc
- if context.CLIARGS['module_name'] in ('import_playbook',):
+ if context.CLIARGS['module_name'] in C._ACTION_IMPORT_PLAYBOOK:
raise AnsibleOptionsError("'%s' is not a valid action for ad-hoc commands"
% context.CLIARGS['module_name'])
diff --git a/lib/ansible/cli/console.py b/lib/ansible/cli/console.py
index a1492ca7b0..ba6b1ff54f 100644
--- a/lib/ansible/cli/console.py
+++ b/lib/ansible/cli/console.py
@@ -182,7 +182,7 @@ class ConsoleCLI(CLI, cmd.Cmd):
result = None
try:
- check_raw = module in ('command', 'shell', 'script', 'raw')
+ check_raw = module in C._ACTION_ALLOWS_RAW_ARGS
play_ds = dict(
name="Ansible Shell",
hosts=self.cwd,
diff --git a/lib/ansible/cli/playbook.py b/lib/ansible/cli/playbook.py
index 300d913349..0487c286de 100644
--- a/lib/ansible/cli/playbook.py
+++ b/lib/ansible/cli/playbook.py
@@ -8,6 +8,7 @@ __metaclass__ = type
import os
import stat
+from ansible import constants as C
from ansible import context
from ansible.cli import CLI
from ansible.cli.arguments import option_helpers as opt_help
@@ -161,7 +162,7 @@ class PlaybookCLI(CLI):
if isinstance(task, Block):
taskmsg += _process_block(task)
else:
- if task.action == 'meta':
+ if task.action in C._ACTION_META:
continue
all_tags.update(task.tags)
diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py
index faceafa5e8..71563d1a9d 100644
--- a/lib/ansible/constants.py
+++ b/lib/ansible/constants.py
@@ -17,6 +17,7 @@ from ansible.module_utils.common.collections import Sequence
from ansible.module_utils.parsing.convert_bool import boolean, BOOLEANS_TRUE
from ansible.module_utils.six import string_types
from ansible.config.manager import ConfigManager, ensure_type, get_ini_config_value
+from ansible.utils.fqcn import add_internal_fqcns
def _warning(msg):
@@ -108,8 +109,8 @@ DOCUMENTABLE_PLUGINS = CONFIGURABLE_PLUGINS + ('module', 'strategy', 'vars')
IGNORE_FILES = ("COPYING", "CONTRIBUTING", "LICENSE", "README", "VERSION", "GUIDELINES") # ignore during module search
INTERNAL_RESULT_KEYS = ('add_host', 'add_group')
LOCALHOST = ('127.0.0.1', 'localhost', '::1')
-MODULE_REQUIRE_ARGS = ('command', 'win_command', 'shell', 'win_shell', 'raw', 'script')
-MODULE_NO_JSON = ('command', 'win_command', 'shell', 'win_shell', 'raw')
+MODULE_REQUIRE_ARGS = tuple(add_internal_fqcns(('command', 'win_command', 'shell', 'win_shell', 'raw', 'script')))
+MODULE_NO_JSON = tuple(add_internal_fqcns(('command', 'win_command', 'shell', 'win_shell', 'raw')))
RESTRICTED_RESULT_KEYS = ('ansible_rsync_path', 'ansible_playbook_python', 'ansible_facts')
TREE_DIR = None
VAULT_VERSION_MIN = 1.0
@@ -196,3 +197,28 @@ for setting in config.data.get_settings():
for warn in config.WARNINGS:
_warning(warn)
+
+
+# The following are hard-coded action names
+_ACTION_DEBUG = add_internal_fqcns(('debug', ))
+_ACTION_IMPORT_PLAYBOOK = add_internal_fqcns(('import_playbook', ))
+_ACTION_IMPORT_ROLE = add_internal_fqcns(('import_role', ))
+_ACTION_IMPORT_TASKS = add_internal_fqcns(('import_tasks', ))
+_ACTION_INCLUDE = add_internal_fqcns(('include', ))
+_ACTION_INCLUDE_ROLE = add_internal_fqcns(('include_role', ))
+_ACTION_INCLUDE_TASKS = add_internal_fqcns(('include_tasks', ))
+_ACTION_INCLUDE_VARS = add_internal_fqcns(('include_vars', ))
+_ACTION_META = add_internal_fqcns(('meta', ))
+_ACTION_SET_FACT = add_internal_fqcns(('set_fact', ))
+_ACTION_SETUP = add_internal_fqcns(('setup', ))
+_ACTION_HAS_CMD = add_internal_fqcns(('command', 'shell', 'script'))
+_ACTION_ALLOWS_RAW_ARGS = _ACTION_HAS_CMD + add_internal_fqcns(('raw', ))
+_ACTION_ALL_INCLUDES = _ACTION_INCLUDE + _ACTION_INCLUDE_TASKS + _ACTION_INCLUDE_ROLE
+_ACTION_ALL_IMPORT_PLAYBOOKS = _ACTION_INCLUDE + _ACTION_IMPORT_PLAYBOOK
+_ACTION_ALL_INCLUDE_IMPORT_TASKS = _ACTION_INCLUDE + _ACTION_INCLUDE_TASKS + _ACTION_IMPORT_TASKS
+_ACTION_ALL_PROPER_INCLUDE_IMPORT_ROLES = _ACTION_INCLUDE_ROLE + _ACTION_IMPORT_ROLE
+_ACTION_ALL_PROPER_INCLUDE_IMPORT_TASKS = _ACTION_INCLUDE_TASKS + _ACTION_IMPORT_TASKS
+_ACTION_ALL_INCLUDE_ROLE_TASKS = _ACTION_INCLUDE_ROLE + _ACTION_INCLUDE_TASKS
+_ACTION_ALL_INCLUDE_TASKS = _ACTION_INCLUDE + _ACTION_INCLUDE_TASKS
+_ACTION_FACT_GATHERING = _ACTION_SETUP + add_internal_fqcns(('gather_facts', ))
+_ACTION_WITH_CLEAN_FACTS = _ACTION_SET_FACT + _ACTION_INCLUDE_VARS
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
index d31546d650..fe27754c84 100644
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -573,7 +573,7 @@ class TaskExecutor:
# if this task is a TaskInclude, we just return now with a success code so the
# main thread can expand the task list for the given host
- if self._task.action in ('include', 'include_tasks'):
+ if self._task.action in C._ACTION_ALL_INCLUDE_TASKS:
include_args = self._task.args.copy()
include_file = include_args.pop('_raw_params', None)
if not include_file:
@@ -583,7 +583,7 @@ class TaskExecutor:
return dict(include=include_file, include_args=include_args)
# if this task is a IncludeRole, we just return now with a success code so the main thread can expand the task list for the given host
- elif self._task.action == 'include_role':
+ elif self._task.action in C._ACTION_INCLUDE_ROLE:
include_args = self._task.args.copy()
return dict(include_args=include_args)
@@ -710,7 +710,7 @@ class TaskExecutor:
return failed_when_result
if 'ansible_facts' in result:
- if self._task.action in ('set_fact', 'include_vars'):
+ if self._task.action in C._ACTION_WITH_CLEAN_FACTS:
vars_copy.update(result['ansible_facts'])
else:
# TODO: cleaning of facts should eventually become part of taskresults instead of vars
@@ -774,7 +774,7 @@ class TaskExecutor:
variables[self._task.register] = wrap_var(result)
if 'ansible_facts' in result:
- if self._task.action in ('set_fact', 'include_vars'):
+ if self._task.action in C._ACTION_WITH_CLEAN_FACTS:
variables.update(result['ansible_facts'])
else:
# TODO: cleaning of facts should eventually become part of taskresults instead of vars
diff --git a/lib/ansible/executor/task_result.py b/lib/ansible/executor/task_result.py
index c3f1a7ce34..a449f88f2d 100644
--- a/lib/ansible/executor/task_result.py
+++ b/lib/ansible/executor/task_result.py
@@ -113,7 +113,7 @@ class TaskResult:
result = TaskResult(self._host, self._task, {}, self._task_fields)
# statuses are already reflected on the event type
- if result._task and result._task.action in ['debug']:
+ if result._task and result._task.action in C._ACTION_DEBUG:
# debug is verbose by default to display vars, no need to add invocation
ignore = _IGNORE + ('invocation',)
else:
diff --git a/lib/ansible/parsing/mod_args.py b/lib/ansible/parsing/mod_args.py
index e01eb7b8c5..8821e39b9a 100644
--- a/lib/ansible/parsing/mod_args.py
+++ b/lib/ansible/parsing/mod_args.py
@@ -25,6 +25,7 @@ from ansible.module_utils._text import to_text
from ansible.parsing.splitter import parse_kv, split_args
from ansible.plugins.loader import module_loader, action_loader
from ansible.template import Templar
+from ansible.utils.fqcn import add_internal_fqcns
from ansible.utils.sentinel import Sentinel
@@ -38,7 +39,7 @@ FREEFORM_ACTIONS = frozenset((
'raw'
))
-RAW_PARAM_MODULES = FREEFORM_ACTIONS.union((
+RAW_PARAM_MODULES = FREEFORM_ACTIONS.union(add_internal_fqcns((
'include',
'include_vars',
'include_tasks',
@@ -49,16 +50,16 @@ RAW_PARAM_MODULES = FREEFORM_ACTIONS.union((
'group_by',
'set_fact',
'meta',
-))
+)))
-BUILTIN_TASKS = frozenset((
+BUILTIN_TASKS = frozenset(add_internal_fqcns((
'meta',
'include',
'include_tasks',
'include_role',
'import_tasks',
'import_role'
-))
+)))
class ModuleArgsParser:
diff --git a/lib/ansible/playbook/__init__.py b/lib/ansible/playbook/__init__.py
index 17b5f2fe76..b9aec39c67 100644
--- a/lib/ansible/playbook/__init__.py
+++ b/lib/ansible/playbook/__init__.py
@@ -90,14 +90,18 @@ class Playbook:
self._loader.set_basedir(cur_basedir)
raise AnsibleParserError("playbook entries must be either a valid play or an include statement", obj=entry)
- if any(action in entry for action in ('import_playbook', 'include')):
- if 'include' in entry:
+ if any(action in entry for action in C._ACTION_ALL_IMPORT_PLAYBOOKS):
+ if any(action in entry for action in C._ACTION_INCLUDE):
display.deprecated("'include' for playbook includes. You should use 'import_playbook' instead", version="2.12")
pb = PlaybookInclude.load(entry, basedir=self._basedir, variable_manager=variable_manager, loader=self._loader)
if pb is not None:
self._entries.extend(pb._entries)
else:
- which = entry.get('import_playbook', entry.get('include', entry))
+ which = entry
+ for k in C._ACTION_IMPORT_PLAYBOOK + C._ACTION_INCLUDE:
+ if k in entry:
+ which = entry[k]
+ break
display.display("skipping playbook '%s' due to conditional test failure" % which, color=C.COLOR_SKIP)
else:
entry_obj = Play.load(entry, variable_manager=variable_manager, loader=self._loader, vars=vars)
diff --git a/lib/ansible/playbook/block.py b/lib/ansible/playbook/block.py
index 4324a77ef5..3571aa4802 100644
--- a/lib/ansible/playbook/block.py
+++ b/lib/ansible/playbook/block.py
@@ -19,6 +19,7 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
+import ansible.constants as C
from ansible.errors import AnsibleParserError
from ansible.playbook.attribute import FieldAttribute
from ansible.playbook.base import Base
@@ -374,8 +375,8 @@ class Block(Base, Conditional, CollectionSearch, Taggable):
filtered_block = evaluate_block(task)
if filtered_block.has_tasks():
tmp_list.append(filtered_block)
- elif (task.action == 'meta' or
- (task.action == 'include' and task.evaluate_tags([], self._play.skip_tags, all_vars=all_vars)) or
+ elif (task.action in C._ACTION_META or
+ (task.action in C._ACTION_INCLUDE and task.evaluate_tags([], self._play.skip_tags, all_vars=all_vars)) or
task.evaluate_tags(self._play.only_tags, self._play.skip_tags, all_vars=all_vars)):
tmp_list.append(task)
return tmp_list
diff --git a/lib/ansible/playbook/helpers.py b/lib/ansible/playbook/helpers.py
index 4eff569943..1a17e18e03 100644
--- a/lib/ansible/playbook/helpers.py
+++ b/lib/ansible/playbook/helpers.py
@@ -129,7 +129,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
# But if it wasn't, we can add the yaml object now to get more detail
raise AnsibleParserError(to_native(e), obj=task_ds, orig_exc=e)
- if action in ('include', 'import_tasks', 'include_tasks'):
+ if action in C._ACTION_ALL_INCLUDE_IMPORT_TASKS:
if use_handlers:
include_class = HandlerTaskInclude
@@ -151,9 +151,9 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
# check to see if this include is dynamic or static:
# 1. the user has set the 'static' option to false or true
# 2. one of the appropriate config options was set
- if action == 'include_tasks':
+ if action in C._ACTION_INCLUDE_TASKS:
is_static = False
- elif action == 'import_tasks':
+ elif action in C._ACTION_IMPORT_TASKS:
is_static = True
elif t.static is not None:
display.deprecated("The use of 'static' has been deprecated. "
@@ -166,7 +166,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
if is_static:
if t.loop is not None:
- if action == 'import_tasks':
+ if action in C._ACTION_IMPORT_TASKS:
raise AnsibleParserError("You cannot use loops on 'import_tasks' statements. You should use 'include_tasks' instead.", obj=task_ds)
else:
raise AnsibleParserError("You cannot use 'static' on an include with a loop", obj=task_ds)
@@ -248,7 +248,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
# nested includes, and we want the include order printed correctly
display.vv("statically imported: %s" % include_file)
except AnsibleFileNotFound:
- if action != 'include' or t.static or \
+ if action not in C._ACTION_INCLUDE or t.static or \
C.DEFAULT_TASK_INCLUDES_STATIC or \
C.DEFAULT_HANDLER_INCLUDES_STATIC and use_handlers:
raise
@@ -285,7 +285,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
tags = tags.split(',')
if len(tags) > 0:
- if action in ('include_tasks', 'import_tasks'):
+ if action in C._ACTION_ALL_PROPER_INCLUDE_IMPORT_TASKS:
raise AnsibleParserError('You cannot specify "tags" inline to the task, it is a task keyword')
if len(ti_copy.tags) > 0:
raise AnsibleParserError(
@@ -315,7 +315,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
t.is_static = False
task_list.append(t)
- elif action in ('include_role', 'import_role'):
+ elif action in C._ACTION_ALL_PROPER_INCLUDE_IMPORT_ROLES:
ir = IncludeRole.load(
task_ds,
block=block,
@@ -328,7 +328,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
# 1. the user has set the 'static' option to false or true
# 2. one of the appropriate config options was set
is_static = False
- if action == 'import_role':
+ if action in C._ACTION_IMPORT_ROLE:
is_static = True
elif ir.static is not None:
@@ -338,7 +338,7 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
if is_static:
if ir.loop is not None:
- if action == 'import_role':
+ if action in C._ACTION_IMPORT_ROLE:
raise AnsibleParserError("You cannot use loops on 'import_role' statements. You should use 'include_role' instead.", obj=task_ds)
else:
raise AnsibleParserError("You cannot use 'static' on an include_role with a loop", obj=task_ds)
diff --git a/lib/ansible/playbook/included_file.py b/lib/ansible/playbook/included_file.py
index 1466367336..2d209deb60 100644
--- a/lib/ansible/playbook/included_file.py
+++ b/lib/ansible/playbook/included_file.py
@@ -21,6 +21,7 @@ __metaclass__ = type
import os
+from ansible import constants as C
from ansible.errors import AnsibleError
from ansible.module_utils._text import to_text
from ansible.playbook.task_include import TaskInclude
@@ -67,7 +68,7 @@ class IncludedFile:
original_host = res._host
original_task = res._task
- if original_task.action in ('include', 'include_tasks', 'include_role'):
+ if original_task.action in C._ACTION_ALL_INCLUDES:
if original_task.loop:
if 'results' not in res._result:
continue
@@ -111,7 +112,7 @@ class IncludedFile:
templar = Templar(loader=loader, variables=task_vars)
- if original_task.action in ('include', 'include_tasks'):
+ if original_task.action in C._ACTION_ALL_INCLUDE_TASKS:
include_file = None
if original_task:
if original_task.static:
diff --git a/lib/ansible/playbook/playbook_include.py b/lib/ansible/playbook/playbook_include.py
index ec3909e38e..41f51bb910 100644
--- a/lib/ansible/playbook/playbook_include.py
+++ b/lib/ansible/playbook/playbook_include.py
@@ -21,6 +21,7 @@ __metaclass__ = type
import os
+import ansible.constants as C
from ansible.errors import AnsibleParserError, AnsibleAssertionError
from ansible.module_utils.six import iteritems, string_types
from ansible.parsing.splitter import split_args, parse_kv
@@ -114,7 +115,7 @@ class PlaybookInclude(Base, Conditional, Taggable):
new_ds.ansible_pos = ds.ansible_pos
for (k, v) in iteritems(ds):
- if k in ('include', 'import_playbook'):
+ if k in C._ACTION_ALL_IMPORT_PLAYBOOKS:
self._preprocess_import(ds, new_ds, k, v)
else:
# some basic error checking, to make sure vars are properly
diff --git a/lib/ansible/playbook/role_include.py b/lib/ansible/playbook/role_include.py
index d1da3c9487..0b87515e9b 100644
--- a/lib/ansible/playbook/role_include.py
+++ b/lib/ansible/playbook/role_include.py
@@ -20,6 +20,7 @@ __metaclass__ = type
from os.path import basename
+import ansible.constants as C
from ansible.errors import AnsibleParserError
from ansible.playbook.attribute import FieldAttribute
from ansible.playbook.block import Block
@@ -126,7 +127,7 @@ class IncludeRole(TaskInclude):
if ir._role_name is None:
raise AnsibleParserError("'name' is a required field for %s." % ir.action, obj=data)
- if 'public' in ir.args and ir.action != 'include_role':
+ if 'public' in ir.args and ir.action not in C._ACTION_INCLUDE_ROLE:
raise AnsibleParserError('Invalid options for %s: public' % ir.action, obj=data)
# validate bad args, otherwise we silently ignore
@@ -140,7 +141,7 @@ class IncludeRole(TaskInclude):
ir._from_files[from_key] = basename(ir.args.get(key))
apply_attrs = ir.args.get('apply', {})
- if apply_attrs and ir.action != 'include_role':
+ if apply_attrs and ir.action not in C._ACTION_INCLUDE_ROLE:
raise AnsibleParserError('Invalid options for %s: apply' % ir.action, obj=data)
elif not isinstance(apply_attrs, dict):
raise AnsibleParserError('Expected a dict for apply but got %s instead' % type(apply_attrs), obj=data)
diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py
index 4836abd2f5..7fd480c895 100644
--- a/lib/ansible/playbook/task.py
+++ b/lib/ansible/playbook/task.py
@@ -148,7 +148,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
def __repr__(self):
''' returns a human readable representation of the task '''
- if self.get_name() == 'meta':
+ if self.get_name() in C._ACTION_META:
return "TASK: meta (%s)" % self.args['_raw_params']
else:
return "TASK: %s" % self.get_name()
@@ -223,7 +223,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
# the command/shell/script modules used to support the `cmd` arg,
# which corresponds to what we now call _raw_params, so move that
# value over to _raw_params (assuming it is empty)
- if action in ('command', 'shell', 'script'):
+ if action in C._ACTION_HAS_CMD:
if 'cmd' in args:
if args.get('_raw_params', '') != '':
raise AnsibleError("The 'cmd' argument cannot be used when other raw parameters are specified."
@@ -255,7 +255,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
# pre-2.0 syntax allowed variables for include statements at the top level of the task,
# so we move those into the 'vars' dictionary here, and show a deprecation message
# as we will remove this at some point in the future.
- if action in ('include',) and k not in self._valid_attrs and k not in self.DEPRECATED_ATTRIBUTES:
+ if action in C._ACTION_INCLUDE and k not in self._valid_attrs and k not in self.DEPRECATED_ATTRIBUTES:
display.deprecated("Specifying include variables at the top-level of the task is deprecated."
" Please see:\nhttps://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse\n\n"
" for currently supported syntax regarding included files and variables", version="2.12")
@@ -318,7 +318,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
env[k] = templar.template(v, convert_bare=False)
except AnsibleUndefinedVariable as e:
error = to_native(e)
- if self.action in ('setup', 'gather_facts') and 'ansible_facts.env' in error or 'ansible_env' in error:
+ if self.action in C._ACTION_FACT_GATHERING and 'ansible_facts.env' in error or 'ansible_env' in error:
# ignore as fact gathering is required for 'env' facts
return
raise
@@ -385,7 +385,7 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
all_vars = dict()
if self._parent:
all_vars.update(self._parent.get_include_params())
- if self.action in ('include', 'include_tasks', 'include_role'):
+ if self.action in C._ACTION_ALL_INCLUDES:
all_vars.update(self.vars)
return all_vars
diff --git a/lib/ansible/playbook/task_include.py b/lib/ansible/playbook/task_include.py
index ca89d0d6d6..e4b97e52fb 100644
--- a/lib/ansible/playbook/task_include.py
+++ b/lib/ansible/playbook/task_include.py
@@ -76,14 +76,14 @@ class TaskInclude(Task):
# validate bad args, otherwise we silently ignore
bad_opts = my_arg_names.difference(self.VALID_ARGS)
- if bad_opts and task.action in ('include_tasks', 'import_tasks'):
+ if bad_opts and task.action in C._ACTION_ALL_PROPER_INCLUDE_IMPORT_TASKS:
raise AnsibleParserError('Invalid options for %s: %s' % (task.action, ','.join(list(bad_opts))), obj=data)
if not task.args.get('_raw_params'):
task.args['_raw_params'] = task.args.pop('file', None)
apply_attrs = task.args.get('apply', {})
- if apply_attrs and task.action != 'include_tasks':
+ if apply_attrs and task.action not in C._ACTION_INCLUDE_TASKS:
raise AnsibleParserError('Invalid options for %s: apply' % task.action, obj=data)
elif not isinstance(apply_attrs, dict):
raise AnsibleParserError('Expected a dict for apply but got %s instead' % type(apply_attrs), obj=data)
@@ -96,7 +96,7 @@ class TaskInclude(Task):
diff = set(ds.keys()).difference(self.VALID_INCLUDE_KEYWORDS)
for k in diff:
# This check doesn't handle ``include`` as we have no idea at this point if it is static or not
- if ds[k] is not Sentinel and ds['action'] in ('include_tasks', 'include_role'):
+ if ds[k] is not Sentinel and ds['action'] in C._ACTION_ALL_INCLUDE_ROLE_TASKS:
if C.INVALID_TASK_ATTRIBUTE_FAILED:
raise AnsibleParserError("'%s' is not a valid attribute for a %s" % (k, self.__class__.__name__), obj=ds)
else:
@@ -115,7 +115,7 @@ class TaskInclude(Task):
we need to include the args of the include into the vars as
they are params to the included tasks. But ONLY for 'include'
'''
- if self.action != 'include':
+ if self.action not in C._ACTION_INCLUDE:
all_vars = super(TaskInclude, self).get_vars()
else:
all_vars = dict()
diff --git a/lib/ansible/plugins/action/gather_facts.py b/lib/ansible/plugins/action/gather_facts.py
index 8cc769a7a8..d76616cf32 100644
--- a/lib/ansible/plugins/action/gather_facts.py
+++ b/lib/ansible/plugins/action/gather_facts.py
@@ -20,7 +20,7 @@ class ActionModule(ActionBase):
mod_args = self._task.args.copy()
# deal with 'setup specific arguments'
- if fact_module != 'setup':
+ if fact_module not in C._ACTION_SETUP:
# network facts modules must support gather_subset
if self._connection._load_name not in ('network_cli', 'httpapi', 'netconf'):
diff --git a/lib/ansible/plugins/action/normal.py b/lib/ansible/plugins/action/normal.py
index 766cebc5a3..4b487b5fc1 100644
--- a/lib/ansible/plugins/action/normal.py
+++ b/lib/ansible/plugins/action/normal.py
@@ -17,6 +17,7 @@
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
+from ansible import constants as C
from ansible.plugins.action import ActionBase
from ansible.utils.vars import merge_hash
@@ -47,7 +48,7 @@ class ActionModule(ActionBase):
# hack to keep --verbose from showing all the setup module result
# moved from setup module as now we filter out all _ansible_ from result
- if self._task.action == 'setup':
+ if self._task.action in C._ACTION_SETUP:
result['_ansible_verbose_override'] = True
if not wrap_async:
diff --git a/lib/ansible/plugins/callback/__init__.py b/lib/ansible/plugins/callback/__init__.py
index ece3b1862a..71287f8b5e 100644
--- a/lib/ansible/plugins/callback/__init__.py
+++ b/lib/ansible/plugins/callback/__init__.py
@@ -251,7 +251,7 @@ class CallbackBase(AnsiblePlugin):
''' removes data from results for display '''
# mostly controls that debug only outputs what it was meant to
- if task_name == 'debug':
+ if task_name in C._ACTION_DEBUG:
if 'msg' in result:
# msg should be alone
for key in list(result.keys()):
diff --git a/lib/ansible/plugins/callback/junit.py b/lib/ansible/plugins/callback/junit.py
index a7f106a1b3..2fe402ea2f 100644
--- a/lib/ansible/plugins/callback/junit.py
+++ b/lib/ansible/plugins/callback/junit.py
@@ -81,6 +81,7 @@ import os
import time
import re
+from ansible import constants as C
from ansible.module_utils._text import to_bytes, to_text
from ansible.plugins.callback import CallbackBase
@@ -281,7 +282,7 @@ class CallbackModule(CallbackBase):
test_cases = []
for task_uuid, task_data in self._task_data.items():
- if task_data.action == 'setup' and self._include_setup_tasks_in_report == 'false':
+ if task_data.action in C._ACTION_SETUP and self._include_setup_tasks_in_report == 'false':
continue
for host_uuid, host_data in task_data.host_data.items():
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py
index caa5422499..dacd204a41 100644
--- a/lib/ansible/plugins/strategy/__init__.py
+++ b/lib/ansible/plugins/strategy/__init__.py
@@ -678,7 +678,7 @@ class StrategyBase:
host_list = self.get_task_hosts(iterator, original_host, original_task)
- if original_task.action == 'include_vars':
+ if original_task.action in C._ACTION_INCLUDE_VARS:
for (var_name, var_value) in iteritems(result_item['ansible_facts']):
# find the host we're actually referring too here, which may
# be a host that is not really in inventory at all
@@ -692,9 +692,10 @@ class StrategyBase:
# we set BOTH fact and nonpersistent_facts (aka hostvar)
# when fact is retrieved from cache in subsequent operations it will have the lower precedence,
# but for playbook setting it the 'higher' precedence is kept
- if original_task.action != 'set_fact' or cacheable:
+ is_set_fact = original_task.action in C._ACTION_SET_FACT
+ if not is_set_fact or cacheable:
self._variable_manager.set_host_facts(target_host, result_item['ansible_facts'].copy())
- if original_task.action == 'set_fact':
+ if is_set_fact:
self._variable_manager.set_nonpersistent_facts(target_host, result_item['ansible_facts'].copy())
if 'ansible_stats' in result_item and 'data' in result_item['ansible_stats'] and result_item['ansible_stats']['data']:
@@ -746,7 +747,7 @@ class StrategyBase:
# If this is a role task, mark the parent role as being run (if
# the task was ok or failed, but not skipped or unreachable)
- if original_task._role is not None and role_ran: # TODO: and original_task.action != 'include_role':?
+ if original_task._role is not None and role_ran: # TODO: and original_task.action not in C._ACTION_INCLUDE_ROLE:?
# lookup the role in the ROLE_CACHE to make sure we're dealing
# with the correct object and mark it as executed
for (entry, role_obj) in iteritems(iterator._play.ROLE_CACHE[original_task._role.get_name()]):
diff --git a/lib/ansible/plugins/strategy/free.py b/lib/ansible/plugins/strategy/free.py
index 264c0e1095..8b04ca5b60 100644
--- a/lib/ansible/plugins/strategy/free.py
+++ b/lib/ansible/plugins/strategy/free.py
@@ -184,7 +184,7 @@ class StrategyModule(StrategyBase):
del self._blocked_hosts[host_name]
continue
- if task.action == 'meta':
+ if task.action in C._ACTION_META:
self._execute_meta(task, play_context, iterator, target_host=host)
self._blocked_hosts[host_name] = False
else:
diff --git a/lib/ansible/plugins/strategy/linear.py b/lib/ansible/plugins/strategy/linear.py
index 6883c9c1cb..7dd5b2be26 100644
--- a/lib/ansible/plugins/strategy/linear.py
+++ b/lib/ansible/plugins/strategy/linear.py
@@ -31,6 +31,7 @@ DOCUMENTATION = '''
author: Ansible Core Team
'''
+from ansible import constants as C
from ansible.errors import AnsibleError, AnsibleAssertionError
from ansible.executor.play_iterator import PlayIterator
from ansible.module_utils.six import iteritems
@@ -260,7 +261,7 @@ class StrategyModule(StrategyBase):
display.debug("'%s' skipped because role has already run" % task)
continue
- if task.action == 'meta':
+ if task.action in C._ACTION_META:
# for the linear strategy, we run meta tasks just once and for
# all hosts currently being iterated over rather than one host
results.extend(self._execute_meta(task, play_context, iterator, host))
@@ -405,7 +406,7 @@ class StrategyModule(StrategyBase):
for res in results:
# execute_meta() does not set 'failed' in the TaskResult
# so we skip checking it with the meta tasks and look just at the iterator
- if (res.is_failed() or res._task.action == 'meta') and iterator.is_failed(res._host):
+ if (res.is_failed() or res._task.action in C._ACTION_META) and iterator.is_failed(res._host):
failed_hosts.append(res._host.name)
elif res.is_unreachable():
unreachable_hosts.append(res._host.name)
diff --git a/lib/ansible/utils/fqcn.py b/lib/ansible/utils/fqcn.py
new file mode 100644
index 0000000000..a492be1f18
--- /dev/null
+++ b/lib/ansible/utils/fqcn.py
@@ -0,0 +1,33 @@
+# (c) 2020, Felix Fontein <felix@fontein.de>
+#
+# This file is part of Ansible
+#
+# Ansible 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.
+#
+# Ansible 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 Ansible. If not, see <http://www.gnu.org/licenses/>.
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+
+def add_internal_fqcns(names):
+ '''
+ Given a sequence of action/module names, returns a list of these names
+ with the same names with the prefixes `ansible.builtin.` and
+ `ansible.legacy.` added for all names that are not already FQCNs.
+ '''
+ result = []
+ for name in names:
+ result.append(name)
+ if '.' not in name:
+ result.append('ansible.builtin.%s' % name)
+ result.append('ansible.legacy.%s' % name)
+ return result
diff --git a/lib/ansible/vars/manager.py b/lib/ansible/vars/manager.py
index 1e8b76593d..4b64ea1d14 100644
--- a/lib/ansible/vars/manager.py
+++ b/lib/ansible/vars/manager.py
@@ -202,7 +202,7 @@ class VariableManager:
# if we have a task in this context, and that task has a role, make
# sure it sees its defaults above any other roles, as we previously
# (v1) made sure each task had a copy of its roles default vars
- if task._role is not None and (play or task.action == 'include_role'):
+ if task._role is not None and (play or task.action in C._ACTION_INCLUDE_ROLE):
all_vars = combine_vars(all_vars, task._role.get_default_vars(dep_chain=task.get_dep_chain()))
if host:
diff --git a/test/integration/targets/debug/main_fqcn.yml b/test/integration/targets/debug/main_fqcn.yml
new file mode 100644
index 0000000000..d6a00fc84c
--- /dev/null
+++ b/test/integration/targets/debug/main_fqcn.yml
@@ -0,0 +1,6 @@
+- hosts: localhost
+ gather_facts: no
+ tasks:
+ - name: test item being present in the output
+ ansible.builtin.debug: var=item
+ loop: [1, 2, 3]
diff --git a/test/integration/targets/debug/runme.sh b/test/integration/targets/debug/runme.sh
index 4ff4e299a7..5ccb1bfda6 100755
--- a/test/integration/targets/debug/runme.sh
+++ b/test/integration/targets/debug/runme.sh
@@ -9,3 +9,9 @@ for i in 1 2 3; do
grep "ok: \[localhost\] => (item=$i)" out
grep "\"item\": $i" out
done
+
+ansible-playbook main_fqcn.yml -i ../../inventory | tee out
+for i in 1 2 3; do
+ grep "ok: \[localhost\] => (item=$i)" out
+ grep "\"item\": $i" out
+done
diff --git a/test/integration/targets/include_import/runme.sh b/test/integration/targets/include_import/runme.sh
index 199cd472bc..00ace7608a 100755
--- a/test/integration/targets/include_import/runme.sh
+++ b/test/integration/targets/include_import/runme.sh
@@ -46,23 +46,29 @@ ANSIBLE_STRATEGY='free' ansible-playbook role/test_include_role.yml -i inventory
## Max Recursion Depth
# https://github.com/ansible/ansible/issues/23609
ANSIBLE_STRATEGY='linear' ansible-playbook test_role_recursion.yml -i inventory "$@"
+ANSIBLE_STRATEGY='linear' ansible-playbook test_role_recursion_fqcn.yml -i inventory "$@"
## Nested tasks
# https://github.com/ansible/ansible/issues/34782
ANSIBLE_STRATEGY='linear' ansible-playbook test_nested_tasks.yml -i inventory "$@"
+ANSIBLE_STRATEGY='linear' ansible-playbook test_nested_tasks_fqcn.yml -i inventory "$@"
ANSIBLE_STRATEGY='free' ansible-playbook test_nested_tasks.yml -i inventory "$@"
+ANSIBLE_STRATEGY='free' ansible-playbook test_nested_tasks_fqcn.yml -i inventory "$@"
## Tons of top level include_tasks
# https://github.com/ansible/ansible/issues/36053
# Fixed by https://github.com/ansible/ansible/pull/36075
gen_task_files
ANSIBLE_STRATEGY='linear' ansible-playbook test_copious_include_tasks.yml -i inventory "$@"
+ANSIBLE_STRATEGY='linear' ansible-playbook test_copious_include_tasks_fqcn.yml -i inventory "$@"
ANSIBLE_STRATEGY='free' ansible-playbook test_copious_include_tasks.yml -i inventory "$@"
+ANSIBLE_STRATEGY='free' ansible-playbook test_copious_include_tasks_fqcn.yml -i inventory "$@"
rm -f tasks/hello/*.yml
# Inlcuded tasks should inherit attrs from non-dynamic blocks in parent chain
# https://github.com/ansible/ansible/pull/38827
ANSIBLE_STRATEGY='linear' ansible-playbook test_grandparent_inheritance.yml -i inventory "$@"
+ANSIBLE_STRATEGY='linear' ansible-playbook test_grandparent_inheritance_fqcn.yml -i inventory "$@"
# undefined_var
ANSIBLE_STRATEGY='linear' ansible-playbook undefined_var/playbook.yml -i inventory "$@"
@@ -108,3 +114,5 @@ ansible-playbook valid_include_keywords/playbook.yml "$@"
# https://github.com/ansible/ansible/issues/64902
ansible-playbook tasks/test_allow_single_role_dup.yml 2>&1 | tee test_allow_single_role_dup.out
test "$(grep -c 'ok=3' test_allow_single_role_dup.out)" = 1
+
+ansible-playbook test_include_loop_fqcn.yml "$@"
diff --git a/test/integration/targets/include_import/test_copious_include_tasks_fqcn.yml b/test/integration/targets/include_import/test_copious_include_tasks_fqcn.yml
new file mode 100644
index 0000000000..32fa9abc6c
--- /dev/null
+++ b/test/integration/targets/include_import/test_copious_include_tasks_fqcn.yml
@@ -0,0 +1,44 @@
+- name: Test many ansible.builtin.include_tasks
+ hosts: testhost
+ gather_facts: no
+
+ tasks:
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-001.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-002.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-003.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-004.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-005.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-006.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-007.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-008.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-009.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-010.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-011.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-012.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-013.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-014.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-015.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-016.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-017.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-018.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-019.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-020.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-021.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-022.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-023.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-024.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-025.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-026.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-027.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-028.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-029.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-030.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-031.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-032.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-033.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-034.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-035.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-036.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-037.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-038.yml"
+ - ansible.builtin.include_tasks: "{{ playbook_dir }}/tasks/hello/tasks-file-039.yml"
diff --git a/test/integration/targets/include_import/test_grandparent_inheritance_fqcn.yml b/test/integration/targets/include_import/test_grandparent_inheritance_fqcn.yml
new file mode 100644
index 0000000000..37a0ad0d6a
--- /dev/null
+++ b/test/integration/targets/include_import/test_grandparent_inheritance_fqcn.yml
@@ -0,0 +1,29 @@
+---
+- hosts: testhost
+ gather_facts: false
+ tasks:
+ - debug:
+ var: inventory_hostname
+
+ - name: Test included tasks inherit from block
+ check_mode: true
+ block:
+ - ansible.builtin.include_tasks: grandchild/block_include_tasks.yml
+
+ - debug:
+ var: block_include_result
+
+ - assert:
+ that:
+ - block_include_result is skipped
+
+ - name: Test included tasks inherit deeply from import
+ ansible.builtin.import_tasks: grandchild/import.yml
+ check_mode: true
+
+ - debug:
+ var: import_include_include_result
+
+ - assert:
+ that:
+ - import_include_include_result is skipped
diff --git a/test/integration/targets/include_import/test_include_loop_fqcn.yml b/test/integration/targets/include_import/test_include_loop_fqcn.yml
new file mode 100644
index 0000000000..62d91f227d
--- /dev/null
+++ b/test/integration/targets/include_import/test_include_loop_fqcn.yml
@@ -0,0 +1,17 @@
+- hosts: localhost
+ gather_facts: false
+ tasks:
+ - name: skipped include undefined loop
+ ansible.builtin.include_tasks: doesnt_matter.yml
+ loop: '{{ lkjsdflkjsdlfkjsdlfkjsdf }}'
+ when: false
+ register: skipped_include
+
+ - debug:
+ var: skipped_include
+
+ - assert:
+ that:
+ - skipped_include.results is undefined
+ - skipped_include.skip_reason is defined
+ - skipped_include is skipped
diff --git a/test/integration/targets/include_import/test_nested_tasks_fqcn.yml b/test/integration/targets/include_import/test_nested_tasks_fqcn.yml
new file mode 100644
index 0000000000..14e72eed1b
--- /dev/null
+++ b/test/integration/targets/include_import/test_nested_tasks_fqcn.yml
@@ -0,0 +1,6 @@
+- name: >-
+ verify that multiple level of nested statements and
+ include+meta doesnt mess included files mecanisms
+ hosts: testhost
+ tasks:
+ - ansible.builtin.include_tasks: ./tasks/nested/nested.yml
diff --git a/test/integration/targets/include_import/test_role_recursion_fqcn.yml b/test/integration/targets/include_import/test_role_recursion_fqcn.yml
new file mode 100644
index 0000000000..13d8d2cbd2
--- /dev/null
+++ b/test/integration/targets/include_import/test_role_recursion_fqcn.yml
@@ -0,0 +1,7 @@
+- name: Test max recursion depth
+ hosts: testhost
+
+ tasks:
+ - ansible.builtin.import_role:
+ name: role1
+ tasks_from: r1t01.yml
diff --git a/test/integration/targets/include_vars/tasks/main.yml b/test/integration/targets/include_vars/tasks/main.yml
index ab2442c6fa..799d7b26a6 100644
--- a/test/integration/targets/include_vars/tasks/main.yml
+++ b/test/integration/targets/include_vars/tasks/main.yml
@@ -65,12 +65,12 @@
- "testing == 456"
- "base_dir == 'services'"
- "webapp_containers == 10"
- - "{{ include_every_dir.ansible_included_var_files | length }} == 6"
+ - "{{ include_every_dir.ansible_included_var_files | length }} == 7"
- "'vars/all/all.yml' in include_every_dir.ansible_included_var_files[0]"
- "'vars/environments/development/all.yml' in include_every_dir.ansible_included_var_files[1]"
- "'vars/environments/development/services/webapp.yml' in include_every_dir.ansible_included_var_files[2]"
- - "'vars/services/webapp.yml' in include_every_dir.ansible_included_var_files[4]"
- - "'vars/webapp/file_without_extension' in include_every_dir.ansible_included_var_files[5]"
+ - "'vars/services/webapp.yml' in include_every_dir.ansible_included_var_files[5]"
+ - "'vars/webapp/file_without_extension' in include_every_dir.ansible_included_var_files[6]"
- name: include every directory in vars except files matching webapp.yml
include_vars:
@@ -85,7 +85,7 @@
that:
- "testing == 789"
- "base_dir == 'environments/development'"
- - "{{ include_without_webapp.ansible_included_var_files | length }} == 3"
+ - "{{ include_without_webapp.ansible_included_var_files | length }} == 4"
- "'webapp.yml' not in '{{ include_without_webapp.ansible_included_var_files | join(' ') }}'"
- "'file_without_extension' not in '{{ include_without_webapp.ansible_included_var_files | join(' ') }}'"
@@ -152,3 +152,13 @@
assert:
that:
- "'Could not find file' in include_with_non_existent_file.message"
+
+- name: include var (FQCN) with raw params
+ ansible.builtin.include_vars: >
+ services/service_vars_fqcn.yml
+
+- name: Verify that FQCN of include_vars works
+ assert:
+ that:
+ - "'my_custom_service' == service_name_fqcn"
+ - "'my_custom_service' == service_name_tmpl_fqcn"
diff --git a/test/integration/targets/include_vars/vars/services/service_vars_fqcn.yml b/test/integration/targets/include_vars/vars/services/service_vars_fqcn.yml
new file mode 100644
index 0000000000..2c04fee505
--- /dev/null
+++ b/test/integration/targets/include_vars/vars/services/service_vars_fqcn.yml
@@ -0,0 +1,3 @@
+---
+service_name_fqcn: 'my_custom_service'
+service_name_tmpl_fqcn: '{{ service_name_fqcn }}' \ No newline at end of file
diff --git a/test/integration/targets/includes/roles/test_includes_free/tasks/inner_fqcn.yml b/test/integration/targets/includes/roles/test_includes_free/tasks/inner_fqcn.yml
new file mode 100644
index 0000000000..5b4ce04041
--- /dev/null
+++ b/test/integration/targets/includes/roles/test_includes_free/tasks/inner_fqcn.yml
@@ -0,0 +1,2 @@
+- set_fact:
+ inner_fqcn: "reached"
diff --git a/test/integration/targets/includes/roles/test_includes_free/tasks/main.yml b/test/integration/targets/includes/roles/test_includes_free/tasks/main.yml
index 7bc19faae1..5ae7882f4c 100644
--- a/test/integration/targets/includes/roles/test_includes_free/tasks/main.yml
+++ b/test/integration/targets/includes/roles/test_includes_free/tasks/main.yml
@@ -4,3 +4,6 @@
- include: inner.yml
with_items:
- '1'
+- ansible.builtin.include: inner_fqcn.yml
+ with_items:
+ - '1'
diff --git a/test/integration/targets/includes/test_include_free.yml b/test/integration/targets/includes/test_include_free.yml
index 4cdc1bca50..dedad73485 100644
--- a/test/integration/targets/includes/test_include_free.yml
+++ b/test/integration/targets/includes/test_include_free.yml
@@ -7,3 +7,4 @@
- assert:
that:
- "inner == 'reached'"
+ - "inner_fqcn == 'reached'"
diff --git a/test/integration/targets/meta_tasks/runme.sh b/test/integration/targets/meta_tasks/runme.sh
index b617965df4..3f456def5c 100755
--- a/test/integration/targets/meta_tasks/runme.sh
+++ b/test/integration/targets/meta_tasks/runme.sh
@@ -10,6 +10,13 @@ for test_strategy in linear free; do
grep -q "META: ending play for testhost2" <<< "$out"
grep -q "play not ended for testhost" <<< "$out"
grep -qv "play not ended for testhost2" <<< "$out"
+
+ out="$(ansible-playbook test_end_host_fqcn.yml -i inventory.yml -e test_strategy=$test_strategy -vv "$@")"
+
+ grep -q "META: end_host conditional evaluated to false, continuing execution for testhost" <<< "$out"
+ grep -q "META: ending play for testhost2" <<< "$out"
+ grep -q "play not ended for testhost" <<< "$out"
+ grep -qv "play not ended for testhost2" <<< "$out"
done
# test end_host meta task, on all hosts
@@ -20,6 +27,13 @@ for test_strategy in linear free; do
grep -q "META: ending play for testhost2" <<< "$out"
grep -qv "play not ended for testhost" <<< "$out"
grep -qv "play not ended for testhost2" <<< "$out"
+
+ out="$(ansible-playbook test_end_host_all_fqcn.yml -i inventory.yml -e test_strategy=$test_strategy -vv "$@")"
+
+ grep -q "META: ending play for testhost" <<< "$out"
+ grep -q "META: ending play for testhost2" <<< "$out"
+ grep -qv "play not ended for testhost" <<< "$out"
+ grep -qv "play not ended for testhost2" <<< "$out"
done
# test end_play meta task
@@ -28,4 +42,9 @@ for test_strategy in linear free; do
grep -q "META: ending play" <<< "$out"
grep -qv 'Failed to end using end_play' <<< "$out"
+
+ out="$(ansible-playbook test_end_play_fqcn.yml -i inventory.yml -e test_strategy=$test_strategy -vv "$@")"
+
+ grep -q "META: ending play" <<< "$out"
+ grep -qv 'Failed to end using end_play' <<< "$out"
done
diff --git a/test/integration/targets/meta_tasks/test_end_host_all_fqcn.yml b/test/integration/targets/meta_tasks/test_end_host_all_fqcn.yml
new file mode 100644
index 0000000000..78b5a2e9c8
--- /dev/null
+++ b/test/integration/targets/meta_tasks/test_end_host_all_fqcn.yml
@@ -0,0 +1,13 @@
+- name: "Testing end_host all hosts with strategy={{ test_strategy | default('linear') }}"
+ hosts:
+ - testhost
+ - testhost2
+ gather_facts: no
+ strategy: "{{ test_strategy | default('linear') }}"
+ tasks:
+ - debug:
+
+ - ansible.builtin.meta: end_host
+
+ - debug:
+ msg: "play not ended {{ inventory_hostname }}"
diff --git a/test/integration/targets/meta_tasks/test_end_host_fqcn.yml b/test/integration/targets/meta_tasks/test_end_host_fqcn.yml
new file mode 100644
index 0000000000..bdb38b536e
--- /dev/null
+++ b/test/integration/targets/meta_tasks/test_end_host_fqcn.yml
@@ -0,0 +1,14 @@
+- name: "Testing end_host with strategy={{ test_strategy | default('linear') }}"
+ hosts:
+ - testhost
+ - testhost2
+ gather_facts: no
+ strategy: "{{ test_strategy | default('linear') }}"
+ tasks:
+ - debug:
+
+ - ansible.builtin.meta: end_host
+ when: "host_var_role_name == 'role2'" # end play for testhost2, see inventory
+
+ - debug:
+ msg: "play not ended for {{ inventory_hostname }}"
diff --git a/test/integration/targets/meta_tasks/test_end_play_fqcn.yml b/test/integration/targets/meta_tasks/test_end_play_fqcn.yml
new file mode 100644
index 0000000000..2ae67fbea2
--- /dev/null
+++ b/test/integration/targets/meta_tasks/test_end_play_fqcn.yml
@@ -0,0 +1,12 @@
+- name: Testing end_play with strategy {{ test_strategy | default('linear') }}
+ hosts: testhost:testhost2
+ gather_facts: no
+ strategy: "{{ test_strategy | default('linear') }}"
+ tasks:
+ - debug:
+ msg: "Testing end_play on host {{ inventory_hostname }}"
+
+ - ansible.builtin.meta: end_play
+
+ - fail:
+ msg: 'Failed to end using end_play'
diff --git a/test/integration/targets/set_fact/incremental.yml b/test/integration/targets/set_fact/incremental.yml
index 03da5bb6c8..3f7aa6c492 100644
--- a/test/integration/targets/set_fact/incremental.yml
+++ b/test/integration/targets/set_fact/incremental.yml
@@ -17,3 +17,19 @@
assert:
that:
- dig_list == ['one', 'two', 'three', 'four']
+
+ - name: Generate inline loop for set_fact (FQCN)
+ ansible.builtin.set_fact:
+ dig_list_fqcn: "{{ dig_list_fqcn + [ item ] }}"
+ loop:
+ - two
+ - three
+ - four
+ vars:
+ dig_list_fqcn:
+ - one
+
+ - name: verify cumulative set fact worked (FQCN)
+ assert:
+ that:
+ - dig_list_fqcn == ['one', 'two', 'three', 'four']
diff --git a/test/integration/targets/set_fact/nowarn_clean_facts.yml b/test/integration/targets/set_fact/nowarn_clean_facts.yml
index 9cde7c6497..74f908d047 100644
--- a/test/integration/targets/set_fact/nowarn_clean_facts.yml
+++ b/test/integration/targets/set_fact/nowarn_clean_facts.yml
@@ -5,3 +5,6 @@
- name: set ssh jump host args
set_fact:
ansible_ssh_common_args: "-o ProxyCommand='ssh -W %h:%p -q root@localhost'"
+ - name: set ssh jump host args (FQCN)
+ ansible.builtin.set_fact:
+ ansible_ssh_common_args: "-o ProxyCommand='ssh -W %h:%p -q root@localhost'"
diff --git a/test/integration/targets/set_fact/set_fact_bool_conv.yml b/test/integration/targets/set_fact/set_fact_bool_conv.yml
index 2e06d75c87..8df249bee2 100644
--- a/test/integration/targets/set_fact/set_fact_bool_conv.yml
+++ b/test/integration/targets/set_fact/set_fact_bool_conv.yml
@@ -18,3 +18,18 @@
- this_is_also_string == False
- this_is_another_string == False
- this_is_more_strings == False
+
+ - ansible.builtin.set_fact:
+ this_is_string_fqcn: "yes"
+ this_is_not_string_fqcn: yes
+ this_is_also_string_fqcn: "{{ string_var }}"
+ this_is_another_string_fqcn: !!str "{% set thing = '' + string_var + '' %}{{ thing }}"
+ this_is_more_strings_fqcn: '{{ string_var + "" }}'
+
+ - assert:
+ that:
+ - this_is_string_fqcn == True
+ - this_is_not_string_fqcn == True
+ - this_is_also_string_fqcn == False
+ - this_is_another_string_fqcn == False
+ - this_is_more_strings_fqcn == False
diff --git a/test/integration/targets/set_fact/set_fact_bool_conv_jinja2_native.yml b/test/integration/targets/set_fact/set_fact_bool_conv_jinja2_native.yml
index 4721f4374f..2642599f48 100644
--- a/test/integration/targets/set_fact/set_fact_bool_conv_jinja2_native.yml
+++ b/test/integration/targets/set_fact/set_fact_bool_conv_jinja2_native.yml
@@ -18,3 +18,18 @@
- this_is_also_string == 'no'
- this_is_another_string == 'no'
- this_is_more_strings == 'no'
+
+ - ansible.builtin.set_fact:
+ this_is_string_fqcn: "yes"
+ this_is_not_string_fqcn: yes
+ this_is_also_string_fqcn: "{{ string_var }}"
+ this_is_another_string_fqcn: !!str "{% set thing = '' + string_var + '' %}{{ thing }}"
+ this_is_more_strings_fqcn: '{{ string_var + "" }}'
+
+ - assert:
+ that:
+ - this_is_string_fqcn == 'yes'
+ - this_is_not_string_fqcn == True
+ - this_is_also_string_fqcn == 'no'
+ - this_is_another_string_fqcn == 'no'
+ - this_is_more_strings_fqcn == 'no'
diff --git a/test/integration/targets/set_fact/set_fact_cached_1.yml b/test/integration/targets/set_fact/set_fact_cached_1.yml
index 450f8da28e..01c9f1e021 100644
--- a/test/integration/targets/set_fact/set_fact_cached_1.yml
+++ b/test/integration/targets/set_fact/set_fact_cached_1.yml
@@ -45,6 +45,49 @@
that:
- fact_not_cached == 'this_should_not_be_cached!'
+ - name: show foobar fact before (FQCN)
+ debug:
+ var: ansible_foobar_fqcn
+
+ - name: set a persistent fact foobar (FQCN)
+ set_fact:
+ ansible_foobar_fqcn: 'foobar_fqcn_from_set_fact_cacheable'
+ cacheable: true
+
+ - name: show foobar fact after (FQCN)
+ debug:
+ var: ansible_foobar_fqcn
+
+ - name: assert ansible_foobar_fqcn is correct value (FQCN)
+ assert:
+ that:
+ - ansible_foobar_fqcn == 'foobar_fqcn_from_set_fact_cacheable'
+
+ - name: set a non persistent fact that will not be cached (FQCN)
+ set_fact:
+ ansible_foobar_not_cached_fqcn: 'this_should_not_be_cached'
+
+ - name: show ansible_foobar_not_cached_fqcn fact after being set (FQCN)
+ debug:
+ var: ansible_foobar_not_cached_fqcn
+
+ - name: assert ansible_foobar_not_cached_fqcn is correct value (FQCN)
+ assert:
+ that:
+ - ansible_foobar_not_cached_fqcn == 'this_should_not_be_cached'
+
+ - name: set another non persistent fact that will not be cached (FQCN)
+ set_fact: "cacheable=no fact_not_cached_fqcn='this_should_not_be_cached!'"
+
+ - name: show fact_not_cached_fqcn fact after being set (FQCN)
+ debug:
+ var: fact_not_cached_fqcn
+
+ - name: assert fact_not_cached_fqcn is correct value (FQCN)
+ assert:
+ that:
+ - fact_not_cached_fqcn == 'this_should_not_be_cached!'
+
- name: the second play
hosts: localhost
tasks:
@@ -57,26 +100,43 @@
that:
- ansible_foobar == 'foobar_from_set_fact_cacheable'
-- name: show ansible_nodename
+ - name: show foobar fact after second play (FQCN)
+ debug:
+ var: ansible_foobar_fqcn
+
+ - name: assert ansible_foobar is correct value (FQCN)
+ assert:
+ that:
+ - ansible_foobar_fqcn == 'foobar_fqcn_from_set_fact_cacheable'
+
+- name: show ansible_nodename and ansible_os_family
hosts: localhost
tasks:
- name: show nodename fact after second play
debug:
var: ansible_nodename
+ - name: show os_family fact after second play (FQCN)
+ debug:
+ var: ansible_os_family
-- name: show ansible_nodename overridden with var
+- name: show ansible_nodename and ansible_os_family overridden with var
hosts: localhost
vars:
ansible_nodename: 'nodename_from_play_vars'
+ ansible_os_family: 'os_family_from_play_vars'
tasks:
- name: show nodename fact after second play
debug:
var: ansible_nodename
+ - name: show os_family fact after second play (FQCN)
+ debug:
+ var: ansible_os_family
- name: verify ansible_nodename from vars overrides the fact
hosts: localhost
vars:
ansible_nodename: 'nodename_from_play_vars'
+ ansible_os_family: 'os_family_from_play_vars'
tasks:
- name: show nodename fact
debug:
@@ -87,7 +147,16 @@
that:
- ansible_nodename == 'nodename_from_play_vars'
-- name: set_fact ansible_nodename
+ - name: show os_family fact (FQCN)
+ debug:
+ var: ansible_os_family
+
+ - name: assert ansible_os_family is correct value (FQCN)
+ assert:
+ that:
+ - ansible_os_family == 'os_family_from_play_vars'
+
+- name: set_fact ansible_nodename and ansible_os_family
hosts: localhost
tasks:
- name: set a persistent fact nodename
@@ -103,10 +172,24 @@
that:
- ansible_nodename == 'nodename_from_set_fact_cacheable'
-- name: verify that set_fact ansible_nodename non_cacheable overrides ansible_nodename in vars
+ - name: set a persistent fact os_family (FQCN)
+ ansible.builtin.set_fact:
+ ansible_os_family: 'os_family_from_set_fact_cacheable'
+
+ - name: show os_family fact (FQCN)
+ debug:
+ var: ansible_os_family
+
+ - name: assert ansible_os_family is correct value (FQCN)
+ assert:
+ that:
+ - ansible_os_family == 'os_family_from_set_fact_cacheable'
+
+- name: verify that set_fact ansible_xxx non_cacheable overrides ansible_xxx in vars
hosts: localhost
vars:
ansible_nodename: 'nodename_from_play_vars'
+ ansible_os_family: 'os_family_from_play_vars'
tasks:
- name: show nodename fact
debug:
@@ -117,10 +200,20 @@
that:
- ansible_nodename == 'nodename_from_set_fact_cacheable'
-- name: verify that set_fact_cacheable in previous play overrides ansible_nodename in vars
+ - name: show os_family fact (FQCN)
+ debug:
+ var: ansible_os_family
+
+ - name: assert ansible_os_family is correct value (FQCN)
+ assert:
+ that:
+ - ansible_os_family == 'os_family_from_set_fact_cacheable'
+
+- name: verify that set_fact_cacheable in previous play overrides ansible_xxx in vars
hosts: localhost
vars:
ansible_nodename: 'nodename_from_play_vars'
+ ansible_os_family: 'os_family_from_play_vars'
tasks:
- name: show nodename fact
debug:
@@ -131,7 +224,16 @@
that:
- ansible_nodename == 'nodename_from_set_fact_cacheable'
-- name: set_fact ansible_nodename cacheable
+ - name: show os_family fact (FQCN)
+ debug:
+ var: ansible_os_family
+
+ - name: assert ansible_os_family is correct value (FQCN)
+ assert:
+ that:
+ - ansible_os_family == 'os_family_from_set_fact_cacheable'
+
+- name: set_fact ansible_nodename and ansible_os_family cacheable
hosts: localhost
tasks:
- name: set a persistent fact nodename
@@ -148,11 +250,26 @@
that:
- ansible_nodename == 'nodename_from_set_fact_cacheable'
+ - name: set a persistent fact os_family (FQCN)
+ ansible.builtin.set_fact:
+ ansible_os_family: 'os_family_from_set_fact_cacheable'
+ cacheable: true
+
+ - name: show os_family fact (FQCN)
+ debug:
+ var: ansible_os_family
-- name: verify that set_fact_cacheable in previous play overrides ansible_nodename in vars
+ - name: assert ansible_os_family is correct value (FQCN)
+ assert:
+ that:
+ - ansible_os_family == 'os_family_from_set_fact_cacheable'
+
+
+- name: verify that set_fact_cacheable in previous play overrides ansible_xxx in vars
hosts: localhost
vars:
ansible_nodename: 'nodename_from_play_vars'
+ ansible_os_family: 'os_family_from_play_vars'
tasks:
- name: show nodename fact
debug:
@@ -163,10 +280,20 @@
that:
- ansible_nodename == 'nodename_from_set_fact_cacheable'
+ - name: show os_family fact (FQCN)
+ debug:
+ var: ansible_os_family
+
+ - name: assert ansible_os_family is correct value (FQCN)
+ assert:
+ that:
+ - ansible_os_family == 'os_family_from_set_fact_cacheable'
+
- name: the fourth play
hosts: localhost
vars:
ansible_foobar: 'foobar_from_play_vars'
+ ansible_foobar_fqcn: 'foobar_fqcn_from_play_vars'
tasks:
- name: show example fact
debug:
@@ -181,3 +308,17 @@
assert:
that:
- ansible_example == 'foobar_from_set_fact_cacheable'
+
+ - name: show example fact (FQCN)
+ debug:
+ var: ansible_example_fqcn
+
+ - name: set a persistent fact example (FQCN)
+ set_fact:
+ ansible_example_fqcn: 'foobar_fqcn_from_set_fact_cacheable'
+ cacheable: true
+
+ - name: assert ansible_example_fqcn is correct value (FQCN)
+ assert:
+ that:
+ - ansible_example_fqcn == 'foobar_fqcn_from_set_fact_cacheable'
diff --git a/test/integration/targets/set_fact/set_fact_cached_2.yml b/test/integration/targets/set_fact/set_fact_cached_2.yml
index 7ca26b9dcb..7df9224403 100644
--- a/test/integration/targets/set_fact/set_fact_cached_2.yml
+++ b/test/integration/targets/set_fact/set_fact_cached_2.yml
@@ -28,3 +28,30 @@
assert:
that:
- fact_not_cached is undefined
+
+ - name: show ansible_foobar_fqcn fact (FQCN)
+ debug:
+ var: ansible_foobar_fqcn
+
+ - name: assert ansible_foobar_fqcn is correct value when read from cache (FQCN)
+ assert:
+ that:
+ - ansible_foobar_fqcn == 'foobar_fqcn_from_set_fact_cacheable'
+
+ - name: show ansible_foobar_fqcn_not_cached fact (FQCN)
+ debug:
+ var: ansible_foobar_fqcn_not_cached
+
+ - name: assert ansible_foobar_fqcn_not_cached is not cached (FQCN)
+ assert:
+ that:
+ - ansible_foobar_fqcn_not_cached is undefined
+
+ - name: show fact_not_cached_fqcn fact (FQCN)
+ debug:
+ var: fact_not_cached_fqcn
+
+ - name: assert fact_not_cached_fqcn is not cached (FQCN)
+ assert:
+ that:
+ - fact_not_cached_fqcn is undefined
diff --git a/test/integration/targets/set_fact/set_fact_no_cache.yml b/test/integration/targets/set_fact/set_fact_no_cache.yml
index 3dffb65f55..f5a99792f1 100644
--- a/test/integration/targets/set_fact/set_fact_no_cache.yml
+++ b/test/integration/targets/set_fact/set_fact_no_cache.yml
@@ -19,3 +19,21 @@
assert:
that:
- ansible_foobar_not_cached is undefined
+
+ - name: show ansible_foobar fact (FQCN)
+ debug:
+ var: ansible_foobar_fqcn
+
+ - name: assert ansible_foobar is correct value (FQCN)
+ assert:
+ that:
+ - ansible_foobar_fqcn is undefined
+
+ - name: show ansible_foobar_not_cached fact (FQCN)
+ debug:
+ var: ansible_foobar_fqcn_not_cached
+
+ - name: assert ansible_foobar_not_cached is not cached (FQCN)
+ assert:
+ that:
+ - ansible_foobar_fqcn_not_cached is undefined