/lib/ansible/playbook/task_include.py
https://github.com/debfx/ansible · Python · 143 lines · 83 code · 27 blank · 33 comment · 18 complexity · 827b82692ea2dd7ddf59c503505a7665 MD5 · raw file
- # (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
- #
- # 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/>.
- # Make coding more python3-ish
- 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.block import Block
- from ansible.playbook.task import Task
- from ansible.utils.display import Display
- from ansible.utils.sentinel import Sentinel
- __all__ = ['TaskInclude']
- display = Display()
- class TaskInclude(Task):
- """
- A task include is derived from a regular task to handle the special
- circumstances related to the `- include: ...` task.
- """
- BASE = frozenset(('file', '_raw_params')) # directly assigned
- OTHER_ARGS = frozenset(('apply',)) # assigned to matching property
- VALID_ARGS = BASE.union(OTHER_ARGS) # all valid args
- VALID_INCLUDE_KEYWORDS = frozenset(('action', 'args', 'debugger', 'ignore_errors', 'loop', 'loop_control',
- 'loop_with', 'name', 'no_log', 'register', 'run_once', 'tags', 'vars',
- 'when'))
- # =================================================================================
- # ATTRIBUTES
- _static = FieldAttribute(isa='bool', default=None)
- def __init__(self, block=None, role=None, task_include=None):
- super(TaskInclude, self).__init__(block=block, role=role, task_include=task_include)
- self.statically_loaded = False
- @staticmethod
- def load(data, block=None, role=None, task_include=None, variable_manager=None, loader=None):
- ti = TaskInclude(block=block, role=role, task_include=task_include)
- task = ti.load_data(data, variable_manager=variable_manager, loader=loader)
- # Validate options
- my_arg_names = frozenset(task.args.keys())
- # validate bad args, otherwise we silently ignore
- bad_opts = my_arg_names.difference(TaskInclude.VALID_ARGS)
- if bad_opts and task.action in ('include_tasks', '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')
- apply_attrs = task.args.get('apply', {})
- if apply_attrs and task.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)
- return task
- def preprocess_data(self, ds):
- ds = super(TaskInclude, self).preprocess_data(ds)
- diff = set(ds.keys()).difference(TaskInclude.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 C.INVALID_TASK_ATTRIBUTE_FAILED:
- raise AnsibleParserError("'%s' is not a valid attribute for a %s" % (k, self.__class__.__name__), obj=ds)
- else:
- display.warning("Ignoring invalid attribute: %s" % k)
- return ds
- def copy(self, exclude_parent=False, exclude_tasks=False):
- new_me = super(TaskInclude, self).copy(exclude_parent=exclude_parent, exclude_tasks=exclude_tasks)
- new_me.statically_loaded = self.statically_loaded
- return new_me
- def get_vars(self):
- '''
- We override the parent Task() classes get_vars here because
- 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':
- all_vars = super(TaskInclude, self).get_vars()
- else:
- all_vars = dict()
- if self._parent:
- all_vars.update(self._parent.get_vars())
- all_vars.update(self.vars)
- all_vars.update(self.args)
- if 'tags' in all_vars:
- del all_vars['tags']
- if 'when' in all_vars:
- del all_vars['when']
- return all_vars
- def build_parent_block(self):
- '''
- This method is used to create the parent block for the included tasks
- when ``apply`` is specified
- '''
- apply_attrs = self.args.pop('apply', {})
- if apply_attrs:
- apply_attrs['block'] = []
- p_block = Block.load(
- apply_attrs,
- play=self._parent._play,
- task_include=self,
- role=self._role,
- variable_manager=self._variable_manager,
- loader=self._loader,
- )
- else:
- p_block = self
- return p_block