Repository: ansible/ansible
Pull request: Fix py3 decoding issues in cyberarkpassword.py
##### SUMMARY
<!--- Describe the change below, including rationale and design decisions -->
This commit fixes the following error while using Python 3:

ERROR! Unexpected Exception, this is probably a bug: a bytes-like object is required, not 'str'

<!--- HINT: Include "Fixes #nnn" if you are fixing an existing issue -->
Fixes #52625

Please backport this change to all still supported Ansible versions.

##### ISSUE TYPE
<!--- Pick one below and delete the rest -->
- Bugfix Pull Request

##### COMPONENT NAME
<!--- Write the short name of the module, plugin, task or feature below -->
cyberarkpassword lookup plugin


Problem statement:
cyberarkpassword: TypeError: a bytes-like object is required, not 'str'
<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and devel branch are affected too -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
Lookup cyberarkpassword results in TypeError: a bytes-like object is required, not 'str' with Python 3.5.

##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
cyberarkpassword lookup plugin

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```paste below
ansible 2.7.7
  config file = /opt/ansibleproj-workdir/ansible.cfg
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible
  executable location = /usr/local/bin/ansible
  python version = 3.5.3 (default, Sep 27 2018, 17:25:39) [GCC 6.3.0 20170516]
```

##### CONFIGURATION
<!--- Paste verbatim output from "ansible-config dump --only-changed" between quotes -->
```paste below
ANSIBLE_SSH_RETRIES(/opt/ansibleproj-workdir/ansible.cfg) = 1
DEFAULT_HOST_LIST(/opt/ansibleproj-workdir/ansible.cfg) = ['/opt/ansibleproj-workdir/inventory/my-vms']
DEFAULT_TIMEOUT(/opt/ansibleproj-workdir/ansible.cfg) = 30
HOST_KEY_CHECKING(/opt/ansibleproj-workdir/ansible.cfg) = False
```

##### OS / ENVIRONMENT
Python 3.5 on Debian Stretch


##### STEPS TO REPRODUCE
<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->
Use a pre-task like the following in a playbook to fetch ssh- and sudo-passwords for the Ansible run.

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- hosts: my-hosts
  gather_facts: false
  pre_tasks:
  - set_fact:
      ansible_username: "{{ item.passprops.username }}"
      ansible_password: "{{ item.password }}"
      ansible_become_pass: "{{ item.password }}"
    with_cyberarkpassword:
      appid: "{{ cyberark_appid }}"
      query: "safe={{ cyberark_safe }};folder=root;object=Application-{{ inventory_hostname }}-{{ cyberark_user }}"
      output: "Password,PassProps.UserName,PassProps.Address,PasswordChangeInProcess"
    loop_control:
      label: "{{ item.passprops }}"
    delegate_to: localhost
```

<!--- HINT: You can paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- Describe what you expected to happen when running the steps above -->
I expected the password fetching to work, just like on other Python versions.

##### ACTUAL RESULTS
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->
See output below:

<!--- Paste verbatim command output between quotes -->
```paste below
Traceback (most recent call last):
  File "/usr/local/bin/ansible-playbook", line 118, in <module>
    exit_code = cli.run()
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/cli/playbook.py", line 122, in run
    results = pbex.run()
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/executor/playbook_executor.py", line 156, in run
    result = self._tqm.run(play=play)
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/executor/task_queue_manager.py", line 291, in run
    play_return = strategy.run(iterator, play_context)
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/plugins/strategy/linear.py", line 282, in run
    task_vars = self._variable_manager.get_vars(play=iterator._play, host=host, task=task)
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/vars/manager.py", line 432, in get_vars
    all_vars['ansible_delegated_vars'], all_vars['_ansible_loop_cache'] = self._get_delegated_vars(play, task, all_vars)
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/vars/manager.py", line 507, in _get_delegated_vars
    items = lookup_loader.get(task.loop_with, loader=self._loader, templar=templar).run(terms=loop_terms, variables=vars_copy)
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/plugins/lookup/cyberarkpassword.py", line 181, in run
    result = cyberark_conn.get()
  File "/opt/ansibleproj-virtualenv/lib/python3.5/site-packages/ansible/plugins/lookup/cyberarkpassword.py", line 143, in get
    output_values = credential.split(self.delimiter)
TypeError: a bytes-like object is required, not 'str'
```

Hints from issue discussion:
Files identified in the description:
* [lib/ansible/plugins/lookup/cyberarkpassword.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/lookup/cyberarkpassword.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @cyberark-bizdev
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@cyberark-bizdev @enunez-cyberark Would you mind taking a look at this?

Commit message: Fix py3 decoding issues in cyberarkpassword.py

This commit fixes the following error while using Python 3:

ERROR! Unexpected Exception, this is probably a bug: a bytes-like object is required, not 'str'

Patch to review:
diff --git a/lib/ansible/plugins/lookup/cyberarkpassword.py b/lib/ansible/plugins/lookup/cyberarkpassword.py
index 348a66f878900e..9cc899ddb512ad 100644
--- a/lib/ansible/plugins/lookup/cyberarkpassword.py
+++ b/lib/ansible/plugins/lookup/cyberarkpassword.py
@@ -108,7 +108,7 @@ def __init__(self, appid=None, query=None, output=None, **kwargs):
             # output 'keys' will be in lowercase.
             self.output = self.output.lower()
 
-        self.delimiter = "@#@"  # Known delimiter to split output results
+        self.delimiter = b"@#@"  # Known delimiter to split output results
 
     def get(self):
 
@@ -144,9 +144,9 @@ def get(self):
                     if "passprops" not in result_dict:
                         result_dict["passprops"] = {}
                     output_prop_name = output_names[i][10:]
-                    result_dict["passprops"][output_prop_name] = output_values[i]
+                    result_dict["passprops"][output_prop_name] = output_values[i].decode("utf-8")
                 else:
-                    result_dict[output_names[i]] = output_values[i]
+                    result_dict[output_names[i]] = output_values[i].decode("utf-8")
 
         except subprocess.CalledProcessError as e:
             raise AnsibleError(e.output)


Code review comments:
diff_hunk: @@ -144,9 +144,9 @@ def get(self):
                     if "passprops" not in result_dict:
                         result_dict["passprops"] = {}
                     output_prop_name = output_names[i][10:]
-                    result_dict["passprops"][output_prop_name] = output_values[i]
+                    result_dict["passprops"][output_prop_name] = output_values[i].decode("utf-8")
path: lib/ansible/plugins/lookup/cyberarkpassword.py
text: @user1:
Please use `to_native` from `from ansible.module_utils._text import to_native` 

@author:
Thank you, fixed.