Add a representer for AnsibleUnsafeBytes (#62598)

* Add a representer for AnsibleUnsafeBytes

* changelog

* Add unit tests

Remove native string test until we have time to evaluate how this the function should work
Add non-ASCII characters to test cases

* Compare to the string on Python 2

Add a comment in the test about this behavior
(cherry picked from commit 4cc4c44dd0)
pull/62624/head
Sloane Hertel 5 years ago committed by Toshio Kuratomi
parent d58d2bc875
commit eae2e0d1f4

@ -0,0 +1,2 @@
bugfixes:
- AnsibleDumper - Add a representer for AnsibleUnsafeBytes (https://github.com/ansible/ansible/issues/62562).

@ -23,7 +23,7 @@ import yaml
from ansible.module_utils.six import PY3 from ansible.module_utils.six import PY3
from ansible.parsing.yaml.objects import AnsibleUnicode, AnsibleSequence, AnsibleMapping, AnsibleVaultEncryptedUnicode from ansible.parsing.yaml.objects import AnsibleUnicode, AnsibleSequence, AnsibleMapping, AnsibleVaultEncryptedUnicode
from ansible.utils.unsafe_proxy import AnsibleUnsafeText from ansible.utils.unsafe_proxy import AnsibleUnsafeText, AnsibleUnsafeBytes
from ansible.vars.hostvars import HostVars, HostVarsVars from ansible.vars.hostvars import HostVars, HostVarsVars
@ -46,8 +46,10 @@ def represent_vault_encrypted_unicode(self, data):
if PY3: if PY3:
represent_unicode = yaml.representer.SafeRepresenter.represent_str represent_unicode = yaml.representer.SafeRepresenter.represent_str
represent_binary = yaml.representer.SafeRepresenter.represent_binary
else: else:
represent_unicode = yaml.representer.SafeRepresenter.represent_unicode represent_unicode = yaml.representer.SafeRepresenter.represent_unicode
represent_binary = yaml.representer.SafeRepresenter.represent_str
AnsibleDumper.add_representer( AnsibleDumper.add_representer(
AnsibleUnicode, AnsibleUnicode,
@ -59,6 +61,11 @@ AnsibleDumper.add_representer(
represent_unicode, represent_unicode,
) )
AnsibleDumper.add_representer(
AnsibleUnsafeBytes,
represent_binary,
)
AnsibleDumper.add_representer( AnsibleDumper.add_representer(
HostVars, HostVars,
represent_hostvars, represent_hostvars,

@ -24,6 +24,8 @@ from units.compat import unittest
from ansible.parsing import vault from ansible.parsing import vault
from ansible.parsing.yaml import dumper, objects from ansible.parsing.yaml import dumper, objects
from ansible.parsing.yaml.loader import AnsibleLoader from ansible.parsing.yaml.loader import AnsibleLoader
from ansible.module_utils.six import PY2
from ansible.utils.unsafe_proxy import AnsibleUnsafeText, AnsibleUnsafeBytes
from units.mock.yaml_helper import YamlTestUtils from units.mock.yaml_helper import YamlTestUtils
from units.mock.vault_helper import TextVaultSecret from units.mock.vault_helper import TextVaultSecret
@ -47,7 +49,7 @@ class TestAnsibleDumper(unittest.TestCase, YamlTestUtils):
def _loader(self, stream): def _loader(self, stream):
return AnsibleLoader(stream, vault_secrets=self.vault.secrets) return AnsibleLoader(stream, vault_secrets=self.vault.secrets)
def test(self): def test_ansible_vault_encrypted_unicode(self):
plaintext = 'This is a string we are going to encrypt.' plaintext = 'This is a string we are going to encrypt.'
avu = objects.AnsibleVaultEncryptedUnicode.from_plaintext(plaintext, vault=self.vault, avu = objects.AnsibleVaultEncryptedUnicode.from_plaintext(plaintext, vault=self.vault,
secret=vault.match_secrets(self.vault_secrets, ['vault_secret'])[0][1]) secret=vault.match_secrets(self.vault_secrets, ['vault_secret'])[0][1])
@ -59,3 +61,43 @@ class TestAnsibleDumper(unittest.TestCase, YamlTestUtils):
data_from_yaml = loader.get_single_data() data_from_yaml = loader.get_single_data()
self.assertEqual(plaintext, data_from_yaml.data) self.assertEqual(plaintext, data_from_yaml.data)
def test_bytes(self):
b_text = u'tréma'.encode('utf-8')
unsafe_object = AnsibleUnsafeBytes(b_text)
yaml_out = self._dump_string(unsafe_object, dumper=self.dumper)
stream = self._build_stream(yaml_out)
loader = self._loader(stream)
data_from_yaml = loader.get_single_data()
result = b_text
if PY2:
# https://pyyaml.org/wiki/PyYAMLDocumentation#string-conversion-python-2-only
# pyyaml on Python 2 can return either unicode or bytes when given byte strings.
# We normalize that to always return unicode on Python2 as that's right most of the
# time. However, this means byte strings can round trip through yaml on Python3 but
# not on Python2. To make this code work the same on Python2 and Python3 (we want
# the Python3 behaviour) we need to change the methods in Ansible to:
# (1) Let byte strings pass through yaml without being converted on Python2
# (2) Convert byte strings to text strings before being given to pyyaml (Without this,
# strings would end up as byte strings most of the time which would mostly be wrong)
# In practice, we mostly read bytes in from files and then pass that to pyyaml, for which
# the present behavior is correct.
# This is a workaround for the current behavior.
result = u'tr\xe9ma'
self.assertEqual(result, data_from_yaml)
def test_unicode(self):
u_text = u'nöel'
unsafe_object = AnsibleUnsafeText(u_text)
yaml_out = self._dump_string(unsafe_object, dumper=self.dumper)
stream = self._build_stream(yaml_out)
loader = self._loader(stream)
data_from_yaml = loader.get_single_data()
self.assertEqual(u_text, data_from_yaml)

Loading…
Cancel
Save