diff options
Diffstat (limited to 'lib')
-rwxr-xr-x | lib/ansible/cli/config.py | 8 | ||||
-rwxr-xr-x | lib/ansible/cli/inventory.py | 22 | ||||
-rw-r--r-- | lib/ansible/config/manager.py | 23 | ||||
-rw-r--r-- | lib/ansible/constants.py | 40 | ||||
-rw-r--r-- | lib/ansible/executor/task_executor.py | 10 | ||||
-rw-r--r-- | lib/ansible/module_utils/ansible_release.py | 2 | ||||
-rw-r--r-- | lib/ansible/module_utils/facts/virtual/linux.py | 2 | ||||
-rw-r--r-- | lib/ansible/modules/blockinfile.py | 2 | ||||
-rw-r--r-- | lib/ansible/modules/dnf.py | 6 | ||||
-rw-r--r-- | lib/ansible/modules/dnf5.py | 17 | ||||
-rw-r--r-- | lib/ansible/modules/find.py | 11 | ||||
-rw-r--r-- | lib/ansible/modules/unarchive.py | 2 | ||||
-rw-r--r-- | lib/ansible/playbook/role/__init__.py | 2 | ||||
-rw-r--r-- | lib/ansible/plugins/action/fetch.py | 4 | ||||
-rw-r--r-- | lib/ansible/plugins/cache/__init__.py | 1 | ||||
-rw-r--r-- | lib/ansible/plugins/connection/winrm.py | 16 | ||||
-rw-r--r-- | lib/ansible/plugins/strategy/free.py | 2 | ||||
-rw-r--r-- | lib/ansible/plugins/strategy/linear.py | 2 | ||||
-rw-r--r-- | lib/ansible/release.py | 2 | ||||
-rw-r--r-- | lib/ansible/vars/hostvars.py | 28 | ||||
-rw-r--r-- | lib/ansible_core.egg-info/PKG-INFO | 2 | ||||
-rw-r--r-- | lib/ansible_core.egg-info/SOURCES.txt | 5 |
22 files changed, 129 insertions, 80 deletions
diff --git a/lib/ansible/cli/config.py b/lib/ansible/cli/config.py index f394ef7..eac8a31 100755 --- a/lib/ansible/cli/config.py +++ b/lib/ansible/cli/config.py @@ -270,7 +270,7 @@ class ConfigCLI(CLI): if not settings[setting].get('description'): continue - default = settings[setting].get('default', '') + default = self.config.template_default(settings[setting].get('default', ''), get_constants()) if subkey == 'env': stype = settings[setting].get('type', '') if stype == 'boolean': @@ -352,7 +352,7 @@ class ConfigCLI(CLI): if entry['key'] not in seen[entry['section']]: seen[entry['section']].append(entry['key']) - default = opt.get('default', '') + default = self.config.template_default(opt.get('default', ''), get_constants()) if opt.get('type', '') == 'list' and not isinstance(default, string_types): # python lists are not valid ini ones default = ', '.join(default) @@ -414,14 +414,16 @@ class ConfigCLI(CLI): if context.CLIARGS['format'] == 'display': if isinstance(config[setting], Setting): # proceed normally + value = config[setting].value if config[setting].origin == 'default': color = 'green' + value = self.config.template_default(value, get_constants()) elif config[setting].origin == 'REQUIRED': # should include '_terms', '_input', etc color = 'red' else: color = 'yellow' - msg = "%s(%s) = %s" % (setting, config[setting].origin, config[setting].value) + msg = "%s(%s) = %s" % (setting, config[setting].origin, value) else: color = 'green' msg = "%s(%s) = %s" % (setting, 'default', config[setting].get('default')) diff --git a/lib/ansible/cli/inventory.py b/lib/ansible/cli/inventory.py index 3550079..02e5eb2 100755 --- a/lib/ansible/cli/inventory.py +++ b/lib/ansible/cli/inventory.py @@ -25,26 +25,6 @@ from ansible.vars.plugins import get_vars_from_inventory_sources, get_vars_from_ display = Display() -INTERNAL_VARS = frozenset(['ansible_diff_mode', - 'ansible_config_file', - 'ansible_facts', - 'ansible_forks', - 'ansible_inventory_sources', - 'ansible_limit', - 'ansible_playbook_python', - 'ansible_run_tags', - 'ansible_skip_tags', - 'ansible_verbosity', - 'ansible_version', - 'inventory_dir', - 'inventory_file', - 'inventory_hostname', - 'inventory_hostname_short', - 'groups', - 'group_names', - 'omit', - 'playbook_dir', ]) - class InventoryCLI(CLI): ''' used to display or dump the configured inventory as Ansible sees it ''' @@ -247,7 +227,7 @@ class InventoryCLI(CLI): @staticmethod def _remove_internal(dump): - for internal in INTERNAL_VARS: + for internal in C.INTERNAL_STATIC_VARS: if internal in dump: del dump[internal] diff --git a/lib/ansible/config/manager.py b/lib/ansible/config/manager.py index 418528a..041e96e 100644 --- a/lib/ansible/config/manager.py +++ b/lib/ansible/config/manager.py @@ -305,6 +305,17 @@ class ConfigManager(object): # ensure we always have config def entry self._base_defs['CONFIG_FILE'] = {'default': None, 'type': 'path'} + def template_default(self, value, variables): + if isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')) and variables is not None: + # template default values if possible + # NOTE: cannot use is_template due to circular dep + try: + t = NativeEnvironment().from_string(value) + value = t.render(variables) + except Exception: + pass # not templatable + return value + def _read_config_yaml_file(self, yml_file): # TODO: handle relative paths as relative to the directory containing the current playbook instead of CWD # Currently this is only used with absolute paths to the `ansible/config` directory @@ -548,17 +559,7 @@ class ConfigManager(object): to_native(_get_entry(plugin_type, plugin_name, config))) else: origin = 'default' - value = defs[config].get('default') - if isinstance(value, string_types) and (value.startswith('{{') and value.endswith('}}')) and variables is not None: - # template default values if possible - # NOTE: cannot use is_template due to circular dep - try: - t = NativeEnvironment().from_string(value) - value = t.render(variables) - except Exception: - pass # not templatable - - # ensure correct type, can raise exceptions on mismatched types + value = self.template_default(defs[config].get('default'), variables) try: value = ensure_type(value, defs[config].get('type'), origin=origin) except ValueError as e: diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py index 514357b..d66ff16 100644 --- a/lib/ansible/constants.py +++ b/lib/ansible/constants.py @@ -112,6 +112,46 @@ CONFIGURABLE_PLUGINS = ('become', 'cache', 'callback', 'cliconf', 'connection', DOCUMENTABLE_PLUGINS = CONFIGURABLE_PLUGINS + ('module', 'strategy', 'test', 'filter') IGNORE_FILES = ("COPYING", "CONTRIBUTING", "LICENSE", "README", "VERSION", "GUIDELINES", "MANIFEST", "Makefile") # ignore during module search INTERNAL_RESULT_KEYS = ('add_host', 'add_group') +INTERNAL_STATIC_VARS = frozenset( + [ + "ansible_async_path", + "ansible_collection_name", + "ansible_config_file", + "ansible_dependent_role_names", + "ansible_diff_mode", + "ansible_config_file", + "ansible_facts", + "ansible_forks", + "ansible_inventory_sources", + "ansible_limit", + "ansible_play_batch", + "ansible_play_hosts", + "ansible_play_hosts_all", + "ansible_play_role_names", + "ansible_playbook_python", + "ansible_role_name", + "ansible_role_names", + "ansible_run_tags", + "ansible_skip_tags", + "ansible_verbosity", + "ansible_version", + "inventory_dir", + "inventory_file", + "inventory_hostname", + "inventory_hostname_short", + "groups", + "group_names", + "omit", + "hostvars", + "playbook_dir", + "play_hosts", + "role_name", + "role_names", + "role_path", + "role_uuid", + "role_names", + ] +) LOCALHOST = ('127.0.0.1', 'localhost', '::1') MODULE_REQUIRE_ARGS = tuple(add_internal_fqcns(('command', 'win_command', 'ansible.windows.win_command', 'shell', 'win_shell', 'ansible.windows.win_shell', 'raw', 'script'))) diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py index 0e7394f..d20635a 100644 --- a/lib/ansible/executor/task_executor.py +++ b/lib/ansible/executor/task_executor.py @@ -841,7 +841,12 @@ class TaskExecutor: # that (with a sleep for "poll" seconds between each retry) until the # async time limit is exceeded. - async_task = Task.load(dict(action='async_status', args={'jid': async_jid}, environment=self._task.environment)) + async_task = Task.load(dict( + action='async_status', + args={'jid': async_jid}, + check_mode=self._task.check_mode, + environment=self._task.environment, + )) # FIXME: this is no longer the case, normal takes care of all, see if this can just be generalized # Because this is an async task, the action handler is async. However, @@ -913,6 +918,7 @@ class TaskExecutor: 'jid': async_jid, 'mode': 'cleanup', }, + 'check_mode': self._task.check_mode, 'environment': self._task.environment, } ) @@ -1086,7 +1092,7 @@ class TaskExecutor: # deals with networking sub_plugins (network_cli/httpapi/netconf) sub = getattr(self._connection, '_sub_plugin', None) - if sub is not None and sub.get('type') != 'external': + if sub and sub.get('type') != 'external': plugin_type = get_plugin_class(sub.get("obj")) varnames.extend(self._set_plugin_options(plugin_type, variables, templar, task_keys)) sub_conn = getattr(self._connection, 'ssh_type_conn', None) diff --git a/lib/ansible/module_utils/ansible_release.py b/lib/ansible/module_utils/ansible_release.py index f8530dc..60200a0 100644 --- a/lib/ansible/module_utils/ansible_release.py +++ b/lib/ansible/module_utils/ansible_release.py @@ -19,6 +19,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -__version__ = '2.16.5' +__version__ = '2.16.6' __author__ = 'Ansible, Inc.' __codename__ = "All My Love" diff --git a/lib/ansible/module_utils/facts/virtual/linux.py b/lib/ansible/module_utils/facts/virtual/linux.py index 31fa061..c368245 100644 --- a/lib/ansible/module_utils/facts/virtual/linux.py +++ b/lib/ansible/module_utils/facts/virtual/linux.py @@ -176,7 +176,7 @@ class LinuxVirtual(Virtual): virtual_facts['virtualization_type'] = 'RHEV' found_virt = True - if product_name in ('VMware Virtual Platform', 'VMware7,1'): + if product_name and product_name.startswith(("VMware",)): guest_tech.add('VMware') if not found_virt: virtual_facts['virtualization_type'] = 'VMware' diff --git a/lib/ansible/modules/blockinfile.py b/lib/ansible/modules/blockinfile.py index 8c83bf0..3ede6fd 100644 --- a/lib/ansible/modules/blockinfile.py +++ b/lib/ansible/modules/blockinfile.py @@ -269,7 +269,7 @@ def main(): module.fail_json(rc=257, msg='Path %s does not exist !' % path) destpath = os.path.dirname(path) - if not os.path.exists(destpath) and not module.check_mode: + if destpath and not os.path.exists(destpath) and not module.check_mode: try: os.makedirs(destpath) except OSError as e: diff --git a/lib/ansible/modules/dnf.py b/lib/ansible/modules/dnf.py index 7f5afc3..50d0ca6 100644 --- a/lib/ansible/modules/dnf.py +++ b/lib/ansible/modules/dnf.py @@ -1441,8 +1441,10 @@ class DnfModule(YumDnf): if self.with_modules: self.module_base = dnf.module.module_base.ModuleBase(self.base) - - self.ensure() + try: + self.ensure() + finally: + self.base.close() def main(): diff --git a/lib/ansible/modules/dnf5.py b/lib/ansible/modules/dnf5.py index 823d3a7..c55b673 100644 --- a/lib/ansible/modules/dnf5.py +++ b/lib/ansible/modules/dnf5.py @@ -484,7 +484,7 @@ class Dnf5Module(YumDnf): conf.config_file_path = self.conf_file try: - base.load_config_from_file() + base.load_config() except RuntimeError as e: self.module.fail_json( msg=str(e), @@ -520,7 +520,8 @@ class Dnf5Module(YumDnf): log_router = base.get_logger() global_logger = libdnf5.logger.GlobalLogger() global_logger.set(log_router.get(), libdnf5.logger.Logger.Level_DEBUG) - logger = libdnf5.logger.create_file_logger(base) + # FIXME hardcoding the filename does not seem right, should libdnf5 expose the default file name? + logger = libdnf5.logger.create_file_logger(base, "dnf5.log") log_router.add_logger(logger) if self.update_cache: @@ -545,7 +546,11 @@ class Dnf5Module(YumDnf): for repo in repo_query: repo.enable() - sack.update_and_load_enabled_repos(True) + try: + sack.load_repos() + except AttributeError: + # dnf5 < 5.2.0.0 + sack.update_and_load_enabled_repos(True) if self.update_cache and not self.names and not self.list: self.module.exit_json( @@ -577,7 +582,11 @@ class Dnf5Module(YumDnf): self.module.exit_json(msg="", results=results, rc=0) settings = libdnf5.base.GoalJobSettings() - settings.group_with_name = True + try: + settings.set_group_with_name(True) + except AttributeError: + # dnf5 < 5.2.0.0 + settings.group_with_name = True if self.bugfix or self.security: advisory_query = libdnf5.advisory.AdvisoryQuery(base) types = [] diff --git a/lib/ansible/modules/find.py b/lib/ansible/modules/find.py index d2e6c8b..0251224 100644 --- a/lib/ansible/modules/find.py +++ b/lib/ansible/modules/find.py @@ -258,6 +258,7 @@ skipped_paths: version_added: '2.12' ''' +import errno import fnmatch import grp import os @@ -434,10 +435,6 @@ def statinfo(st): } -def handle_walk_errors(e): - raise e - - def main(): module = AnsibleModule( argument_spec=dict( @@ -482,6 +479,12 @@ def main(): filelist = [] skipped = {} + def handle_walk_errors(e): + if e.errno in (errno.EPERM, errno.EACCES): + skipped[e.filename] = to_text(e) + return + raise e + if params['age'] is None: age = None else: diff --git a/lib/ansible/modules/unarchive.py b/lib/ansible/modules/unarchive.py index ec15a57..b3e8058 100644 --- a/lib/ansible/modules/unarchive.py +++ b/lib/ansible/modules/unarchive.py @@ -969,7 +969,7 @@ class TarZstdArchive(TgzArchive): class ZipZArchive(ZipArchive): def __init__(self, src, b_dest, file_args, module): super(ZipZArchive, self).__init__(src, b_dest, file_args, module) - self.zipinfoflag = '-Z' + self.zipinfoflag = '-Zl' self.binaries = ( ('unzip', 'cmd_path'), ('unzip', 'zipinfo_cmd_path'), diff --git a/lib/ansible/playbook/role/__init__.py b/lib/ansible/playbook/role/__init__.py index 34d8ba9..49254fc 100644 --- a/lib/ansible/playbook/role/__init__.py +++ b/lib/ansible/playbook/role/__init__.py @@ -586,7 +586,7 @@ class Role(Base, Conditional, Taggable, CollectionSearch, Delegatable): at least one task was run ''' - return host.name in self._completed and not self._metadata.allow_duplicates + return host.name in self._completed def compile(self, play, dep_chain=None): ''' diff --git a/lib/ansible/plugins/action/fetch.py b/lib/ansible/plugins/action/fetch.py index 11c91eb..d057ed2 100644 --- a/lib/ansible/plugins/action/fetch.py +++ b/lib/ansible/plugins/action/fetch.py @@ -150,6 +150,10 @@ class ActionModule(ActionBase): # destination filename base = os.path.basename(source_local) dest = os.path.join(dest, base) + + if os.path.isdir(to_bytes(dest, errors='surrogate_or_strict')): + raise AnsibleActionFail( + f"calculated dest '{dest}' is an existing directory, use another path that does not point to an existing directory") if not dest.startswith("/"): # if dest does not start with "/", we'll assume a relative path dest = self._loader.path_dwim(dest) diff --git a/lib/ansible/plugins/cache/__init__.py b/lib/ansible/plugins/cache/__init__.py index f3abcb7..24f4e77 100644 --- a/lib/ansible/plugins/cache/__init__.py +++ b/lib/ansible/plugins/cache/__init__.py @@ -165,6 +165,7 @@ class BaseFileCacheModule(BaseCacheModule): display.warning("error in '%s' cache plugin while trying to write to '%s' : %s" % (self.plugin_name, tmpfile_path, to_bytes(e))) try: os.rename(tmpfile_path, cachefile) + os.chmod(cachefile, mode=0o644) except (OSError, IOError) as e: display.warning("error in '%s' cache plugin while trying to move '%s' to '%s' : %s" % (self.plugin_name, tmpfile_path, cachefile, to_bytes(e))) finally: diff --git a/lib/ansible/plugins/connection/winrm.py b/lib/ansible/plugins/connection/winrm.py index 7104369..b297495 100644 --- a/lib/ansible/plugins/connection/winrm.py +++ b/lib/ansible/plugins/connection/winrm.py @@ -199,7 +199,7 @@ from ansible.utils.display import Display try: import winrm - from winrm.exceptions import WinRMError, WinRMOperationTimeoutError + from winrm.exceptions import WinRMError, WinRMOperationTimeoutError, WinRMTransportError from winrm.protocol import Protocol import requests.exceptions HAS_WINRM = True @@ -684,7 +684,19 @@ class Connection(ConnectionBase): raise AnsibleConnectionFailure('winrm connection error: %s' % to_native(exc)) finally: if command_id: - self.protocol.cleanup_command(self.shell_id, command_id) + # Due to a bug in how pywinrm works with message encryption we + # ignore a 400 error which can occur when a task timeout is + # set and the code tries to clean up the command. This happens + # as the cleanup msg is sent over a new socket but still uses + # the already encrypted payload bound to the other socket + # causing the server to reply with 400 Bad Request. + try: + self.protocol.cleanup_command(self.shell_id, command_id) + except WinRMTransportError as e: + if e.code != 400: + raise + + display.warning("Failed to cleanup running WinRM command, resources might still be in use on the target server") def _connect(self) -> Connection: diff --git a/lib/ansible/plugins/strategy/free.py b/lib/ansible/plugins/strategy/free.py index 82a21b1..5e64ef3 100644 --- a/lib/ansible/plugins/strategy/free.py +++ b/lib/ansible/plugins/strategy/free.py @@ -177,7 +177,7 @@ class StrategyModule(StrategyBase): # role which has already run (and whether that role allows duplicate execution) if not isinstance(task, Handler) and task._role: role_obj = self._get_cached_role(task, iterator._play) - if role_obj.has_run(host) and role_obj._metadata.allow_duplicates is False: + if role_obj.has_run(host) and task._role._metadata.allow_duplicates is False: display.debug("'%s' skipped because role has already run" % task, host=host_name) del self._blocked_hosts[host_name] continue diff --git a/lib/ansible/plugins/strategy/linear.py b/lib/ansible/plugins/strategy/linear.py index 2fd4cba..f3b117b 100644 --- a/lib/ansible/plugins/strategy/linear.py +++ b/lib/ansible/plugins/strategy/linear.py @@ -172,7 +172,7 @@ class StrategyModule(StrategyBase): # role which has already run (and whether that role allows duplicate execution) if not isinstance(task, Handler) and task._role: role_obj = self._get_cached_role(task, iterator._play) - if role_obj.has_run(host) and role_obj._metadata.allow_duplicates is False: + if role_obj.has_run(host) and task._role._metadata.allow_duplicates is False: display.debug("'%s' skipped because role has already run" % task) continue diff --git a/lib/ansible/release.py b/lib/ansible/release.py index f8530dc..60200a0 100644 --- a/lib/ansible/release.py +++ b/lib/ansible/release.py @@ -19,6 +19,6 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -__version__ = '2.16.5' +__version__ = '2.16.6' __author__ = 'Ansible, Inc.' __codename__ = "All My Love" diff --git a/lib/ansible/vars/hostvars.py b/lib/ansible/vars/hostvars.py index 6222954..a76811b 100644 --- a/lib/ansible/vars/hostvars.py +++ b/lib/ansible/vars/hostvars.py @@ -21,26 +21,9 @@ __metaclass__ = type from collections.abc import Mapping +from ansible import constants as C from ansible.template import Templar, AnsibleUndefined -STATIC_VARS = [ - 'ansible_version', - 'ansible_play_hosts', - 'ansible_dependent_role_names', - 'ansible_play_role_names', - 'ansible_role_names', - 'inventory_hostname', - 'inventory_hostname_short', - 'inventory_file', - 'inventory_dir', - 'groups', - 'group_names', - 'omit', - 'playbook_dir', - 'play_hosts', - 'role_names', - 'ungrouped', -] __all__ = ['HostVars', 'HostVarsVars'] @@ -134,10 +117,12 @@ class HostVarsVars(Mapping): def __init__(self, variables, loader): self._vars = variables self._loader = loader + # NOTE: this only has access to the host's own vars, + # so templates that depend on vars in other scopes will not work. + self._templar = Templar(variables=self._vars, loader=self._loader) def __getitem__(self, var): - templar = Templar(variables=self._vars, loader=self._loader) - return templar.template(self._vars[var], fail_on_undefined=False, static_vars=STATIC_VARS) + return self._templar.template(self._vars[var], fail_on_undefined=False, static_vars=C.INTERNAL_STATIC_VARS) def __contains__(self, var): return (var in self._vars) @@ -150,5 +135,4 @@ class HostVarsVars(Mapping): return len(self._vars.keys()) def __repr__(self): - templar = Templar(variables=self._vars, loader=self._loader) - return repr(templar.template(self._vars, fail_on_undefined=False, static_vars=STATIC_VARS)) + return repr(self._templar.template(self._vars, fail_on_undefined=False, static_vars=C.INTERNAL_STATIC_VARS)) diff --git a/lib/ansible_core.egg-info/PKG-INFO b/lib/ansible_core.egg-info/PKG-INFO index 263e42f..406d6ef 100644 --- a/lib/ansible_core.egg-info/PKG-INFO +++ b/lib/ansible_core.egg-info/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: ansible-core -Version: 2.16.5 +Version: 2.16.6 Summary: Radically simple IT automation Home-page: https://ansible.com/ Author: Ansible, Inc. diff --git a/lib/ansible_core.egg-info/SOURCES.txt b/lib/ansible_core.egg-info/SOURCES.txt index 3c8d1f4..6bcc388 100644 --- a/lib/ansible_core.egg-info/SOURCES.txt +++ b/lib/ansible_core.egg-info/SOURCES.txt @@ -1038,6 +1038,7 @@ test/integration/targets/ansible-test-sanity-ansible-doc/aliases test/integration/targets/ansible-test-sanity-ansible-doc/runme.sh test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/lookup/lookup1.py test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/lookup/a/b/lookup2.py +test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/modules/_module3.py test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/modules/module1.py test/integration/targets/ansible-test-sanity-ansible-doc/ansible_collections/ns/col/plugins/modules/a/b/module2.py test/integration/targets/ansible-test-sanity-import/aliases @@ -1279,6 +1280,7 @@ test/integration/targets/assert/quiet.yml test/integration/targets/assert/runme.sh test/integration/targets/async/aliases test/integration/targets/async/callback_test.yml +test/integration/targets/async/check_task_test.yml test/integration/targets/async/library/async_test.py test/integration/targets/async/meta/main.yml test/integration/targets/async/tasks/main.yml @@ -1666,6 +1668,8 @@ test/integration/targets/connection_delegation/connection_plugins/delegation_con test/integration/targets/connection_local/aliases test/integration/targets/connection_local/runme.sh test/integration/targets/connection_local/test_connection.inventory +test/integration/targets/connection_local/test_network_connection.inventory +test/integration/targets/connection_local/connection_plugins/network_noop.py test/integration/targets/connection_paramiko_ssh/aliases test/integration/targets/connection_paramiko_ssh/runme.sh test/integration/targets/connection_paramiko_ssh/test.sh @@ -2352,6 +2356,7 @@ test/integration/targets/include_import/tasks/tasks4.yml test/integration/targets/include_import/tasks/tasks5.yml test/integration/targets/include_import/tasks/tasks6.yml test/integration/targets/include_import/tasks/test_allow_single_role_dup.yml +test/integration/targets/include_import/tasks/test_dynamic_allow_dup.yml test/integration/targets/include_import/tasks/test_import_tasks.yml test/integration/targets/include_import/tasks/test_import_tasks_tags.yml test/integration/targets/include_import/tasks/test_include_dupe_loop.yml |