ansible.utils
ansible.utils copied to clipboard
from_xml filter returns a string instead of a python dictionary
SUMMARY
The from_xml
filter returns a string instead of returning a python dictionary as its documentation reports and as the from_json
and from_yaml
filters do.
ISSUE TYPE
- Bug Report
COMPONENT NAME
from_xml
ANSIBLE VERSION
ansible [core 2.11.3]
config file = /home/user/workspace/ansible-playbooks-2/ansible.cfg
configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/user/workspace/ansible-playbooks-2/.direnv/python-3.8.10/lib/python3.8/site-packages/ansible
ansible collection location = /home/user/workspace/ansible-playbooks-2/collections
executable location = /home/user/workspace/ansible-playbooks-2/.direnv/python-3.8.10/bin/ansible
python version = 3.8.10 (default, Nov 26 2021, 20:14:08) [GCC 9.3.0]
jinja version = 3.0.1
libyaml = True
COLLECTION VERSION
# /home/user/workspace/ansible-playbooks-2/collections/ansible_collections
Collection Version
------------- -------
ansible.utils 2.4.2
CONFIGURATION
AGNOSTIC_BECOME_PROMPT(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = False
ANSIBLE_FORCE_COLOR(env: ANSIBLE_FORCE_COLOR) = True
CALLBACKS_ENABLED(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = ['timer', 'ansible.posix.profile_tasks']
COLLECTIONS_PATHS(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = ['/home/user/workspace/ansible-playbooks-2/collections']
DEFAULT_CONNECTION_PLUGIN_PATH(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = ['/home/user/workspace/ansible-playbooks-2/connection_plugins']
DEFAULT_FORKS(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = 10
DEFAULT_HOST_LIST(env: ANSIBLE_INVENTORY) = ['/home/user/workspace/ansible-playbooks-2/inventories/test']
DEFAULT_TIMEOUT(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = 10
DEFAULT_VAULT_PASSWORD_FILE(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = /home/user/workspace/ansible-playbooks-2/inventories/vault_password.sh
DISPLAY_SKIPPED_HOSTS(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = False
HOST_KEY_CHECKING(env: ANSIBLE_HOST_KEY_CHECKING) = False
INVENTORY_ANY_UNPARSED_IS_FAILED(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = True
INVENTORY_ENABLED(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = ['host_list', 'ini', 'constructed']
INVENTORY_IGNORE_EXTS(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = ['~', '.orig', '.bak', '.cfg', '.retry', '.pyc', '.pyo', 'LICENSE', '.md', '.txt', 'secrets.yml', 'vars.yml', 'ssh_private_key']
PLAYBOOK_DIR(env: ANSIBLE_PLAYBOOK_DIR) = /home/user/workspace/ansible-playbooks-2
RETRY_FILES_ENABLED(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = True
RETRY_FILES_SAVE_PATH(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = /tmp
TASK_TIMEOUT(env: ANSIBLE_TASK_TIMEOUT) = 180
VARIABLE_PRECEDENCE(/home/user/workspace/ansible-playbooks-2/ansible.cfg) = ['all_inventory', 'groups_inventory', 'all_plugins_play', 'groups_plugins_play', 'all_plugins_inventory', 'groups_plugins_inventory']
OS / ENVIRONMENT
Ubuntu 20.04.3 LTS (Focal Fossa)
STEPS TO REPRODUCE
- hosts: localhost
diff: true
gather_facts: false
tasks:
- debug:
msg: "{{ (some_xml | ansible.utils.from_xml)['root']['leaf'] }}"
vars:
some_xml: |
<?xml version="1.0" encoding="UTF-8"?>
<root>
<leaf>
<attribute>foobar</attribute>
</leaf>
</root>
EXPECTED RESULTS
This should print
"msg": {
"attribute": "foobar"
}
ACTUAL RESULTS
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'str object' has no attribute 'root'\n\nThe error appears to be in '/home/john/workspace_tagpay/ansible-playbooks-2/foo.tmp.yml': line 6, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - debug:\n ^ here\n"}
@jpiron Hi, can you try following code snippet?
-
hosts: localhost
connection: ansible.netcommon.network_cli
gather_facts: no
vars:
ansible_persistent_log_messages: True
some_xml: |
<?xml version="1.0" encoding="UTF-8"?>
<root>
<leaf>
<attribute>foobar</attribute>
</leaf>
</root>
tasks:
- ansible.builtin.set_fact:
test: "{{ (some_xml | ansible.utils.from_xml)}}"
- debug:
msg: "{{test.root.leaf}}"
Hi @ashwini-mhatre, using an intermediate variable works but this prevents from doing something like:
- hosts: localhost
connection: local
gather_facts: no
tasks:
- uri:
url: http://httpbin.org/xml
headers:
accept: "application/xml"
return_content: true
register: result
until: (result.content | ansible.utils.from_xml)['slideshow']['@author'] == 'Yours Truly'
retries: 3
delay: 2
It works by chaining the from_json
filter like the following:
- hosts: localhost
connection: local
gather_facts: no
tasks:
- uri:
url: http://httpbin.org/xml
headers:
accept: "application/xml"
return_content: true
register: result
until: (result.content | ansible.utils.from_xml | from_json)['slideshow']['@author'] == 'Yours Truly'
retries: 3
delay: 2
but it shouldn't be required if the goal is to provide the same behavior as from_yaml
and from_json
filters.
Concur, this should be fixed
Workaround is to use the from_yaml filter afterwards