1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

yaml callback: prevent plugin from modifying PyYAML (#3478)

* Prevent yaml callback from modifying PyYAML.

* Fix changelog fragment.

* Update changelogs/fragments/3478-yaml-callback.yml

Co-authored-by: Brian Scholer <1260690+briantist@users.noreply.github.com>

Co-authored-by: Brian Scholer <1260690+briantist@users.noreply.github.com>
This commit is contained in:
Felix Fontein 2021-10-01 22:42:39 +02:00 committed by GitHub
parent 774b2f642b
commit 5895e50185
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 24 deletions

View file

@ -0,0 +1,2 @@
bugfixes:
- "yaml callback plugin - avoid modifying PyYAML so that other plugins using it on the controller, like the ``to_yaml`` filter, do not produce different output (https://github.com/ansible-collections/community.general/issues/3471, https://github.com/ansible-collections/community.general/pull/3478)."

View file

@ -42,28 +42,29 @@ def should_use_block(value):
return False return False
def my_represent_scalar(self, tag, value, style=None): class MyDumper(AnsibleDumper):
"""Uses block style for multi-line strings""" def represent_scalar(self, tag, value, style=None):
if style is None: """Uses block style for multi-line strings"""
if should_use_block(value): if style is None:
style = '|' if should_use_block(value):
# we care more about readable than accuracy, so... style = '|'
# ...no trailing space # we care more about readable than accuracy, so...
value = value.rstrip() # ...no trailing space
# ...and non-printable characters value = value.rstrip()
value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0) # ...and non-printable characters
# ...tabs prevent blocks from expanding value = ''.join(x for x in value if x in string.printable or ord(x) >= 0xA0)
value = value.expandtabs() # ...tabs prevent blocks from expanding
# ...and odd bits of whitespace value = value.expandtabs()
value = re.sub(r'[\x0b\x0c\r]', '', value) # ...and odd bits of whitespace
# ...as does trailing space value = re.sub(r'[\x0b\x0c\r]', '', value)
value = re.sub(r' +\n', '\n', value) # ...as does trailing space
else: value = re.sub(r' +\n', '\n', value)
style = self.default_style else:
node = yaml.representer.ScalarNode(tag, value, style=style) style = self.default_style
if self.alias_key is not None: node = yaml.representer.ScalarNode(tag, value, style=style)
self.represented_objects[self.alias_key] = node if self.alias_key is not None:
return node self.represented_objects[self.alias_key] = node
return node
class CallbackModule(Default): class CallbackModule(Default):
@ -79,7 +80,6 @@ class CallbackModule(Default):
def __init__(self): def __init__(self):
super(CallbackModule, self).__init__() super(CallbackModule, self).__init__()
yaml.representer.BaseRepresenter.represent_scalar = my_represent_scalar
def _dump_results(self, result, indent=None, sort_keys=True, keep_invocation=False): def _dump_results(self, result, indent=None, sort_keys=True, keep_invocation=False):
if result.get('_ansible_no_log', False): if result.get('_ansible_no_log', False):
@ -121,7 +121,7 @@ class CallbackModule(Default):
if abridged_result: if abridged_result:
dumped += '\n' dumped += '\n'
dumped += to_text(yaml.dump(abridged_result, allow_unicode=True, width=1000, Dumper=AnsibleDumper, default_flow_style=False)) dumped += to_text(yaml.dump(abridged_result, allow_unicode=True, width=1000, Dumper=MyDumper, default_flow_style=False))
# indent by a couple of spaces # indent by a couple of spaces
dumped = '\n '.join(dumped.split('\n')).rstrip() dumped = '\n '.join(dumped.split('\n')).rstrip()

View file

@ -58,3 +58,40 @@
"PLAY RECAP *********************************************************************", "PLAY RECAP *********************************************************************",
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 " "testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
] ]
- name: Test to_yaml
environment:
ANSIBLE_NOCOLOR: 'true'
ANSIBLE_FORCE_COLOR: 'false'
ANSIBLE_STDOUT_CALLBACK: community.general.yaml
playbook: |
- hosts: testhost
gather_facts: false
vars:
data: |
line 1
line 2
line 3
tasks:
- name: Test to_yaml
debug:
msg: "{{ '{{' }}'{{ '{{' }}'{{ '}}' }} data | to_yaml {{ '{{' }}'{{ '}}' }}'{{ '}}' }}"
# The above should be: msg: "{{ data | to_yaml }}"
# Unfortunately, the way Ansible handles templating, we need to do some funny 'escaping' tricks...
expected_output: [
"",
"PLAY [testhost] ****************************************************************",
"",
"TASK [Test to_yaml] ************************************************************",
"ok: [testhost] => ",
" msg: |-",
" 'line 1",
" ",
" line 2",
" ",
" line 3",
" ",
" '",
"",
"PLAY RECAP *********************************************************************",
"testhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 "
]