Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inventory plugins: make wrapping variables as unsafe smarter to avoid triggering an AWX bug #102

Merged
merged 1 commit into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/102-unsafe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- "inventory plugins - add unsafe wrapper to avoid marking strings that do not contain ``{`` or ``}`` as unsafe, to work around a bug in AWX (https://github.com/ansible-collections/community.hrobot/pull/102)."
2 changes: 1 addition & 1 deletion plugins/inventory/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@
from ansible.plugins.inventory import BaseInventoryPlugin, Constructable, Cacheable
from ansible.template import Templar
from ansible.utils.display import Display
from ansible.utils.unsafe_proxy import wrap_var as make_unsafe

from ansible_collections.community.hrobot.plugins.module_utils.robot import (
BASE_URL,
PluginException,
plugin_open_url_json,
)
from ansible_collections.community.hrobot.plugins.plugin_utils.unsafe import make_unsafe

display = Display()

Expand Down
41 changes: 41 additions & 0 deletions plugins/plugin_utils/unsafe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (c) 2023, Felix Fontein <[email protected]>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import re

from ansible.module_utils.six import binary_type, text_type
from ansible.module_utils.common._collections_compat import Mapping, Set
from ansible.module_utils.common.collections import is_sequence
from ansible.utils.unsafe_proxy import (
AnsibleUnsafe,
wrap_var as _make_unsafe,
)

_RE_TEMPLATE_CHARS = re.compile(u'[{}]')
_RE_TEMPLATE_CHARS_BYTES = re.compile(b'[{}]')


def make_unsafe(value):
if value is None or isinstance(value, AnsibleUnsafe):
return value

if isinstance(value, Mapping):
return dict((make_unsafe(key), make_unsafe(val)) for key, val in value.items())
elif isinstance(value, Set):
return set(make_unsafe(elt) for elt in value)
elif is_sequence(value):
return type(value)(make_unsafe(elt) for elt in value)
elif isinstance(value, binary_type):
if _RE_TEMPLATE_CHARS_BYTES.search(value):
value = _make_unsafe(value)
return value
elif isinstance(value, text_type):
if _RE_TEMPLATE_CHARS.search(value):
value = _make_unsafe(value)
return value

return value
20 changes: 10 additions & 10 deletions tests/unit/plugins/inventory/test_robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,14 +368,14 @@ def test_unsafe(inventory, mocker):
.result_json([
{
'server': {
'server_ip': '1.2.3.4',
'server_ip': '1.2.{3.4',
'dc': 'abc',
},
},
{
'server': {
'server_ip': '1.2.3.5',
'server_name': 'foo',
'server_name': 'fo{o',
'dc': 'EVALU{{ "" }}ATED',
},
},
Expand All @@ -389,27 +389,27 @@ def test_unsafe(inventory, mocker):

open_url.assert_is_done()

host_1 = inventory.inventory.get_host('1.2.3.4')
host_2 = inventory.inventory.get_host('foo')
host_1 = inventory.inventory.get_host('1.2.{3.4')
host_2 = inventory.inventory.get_host('fo{o')

host_1_vars = host_1.get_vars()
host_2_vars = host_2.get_vars()

assert host_1_vars['ansible_host'] == '1.2.3.4'
assert host_1_vars['hrobot_server_ip'] == '1.2.3.4'
assert host_1_vars['ansible_host'] == '1.2.{3.4'
assert host_1_vars['hrobot_server_ip'] == '1.2.{3.4'
assert host_1_vars['hrobot_dc'] == 'abc'

assert host_2_vars['ansible_host'] == '1.2.3.5'
assert host_2_vars['hrobot_server_ip'] == '1.2.3.5'
assert host_2_vars['hrobot_server_name'] == 'foo'
assert host_2_vars['hrobot_server_name'] == 'fo{o'
assert host_2_vars['hrobot_dc'] == 'EVALU{{ "" }}ATED'

# Make sure everything is unsafe
assert isinstance(host_1_vars['ansible_host'], AnsibleUnsafe)
assert isinstance(host_1_vars['hrobot_server_ip'], AnsibleUnsafe)
assert isinstance(host_1_vars['hrobot_dc'], AnsibleUnsafe)
assert not isinstance(host_1_vars['hrobot_dc'], AnsibleUnsafe)

assert isinstance(host_2_vars['ansible_host'], AnsibleUnsafe)
assert isinstance(host_2_vars['hrobot_server_ip'], AnsibleUnsafe)
assert not isinstance(host_2_vars['ansible_host'], AnsibleUnsafe)
assert not isinstance(host_2_vars['hrobot_server_ip'], AnsibleUnsafe)
assert isinstance(host_2_vars['hrobot_server_name'], AnsibleUnsafe)
assert isinstance(host_2_vars['hrobot_dc'], AnsibleUnsafe)