Repository: ansible/ansible

Issue:
traceback on set_fact with numeric var names
##### ISSUE TYPE
- Bug Report
##### ANSIBLE VERSION

```
 ansible --version
ansible 2.2.0 (testbug 329c62e914) last updated 2016/05/26 09:29:16 (GMT -400)
  lib/ansible/modules/core: (devel fb77ab49ab) last updated 2016/05/26 09:29:21 (GMT -400)
  lib/ansible/modules/extras: (devel 0e4a023a7e) last updated 2016/05/26 09:29:25 (GMT -400)
  config file = 
  configured module search path = Default w/o overrides
```
##### CONFIGURATION
- default ansible.cfg
##### OS / ENVIRONMENT
- fedora23 control host
##### SUMMARY

setting a fact with a numeric key causes a traceback
##### STEPS TO REPRODUCE

```
$ cat site.yml 
- hosts: el6host
  gather_facts: False
  tasks:
      - set_fact:
            21: jumpstreet
```
##### EXPECTED RESULTS

No traceback.
##### ACTUAL RESULTS

```
the full traceback was:

Traceback (most recent call last):
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/bin/ansible-playbook", line 92, in <module>
    exit_code = cli.run()
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/cli/playbook.py", line 154, in run
    results = pbex.run()
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/executor/playbook_executor.py", line 72, in run
    pb = Playbook.load(playbook_path, variable_manager=self._variable_manager, loader=self._loader)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/__init__.py", line 53, in load
    pb._load_playbook_data(file_name=file_name, variable_manager=variable_manager)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/__init__.py", line 98, in _load_playbook_data
    entry_obj = Play.load(entry, variable_manager=variable_manager, loader=self._loader)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/play.py", line 115, in load
    return p.load_data(data, variable_manager=variable_manager, loader=loader)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/base.py", line 206, in load_data
    self._attributes[name] = method(name, ds[name])
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/play.py", line 167, in _load_tasks
    return load_list_of_blocks(ds=ds, play=self, variable_manager=self._variable_manager, loader=self._loader)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/helpers.py", line 58, in load_list_of_blocks
    loader=loader
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/block.py", line 81, in load
    return b.load_data(data, variable_manager=variable_manager, loader=loader)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/base.py", line 206, in load_data
    self._attributes[name] = method(name, ds[name])
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/block.py", line 117, in _load_block
    use_handlers=self._use_handlers,
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/helpers.py", line 240, in load_list_of_tasks
    t = Task.load(task_ds, block=block, role=role, task_include=task_include, variable_manager=variable_manager, loader=loader)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/task.py", line 135, in load
    return t.load_data(data, variable_manager=variable_manager, loader=loader)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/base.py", line 195, in load_data
    ds = self.preprocess_data(ds)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/playbook/task.py", line 175, in preprocess_data
    (action, args, delegate_to) = args_parser.parse()
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/parsing/mod_args.py", line 293, in parse
    action, args = self._normalize_parameters(value, action=action, additional_args=additional_args)
  File "/home/jtanner/workspace/issues/AMC-3742/ansible/lib/ansible/parsing/mod_args.py", line 171, in _normalize_parameters
    if arg.startswith('_ansible_'):
AttributeError: 'int' object has no attribute 'startswith'
```



Discussion:
https://github.com/ansible/community/issues/107 it was agreed that we would fix the traceback and cast all var names in set_fact to strings.


Resolving patch:
diff --git a/lib/ansible/parsing/mod_args.py b/lib/ansible/parsing/mod_args.py
--- a/lib/ansible/parsing/mod_args.py
+++ b/lib/ansible/parsing/mod_args.py
@@ -22,6 +22,7 @@
 from ansible.compat.six import iteritems, string_types
 
 from ansible.errors import AnsibleParserError,AnsibleError
+from ansible.module_utils._text import to_text
 from ansible.plugins import module_loader
 from ansible.parsing.splitter import parse_kv, split_args
 from ansible.template import Templar
@@ -165,6 +166,7 @@ def _normalize_parameters(self, thing, action=None, additional_args=dict()):
         # we don't allow users to set them directy in arguments
         if args and action not in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw'):
             for arg in args:
+                arg = to_text(arg)
                 if arg.startswith('_ansible_'):
                     raise AnsibleError("invalid parameter specified for action '%s': '%s'" % (action, arg))
 


Test patch: