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
pull/62619/head
Sloane Hertel 5 years ago committed by GitHub
parent c8e220a62e
commit 4cc4c44dd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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