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

psrp - fix unicode handling in Python 2 #47461

Merged
merged 2 commits into from
Oct 23, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/psrp-utf8.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- psrp - Fix issue when dealing with unicode values in the output for Python 2
34 changes: 16 additions & 18 deletions lib/ansible/plugins/connection/psrp.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,26 +553,24 @@ def _parse_pipeline_result(self, pipeline):
# TODO: figure out a better way of merging this with the host output
stdout_list = []
for output in pipeline.output:
# not all pipeline outputs can be casted to a string, we will
# create our own output based on the properties if that is the
# case+
try:
output_msg = str(output)
except TypeError:
if isinstance(output, GenericComplexObject):
obj_lines = output.property_sets
for key, value in output.adapted_properties.items():
obj_lines.append("%s: %s" % (key, value))
for key, value in output.extended_properties.items():
obj_lines.append("%s: %s" % (key, value))
output_msg = "\n".join(obj_lines)
else:
output_msg = ""
# Not all pipeline outputs are a string or contain a __str__ value,
# we will create our own output based on the properties of the
# complex object if that is the case.
if isinstance(output, GenericComplexObject) and output.to_string is None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If .to_string() exists, do we have to call that explicitly?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Also, is this the way to check for to_string? I don't know the API so I don't know if it really creates the attribute but sets it to None or if it omits the attribute altogether.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to_string always exists, it's just set to None by default https://github.com/jborean93/pypsrp/blob/master/pypsrp/complex_objects.py#L109. It will get populated if the <ToString></ToString> element is populated on the XML being deserialized from the server. In the first case, to_string is None so we need to manually build the string representation from the properties otherwise we just call str() which works for a GenericComplexObject as well as any other non generic ComplexObjects.

obj_lines = output.property_sets
for key, value in output.adapted_properties.items():
obj_lines.append(u"%s: %s" % (key, value))
for key, value in output.extended_properties.items():
obj_lines.append(u"%s: %s" % (key, value))
output_msg = u"\n".join(obj_lines)
else:
output_msg = to_text(output, nonstring='simplerepr')

stdout_list.append(output_msg)

stdout = "\r\n".join(stdout_list)
stdout = u"\r\n".join(stdout_list)
if len(self.host.ui.stdout) > 0:
stdout += "\r\n" + "".join(self.host.ui.stdout)
stdout += u"\r\n" + u"".join(self.host.ui.stdout)

stderr_list = []
for error in pipeline.streams.error:
Expand Down Expand Up @@ -604,4 +602,4 @@ def _parse_pipeline_result(self, pipeline):
self.host.ui.stdout = []
self.host.ui.stderr = []

return rc, stdout, stderr
return rc, to_bytes(stdout, encoding='utf-8'), to_bytes(stderr, encoding='utf-8')
3 changes: 3 additions & 0 deletions test/integration/targets/connection_psrp/inventory.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[windows:vars]
ansible_connection=psrp
ansible_psrp_cert_validation=ignore
10 changes: 7 additions & 3 deletions test/integration/targets/connection_psrp/runme.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

set -eux

pip install pypsrp
python.py -m pip install pypsrp
cd ../connection

INVENTORY=../../inventory.winrm ./test.sh \
-i ../connection_psrp/inventory.ini \
-e target_hosts=winrm \
-e action_prefix=win_ \
-e local_tmp=/tmp/ansible-local \
-e remote_tmp=c:/windows/temp/ansible-remote \
-e ansible_psrp_cert_validation=False \
-c psrp \
"$@"

cd ../connection_psrp

ansible-playbook -i ../../inventory.winrm -i inventory.ini tests.yml \
"$@"
61 changes: 61 additions & 0 deletions test/integration/targets/connection_psrp/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
# these are extra tests for psrp that aren't covered under test/integration/targets/connection/*
- name: test out psrp specific tests
hosts: winrm
serial: 1
gather_facts: no

tasks:
- name: test complex objects in raw output
# until PyYAML is upgraded to 4.x we need to use the \U escape for a unicode codepoint
# and enclose in a quote to it translates the \U
raw: "
[PSCustomObject]@{string = 'string'};
[PSCustomObject]@{unicode = 'poo - \U0001F4A9'};
[PSCustomObject]@{integer = 1};
[PSCustomObject]@{list = @(1, 2)};
Get-Service -Name winrm;
Write-Output -InputObject 'string - \U0001F4A9';"
register: raw_out

- name: assert complex objects in raw output
assert:
that:
- raw_out.stdout_lines|count == 6
- "raw_out.stdout_lines[0] == 'string: string'"
- "raw_out.stdout_lines[1] == 'unicode: poo - \U0001F4A9'"
- "raw_out.stdout_lines[2] == 'integer: 1'"
- "raw_out.stdout_lines[3] == \"list: [1, 2]\""
- raw_out.stdout_lines[4] == "winrm"
- raw_out.stdout_lines[5] == "string - \U0001F4A9"

# Become only works on Server 2008 when running with basic auth, skip this host for now as it is too complicated to
# override the auth protocol in the tests.
- name: check if we running on Server 2008
win_shell: '[System.Environment]::OSVersion.Version -ge [Version]"6.1"'
register: os_version

- name: test out become with psrp
win_whoami:
when: os_version|bool
register: whoami_out
become: yes
become_method: runas
become_user: SYSTEM

- name: assert test out become with psrp
assert:
that:
- whoami_out.account.sid == "S-1-5-18"
when: os_version|bool

- name: test out async with psrp
win_shell: Start-Sleep -Seconds 2; Write-Output abc
async: 5
poll: 1
register: async_out

- name: assert est out async with psrp
assert:
that:
- async_out.stdout_lines == ["abc"]