Optimizations in mod_args parsing

* Make it less likely that we have to identify all the modules during
  a playbook run.  PluginLoader is optimized to look for modules one
  directory at a time.  If we find a module before we've examined all
  the directories we never have to touch the other directories.
  Reordering this conditional makes it so tasks which don't have
  a module file will not force us to examine all the module directories
  before moving on to other sources of task actions.
* Change several variables we consult to see if a task is in a certain
  category from lists/tuples to frozensets.  These are static lists
  which we only do containment tests on so frozensets should be faster
This commit is contained in:
Toshio Kuratomi 2018-03-22 14:11:22 -07:00
parent 1f824bd620
commit 9890ce47e8

View file

@ -28,12 +28,16 @@ from ansible.template import Templar
# For filtering out modules correctly below
RAW_PARAM_MODULES = ([
FREEFORM_ACTIONS = frozenset((
'command',
'win_command',
'shell',
'win_shell',
'script',
'raw'
))
RAW_PARAM_MODULES = FREEFORM_ACTIONS.union((
'include',
'include_vars',
'include_tasks',
@ -43,9 +47,17 @@ RAW_PARAM_MODULES = ([
'add_host',
'group_by',
'set_fact',
'raw',
'meta',
])
))
BUILTIN_TASKS = frozenset((
'meta',
'include',
'include_tasks',
'include_role',
'import_tasks',
'import_role'
))
class ModuleArgsParser:
@ -158,7 +170,7 @@ class ModuleArgsParser:
# only internal variables can start with an underscore, so
# we don't allow users to set them directly in arguments
if args and action not in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw'):
if args and action not in FREEFORM_ACTIONS:
for arg in args:
arg = to_text(arg)
if arg.startswith('_ansible_'):
@ -189,7 +201,7 @@ class ModuleArgsParser:
args = thing
elif isinstance(thing, string_types):
# form is like: copy: src=a dest=b
check_raw = action in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
check_raw = action in FREEFORM_ACTIONS
args = parse_kv(thing, check_raw=check_raw)
elif thing is None:
# this can happen with modules which take no params, like ping:
@ -214,21 +226,20 @@ class ModuleArgsParser:
action = None
args = None
actions_allowing_raw = ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
if isinstance(thing, dict):
# form is like: action: { module: 'copy', src: 'a', dest: 'b' }
thing = thing.copy()
if 'module' in thing:
action, module_args = self._split_module_string(thing['module'])
args = thing.copy()
check_raw = action in actions_allowing_raw
check_raw = action in FREEFORM_ACTIONS
args.update(parse_kv(module_args, check_raw=check_raw))
del args['module']
elif isinstance(thing, string_types):
# form is like: action: copy src=a dest=b
(action, args) = self._split_module_string(thing)
check_raw = action in actions_allowing_raw
check_raw = action in FREEFORM_ACTIONS
args = parse_kv(args, check_raw=check_raw)
else:
@ -275,7 +286,7 @@ class ModuleArgsParser:
# walk the input dictionary to see we recognize a module name
for (item, value) in iteritems(self._task_ds):
if item in module_loader or item in action_loader or item in ['meta', 'include', 'include_tasks', 'include_role', 'import_tasks', 'import_role']:
if item in BUILTIN_TASKS or item in action_loader or item in module_loader:
# finding more than one module name is a problem
if action is not None:
raise AnsibleParserError("conflicting action statements: %s, %s" % (action, item), obj=self._task_ds)