def test_bogus_action(self): args_dict = {'bogusaction': {}} m = ModuleArgsParser(args_dict) with pytest.raises(AnsibleParserError) as err: m.parse() assert err.value.args[0].startswith("couldn't resolve module/action 'bogusaction'")
def test_multiple_actions(self): args_dict = {'ping': 'data=hi', 'shell': 'echo hi'} m = ModuleArgsParser(args_dict) with pytest.raises(AnsibleParserError) as err: m.parse() assert err.value.args[0].startswith("conflicting action statements: ") actions = set(re.search(r'(\w+), (\w+)', err.value.args[0]).groups()) assert actions == set(['ping', 'shell'])
def test_multiple_actions(self): args_dict = {'ping': 'data=hi', 'shell': 'echo hi'} m = ModuleArgsParser(args_dict) with pytest.raises(AnsibleParserError) as err: m.parse() assert err.value.args[0].startswith("conflicting action statements: ") conflicts = set(err.value.args[0][len("conflicting action statements: "):].split(', ')) assert conflicts == set(('ping', 'shell'))
class TestModArgsDwim(unittest.TestCase): def setUp(self): self.m = ModuleArgsParser() pass def tearDown(self): pass def test_action_to_shell(self): mod, args, to = self.m.parse('action', 'shell echo hi') assert mod == 'shell' assert args == dict(free_form='echo hi', use_shell=True) assert to is None def test_basic_shell(self): mod, args, to = self.m.parse('shell', 'echo hi') assert mod == 'shell' assert args == dict(free_form='echo hi', use_shell=True) assert to is None def test_basic_command(self): mod, args, to = self.m.parse('command', 'echo hi') assert mod == 'command' assert args == dict(free_form='echo hi', use_shell=False) assert to is None def test_shell_with_modifiers(self): mod, args, to = self.m.parse( 'shell', '/bin/foo creates=/tmp/baz removes=/tmp/bleep') assert mod == 'shell' assert args == dict(free_form='echo hi', use_shell=False, creates='/tmp/baz', removes='/tmp/bleep') assert to is None def test_normal_usage(self): mod, args, to = self.m.parse('copy', 'src=a dest=b') assert mod == 'copy' assert args == dict(src='a', dest='b') assert to is None def test_complex_args(self): mod, args, to = self.m.parse('copy', dict(src=a, dest=b)) assert mod == 'copy' assert args == dict(src='a', dest='b') assert to is None def test_action_with_complex(self): mod, args, to = self.m.parse('action', dict(module='copy', src='a', dest='b')) assert mod == 'action' assert args == dict(src='a', dest='b') assert to is None def test_local_action_string(self): mod, args, to = self.m.parse('local_action', 'copy src=a dest=b') assert mod == 'copy' assert args == dict(src=a, dest=b) assert to is 'localhost'
def test_complex_args(self): m = ModuleArgsParser(dict(copy=dict(src="a", dest="b"))) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, "copy") self.assertEqual(args, dict(src="a", dest="b")) self.assertIsNone(to)
def munge(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance(ds, dict) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = dict() # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser() (action, args, delegate_to) = args_parser.parse(ds) new_ds['action'] = action new_ds['args'] = args new_ds['delegate_to'] = delegate_to for (k,v) in ds.iteritems(): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue elif "with_%s" % k in lookup_finder: self._munge_loop(ds, new_ds, k, v) else: new_ds[k] = v return new_ds
def test_action_with_complex_and_complex_args(self): m = ModuleArgsParser(dict(action=dict(module="copy", args=dict(src="a", dest="b")))) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, "copy") self.assertEqual(args, dict(src="a", dest="b")) self.assertIsNone(to)
def normalize_task_v2(task): '''Ensures tasks have an action key and strings are converted to python objects''' result = dict() mod_arg_parser = ModuleArgsParser(task) action, arguments, result['delegate_to'] = mod_arg_parser.parse() # denormalize shell -> command conversion if '_use_shell' in arguments: action = 'shell' del(arguments['_use_shell']) for (k, v) in list(task.items()): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue else: result[k] = v result['action'] = dict(module=action) if '_raw_params' in arguments: result['action']['module_arguments'] = arguments['_raw_params'].split() del(arguments['_raw_params']) else: result['action']['module_arguments'] = list() result['action'].update(arguments) return result
def test_action_with_complex(self): m = ModuleArgsParser(dict(action=dict(module='copy', src='a', dest='b'))) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, 'copy') self.assertEqual(args, dict(src='a', dest='b')) self.assertIsNone(to)
def test_basic_shell(self): m = ModuleArgsParser(dict(shell="echo hi")) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, "command") self.assertEqual(args, dict(_raw_params="echo hi", _uses_shell=True)) self.assertIsNone(to)
def test_normal_usage(self): m = ModuleArgsParser(dict(copy="src=a dest=b")) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, "copy") self.assertEqual(args, dict(src="a", dest="b")) self.assertIsNone(to)
def test_local_action_string(self): m = ModuleArgsParser(dict(local_action='copy src=a dest=b')) mod, args, connection = m.parse() self._debug(mod, args, connection) self.assertEqual(mod, 'copy') self.assertEqual(args, dict(src='a', dest='b', _local_action=True)) self.assertIs(connection, 'local')
def test_local_action_string(self): m = ModuleArgsParser(dict(local_action="copy src=a dest=b")) mod, args, connection = m.parse() self._debug(mod, args, connection) self.assertEqual(mod, "copy") self.assertEqual(args, dict(src="a", dest="b")) self.assertIs(connection, "local")
def test_shell_with_modifiers(self): m = ModuleArgsParser(dict(shell="/bin/foo creates=/tmp/baz removes=/tmp/bleep")) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, "command") self.assertEqual(args, dict(creates="/tmp/baz", removes="/tmp/bleep", _raw_params="/bin/foo", _uses_shell=True)) self.assertIsNone(to)
def test_basic_command(self): m = ModuleArgsParser(dict(command="echo hi")) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, "command") self.assertEqual(args, dict(_raw_params="echo hi")) self.assertIsNone(to)
def test_basic_command(self): m = ModuleArgsParser(dict(command='echo hi')) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, 'command') self.assertEqual(args, dict(_raw_params='echo hi', )) self.assertIsNone(to)
def test_local_action_string(self): m = ModuleArgsParser(dict(local_action='copy src=a dest=b')) mod, args, delegate_to = m.parse() self._debug(mod, args, delegate_to) self.assertEqual(mod, 'copy') self.assertEqual(args, dict(src='a', dest='b')) self.assertIs(delegate_to, 'localhost')
def munge(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance(ds, dict) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = dict() # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser() (action, args, delegate_to) = args_parser.parse(ds) new_ds['action'] = action new_ds['args'] = args new_ds['delegate_to'] = delegate_to for (k, v) in ds.iteritems(): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue elif "with_%s" % k in lookup_finder: self._munge_loop(ds, new_ds, k, v) else: new_ds[k] = v return new_ds
def test_normal_usage(self): m = ModuleArgsParser(dict(copy='src=a dest=b')) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, 'copy') self.assertEqual(args, dict(src='a', dest='b')) self.assertIsNone(to)
def test_complex_args(self): m = ModuleArgsParser(dict(copy=dict(src='a', dest='b'))) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, 'copy') self.assertEqual(args, dict(src='a', dest='b')) self.assertIsNone(to)
def normalize_task(task, filename, custom_modules=[]): """Ensure tasks have an action key and strings are converted to python objects.""" ansible_action_type = task.get("__ansible_action_type__", "task") if "__ansible_action_type__" in task: del (task["__ansible_action_type__"]) # temp. extract metadata ansible_meta = dict() for key in ["__line__", "__file__", "__ansible_action_meta__"]: default = None if key == "__ansible_action_meta__": default = dict() ansible_meta[key] = task.pop(key, default) normalized = dict() builtin = list(ansible.parsing.mod_args.BUILTIN_TASKS) builtin = list(set(builtin + custom_modules)) ansible.parsing.mod_args.BUILTIN_TASKS = frozenset(builtin) mod_arg_parser = ModuleArgsParser(task) try: action, arguments, normalized["delegate_to"] = mod_arg_parser.parse() except AnsibleParserError as e: raise LaterAnsibleError("syntax error", e) # denormalize shell -> command conversion if "_uses_shell" in arguments: action = "shell" del (arguments["_uses_shell"]) for (k, v) in list(task.items()): if k in ("action", "local_action", "args", "delegate_to") or k == action: # we don"t want to re-assign these values, which were # determined by the ModuleArgsParser() above continue else: normalized[k] = v normalized["action"] = dict(__ansible_module__=action) if "_raw_params" in arguments: normalized["action"]["__ansible_arguments__"] = arguments["_raw_params"].strip().split() del (arguments["_raw_params"]) else: normalized["action"]["__ansible_arguments__"] = list() normalized["action"].update(arguments) normalized[FILENAME_KEY] = filename normalized["__ansible_action_type__"] = ansible_action_type # add back extracted metadata for (k, v) in ansible_meta.items(): if v: normalized[k] = v return normalized
def test_local_action_string(self): m = ModuleArgsParser(dict(local_action='copy src=a dest=b')) mod, args, delegate_to = m.parse() self._debug(mod, args, delegate_to) assert mod == 'copy' assert args == dict(src='a', dest='b') assert delegate_to == 'localhost'
def test_complex_args(self): m = ModuleArgsParser(dict(copy=dict(src='a', dest='b'))) mod, args, to = m.parse() self._debug(mod, args, to) assert mod, 'copy' assert args, dict(src='a', dest='b') assert to is Sentinel
def test_normal_usage(self): m = ModuleArgsParser(dict(copy='src=a dest=b')) mod, args, to = m.parse() self._debug(mod, args, to) assert mod, 'copy' assert args, dict(src='a', dest='b') assert to is Sentinel
def test_basic_command(self): m = ModuleArgsParser(dict(command='echo hi')) mod, args, to = m.parse() self._debug(mod, args, to) assert mod == 'command' assert args == dict(_raw_params='echo hi', ) assert to is Sentinel
def test_complex_args(self): m = ModuleArgsParser(dict(copy=dict(src='a', dest='b'))) mod, args, to = m.parse() self._debug(mod, args, to) assert mod, 'copy' assert args, dict(src='a', dest='b') assert to is None
def test_action_with_complex_and_complex_args(self): m = ModuleArgsParser(dict(action=dict(module='copy', args=dict(src='a', dest='b')))) mod, args, to = m.parse() self._debug(mod, args, to) assert mod == 'copy' assert args == dict(src='a', dest='b') assert to is None
def test_normal_usage(self): m = ModuleArgsParser(dict(copy='src=a dest=b')) mod, args, to = m.parse() self._debug(mod, args, to) assert mod, 'copy' assert args, dict(src='a', dest='b') assert to is None
def test_basic_shell(self): m = ModuleArgsParser(dict(shell='echo hi')) mod, args, to = m.parse() self._debug(mod, args, to) assert mod == 'shell' assert args == dict(_raw_params='echo hi', ) assert to is Sentinel
def preprocess_data(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance(ds, dict) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = AnsibleMapping() if isinstance(ds, AnsibleBaseYAMLObject): new_ds.ansible_pos = ds.ansible_pos # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser(task_ds=ds) (action, args, connection) = args_parser.parse() new_ds['action'] = action new_ds['args'] = args new_ds['connection'] = connection # we handle any 'vars' specified in the ds here, as we may # be adding things to them below (special handling for includes). # When that deprecated feature is removed, this can be too. if 'vars' in ds: # _load_vars is defined in Base, and is used to load a dictionary # or list of dictionaries in a standard way new_ds['vars'] = self._load_vars(None, ds.pop('vars')) else: new_ds['vars'] = dict() for (k, v) in iteritems(ds): if k in ('action', 'local_action', 'args', 'connection') or k == action or k == 'shell': # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue elif k.replace("with_", "") in lookup_loader: self._preprocess_loop(ds, new_ds, k, v) else: # pre-2.0 syntax allowed variables for include statements at the # top level of the task, so we move those into the 'vars' dictionary # here, and show a deprecation message as we will remove this at # some point in the future. if action == 'include' and k not in self._get_base_attributes( ) and k not in self.DEPRECATED_ATTRIBUTES: self._display.deprecated( "Specifying include variables at the top-level of the task is deprecated. Please see:\nhttp://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse\n\nfor currently supported syntax regarding included files and variables" ) new_ds['vars'][k] = v else: new_ds[k] = v return super(Task, self).preprocess_data(new_ds)
def normalize_task_v2(task: dict) -> dict: # noqa: C901 """Ensure tasks have an action key and strings are converted to python objects.""" result = dict() if 'always_run' in task: # FIXME(ssbarnea): Delayed import to avoid circular import # See https://github.com/ansible/ansible-lint/issues/880 # noqa: # pylint:disable=cyclic-import,import-outside-toplevel from ansiblelint.rules.AlwaysRunRule import AlwaysRunRule raise MatchError(rule=AlwaysRunRule, filename=task[FILENAME_KEY], linenumber=task[LINE_NUMBER_KEY]) sanitized_task = _sanitize_task(task) mod_arg_parser = ModuleArgsParser(sanitized_task) try: action, arguments, result['delegate_to'] = mod_arg_parser.parse() except AnsibleParserError as e: try: task_info = "%s:%s" % (task[FILENAME_KEY], task[LINE_NUMBER_KEY]) except KeyError: task_info = "Unknown" pp = pprint.PrettyPrinter(indent=2) task_pprint = pp.pformat(sanitized_task) _logger.critical("Couldn't parse task at %s (%s)\n%s", task_info, e.message, task_pprint) raise SystemExit(ANSIBLE_FAILURE_RC) # denormalize shell -> command conversion if '_uses_shell' in arguments: action = 'shell' del arguments['_uses_shell'] for (k, v) in list(task.items()): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue else: result[k] = v result['action'] = dict(__ansible_module__=action) if '_raw_params' in arguments: result['action']['__ansible_arguments__'] = arguments[ '_raw_params'].split(' ') del arguments['_raw_params'] else: result['action']['__ansible_arguments__'] = list() if 'argv' in arguments and not result['action']['__ansible_arguments__']: result['action']['__ansible_arguments__'] = arguments['argv'] del arguments['argv'] result['action'].update(arguments) return result
def test_basic_shell(self): m = ModuleArgsParser(dict(shell='echo hi')) mod, args, to = m.parse() self._debug(mod, args, to) assert mod == 'shell' assert args == dict( _raw_params='echo hi', ) assert to is None
def handle_task(self, a_task, ru_task): """handle a single task""" mod_arg_parser = ModuleArgsParser(a_task) try: action, args, delegate_to = mod_arg_parser.parse( skip_action_validation=True) except AnsibleParserError as e: raise LSRException("Couldn't parse task at %s (%s)\n%s" % (a_task.ansible_pos, e.message, a_task)) self.task_cb(a_task, ru_task, action, args, delegate_to)
def test_basic_shell(self): m = ModuleArgsParser(dict(shell='echo hi')) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, 'command') self.assertEqual(args, dict( _raw_params = 'echo hi', _uses_shell = True, )) self.assertIsNone(to)
def test_basic_command(self): m = ModuleArgsParser(dict(command='echo hi')) mod, args, to = m.parse() self._debug(mod, args, to) assert mod == 'command' assert args == dict( _raw_params='echo hi', ) assert to is None
def preprocess_data(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance(ds, dict) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = AnsibleMapping() if isinstance(ds, AnsibleBaseYAMLObject): new_ds.ansible_pos = ds.ansible_pos # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser(task_ds=ds) (action, args, connection) = args_parser.parse() new_ds['action'] = action new_ds['args'] = args new_ds['connection'] = connection # we handle any 'vars' specified in the ds here, as we may # be adding things to them below (special handling for includes). # When that deprecated feature is removed, this can be too. if 'vars' in ds: # _load_vars is defined in Base, and is used to load a dictionary # or list of dictionaries in a standard way new_ds['vars'] = self._load_vars(None, ds.pop('vars')) else: new_ds['vars'] = dict() for (k,v) in iteritems(ds): if k in ('action', 'local_action', 'args', 'connection') or k == action or k == 'shell': # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue elif k.replace("with_", "") in lookup_loader: self._preprocess_loop(ds, new_ds, k, v) else: # pre-2.0 syntax allowed variables for include statements at the # top level of the task, so we move those into the 'vars' dictionary # here, and show a deprecation message as we will remove this at # some point in the future. if action == 'include' and k not in self._get_base_attributes() and k not in self.DEPRECATED_ATTRIBUTES: self._display.deprecated("Specifying include variables at the top-level of the task is deprecated. Please see:\nhttp://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse\n\nfor currently supported syntax regarding included files and variables") new_ds['vars'][k] = v else: new_ds[k] = v return super(Task, self).preprocess_data(new_ds)
def normalize_task_v2(task: Dict[str, Any]) -> Dict[str, Any]: """Ensure tasks have a normalized action key and strings are converted to python objects.""" result = dict() sanitized_task = _sanitize_task(task) mod_arg_parser = ModuleArgsParser(sanitized_task) try: action, arguments, result['delegate_to'] = mod_arg_parser.parse( skip_action_validation=options.skip_action_validation) except AnsibleParserError as e: raise MatchError( rule=AnsibleParserErrorRule(), message=e.message, filename=task.get(FILENAME_KEY, "Unknown"), linenumber=task.get(LINE_NUMBER_KEY, 0), ) # denormalize shell -> command conversion if '_uses_shell' in arguments: action = 'shell' del arguments['_uses_shell'] for (k, v) in list(task.items()): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue result[k] = v if not isinstance(action, str): raise RuntimeError("Task actions can only be strings, got %s" % action) action_unnormalized = action # convert builtin fqn calls to short forms because most rules know only # about short calls but in the future we may switch the normalization to do # the opposite. Mainly we currently consider normalized the module listing # used by `ansible-doc -t module -l 2>/dev/null` action = removeprefix(action, "ansible.builtin.") result['action'] = dict(__ansible_module__=action, __ansible_module_original__=action_unnormalized) if '_raw_params' in arguments: result['action']['__ansible_arguments__'] = arguments[ '_raw_params'].split(' ') del arguments['_raw_params'] else: result['action']['__ansible_arguments__'] = list() if 'argv' in arguments and not result['action']['__ansible_arguments__']: result['action']['__ansible_arguments__'] = arguments['argv'] del arguments['argv'] result['action'].update(arguments) return result
def test_shell_with_modifiers(self): m = ModuleArgsParser(dict(shell='/bin/foo creates=/tmp/baz removes=/tmp/bleep')) mod, args, to = m.parse() self._debug(mod, args, to) assert mod == 'shell' assert args == dict( creates='/tmp/baz', removes='/tmp/bleep', _raw_params='/bin/foo', ) assert to is None
def test_shell_with_modifiers(self): m = ModuleArgsParser(dict(shell='/bin/foo creates=/tmp/baz removes=/tmp/bleep')) mod, args, to = m.parse() self._debug(mod, args, to) self.assertEqual(mod, 'command') self.assertEqual(args, dict( creates = '/tmp/baz', removes = '/tmp/bleep', _raw_params = '/bin/foo', _uses_shell = True, )) self.assertIsNone(to)
def normalize_task_v2(task): '''Ensures tasks have an action key and strings are converted to python objects''' result = dict() mod_arg_parser = ModuleArgsParser(task) try: action, arguments, result['delegate_to'] = mod_arg_parser.parse() except AnsibleParserError as e: try: task_info = "%s:%s" % (task[FILENAME_KEY], task[LINE_NUMBER_KEY]) del task[FILENAME_KEY] del task[LINE_NUMBER_KEY] except KeyError: task_info = "Unknown" try: import pprint pp = pprint.PrettyPrinter(indent=2) task_pprint = pp.pformat(task) except ImportError: task_pprint = task raise SystemExit("Couldn't parse task at %s (%s)\n%s" % (task_info, e.message, task_pprint)) # denormalize shell -> command conversion if '_uses_shell' in arguments: action = 'shell' del (arguments['_uses_shell']) for (k, v) in list(task.items()): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue else: result[k] = v result['action'] = dict(__ansible_module__=action) if '_raw_params' in arguments: result['action']['__ansible_arguments__'] = arguments[ '_raw_params'].split(' ') del (arguments['_raw_params']) else: result['action']['__ansible_arguments__'] = list() if 'argv' in arguments and not result['action']['__ansible_arguments__']: result['action']['__ansible_arguments__'] = arguments['argv'] del (arguments['argv']) result['action'].update(arguments) return result
def normalize_task_v2(task): '''Ensures tasks have an action key and strings are converted to python objects''' result = dict() mod_arg_parser = ModuleArgsParser(task) try: action, arguments, result['delegate_to'] = mod_arg_parser.parse() except AnsibleParserError as e: try: task_info = "%s:%s" % (task[FILENAME_KEY], task[LINE_NUMBER_KEY]) del task[FILENAME_KEY] del task[LINE_NUMBER_KEY] except KeyError: task_info = "Unknown" try: import pprint pp = pprint.PrettyPrinter(indent=2) task_pprint = pp.pformat(task) except ImportError: task_pprint = task raise SystemExit("Couldn't parse task at %s (%s)\n%s" % (task_info, e.message, task_pprint)) # denormalize shell -> command conversion if '_uses_shell' in arguments: action = 'shell' del(arguments['_uses_shell']) for (k, v) in list(task.items()): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue else: result[k] = v result['action'] = dict(__ansible_module__=action) if '_raw_params' in arguments: result['action']['__ansible_arguments__'] = arguments['_raw_params'].split(' ') del(arguments['_raw_params']) else: result['action']['__ansible_arguments__'] = list() if 'argv' in arguments and not result['action']['__ansible_arguments__']: result['action']['__ansible_arguments__'] = arguments['argv'] del(arguments['argv']) result['action'].update(arguments) return result
def cleanAnsible(x): f = StringIO(x) ymlfiles = [] ## load all modules name in list ## listmodules = [line.rstrip('\n') for line in open("modules.txt")] ### open all *.yml ### composefile = [] flag = 0 try: for x in f: for e in listmodules: if x.startswith(" " + e + ":") == True and len(x.strip()) > len(e + ":"): module = x.split(':', 1)[0].strip() arguments = x.split(':', 1)[1] composefile.append(" " + module + ":\n") res = dict() flag = 1 res[module] = arguments m = ModuleArgsParser(res) mod, args, to = m.parse() for x in args: if x == "_raw_params": del composefile[-1] composefile.append(" " + module + ": " + args[x] + "\n") else: tmp = args[x].replace("\n", "\\n") if tmp.find('{{') != -1 and tmp.find('}}') != -1: composefile.append(" " + x + ": " + '"' + tmp + '"' + "\n") else: composefile.append(" " + x + ": " + tmp + "\n") break composefile.append(x) if flag == 1: flag = 0 composefile.pop(len(composefile) - 1) except (AnsibleParserError): composefile = "Error Ansible Syntax" return composefile
def normalize_task_v2(task: dict) -> dict: # noqa: C901 """Ensure tasks have an action key and strings are converted to python objects.""" result = dict() sanitized_task = _sanitize_task(task) mod_arg_parser = ModuleArgsParser(sanitized_task) try: action, arguments, result['delegate_to'] = mod_arg_parser.parse() except AnsibleParserError as e: raise MatchError( rule=AnsibleParserErrorRule(), message=e.message, filename=task.get(FILENAME_KEY, "Unknown"), linenumber=task.get(LINE_NUMBER_KEY, 0), ) # denormalize shell -> command conversion if '_uses_shell' in arguments: action = 'shell' del arguments['_uses_shell'] for (k, v) in list(task.items()): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action: # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue else: result[k] = v result['action'] = dict(__ansible_module__=action) if '_raw_params' in arguments: result['action']['__ansible_arguments__'] = arguments[ '_raw_params'].split(' ') del arguments['_raw_params'] else: result['action']['__ansible_arguments__'] = list() if 'argv' in arguments and not result['action']['__ansible_arguments__']: result['action']['__ansible_arguments__'] = arguments['argv'] del arguments['argv'] result['action'].update(arguments) return result
def preprocess_data(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance(ds, dict) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = AnsibleMapping() if isinstance(ds, AnsibleBaseYAMLObject): new_ds.ansible_pos = ds.ansible_pos # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser(task_ds=ds) (action, args, delegate_to) = args_parser.parse() new_ds['action'] = action new_ds['args'] = args new_ds['delegate_to'] = delegate_to for (k, v) in ds.iteritems(): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action or k == 'shell': # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue elif k.replace("with_", "") in lookup_loader: self._preprocess_loop(ds, new_ds, k, v) else: new_ds[k] = v return super(Task, self).preprocess_data(new_ds)
def preprocess_data(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance(ds, dict) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = AnsibleMapping() if isinstance(ds, AnsibleBaseYAMLObject): new_ds.ansible_pos = ds.ansible_pos # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser(task_ds=ds) (action, args, delegate_to) = args_parser.parse() new_ds['action'] = action new_ds['args'] = args new_ds['delegate_to'] = delegate_to for (k,v) in ds.iteritems(): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action or k == 'shell': # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue elif k.replace("with_", "") in lookup_loader: self._preprocess_loop(ds, new_ds, k, v) else: new_ds[k] = v return super(Task, self).preprocess_data(new_ds)
def preprocess_data(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance( ds, dict), 'ds (%s) should be a dict but was a %s' % (ds, type(ds)) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = AnsibleMapping() if isinstance(ds, AnsibleBaseYAMLObject): new_ds.ansible_pos = ds.ansible_pos # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser(task_ds=ds) try: (action, args, delegate_to) = args_parser.parse() except AnsibleParserError as e: raise AnsibleParserError(to_native(e), obj=ds, orig_exc=e) # the command/shell/script modules used to support the `cmd` arg, # which corresponds to what we now call _raw_params, so move that # value over to _raw_params (assuming it is empty) if action in ('command', 'shell', 'script'): if 'cmd' in args: if args.get('_raw_params', '') != '': raise AnsibleError( "The 'cmd' argument cannot be used when other raw parameters are specified." " Please put everything in one or the other place.", obj=ds) args['_raw_params'] = args.pop('cmd') new_ds['action'] = action new_ds['args'] = args new_ds['delegate_to'] = delegate_to # we handle any 'vars' specified in the ds here, as we may # be adding things to them below (special handling for includes). # When that deprecated feature is removed, this can be too. if 'vars' in ds: # _load_vars is defined in Base, and is used to load a dictionary # or list of dictionaries in a standard way new_ds['vars'] = self._load_vars(None, ds.get('vars')) else: new_ds['vars'] = dict() for (k, v) in iteritems(ds): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action or k == 'shell': # we don't want to re-assign these values, which were determined by the ModuleArgsParser() above continue elif k.replace("with_", "") in lookup_loader: # transform into loop property self._preprocess_with_loop(ds, new_ds, k, v) else: # pre-2.0 syntax allowed variables for include statements at the top level of the task, # so we move those into the 'vars' dictionary here, and show a deprecation message # as we will remove this at some point in the future. if action in ( 'include', 'include_tasks' ) and k not in self._valid_attrs and k not in self.DEPRECATED_ATTRIBUTES: display.deprecated( "Specifying include variables at the top-level of the task is deprecated." " Please see:\nhttp://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse\n\n" " for currently supported syntax regarding included files and variables", version="2.7") new_ds['vars'][k] = v elif k in self._valid_attrs: new_ds[k] = v else: display.warning("Ignoring invalid attribute: %s" % k) return super(Task, self).preprocess_data(new_ds)
def preprocess_data(self, ds): ''' tasks are especially complex arguments so need pre-processing. keep it short. ''' assert isinstance(ds, dict), 'ds (%s) should be a dict but was a %s' % (ds, type(ds)) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = AnsibleMapping() if isinstance(ds, AnsibleBaseYAMLObject): new_ds.ansible_pos = ds.ansible_pos # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser(task_ds=ds) try: (action, args, delegate_to) = args_parser.parse() except AnsibleParserError as e: raise AnsibleParserError(to_native(e), obj=ds, orig_exc=e) # the command/shell/script modules used to support the `cmd` arg, # which corresponds to what we now call _raw_params, so move that # value over to _raw_params (assuming it is empty) if action in ('command', 'shell', 'script'): if 'cmd' in args: if args.get('_raw_params', '') != '': raise AnsibleError("The 'cmd' argument cannot be used when other raw parameters are specified." " Please put everything in one or the other place.", obj=ds) args['_raw_params'] = args.pop('cmd') new_ds['action'] = action new_ds['args'] = args new_ds['delegate_to'] = delegate_to # we handle any 'vars' specified in the ds here, as we may # be adding things to them below (special handling for includes). # When that deprecated feature is removed, this can be too. if 'vars' in ds: # _load_vars is defined in Base, and is used to load a dictionary # or list of dictionaries in a standard way new_ds['vars'] = self._load_vars(None, ds.get('vars')) else: new_ds['vars'] = dict() for (k, v) in iteritems(ds): if k in ('action', 'local_action', 'args', 'delegate_to') or k == action or k == 'shell': # we don't want to re-assign these values, which were determined by the ModuleArgsParser() above continue elif k.replace("with_", "") in lookup_loader: # transform into loop property self._preprocess_loop(ds, new_ds, k, v) else: # pre-2.0 syntax allowed variables for include statements at the top level of the task, # so we move those into the 'vars' dictionary here, and show a deprecation message # as we will remove this at some point in the future. if action in ('include', 'include_tasks') and k not in self._valid_attrs and k not in self.DEPRECATED_ATTRIBUTES: display.deprecated("Specifying include variables at the top-level of the task is deprecated." " Please see:\nhttp://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse\n\n" " for currently supported syntax regarding included files and variables", version="2.7") new_ds['vars'][k] = v elif k in self._valid_attrs: new_ds[k] = v else: display.warning("Ignoring invalid attribute: %s" % k) return super(Task, self).preprocess_data(new_ds)
def test_multiple_actions(self, args_dict, msg): m = ModuleArgsParser(args_dict) with pytest.raises(AnsibleParserError) as err: m.parse() assert err.value.args[0] == msg
def preprocess_data(self, ds): """ tasks are especially complex arguments so need pre-processing. keep it short. """ assert isinstance(ds, dict) # the new, cleaned datastructure, which will have legacy # items reduced to a standard structure suitable for the # attributes of the task class new_ds = AnsibleMapping() if isinstance(ds, AnsibleBaseYAMLObject): new_ds.ansible_pos = ds.ansible_pos # use the args parsing class to determine the action, args, # and the delegate_to value from the various possible forms # supported as legacy args_parser = ModuleArgsParser(task_ds=ds) try: (action, args, delegate_to) = args_parser.parse() except AnsibleParserError as e: raise AnsibleParserError(to_str(e), obj=ds) # the command/shell/script modules used to support the `cmd` arg, # which corresponds to what we now call _raw_params, so move that # value over to _raw_params (assuming it is empty) if action in ("command", "shell", "script"): if "cmd" in args: if args.get("_raw_params", "") != "": raise AnsibleError( "The 'cmd' argument cannot be used when other raw parameters are specified." " Please put everything in one or the other place.", obj=ds, ) args["_raw_params"] = args.pop("cmd") new_ds["action"] = action new_ds["args"] = args new_ds["delegate_to"] = delegate_to # we handle any 'vars' specified in the ds here, as we may # be adding things to them below (special handling for includes). # When that deprecated feature is removed, this can be too. if "vars" in ds: # _load_vars is defined in Base, and is used to load a dictionary # or list of dictionaries in a standard way new_ds["vars"] = self._load_vars(None, ds.get("vars")) else: new_ds["vars"] = dict() for (k, v) in iteritems(ds): if k in ("action", "local_action", "args", "delegate_to") or k == action or k == "shell": # we don't want to re-assign these values, which were # determined by the ModuleArgsParser() above continue elif k.replace("with_", "") in lookup_loader: self._preprocess_loop(ds, new_ds, k, v) else: # pre-2.0 syntax allowed variables for include statements at the # top level of the task, so we move those into the 'vars' dictionary # here, and show a deprecation message as we will remove this at # some point in the future. if action == "include" and k not in self._get_base_attributes() and k not in self.DEPRECATED_ATTRIBUTES: display.deprecated( "Specifying include variables at the top-level of the task is deprecated." " Please see:\nhttp://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse\n\n" " for currently supported syntax regarding included files and variables" ) new_ds["vars"][k] = v else: new_ds[k] = v return super(Task, self).preprocess_data(new_ds)