Exemple #1
0
def test_process_include_diff_files(mock_iterator, mock_variable_manager):
    hostname = "testhost1"
    hostname2 = "testhost2"

    parent_task_ds = {'debug': 'msg=foo'}
    parent_task = Task.load(parent_task_ds)

    task_ds = {'include': 'include_test.yml'}
    loaded_task = TaskInclude.load(task_ds, task_include=parent_task)

    child_task_ds = {'include': 'other_include_test.yml'}
    loaded_child_task = TaskInclude.load(child_task_ds, task_include=loaded_task)

    return_data = {'include': 'include_test.yml'}
    # The task in the TaskResult has to be a TaskInclude so it has a .static attr
    result1 = task_result.TaskResult(host=hostname, task=loaded_task, return_data=return_data)

    return_data = {'include': 'other_include_test.yml'}
    result2 = task_result.TaskResult(host=hostname2, task=loaded_child_task, return_data=return_data)
    results = [result1, result2]

    fake_loader = DictDataLoader({'include_test.yml': "",
                                  'other_include_test.yml': ""})

    res = IncludedFile.process_include_results(results, mock_iterator, fake_loader, mock_variable_manager)
    assert isinstance(res, list)
    assert res[0]._filename == os.path.join(os.getcwd(), 'include_test.yml')
    assert res[1]._filename == os.path.join(os.getcwd(), 'other_include_test.yml')

    assert res[0]._hosts == ['testhost1']
    assert res[1]._hosts == ['testhost2']

    assert res[0]._args == {}
    assert res[1]._args == {}
Exemple #2
0
    def deserialize(self, data):
        block_data = data.get('block')
        self._dep_chain = data.get('dep_chain', [])

        if block_data:
            b = Block()
            b.deserialize(block_data)
            self._block = b
            del data['block']

        role_data = data.get('role')
        if role_data:
            r = Role()
            r.deserialize(role_data)
            self._role = r
            del data['role']

        ti_data = data.get('task_include')
        if ti_data:
            ti = TaskInclude()
            ti.deserialize(ti_data)
            self._task_include = ti
            del data['task_include']

        super(Task, self).deserialize(data)
Exemple #3
0
    def test_process_include_results(self):
        hostname = "testhost1"
        hostname2 = "testhost2"

        parent_task_ds = {'debug': 'msg=foo'}
        parent_task = Task()
        parent_task.load(parent_task_ds)

        task_ds = {'include': 'include_test.yml'}
        task_include = TaskInclude()
        loaded_task = task_include.load(task_ds, task_include=parent_task)

        child_task_ds = {'include': 'other_include_test.yml'}
        child_task_include = TaskInclude()
        loaded_child_task = child_task_include.load(child_task_ds, task_include=loaded_task)

        return_data = {'include': 'include_test.yml'}
        # The task in the TaskResult has to be a TaskInclude so it has a .static attr
        result1 = task_result.TaskResult(host=hostname, task=loaded_task, return_data=return_data)

        return_data = {'include': 'other_include_test.yml'}
        result2 = task_result.TaskResult(host=hostname2, task=loaded_child_task, return_data=return_data)
        results = [result1, result2]

        fake_loader = DictDataLoader({'include_test.yml': "",
                                      'other_include_test.yml': ""})

        mock_tqm = MagicMock(name='MockTaskQueueManager')

        mock_play = MagicMock(name='MockPlay')

        mock_iterator = MagicMock(name='MockIterator')
        mock_iterator._play = mock_play

        mock_inventory = MagicMock(name='MockInventory')
        mock_inventory._hosts_cache = dict()

        def _get_host(host_name):
            return None

        mock_inventory.get_host.side_effect = _get_host

        # TODO: can we use a real VariableManager?
        mock_variable_manager = MagicMock(name='MockVariableManager')
        mock_variable_manager.get_vars.return_value = dict()

        res = IncludedFile.process_include_results(results, mock_tqm, mock_iterator,
                                                   mock_inventory, fake_loader,
                                                   mock_variable_manager)
        self.assertIsInstance(res, list)
        self.assertEquals(res[0]._filename, os.path.join(os.getcwd(), 'include_test.yml'))
        self.assertEquals(res[1]._filename, os.path.join(os.getcwd(), 'other_include_test.yml'))

        self.assertEquals(res[0]._hosts, ['testhost1'])
        self.assertEquals(res[1]._hosts, ['testhost2'])

        self.assertEquals(res[0]._args, {})
        self.assertEquals(res[1]._args, {})
 def test_one_include_not_static(self):
     ds = [{
         'include_tasks': '/dev/null/includes/static_test_include.yml',
     }]
     # a_block = Block()
     ti_ds = {'include_tasks': '/dev/null/includes/ssdftatic_test_include.yml'}
     a_task_include = TaskInclude()
     ti = a_task_include.load(ti_ds)
     res = helpers.load_list_of_tasks(ds, play=self.mock_play,
                                      block=ti,
                                      variable_manager=self.mock_variable_manager, loader=self.fake_include_loader)
     self._assert_is_task_list_or_blocks(res)
     self.assertIsInstance(res[0], Task)
     self.assertEqual(res[0].args['_raw_params'], '/dev/null/includes/static_test_include.yml')
Exemple #5
0
def test_empty_raw_params():
    parent_task_ds = {'debug': 'msg=foo'}
    parent_task = Task.load(parent_task_ds)
    parent_task._play = None

    task_ds_list = [{
        'include': ''
    }, {
        'include_tasks': ''
    }, {
        'import_tasks': ''
    }]
    for task_ds in task_ds_list:
        with pytest.raises(AnsibleParserError):
            TaskInclude.load(task_ds, task_include=parent_task)
Exemple #6
0
 def test_one_include_not_static(self):
     ds = [{
         'include': '/dev/null/includes/static_test_include.yml',
         'static': False
     }]
     # a_block = Block()
     ti_ds = {'include': '/dev/null/includes/ssdftatic_test_include.yml'}
     a_task_include = TaskInclude()
     ti = a_task_include.load(ti_ds)
     res = helpers.load_list_of_tasks(ds, play=self.mock_play,
                                      block=ti,
                                      variable_manager=self.mock_variable_manager, loader=self.fake_include_loader)
     self._assert_is_task_list_or_blocks(res)
     self.assertIsInstance(res[0], Task)
     self.assertEquals(res[0].args['_raw_params'], '/dev/null/includes/static_test_include.yml')
Exemple #7
0
    def deserialize(self, data):

        # import is here to avoid import loops
        from ansible.playbook.task_include import TaskInclude
        from ansible.playbook.handler_task_include import HandlerTaskInclude

        parent_data = data.get('parent', None)
        if parent_data:
            parent_type = data.get('parent_type')
            if parent_type == 'Block':
                p = Block()
            elif parent_type == 'TaskInclude':
                p = TaskInclude()
            elif parent_type == 'HandlerTaskInclude':
                p = HandlerTaskInclude()
            p.deserialize(parent_data)
            self._parent = p
            del data['parent']

        role_data = data.get('role')
        if role_data:
            r = Role()
            r.deserialize(role_data)
            self._role = r
            del data['role']

        self._ansible_internal_redirect_list = data.get(
            '_ansible_internal_redirect_list', [])

        self.implicit = data.get('implicit', False)
        self.resolved_action = data.get('resolved_action')

        super(Task, self).deserialize(data)
Exemple #8
0
def load_list_of_tasks(ds, block=None, role=None, task_include=None, loader=None):
    """
    Given a list of task datastructures (parsed from YAML),
    return a list of Task() or TaskInclude() objects.
    """

    # we import here to prevent a circular dependency with imports
    from ansible.playbook.task import Task
    from ansible.playbook.task_include import TaskInclude

    assert type(ds) == list

    task_list = []
    for task in ds:
        if not isinstance(task, dict):
            raise AnsibleParserError("task/handler entries must be dictionaries (got a %s)" % type(task), obj=ds)

        if "include" in task:
            cur_basedir = None
            if isinstance(task, AnsibleBaseYAMLObject) and loader:
                pos_info = task.get_position_info()
                new_basedir = os.path.dirname(pos_info[0])
                cur_basedir = loader.get_basedir()
                loader.set_basedir(new_basedir)

            t = TaskInclude.load(task, block=block, role=role, task_include=task_include, loader=loader)

            if cur_basedir and loader:
                loader.set_basedir(cur_basedir)
        else:
            t = Task.load(task, block=block, role=role, task_include=task_include, loader=loader)

        task_list.append(t)

    return task_list
Exemple #9
0
    def deserialize(self, data):

        # import is here to avoid import loops
        from ansible.playbook.task_include import TaskInclude
        from ansible.playbook.handler_task_include import HandlerTaskInclude

        parent_data = data.get('parent', None)
        if parent_data:
            parent_type = data.get('parent_type')
            if parent_type == 'Block':
                p = Block()
            elif parent_type == 'TaskInclude':
                p = TaskInclude()
            elif parent_type == 'HandlerTaskInclude':
                p = HandlerTaskInclude()
            p.deserialize(parent_data)
            self._parent = p
            del data['parent']

        role_data = data.get('role')
        if role_data:
            r = Role()
            r.deserialize(role_data)
            self._role = r
            del data['role']

        super(Task, self).deserialize(data)
Exemple #10
0
def load_list_of_tasks(ds,
                       block=None,
                       role=None,
                       task_include=None,
                       loader=None):
    '''
    Given a list of task datastructures (parsed from YAML),
    return a list of Task() or TaskInclude() objects.
    '''

    # we import here to prevent a circular dependency with imports
    from ansible.playbook.task import Task
    from ansible.playbook.task_include import TaskInclude

    assert type(ds) == list

    task_list = []
    for task in ds:
        if not isinstance(task, dict):
            raise AnsibleParserError(
                "task/handler entries must be dictionaries (got a %s)" %
                type(task),
                obj=ds)

        if 'include' in task:
            cur_basedir = None
            if isinstance(task, AnsibleBaseYAMLObject) and loader:
                pos_info = task.get_position_info()
                new_basedir = os.path.dirname(pos_info[0])
                cur_basedir = loader.get_basedir()
                loader.set_basedir(new_basedir)

            t = TaskInclude.load(task,
                                 block=block,
                                 role=role,
                                 task_include=task_include,
                                 loader=loader)

            if cur_basedir and loader:
                loader.set_basedir(cur_basedir)
        else:
            t = Task.load(task,
                          block=block,
                          role=role,
                          task_include=task_include,
                          loader=loader)

        task_list.append(t)

    return task_list
Exemple #11
0
    def deserialize(self, data):
        '''
        Override of the default deserialize method, to match the above overridden
        serialize method
        '''

        from ansible.playbook.task_include import TaskInclude

        # unpack the when attribute, which is the only one we want
        self.when = data.get('when')

        # if there was a serialized role, unpack it too
        role_data = data.get('role')
        if role_data:
            r = Role()
            r.deserialize(role_data)
            self._role = r

        # if there was a serialized task include, unpack it too
        ti_data = data.get('task_include')
        if ti_data:
            ti = TaskInclude()
            ti.deserialize(ti_data)
            self._task_include = ti
Exemple #12
0
    def deserialize(self, data):
        '''
        Override of the default deserialize method, to match the above overridden
        serialize method
        '''

        # import is here to avoid import loops
        from ansible.playbook.task import Task
        from ansible.playbook.task_include import TaskInclude
        from ansible.playbook.handler_task_include import HandlerTaskInclude

        # we don't want the full set of attributes (the task lists), as that
        # would lead to a serialize/deserialize loop
        for attr in self._valid_attrs:
            if attr in data and attr not in ('block', 'rescue', 'always'):
                setattr(self, attr, data.get(attr))

        self._dep_chain = data.get('dep_chain', None)
        self._eor = data.get('eor', False)

        # if there was a serialized role, unpack it too
        role_data = data.get('role')
        if role_data:
            r = Role()
            r.deserialize(role_data)
            self._role = r

        parent_data = data.get('parent')
        if parent_data:
            parent_type = data.get('parent_type')
            if parent_type == 'Block':
                p = Block()
            elif parent_type == 'TaskInclude':
                p = TaskInclude()
            elif parent_type == 'HandlerTaskInclude':
                p = HandlerTaskInclude()
            p.deserialize(parent_data)
            self._parent = p
            self._dep_chain = self._parent.get_dep_chain()
Exemple #13
0
 def test_basic_task_include(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml'),
                           loader=self._fake_loader)
     tasks = ti.compile()
Exemple #14
0
    def test_process_include_results(self):
        hostname = "testhost1"
        hostname2 = "testhost2"

        parent_task_ds = {'debug': 'msg=foo'}
        parent_task = Task()
        parent_task.load(parent_task_ds)

        task_ds = {'include': 'include_test.yml'}
        task_include = TaskInclude()
        loaded_task = task_include.load(task_ds, task_include=parent_task)

        child_task_ds = {'include': 'other_include_test.yml'}
        child_task_include = TaskInclude()
        loaded_child_task = child_task_include.load(child_task_ds,
                                                    task_include=loaded_task)

        return_data = {'include': 'include_test.yml'}
        # The task in the TaskResult has to be a TaskInclude so it has a .static attr
        result1 = task_result.TaskResult(host=hostname,
                                         task=loaded_task,
                                         return_data=return_data)

        return_data = {'include': 'other_include_test.yml'}
        result2 = task_result.TaskResult(host=hostname2,
                                         task=loaded_child_task,
                                         return_data=return_data)
        results = [result1, result2]

        fake_loader = DictDataLoader({
            'include_test.yml': "",
            'other_include_test.yml': ""
        })

        mock_tqm = MagicMock(name='MockTaskQueueManager')

        mock_play = MagicMock(name='MockPlay')

        mock_iterator = MagicMock(name='MockIterator')
        mock_iterator._play = mock_play

        mock_inventory = MagicMock(name='MockInventory')
        mock_inventory._hosts_cache = dict()

        def _get_host(host_name):
            return None

        mock_inventory.get_host.side_effect = _get_host

        # TODO: can we use a real VariableManager?
        mock_variable_manager = MagicMock(name='MockVariableManager')
        mock_variable_manager.get_vars.return_value = dict()

        res = IncludedFile.process_include_results(results, mock_tqm,
                                                   mock_iterator,
                                                   mock_inventory, fake_loader,
                                                   mock_variable_manager)
        self.assertIsInstance(res, list)
        self.assertEquals(res[0]._filename,
                          os.path.join(os.getcwd(), 'include_test.yml'))
        self.assertEquals(res[1]._filename,
                          os.path.join(os.getcwd(), 'other_include_test.yml'))

        self.assertEquals(res[0]._hosts, ['testhost1'])
        self.assertEquals(res[1]._hosts, ['testhost2'])

        self.assertEquals(res[0]._args, {})
        self.assertEquals(res[1]._args, {})
Exemple #15
0
 def test_basic_task_include(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml'), loader=self._fake_loader)
     tasks = ti.compile()
Exemple #16
0
 def test_task_include_with_loop(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml', with_items=['a', 'b', 'c']), loader=self._fake_loader)
Exemple #17
0
def load_list_of_tasks(ds,
                       play,
                       block=None,
                       role=None,
                       task_include=None,
                       use_handlers=False,
                       variable_manager=None,
                       loader=None):
    '''
    Given a list of task datastructures (parsed from YAML),
    return a list of Task() or TaskInclude() objects.
    '''

    # we import here to prevent a circular dependency with imports
    from ansible.playbook.block import Block
    from ansible.playbook.handler import Handler
    from ansible.playbook.task import Task
    from ansible.playbook.task_include import TaskInclude
    from ansible.template import Templar

    assert isinstance(ds, list)

    task_list = []
    for task_ds in ds:
        assert isinstance(task_ds, dict)

        if 'block' in task_ds:
            t = Block.load(
                task_ds,
                play=play,
                parent_block=block,
                role=role,
                task_include=task_include,
                use_handlers=use_handlers,
                variable_manager=variable_manager,
                loader=loader,
            )
            task_list.append(t)
        else:
            if 'include' in task_ds:
                t = TaskInclude.load(task_ds,
                                     block=block,
                                     role=role,
                                     task_include=task_include,
                                     variable_manager=variable_manager,
                                     loader=loader)

                all_vars = variable_manager.get_vars(loader=loader,
                                                     play=play,
                                                     task=t)
                templar = Templar(loader=loader, variables=all_vars)

                # check to see if this include is static, which can be true if:
                # 1. the user set the 'static' option to true
                # 2. one of the appropriate config options was set
                # 3. the included file name contains no variables, and has no loop
                is_static = t.static or \
                            C.DEFAULT_TASK_INCLUDES_STATIC or \
                            (use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \
                            not templar._contains_vars(t.args.get('_raw_params')) and t.loop is None

                if is_static:
                    if t.loop is not None:
                        raise AnsibleParserError(
                            "You cannot use 'static' on an include with a loop",
                            obj=task_ds)

                    # FIXME: all of this code is very similar (if not identical) to that in
                    #        plugins/strategy/__init__.py, and should be unified to avoid
                    #        patches only being applied to one or the other location
                    if task_include:
                        # handle relative includes by walking up the list of parent include
                        # tasks and checking the relative result to see if it exists
                        parent_include = task_include
                        cumulative_path = None
                        while parent_include is not None:
                            parent_include_dir = templar.template(
                                os.path.dirname(
                                    parent_include.args.get('_raw_params')))
                            if cumulative_path is None:
                                cumulative_path = parent_include_dir
                            elif not os.path.isabs(cumulative_path):
                                cumulative_path = os.path.join(
                                    parent_include_dir, cumulative_path)
                            include_target = templar.template(
                                t.args['_raw_params'])
                            if t._role:
                                new_basedir = os.path.join(
                                    t._role._role_path, 'tasks',
                                    cumulative_path)
                                include_file = loader.path_dwim_relative(
                                    new_basedir, 'tasks', include_target)
                            else:
                                include_file = loader.path_dwim_relative(
                                    loader.get_basedir(), cumulative_path,
                                    include_target)

                            if os.path.exists(include_file):
                                break
                            else:
                                parent_include = parent_include._task_include
                    else:
                        try:
                            include_target = templar.template(
                                t.args['_raw_params'])
                        except AnsibleUndefinedVariable as e:
                            raise AnsibleParserError(
                                      "Error when evaluating variable in include name: %s.\n\n" \
                                      "When using static includes, ensure that any variables used in their names are defined in vars/vars_files\n" \
                                      "or extra-vars passed in from the command line. Static includes cannot use variables from inventory\n" \
                                      "sources like group or host vars." % t.args['_raw_params'],
                                      obj=task_ds,
                                      suppress_extended_error=True,
                                  )
                        if t._role:
                            if use_handlers:
                                include_file = loader.path_dwim_relative(
                                    t._role._role_path, 'handlers',
                                    include_target)
                            else:
                                include_file = loader.path_dwim_relative(
                                    t._role._role_path, 'tasks',
                                    include_target)
                        else:
                            include_file = loader.path_dwim(include_target)

                    data = loader.load_from_file(include_file)
                    if data is None:
                        return []
                    elif not isinstance(data, list):
                        raise AnsibleError(
                            "included task files must contain a list of tasks",
                            obj=data)

                    included_blocks = load_list_of_blocks(
                        data,
                        play=play,
                        parent_block=block,
                        task_include=t,
                        role=role,
                        use_handlers=use_handlers,
                        loader=loader,
                        variable_manager=variable_manager,
                    )

                    # Remove the raw params field from the module args, so it won't show up
                    # later when getting the vars for this task/childen
                    t.args.pop('_raw_params', None)

                    # pop tags out of the include args, if they were specified there, and assign
                    # them to the include. If the include already had tags specified, we raise an
                    # error so that users know not to specify them both ways
                    tags = t.vars.pop('tags', [])
                    if isinstance(tags, string_types):
                        tags = tags.split(',')

                    if len(tags) > 0:
                        if len(t.tags) > 0:
                            raise AnsibleParserError(
                                "Include tasks should not specify tags in more than one way (both via args and directly on the task)." \
                                " Mixing tag specify styles is prohibited for whole import hierarchy, not only for single import statement",
                                obj=task_ds,
                                suppress_extended_error=True,
                            )
                        display.deprecated(
                            "You should not specify tags in the include parameters. All tags should be specified using the task-level option"
                        )
                    else:
                        tags = t.tags[:]

                    # now we extend the tags on each of the included blocks
                    for b in included_blocks:
                        b.tags = list(set(b.tags).union(tags))
                    # END FIXME

                    # FIXME: send callback here somehow...
                    # FIXME: handlers shouldn't need this special handling, but do
                    #        right now because they don't iterate blocks correctly
                    if use_handlers:
                        for b in included_blocks:
                            task_list.extend(b.block)
                    else:
                        task_list.extend(included_blocks)
                else:
                    task_list.append(t)
            elif use_handlers:
                t = Handler.load(task_ds,
                                 block=block,
                                 role=role,
                                 task_include=task_include,
                                 variable_manager=variable_manager,
                                 loader=loader)
                task_list.append(t)
            else:
                t = Task.load(task_ds,
                              block=block,
                              role=role,
                              task_include=task_include,
                              variable_manager=variable_manager,
                              loader=loader)
                task_list.append(t)

    return task_list
Exemple #18
0
 def test_task_include_with_conditional(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml', when="1 == 1"), loader=self._fake_loader)
Exemple #19
0
 def test_task_include_with_tags(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml', tags="foo"), loader=self._fake_loader)
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml', tags=["foo", "bar"]), loader=self._fake_loader)
def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_handlers=False, variable_manager=None, loader=None):
    '''
    Given a list of task datastructures (parsed from YAML),
    return a list of Task() or TaskInclude() objects.
    '''

    # we import here to prevent a circular dependency with imports
    from ansible.playbook.block import Block
    from ansible.playbook.handler import Handler
    from ansible.playbook.task import Task
    from ansible.playbook.task_include import TaskInclude
    from ansible.template import Templar

    assert isinstance(ds, list)

    task_list = []
    for task_ds in ds:
        assert isinstance(task_ds, dict)

        if 'block' in task_ds:
            t = Block.load(
                task_ds,
                play=play,
                parent_block=block,
                role=role,
                task_include=task_include,
                use_handlers=use_handlers,
                variable_manager=variable_manager,
                loader=loader,
            )
            task_list.append(t)
        else:
            if 'include' in task_ds:
                t = TaskInclude.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader)

                all_vars = variable_manager.get_vars(loader=loader, play=play, task=t)
                templar = Templar(loader=loader, variables=all_vars)

                # check to see if this include is static, which can be true if:
                # 1. the user set the 'static' option to true
                # 2. one of the appropriate config options was set
                # 3. the included file name contains no variables, and has no loop
                is_static = t.static or \
                            C.DEFAULT_TASK_INCLUDES_STATIC or \
                            (use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \
                            not templar._contains_vars(t.args.get('_raw_params')) and t.loop is None

                if is_static:
                    if t.loop is not None:
                        raise AnsibleParserError("You cannot use 'static' on an include with a loop", obj=task_ds)

                    # FIXME: all of this code is very similar (if not identical) to that in 
                    #        plugins/strategy/__init__.py, and should be unified to avoid
                    #        patches only being applied to one or the other location
                    if task_include:
                        # handle relative includes by walking up the list of parent include
                        # tasks and checking the relative result to see if it exists
                        parent_include = task_include
                        cumulative_path = None
                        while parent_include is not None:
                            parent_include_dir = templar.template(os.path.dirname(parent_include.args.get('_raw_params')))
                            if cumulative_path is None:
                                cumulative_path = parent_include_dir
                            elif not os.path.isabs(cumulative_path):
                                cumulative_path = os.path.join(parent_include_dir, cumulative_path)
                            include_target = templar.template(t.args['_raw_params'])
                            if t._role:
                                new_basedir = os.path.join(t._role._role_path, 'tasks', cumulative_path)
                                include_file = loader.path_dwim_relative(new_basedir, 'tasks', include_target)
                            else:
                                include_file = loader.path_dwim_relative(loader.get_basedir(), cumulative_path, include_target)

                            if os.path.exists(include_file):
                                break
                            else:
                                parent_include = parent_include._task_include
                    else:
                        try:
                            include_target = templar.template(t.args['_raw_params'])
                        except AnsibleUndefinedVariable as e:
                            raise AnsibleParserError(
                                      "Error when evaluating variable in include name: %s.\n\n" \
                                      "When using static includes, ensure that any variables used in their names are defined in vars/vars_files\n" \
                                      "or extra-vars passed in from the command line. Static includes cannot use variables from inventory\n" \
                                      "sources like group or host vars." % t.args['_raw_params'],
                                      obj=task_ds,
                                      suppress_extended_error=True,
                                  )
                        if t._role:
                            if use_handlers:
                                include_file = loader.path_dwim_relative(t._role._role_path, 'handlers', include_target)
                            else:
                                include_file = loader.path_dwim_relative(t._role._role_path, 'tasks', include_target)
                        else:
                            include_file = loader.path_dwim(include_target)

                    try:
                        data = loader.load_from_file(include_file)
                        if data is None:
                            return []
                        elif not isinstance(data, list):
                            raise AnsibleError("included task files must contain a list of tasks", obj=data)
                    except AnsibleFileNotFound as e:
                        if t.static or \
                           C.DEFAULT_TASK_INCLUDES_STATIC or \
                           C.DEFAULT_HANDLER_INCLUDES_STATIC and use_handlers:
                            raise
                        display.deprecated(
                            "Included file '%s' not found, however since this include is not " \
                            "explicitly marked as 'static: yes', we will try and include it dynamically " \
                            "later. In the future, this will be an error unless 'static: no' is used " \
                            "on the include task. If you do not want missing includes to be considered " \
                            "dynamic, use 'static: yes' on the include or set the global ansible.cfg " \
                            "options to make all inclues static for tasks and/or handlers" % include_file,
                        )
                        task_list.append(t)
                        continue

                    included_blocks = load_list_of_blocks(
                        data,
                        play=play,
                        parent_block=block,
                        task_include=t,
                        role=role,
                        use_handlers=use_handlers,
                        loader=loader,
                        variable_manager=variable_manager,
                    )

                    # pop tags out of the include args, if they were specified there, and assign
                    # them to the include. If the include already had tags specified, we raise an
                    # error so that users know not to specify them both ways
                    tags = t.vars.pop('tags', [])
                    if isinstance(tags, string_types):
                        tags = tags.split(',')

                    if len(tags) > 0:
                        if len(t.tags) > 0:
                            raise AnsibleParserError(
                                "Include tasks should not specify tags in more than one way (both via args and directly on the task)." \
                                " Mixing tag specify styles is prohibited for whole import hierarchy, not only for single import statement",
                                obj=task_ds,
                                suppress_extended_error=True,
                            )
                        display.deprecated("You should not specify tags in the include parameters. All tags should be specified using the task-level option")
                    else:
                        tags = t.tags[:]

                    # now we extend the tags on each of the included blocks
                    for b in included_blocks:
                        b.tags = list(set(b.tags).union(tags))
                    # END FIXME

                    # FIXME: send callback here somehow...
                    # FIXME: handlers shouldn't need this special handling, but do
                    #        right now because they don't iterate blocks correctly
                    if use_handlers:
                        for b in included_blocks:
                            task_list.extend(b.block)
                    else:
                        task_list.extend(included_blocks)
                else:
                    task_list.append(t)
            elif use_handlers:
                t = Handler.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader)
                task_list.append(t)
            else:
                t = Task.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader)
                task_list.append(t)

    return task_list
Exemple #21
0
 def test_task_include_with_tags(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml', tags="foo"),
                           loader=self._fake_loader)
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml',
                                          tags=["foo", "bar"]),
                           loader=self._fake_loader)
Exemple #22
0
 def test_task_include_with_conditional(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml', when="1 == 1"),
                           loader=self._fake_loader)
Exemple #23
0
 def test_task_include_with_loop(self):
     ti = TaskInclude.load(AnsibleMapping(include='foo.yml',
                                          with_items=['a', 'b', 'c']),
                           loader=self._fake_loader)
Exemple #24
0
 def test_empty_task_include(self):
     ti = TaskInclude()
Exemple #25
0
def load_list_of_tasks(ds,
                       play,
                       block=None,
                       role=None,
                       task_include=None,
                       use_handlers=False,
                       variable_manager=None,
                       loader=None):
    '''
    Given a list of task datastructures (parsed from YAML),
    return a list of Task() or TaskInclude() objects.
    '''

    # we import here to prevent a circular dependency with imports
    from ansible.playbook.block import Block
    from ansible.playbook.handler import Handler
    from ansible.playbook.task import Task
    from ansible.playbook.task_include import TaskInclude
    from ansible.playbook.handler_task_include import HandlerTaskInclude
    from ansible.template import Templar

    assert isinstance(ds, list)

    task_list = []
    for task_ds in ds:
        assert isinstance(task_ds, dict)

        if 'block' in task_ds:
            t = Block.load(
                task_ds,
                play=play,
                parent_block=block,
                role=role,
                task_include=None,
                use_handlers=use_handlers,
                variable_manager=variable_manager,
                loader=loader,
            )
            task_list.append(t)
        else:
            if 'include' in task_ds:
                if use_handlers:
                    t = HandlerTaskInclude.load(
                        task_ds,
                        block=block,
                        role=role,
                        task_include=task_include,
                        variable_manager=variable_manager,
                        loader=loader)
                else:
                    t = TaskInclude.load(task_ds,
                                         block=block,
                                         role=role,
                                         task_include=task_include,
                                         variable_manager=variable_manager,
                                         loader=loader)
                all_vars = variable_manager.get_vars(loader=loader,
                                                     play=play,
                                                     task=t)
                templar = Templar(loader=loader, variables=all_vars)

                # 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 t.static is not None:
                    is_static = t.static
                else:
                    is_static = C.DEFAULT_TASK_INCLUDES_STATIC or \
                                (use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \
                                (not templar._contains_vars(t.args['_raw_params']) and t.all_parents_static() and not t.loop)

                if is_static:
                    if t.loop is not None:
                        raise AnsibleParserError(
                            "You cannot use 'static' on an include with a loop",
                            obj=task_ds)

                    # we set a flag to indicate this include was static
                    t.statically_loaded = True

                    # handle relative includes by walking up the list of parent include
                    # tasks and checking the relative result to see if it exists
                    parent_include = task_include
                    cumulative_path = None

                    found = False
                    while parent_include is not None:
                        parent_include_dir = templar.template(
                            os.path.dirname(
                                parent_include.args.get('_raw_params')))
                        if cumulative_path is None:
                            cumulative_path = parent_include_dir
                        elif not os.path.isabs(cumulative_path):
                            cumulative_path = os.path.join(
                                parent_include_dir, cumulative_path)
                        include_target = templar.template(
                            t.args['_raw_params'])
                        if t._role:
                            new_basedir = os.path.join(t._role._role_path,
                                                       'tasks',
                                                       cumulative_path)
                            include_file = loader.path_dwim_relative(
                                new_basedir, 'tasks', include_target)
                        else:
                            include_file = loader.path_dwim_relative(
                                loader.get_basedir(), cumulative_path,
                                include_target)

                        if os.path.exists(include_file):
                            found = True
                            break
                        else:
                            parent_include = parent_include._task_include

                    if not found:
                        try:
                            include_target = templar.template(
                                t.args['_raw_params'])
                        except AnsibleUndefinedVariable as e:
                            raise AnsibleParserError(
                                      "Error when evaluating variable in include name: %s.\n\n" \
                                      "When using static includes, ensure that any variables used in their names are defined in vars/vars_files\n" \
                                      "or extra-vars passed in from the command line. Static includes cannot use variables from inventory\n" \
                                      "sources like group or host vars." % t.args['_raw_params'],
                                      obj=task_ds,
                                      suppress_extended_error=True,
                                  )
                        if t._role:
                            if use_handlers:
                                include_file = loader.path_dwim_relative(
                                    t._role._role_path, 'handlers',
                                    include_target)
                            else:
                                include_file = loader.path_dwim_relative(
                                    t._role._role_path, 'tasks',
                                    include_target)
                        else:
                            include_file = loader.path_dwim(include_target)

                    try:
                        data = loader.load_from_file(include_file)
                        if data is None:
                            return []
                        elif not isinstance(data, list):
                            raise AnsibleError(
                                "included task files must contain a list of tasks",
                                obj=data)

                        # since we can't send callbacks here, we display a message directly in
                        # the same fashion used by the on_include callback. We also do it here,
                        # because the recursive nature of helper methods means we may be loading
                        # nested includes, and we want the include order printed correctly
                        display.display("statically included: %s" %
                                        include_file,
                                        color=C.COLOR_SKIP)
                    except AnsibleFileNotFound as e:
                        if t.static or \
                           C.DEFAULT_TASK_INCLUDES_STATIC or \
                           C.DEFAULT_HANDLER_INCLUDES_STATIC and use_handlers:
                            raise
                        display.deprecated(
                            "Included file '%s' not found, however since this include is not " \
                            "explicitly marked as 'static: yes', we will try and include it dynamically " \
                            "later. In the future, this will be an error unless 'static: no' is used " \
                            "on the include task. If you do not want missing includes to be considered " \
                            "dynamic, use 'static: yes' on the include or set the global ansible.cfg " \
                            "options to make all inclues static for tasks and/or handlers" % include_file,
                        )
                        task_list.append(t)
                        continue

                    included_blocks = load_list_of_blocks(
                        data,
                        play=play,
                        parent_block=block,
                        task_include=t,
                        role=role,
                        use_handlers=use_handlers,
                        loader=loader,
                        variable_manager=variable_manager,
                    )

                    # pop tags out of the include args, if they were specified there, and assign
                    # them to the include. If the include already had tags specified, we raise an
                    # error so that users know not to specify them both ways
                    tags = t.vars.pop('tags', [])
                    if isinstance(tags, string_types):
                        tags = tags.split(',')

                    if len(tags) > 0:
                        if len(t.tags) > 0:
                            raise AnsibleParserError(
                                "Include tasks should not specify tags in more than one way (both via args and directly on the task)." \
                                " Mixing tag specify styles is prohibited for whole import hierarchy, not only for single import statement",
                                obj=task_ds,
                                suppress_extended_error=True,
                            )
                        display.deprecated(
                            "You should not specify tags in the include parameters. All tags should be specified using the task-level option"
                        )
                    else:
                        tags = t.tags[:]

                    # now we extend the tags on each of the included blocks
                    for b in included_blocks:
                        b.tags = list(set(b.tags).union(tags))
                    # END FIXME

                    # FIXME: handlers shouldn't need this special handling, but do
                    #        right now because they don't iterate blocks correctly
                    if use_handlers:
                        for b in included_blocks:
                            task_list.extend(b.block)
                    else:
                        task_list.extend(included_blocks)
                else:
                    task_list.append(t)
            else:
                if use_handlers:
                    t = Handler.load(task_ds,
                                     block=block,
                                     role=role,
                                     task_include=task_include,
                                     variable_manager=variable_manager,
                                     loader=loader)
                else:
                    t = Task.load(task_ds,
                                  block=block,
                                  role=role,
                                  task_include=task_include,
                                  variable_manager=variable_manager,
                                  loader=loader)
                task_list.append(t)

    return task_list