def test_process_include_simulate_free(mock_iterator, mock_variable_manager): hostname = "testhost1" hostname2 = "testhost2" parent_task_ds = {'debug': 'msg=foo'} parent_task1 = Task.load(parent_task_ds) parent_task2 = Task.load(parent_task_ds) task_ds = {'include': 'include_test.yml'} loaded_task1 = TaskInclude.load(task_ds, task_include=parent_task1) loaded_task2 = TaskInclude.load(task_ds, task_include=parent_task2) 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_task1, return_data=return_data) result2 = task_result.TaskResult(host=hostname2, task=loaded_task2, return_data=return_data) results = [result1, result2] fake_loader = DictDataLoader({'include_test.yml': ""}) res = IncludedFile.process_include_results(results, mock_iterator, fake_loader, mock_variable_manager) assert isinstance(res, list) assert len(res) == 2 assert res[0]._filename == os.path.join(os.getcwd(), 'include_test.yml') assert res[1]._filename == os.path.join(os.getcwd(), 'include_test.yml') assert res[0]._hosts == ['testhost1'] assert res[1]._hosts == ['testhost2'] assert res[0]._args == {} assert res[1]._args == {}
def test_collection_invalid_data_task(): """Test that collection as a dict at the task level fails with parser error""" collection_name = {'name': 'foo'} with pytest.raises(AnsibleParserError): Task.load(dict( name="test task", collections=collection_name, ))
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 load_list_of_tasks(ds, 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 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 'block' in task: t = Block.load( task, parent_block=block, role=role, task_include=task_include, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader, ) else: if use_handlers: t = Handler.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) else: t = Task.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader)
def _load_list_of_tasks(self, ds): assert type(ds) == list task_list = [] for task in ds: t = Task.load(task) task_list.append(t) return task_list
def test_load_task_kv_form_error_36848(self, mock_get_err_lines): ds = objects.AnsibleMapping(kv_bad_args_ds) ds.ansible_pos = ('test_task_faux_playbook.yml', 1, 1) mock_get_err_lines.return_value = (kv_bad_args_str, '') with self.assertRaises(errors.AnsibleParserError) as cm: Task.load(ds) self.assertIsInstance(cm.exception, errors.AnsibleParserError) self.assertEqual(cm.exception.obj, ds) self.assertEqual(cm.exception.obj, kv_bad_args_ds) self.assertIn("The error appears to be in 'test_task_faux_playbook.yml", cm.exception.message) self.assertIn(kv_bad_args_str, cm.exception.message) self.assertIn('apk', cm.exception.message) self.assertEqual(cm.exception.message.count('The offending line'), 1) self.assertEqual(cm.exception.message.count('The error appears to be in'), 1)
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
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 assert isinstance(ds, list) task_list = [] for task in ds: assert isinstance(task, dict) if 'block' in task: t = Block.load( task, play=play, parent_block=block, role=role, task_include=task_include, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader, ) else: if use_handlers: t = Handler.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) else: t = Task.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) task_list.append(t) return task_list
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
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)
def check_tasks(file): """Parse a tasks file.""" print(file) errors = [] with open(file) as f: data = yaml.load(f) # If data is None it means is not a valid YAML file if data: for ds in get_tasks(data): try: task = Task.load(ds, variable_manager=variable_manager, loader=loader) route_class = [ 'modules', 'connection', 'module_utils', 'cliconf', 'terminal', 'action', 'become', 'cache', 'callback', 'doc_fragments', 'filter', 'httpapi', 'inventory', 'lookup', 'netconf', 'shell', 'test' ] for route in route_class: module = routing[route].get(task.action, {}).get('redirect') if module: errors.append( (file, task.action, "this task should be called as: " + str(module))) break print(task.action) if '.' not in task.action: errors.append((file, task.action, "all tasks must have dots in namespace")) if task.action == 'ansible.builtin.shell': if 'executable' not in task._attributes['args']: errors.append(( file, task.action, "must define the executable as an args, like /bin/bash" )) except AnsibleParserError: pass except Exception: pass return errors
def load_list_of_tasks(ds, 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.handler import Handler 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, # use_handlers=use_handlers, # loader=loader # ) # if cur_basedir and loader: # loader.set_basedir(cur_basedir) #else: if True: if use_handlers: t = Handler.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) else: t = Task.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) task_list.append(t) return task_list
def create_action_module(name, args=None, task_vars=None): play = Play.load(dict()) play_context = PlayContext(play=play) module = LintActionModule(task=Task.load(data=dict(local_action=name, args=args), block=Block(play=play)), connection=Connection(play_context, new_stdin=False), play_context=play_context, loader=play._loader, templar=Templar(play._loader), shared_loader_obj=None) module.use_display(NullDisplay()) return module
def TestInput(input_bytes): if len(input_bytes) < 5: return fdp = atheris.FuzzedDataProvider(input_bytes) try: task = Task.load({ 'name': fdp.ConsumeString(10), 'shell': fdp.ConsumeString(10), 'action': fdp.ConsumeString(10), 'debug': fdp.ConsumeString(10) }) task.get_vars() task.get_include_params() task.copy() data = task.serialize() task.deserialize(data) except (AnsibleError, AnsibleParserError, AnsibleUndefinedVariable) as e: pass
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 assert isinstance(ds, list) task_list = [] for task in ds: assert isinstance(task, dict) if 'block' in task: t = Block.load( task, play=play, parent_block=block, role=role, task_include=task_include, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader, ) else: if use_handlers: t = Handler.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader, play=play) else: t = Task.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) if isinstance(t, list): task_list.extend(t) else: task_list.append(t) return task_list
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 if not isinstance(ds, list): raise AnsibleParserError('task has bad type: "%s". Expected "list"' % type(ds).__name__, obj=ds) task_list = [] for task in ds: if not isinstance(task, dict): raise AnsibleParserError('task/handler has bad type: "%s". Expected "dict"' % type(task).__name__, obj=task) if 'block' in task: t = Block.load( task, play=play, parent_block=block, role=role, task_include=task_include, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader, ) else: if use_handlers: t = Handler.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) else: t = Task.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) task_list.append(t) return task_list
def check_tasks(file): """Parse a tasks file.""" print(file) errors = [] with open(file) as f: data = yaml.load(f) # If data is None it means is not a valid YAML file if data: for ds in get_tasks(data): try: task = Task.load(ds, variable_manager=variable_manager, loader=loader) route_class = [ 'modules', 'connection', 'module_utils', 'cliconf', 'terminal', 'action', 'become', 'cache', 'callback', 'doc_fragments', 'filter', 'httpapi', 'inventory', 'lookup', 'netconf', 'shell', 'test' ] for route in route_class: module = routing[route].get(task.action, {}).get('redirect') if module: errors.append((file, task.action, module)) break print(task.action) if '.' not in task.action: errors.append((file, task.action, "no dot in namespace")) except AnsibleParserError: pass except Exception: pass return errors
def test_task_auto_name(self): assert 'name' not in kv_shell_task t = Task.load(kv_shell_task)
def test_load_task_kv_form(self): t = Task.load(kv_shell_task) print("task action is %s" % t.action) self.assertEqual(t.action, 'command') self.assertEqual(t.args, dict(_raw_params='echo hi', _uses_shell=True))
def test_load_task_simple(self): t = Task.load(basic_shell_task) assert t is not None self.assertEqual(t.name, basic_shell_task['name']) self.assertEqual(t.action, 'command') self.assertEqual(t.args, dict(_raw_params='echo hi', _uses_shell=True))
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.role_include import IncludeRole from ansible.playbook.handler_task_include import HandlerTaskInclude from ansible.template import Templar if not isinstance(ds, list): raise AnsibleAssertionError( 'The ds (%s) should be a list but was a %s' % (ds, type(ds))) task_list = [] for task_ds in ds: if not isinstance(task_ds, dict): raise AnsibleAssertionError( 'The ds (%s) should be a dict but was a %s' % (ds, type(ds))) 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: args_parser = ModuleArgsParser(task_ds) try: (action, args, delegate_to) = args_parser.parse(skip_action_validation=True) except AnsibleParserError as e: # if the raises exception was created with obj=ds args, then it includes the detail # so we dont need to add it so we can just re raise. if e.obj: raise # 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 C._ACTION_ALL_INCLUDE_IMPORT_TASKS: if use_handlers: include_class = HandlerTaskInclude else: include_class = TaskInclude t = include_class.load(task_ds, block=block, role=role, task_include=None, variable_manager=variable_manager, loader=loader) all_vars = variable_manager.get_vars(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 action in C._ACTION_INCLUDE_TASKS: is_static = False elif action in C._ACTION_IMPORT_TASKS: is_static = True else: display.deprecated( '"include" is deprecated, use include_tasks/import_tasks instead', "2.16") is_static = not templar.is_template( t.args['_raw_params']) and t.all_parents_static( ) and not t.loop if is_static: if t.loop is not None: 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) # 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 = block cumulative_path = None found = False subdir = 'tasks' if use_handlers: subdir = 'handlers' while parent_include is not None: if not isinstance(parent_include, TaskInclude): parent_include = parent_include._parent continue try: parent_include_dir = os.path.dirname( templar.template( parent_include.args.get('_raw_params'))) except AnsibleUndefinedVariable as e: if not parent_include.statically_loaded: raise AnsibleParserError( "Error when evaluating variable in dynamic parent include path: %s. " "When using static imports, the parent dynamic include cannot utilize host facts " "or variables from inventory" % parent_include.args.get('_raw_params'), obj=task_ds, suppress_extended_error=True, orig_exc=e) raise 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, subdir, cumulative_path) include_file = loader.path_dwim_relative( new_basedir, subdir, 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._parent if not found: try: include_target = templar.template( t.args['_raw_params']) except AnsibleUndefinedVariable as e: raise AnsibleParserError( "Error when evaluating variable in import path: %s.\n\n" "When using static imports, 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 imports cannot use variables from facts or inventory\n" "sources like group or host vars." % t.args['_raw_params'], obj=task_ds, suppress_extended_error=True, orig_exc=e) if t._role: include_file = loader.path_dwim_relative( t._role._role_path, subdir, include_target) else: include_file = loader.path_dwim(include_target) data = loader.load_from_file(include_file) if not data: display.warning( 'file %s is empty and had no tasks to include' % include_file) continue elif not isinstance(data, list): raise AnsibleParserError( "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.vv("statically imported: %s" % include_file) ti_copy = t.copy(exclude_parent=True) ti_copy._parent = block included_blocks = load_list_of_blocks( data, play=play, parent_block=None, task_include=ti_copy, role=role, use_handlers=use_handlers, loader=loader, variable_manager=variable_manager, ) tags = ti_copy.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: t.is_static = False task_list.append(t) elif action in C._ACTION_ALL_PROPER_INCLUDE_IMPORT_ROLES: ir = IncludeRole.load( task_ds, block=block, role=role, task_include=None, variable_manager=variable_manager, loader=loader, ) # 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 in C._ACTION_IMPORT_ROLE: is_static = True if is_static: if ir.loop is not None: 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) # we set a flag to indicate this include was static ir.statically_loaded = True # template the role name now, if needed all_vars = variable_manager.get_vars(play=play, task=ir) templar = Templar(loader=loader, variables=all_vars) ir._role_name = templar.template(ir._role_name) # uses compiled list from object blocks, _ = ir.get_block_list( variable_manager=variable_manager, loader=loader) task_list.extend(blocks) else: # passes task object itself for latter generation of list task_list.append(ir) 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
def test_load_task_simple(self): t = Task.load(basic_shell_task) assert t is not None assert t.name == basic_shell_task['name'] assert t.action == 'shell' assert t.args == 'echo hi'
def test_load_task_kv_form(self): t = Task.load(kv_shell_task) assert t.action == 'shell'
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 if not isinstance(ds, list): raise AnsibleAssertionError( 'The ds (%s) should be a list but was a %s' % (ds, type(ds))) task_list = [] for task_ds in ds: if not isinstance(task_ds, dict): raise AnsibleAssertionError( 'The ds (%s) should be a dict but was a %s' % (ds, type(ds))) 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: args_parser = ModuleArgsParser(task_ds) try: (action, args, delegate_to) = args_parser.parse(skip_action_validation=True) except AnsibleParserError as e: # if the raises exception was created with obj=ds args, then it includes the detail # so we dont need to add it so we can just re raise. if e._obj: raise # 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'): task_list = _list_action_in_task( task_ds, play, action, task_list, block=block, role=role, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader) elif action in ('include_role', 'import_role'): task_list = _list_action_in_role( task_ds, play, action, task_list, block=block, role=role, variable_manager=variable_manager, loader=loader) 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
def test_load_task_simple(self): t = Task.load(basic_command_task) assert t is not None self.assertEqual(t.name, basic_command_task['name']) self.assertEqual(t.action, 'command') self.assertEqual(t.args, dict(_raw_params='echo hi'))
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.role_include import IncludeRole 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=task_include, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader, ) task_list.append(t) else: if 'include' in task_ds: if use_handlers: include_class = HandlerTaskInclude else: include_class = TaskInclude t = include_class.load(task_ds, block=block, role=role, task_include=None, 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 = block cumulative_path = None found = False subdir = 'tasks' if use_handlers: subdir = 'handlers' while parent_include is not None: if not isinstance(parent_include, TaskInclude): parent_include = parent_include._parent continue 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, subdir, cumulative_path) include_file = loader.path_dwim_relative( new_basedir, subdir, 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._parent if not found: try: include_target = templar.template( t.args['_raw_params']) except AnsibleUndefinedVariable: 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: include_file = loader.path_dwim_relative( t._role._role_path, subdir, 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 AnsibleParserError( "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.vv("statically included: %s" % include_file) except AnsibleFileNotFound: 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=None, task_include=t.copy(), 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 styles in which tags are specified 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) elif 'include_role' in task_ds: ir = IncludeRole.load(task_ds, block=block, role=role, task_include=None, variable_manager=variable_manager, loader=loader) # 1. the user has set the 'static' option to false or true # 2. one of the appropriate config options was set if ir.static is not None: is_static = ir.static else: display.debug('Determine if include_role is static') # Check to see if this include is dynamic or static: all_vars = variable_manager.get_vars(loader=loader, play=play, task=ir) templar = Templar(loader=loader, variables=all_vars) needs_templating = False for param in ir.args: if templar._contains_vars(ir.args[param]): if not templar.templatable(ir.args[param]): needs_templating = True break is_static = C.DEFAULT_TASK_INCLUDES_STATIC or \ (use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \ (not needs_templating and ir.all_parents_static() and not ir.loop) display.debug( 'Determined that if include_role static is %s' % str(is_static)) if is_static: # uses compiled list from object t = task_list.extend( ir.get_block_list(variable_manager=variable_manager, loader=loader)) else: # passes task object itself for latter generation of list t = task_list.append(ir) 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
def load_list_of_tasks(ds, 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.handler import Handler 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.ansible_pos # 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, # use_handlers=use_handlers, # loader=loader # ) # if cur_basedir and loader: # loader.set_basedir(cur_basedir) #else: if True: if use_handlers: t = Handler.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) else: t = Task.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) task_list.append(t) return task_list
def test_can_auto_name(self): assert 'name' not in kv_shell_task t = Task.load(kv_shell_task) print "GOT NAME=(%s)" % t.name assert t.name == 'shell echo hi'
def test_load_task_simple(self): t = Task.load(basic_shell_task) assert t is not None self.assertEqual(t.name, basic_shell_task["name"]) self.assertEqual(t.action, "command") self.assertEqual(t.args, dict(_raw_params="echo hi", _uses_shell=True))
if 'block' in task: t = Block.load( task, parent_block=block, role=role, task_include=task_include, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader, ) else: >>>>>>> remote if use_handlers: t = Handler.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) else: t = Task.load(task, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader) task_list.append(t) return task_list def load_list_of_roles(ds, current_role_path=None, variable_manager=None, loader=None): ''' Loads and returns a list of RoleInclude objects from the datastructure list of role definitions ''' # we import here to prevent a circular dependency with imports from ansible.playbook.role.include import RoleInclude
def test_pire_agent(spire_runners: SpireRunners, test_case: str, initial_state: StateOfAgent, expected_state: StateOfAgent, outcome_part: Dict[str, Any], expected_local_probing: Dict[str, Any]) -> None: server_runner: ServerRunner = spire_runners.server agent_runner: AgentRunner = spire_runners.agent server_runner.install_and_start(spire_version=test_data.spire_version, must_be_ready=True) file_modes = FileModes(mode_dir="u=xrw,g=xrw,o=", mode_file_not_exe="u=rw,g=rw,o=", mode_file_exe="u=xrw,g=xr,o=xr") #spire_runners.to_server_initial_state(initial_state, initial_version, file_modes) spire_runners.to_agent_initial_state(initial_state, test_data.spire_version, file_modes) inventory, data_loader, var_manager = give_inventory_and_data_loader() play: Play = Play.load({"hosts": "spire_agent"}, variable_manager=var_manager, loader=data_loader) play_context = PlayContext(play=play) # ansible.plugins.connection.local.Connection connection: Connection = connection_loader.get('local', play_context, os.devnull) data: Dict[str, Any] = { "name": "spire-agent-local1", "io_patricecongo.spire.spire_agent": { "state": expected_state.state.name, "substate_service_installation": expected_state.substate_service_installation_name(), "substate_service_status": expected_state.substate_service_status_name(), "substate_agent_registered": expected_state.substate_agent_registered_name(), "spire_server_host": "spire_server", "spire_server_install_dir": server_runner.dir_install, "spire_server_registration_uds_path": server_runner.registration_uds_path, "spire_server_address": server_runner.bind_address, "spire_server_port": server_runner.bind_port, "spire_agent_config_dir": agent_runner.dir_config, "spire_agent_data_dir": agent_runner.dir_data, "spire_agent_install_dir": agent_runner.dir_install, "spire_agent_service_dir": agent_runner.service.install_dir, "spire_agent_log_dir": agent_runner.dir_log, "spire_agent_install_file_owner": None, "spire_agent_install_dir_mode": file_modes.mode_dir, "spire_agent_install_file_mode": file_modes.mode_file_not_exe, # "u=rw,g=rw", "spire_agent_install_file_mode_exe": file_modes.mode_file_exe, # "u=xrw,g=xr,o=xr", "spire_agent_version": test_data.spire_version, "spire_agent_additional_spiffe_id": agent_runner.additional_spiffe_id, "spire_agent_join_token_ttl": agent_runner.join_token_ttl, "spire_agent_log_level": "DEBUG", "spire_agent_trust_domain": server_runner.trust_domain, "spire_agent_socket_path": agent_runner.socket_path, "spire_agent_service_name": agent_runner.service.service_name, "spire_agent_service_scope": "user", "spire_agent_healthiness_probe_timeout_seconds": 5, "spire_download_url": server_runner.url_dist_tar_gz(test_data.spire_version), } } task: Task = Task.load(data=data, variable_manager=var_manager, loader=data_loader) all_vars = var_manager.get_vars(play=play, task=task, host=inventory.get_host("localhost")) templar = Templar(loader=data_loader, shared_loader_obj=plugins_loader, variables=None) action = spire_agent.ActionModule(task=task, connection=connection, play_context=play_context, loader=data_loader, templar=templar, shared_loader_obj=plugins_loader) action._low_level_execute_command = functools.partial( _low_level_execute_command, action._low_level_execute_command) ### ret = action.run(task_vars=all_vars) ### keys_to_check = [ 'changed', 'actual_state', 'actual_substate_agent_registered', 'actual_substate_service_installation', 'actual_substate_service_status', 'actual_spire_agent_version', "failed" ] assert { **expected_state.to_ansible_return_data(), **outcome_part } == {key: ret.get(key) for key in keys_to_check} agent_health_res = agent_runner.is_healthy() agent_srv_running_res = agent_runner.service.is_active() agent_srv_enabled_res = agent_runner.service.is_enabled() assert expected_local_probing == { "healthy": agent_health_res.res, "enabled": agent_srv_enabled_res.res, "running": agent_srv_running_res.res }, \ { "ret": ret, "health": agent_health_res, "enabled": agent_srv_enabled_res, "running": agent_srv_running_res, "expected_local_probing": expected_local_probing } ### check-mode diff data["check_mode"] = True data["diff"] = True task = Task.load(data=data, variable_manager=var_manager, loader=data_loader) all_vars = var_manager.get_vars(play=play, task=task, host=inventory.get_host("localhost")) action = spire_agent.ActionModule(task=task, connection=connection, play_context=play_context, loader=data_loader, templar=templar, shared_loader_obj=plugins_loader) server_runner.register_extra_cleanup_task(action.cleanup) action._low_level_execute_command = functools.partial( _low_level_execute_command, action._low_level_execute_command) ret = action.run(task_vars={**all_vars}) ### assert ret == {"changed":False, "diff": []}, \ { "actual": ret, "expected":{"changed":False, "diff": []} }
def test_task_auto_name(self): assert 'name' not in kv_command_task Task.load(kv_command_task)
def test_load_task_kv_form(self): t = Task.load(kv_shell_task) self.assertEqual(t.action, "command") self.assertEqual(t.args, dict(_raw_params="echo hi", _uses_shell=True))
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
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.role_include import IncludeRole 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=task_include, use_handlers=use_handlers, variable_manager=variable_manager, loader=loader, ) task_list.append(t) else: if 'include' in task_ds: if use_handlers: include_class = HandlerTaskInclude else: include_class = TaskInclude t = include_class.load( task_ds, block=block, role=role, task_include=None, 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 = block cumulative_path = None found = False subdir = 'tasks' if use_handlers: subdir = 'handlers' while parent_include is not None: if not isinstance(parent_include, TaskInclude): parent_include = parent_include._parent continue 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, subdir, cumulative_path) include_file = loader.path_dwim_relative(new_basedir, subdir, 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._parent if not found: try: include_target = templar.template(t.args['_raw_params']) except AnsibleUndefinedVariable: 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: include_file = loader.path_dwim_relative(t._role._role_path, subdir, 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 AnsibleParserError("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.vv("statically included: %s" % include_file) except AnsibleFileNotFound: 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=None, task_include=t.copy(), 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 styles in which tags are specified 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) elif 'include_role' in task_ds: ir = IncludeRole.load( task_ds, block=block, role=role, task_include=None, variable_manager=variable_manager, loader=loader ) # 1. the user has set the 'static' option to false or true # 2. one of the appropriate config options was set if ir.static is not None: is_static = ir.static else: display.debug('Determine if include_role is static') # Check to see if this include is dynamic or static: all_vars = variable_manager.get_vars(loader=loader, play=play, task=ir) templar = Templar(loader=loader, variables=all_vars) needs_templating = False for param in ir.args: if templar._contains_vars(ir.args[param]): if not templar.templatable(ir.args[param]): needs_templating = True break is_static = C.DEFAULT_TASK_INCLUDES_STATIC or \ (use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \ (not needs_templating and ir.all_parents_static() and not ir.loop) display.debug('Determined that if include_role static is %s' % str(is_static)) if is_static: # uses compiled list from object t = task_list.extend(ir.get_block_list(variable_manager=variable_manager, loader=loader)) else: # passes task object itself for latter generation of list t = task_list.append(ir) 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
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.role_include import IncludeRole from ansible.playbook.handler_task_include import HandlerTaskInclude from ansible.template import Templar if not isinstance(ds, list): raise AnsibleAssertionError( 'The ds (%s) should be a list but was a %s' % (ds, type(ds))) task_list = [] for task_ds in ds: if not isinstance(task_ds, dict): raise AnsibleAssertionError( 'The ds (%s) should be a dict but was a %s' % (ds, type(ds))) 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: args_parser = ModuleArgsParser(task_ds) try: (action, args, delegate_to) = args_parser.parse(skip_action_validation=True) except AnsibleParserError as e: # if the raises exception was created with obj=ds args, then it includes the detail # so we dont need to add it so we can just re raise. if e._obj: raise # 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 use_handlers: include_class = HandlerTaskInclude else: include_class = TaskInclude t = include_class.load(task_ds, block=block, role=role, task_include=None, variable_manager=variable_manager, loader=loader) all_vars = variable_manager.get_vars(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 action == 'include_tasks': is_static = False elif action == 'import_tasks': is_static = True elif t.static is not None: display.deprecated( "The use of 'static' has been deprecated. " "Use 'import_tasks' for static inclusion, or 'include_tasks' for dynamic inclusion", version='ansible.builtin:2.12') is_static = t.static else: is_static = C.DEFAULT_TASK_INCLUDES_STATIC or \ (use_handlers and C.DEFAULT_HANDLER_INCLUDES_STATIC) or \ (not templar.is_template(t.args['_raw_params']) and t.all_parents_static() and not t.loop) if is_static: if t.loop is not None: if 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) # 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 = block cumulative_path = None found = False subdir = 'tasks' if use_handlers: subdir = 'handlers' while parent_include is not None: if not isinstance(parent_include, TaskInclude): parent_include = parent_include._parent continue try: parent_include_dir = os.path.dirname( templar.template( parent_include.args.get('_raw_params'))) except AnsibleUndefinedVariable as e: if not parent_include.statically_loaded: raise AnsibleParserError( "Error when evaluating variable in dynamic parent include path: %s. " "When using static imports, the parent dynamic include cannot utilize host facts " "or variables from inventory" % parent_include.args.get('_raw_params'), obj=task_ds, suppress_extended_error=True, orig_exc=e) raise 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, subdir, cumulative_path) include_file = loader.path_dwim_relative( new_basedir, subdir, 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._parent if not found: try: include_target = templar.template( t.args['_raw_params']) except AnsibleUndefinedVariable as e: raise AnsibleParserError( "Error when evaluating variable in import path: %s.\n\n" "When using static imports, 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 imports cannot use variables from facts or inventory\n" "sources like group or host vars." % t.args['_raw_params'], obj=task_ds, suppress_extended_error=True, orig_exc=e) if t._role: include_file = loader.path_dwim_relative( t._role._role_path, subdir, include_target) else: include_file = loader.path_dwim(include_target) try: data = loader.load_from_file(include_file) if data is None: display.warning( 'file %s is empty and had no tasks to include' % include_file) continue elif not isinstance(data, list): raise AnsibleParserError( "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.vv("statically imported: %s" % include_file) except AnsibleFileNotFound: if action != 'include' or 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 includes static for tasks and/or handlers" % include_file, version="ansible.builtin:2.12") task_list.append(t) continue ti_copy = t.copy(exclude_parent=True) ti_copy._parent = block included_blocks = load_list_of_blocks( data, play=play, parent_block=None, task_include=ti_copy, role=role, use_handlers=use_handlers, loader=loader, variable_manager=variable_manager, ) # FIXME: remove once 'include' is removed # 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 = ti_copy.vars.pop('tags', []) if isinstance(tags, string_types): tags = tags.split(',') if len(tags) > 0: if action in ('include_tasks', '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( "Include tasks should not specify tags in more than one way (both via args and directly on the task). " "Mixing styles in which tags are specified 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", version="ansible.builtin:2.12") else: tags = ti_copy.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: t.is_static = False task_list.append(t) elif action in ('include_role', 'import_role'): ir = IncludeRole.load( task_ds, block=block, role=role, task_include=None, variable_manager=variable_manager, loader=loader, ) # 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': is_static = True elif ir.static is not None: display.deprecated( "The use of 'static' for 'include_role' has been deprecated. " "Use 'import_role' for static inclusion, or 'include_role' for dynamic inclusion", version='ansible.builtin:2.12') is_static = ir.static if is_static: if ir.loop is not None: if 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) # we set a flag to indicate this include was static ir.statically_loaded = True # template the role name now, if needed all_vars = variable_manager.get_vars(play=play, task=ir) templar = Templar(loader=loader, variables=all_vars) ir._role_name = templar.template(ir._role_name) # uses compiled list from object blocks, _ = ir.get_block_list( variable_manager=variable_manager, loader=loader) task_list.extend(blocks) else: # passes task object itself for latter generation of list task_list.append(ir) 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
def test_load_task_kv_form(self): t = Task.load(kv_shell_task) self.assertEqual(t.action, 'command') self.assertEqual(t.args, dict(_raw_params='echo hi', _uses_shell=True))
def test_load_task_kv_form(self): t = Task.load(kv_command_task) self.assertEqual(t.action, 'command') self.assertEqual(t.args, dict(_raw_params='echo hi'))
def test_pire_server(spire_runners: SpireRunners, test_case: str, initial_state: StateOfServer, initial_version: str, expected_state: StateOfServer, expected_outcome_part: Dict[str, Any], expected_local_probing: Dict[str, Any]) -> None: server_runner: ServerRunner = spire_runners.server file_modes = FileModes(mode_dir="u=xrw,g=xrw,o=", mode_file_not_exe="u=rw,g=rw,o=", mode_file_exe="u=xrw,g=xr,o=xr") spire_runners.to_server_initial_state(initial_state, initial_version, file_modes) # TODCHECK is expected_version being None an issue. # ? use a separate parameter, because this is not the same as the task parameter # ! but the task parameter should be allow to be None if expected state is absent expected_version: str = expected_outcome_part[ 'actual_spire_server_version'] inventory, data_loader, var_manager = give_inventory_and_data_loader() play: Play = Play.load({"hosts": "spire_server"}, variable_manager=var_manager, loader=data_loader) play_context = PlayContext(play=play) # ansible.plugins.connection.local.Connection connection: Connection = connection_loader.get('local', play_context, os.devnull) spire_download_url = None if strings.is_blank(expected_version) \ else server_runner.url_dist_tar_gz(expected_version) data: Dict[str, Any] = { "name": "spire-server-local1", "io_patricecongo.spire.spire_server": { "state": expected_state.state.name, "substate_service_installation": expected_state.substate_service_installation_name(), "substate_service_status": expected_state.substate_service_status_name(), "spire_server_install_dir": server_runner.dir_install, "spire_server_registration_uds_path": server_runner.registration_uds_path, "spire_server_address": server_runner.bind_address, "spire_server_port": server_runner.bind_port, "spire_server_config_dir": server_runner.dir_config, "spire_server_data_dir": server_runner.dir_data, "spire_server_install_dir": server_runner.dir_install, "spire_server_service_dir": server_runner.service.install_dir, "spire_server_log_dir": server_runner.dir_log, "spire_server_install_file_owner": None, "spire_server_install_dir_mode": file_modes.mode_dir, "spire_server_install_file_mode": file_modes.mode_file_not_exe, # "u=xrw,g=xrw", "spire_server_install_file_mode_exe": file_modes.mode_file_exe, # "u=xrw,g=xr,o=xr", "spire_server_version": expected_version, "spire_server_log_level": "DEBUG", "spire_server_log_format": "text", "spire_server_trust_domain": server_runner.trust_domain, "spire_server_service_name": server_runner.service.service_name, "spire_server_service_scope": "user", "spire_server_healthiness_probe_timeout_seconds": 5, "spire_download_url": spire_download_url, "spire_server_ca_key_type": "ec-p256", "spire_server_ca_ttl": "168h", "spire_server_ca_subject_commom_name": "unit-test-ca", "spire_server_ca_subject_country": "de", "spire_server_ca_subject_organization": "dev", "spire_server_jwt_issuer": "unit-test-ca", "spire_server_registration_uds_path": server_runner.registration_uds_path, "spire_server_plugins": [{ "type": "DataStore", "name": "sql", "data": { "database_type": "sqlite3", "connection_string": f"{server_runner.dir_data}/datastore.sqlite3" }, }, { "type": "KeyManager", "name": "disk", "data": { "keys_path": f"{server_runner.dir_data}/keys.json" } }, { "type": "NodeAttestor", "name": "join_token", "data": {} }] } } task: Task = Task.load(data=data, variable_manager=var_manager, loader=data_loader) all_vars = var_manager.get_vars(play=play, task=task, host=inventory.get_host("localhost")) templar = Templar(loader=data_loader, shared_loader_obj=plugins_loader, variables=None) action = spire_server.ActionModule(task=task, connection=connection, play_context=play_context, loader=data_loader, templar=templar, shared_loader_obj=plugins_loader) server_runner.register_extra_cleanup_task(action.cleanup) action._low_level_execute_command = functools.partial( _low_level_execute_command, action._low_level_execute_command) ### ret = action.run(task_vars=all_vars) ### keys_to_check = [ 'changed', 'actual_state', 'actual_substate_service_installation', 'actual_substate_service_status', 'actual_spire_server_version', "failed" ] assert { **expected_state.to_ansible_return_data(), **expected_outcome_part } == {key: ret.get(key) for key in keys_to_check} server_health_res = server_runner.is_healthy() server_srv_running_res = server_runner.service.is_active() server_srv_enabled_res = server_runner.service.is_enabled() assert expected_local_probing == { "healthy": server_health_res.res, "enabled": server_srv_enabled_res.res, "running": server_srv_running_res.res }, \ { "ret": ret, "health": server_health_res, "enabled": server_srv_enabled_res, "running": server_srv_running_res, "expected_local_probing": expected_local_probing } ### check-mode diff data["check_mode"] = True data["diff"] = True task = Task.load(data=data, variable_manager=var_manager, loader=data_loader) all_vars = var_manager.get_vars(play=play, task=task, host=inventory.get_host("localhost")) action = spire_server.ActionModule(task=task, connection=connection, play_context=play_context, loader=data_loader, templar=templar, shared_loader_obj=plugins_loader) server_runner.register_extra_cleanup_task(action.cleanup) action._low_level_execute_command = functools.partial( _low_level_execute_command, action._low_level_execute_command) ret = action.run(task_vars={**all_vars}) ### assert ret == {"changed":False, "diff": []}, \ { "actual": ret, "expected":{"changed":False, "diff": []} }
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