ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
815 stars 1.49k forks source link

ldap_search: Missing attribute #7747

Closed bepri closed 8 months ago

bepri commented 9 months ago

Summary

In this playbook, I have a step using ldap_search to get somebody's real name from their username in our system. Using the command-line ldapsearch, I'm able to get this info just fine. Using (what I believe to be) an equivalent search with ldap_search, I get a Python import error: module 'ldap' has no attribute 'set_option'.

I've run the same version of Python as is being ran by Ansible and I'm able to import set_option() just fine (note - I run Ansible as root, and so I must run Python as root here to get the same libraries):

» sudo /usr/bin/python3 -c 'from ldap import set_option'
» echo $?
0

python-ldap version info:

» sudo /usr/bin/python3 -m pip show python-ldap
Name: python-ldap
Version: 3.4.4
Summary: Python modules for implementing LDAP clients
Home-page: https://www.python-ldap.org/
Author: python-ldap project
Author-email: python-ldap@python.org
License: Python style
Location: /usr/local/lib64/python3.9/site-packages
Requires: pyasn1, pyasn1-modules
Required-by:

Issue Type

Bug Report

Component Name

ldap_search

Ansible Version

$ ansible --version
ansible [core 2.14.9]
  config file = /local_scratch/macos-ansible/ansible.cfg
  configured module search path = ['/home/REDACTED/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3.9/site-packages/ansible
  ansible collection location = /local_scratch/ansible-dev/ipelton-test/collections:/var/lib/ansible/ansible-dev/galaxy_roles:/var/lib/ansible/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.9.18 (main, Sep  7 2023, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True

Community.general Version

$ ansible-galaxy collection list community.general
# /local_scratch/ansible-dev/ipelton-test/collections/ansible_collections
Collection        Version
----------------- -------
community.general 8.1.0

Configuration

$ ansible-config dump --only-changed
ANSIBLE_NOCOWS(/local_scratch/macos-ansible/ansible.cfg) = True
COLLECTIONS_PATHS(/local_scratch/macos-ansible/ansible.cfg) = ['/local_scratch/ansible-dev/ipelton-test/collections', '/var/lib/ansible/ansible-dev/galaxy_roles', '/var/lib/ansible/.ansible/collecti>
CONFIG_FILE() = /local_scratch/macos-ansible/ansible.cfg
DEFAULT_FORKS(/local_scratch/macos-ansible/ansible.cfg) = 60
DEFAULT_HOST_LIST(/local_scratch/macos-ansible/ansible.cfg) = ['/local_scratch/ansible-dev/hosts']
DEFAULT_ROLES_PATH(/local_scratch/macos-ansible/ansible.cfg) = ['/local_scratch/ansible-dev/ipelton-test/collections', '/local_scratch/macos-ansible/roles', '/var/lib/ansible/ansible-dev/galaxy_role>
DEFAULT_STDOUT_CALLBACK(/local_scratch/macos-ansible/ansible.cfg) = yaml
DEPRECATION_WARNINGS(/local_scratch/macos-ansible/ansible.cfg) = False
HOST_KEY_CHECKING(/local_scratch/macos-ansible/ansible.cfg) = False

OS / Environment

OS: RHEL9.3, Kernel version: 5.14.0-362.8.1.el9_3.x86_64

Steps to Reproduce

        - name: Get NetID
          ansible.builtin.pause:
            prompt: "NetID of new user?"
          register: user_netid

        - name: Look up user
          delegate_to: localhost
          become: false
          community.general.ldap_search:
            attrs:
              - "cn"
            bind_dn: "" # Blank for anonymous bind
            dn: "dn=REDACTED"
            filter: "uid={{ user_netid.user_input }}"
            server_uri: "ldaps://REDACTED"
            validate_certs: false
            scope: "children"
          register: ldap_result

Expected Results

I expected a valid response from LDAP with the information I queried.

Actual Results

TASK [macconfig : Look up user] ******************************************************************************************************************************************************
fatal: [REDACTED.com -> localhost]: FAILED! => changed=false 
  details: module 'ldap' has no attribute 'set_option'
  msg: Attribute action failed.

Code of Conduct

ansibullbot commented 9 months ago

Files identified in the description:

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

click here for bot help

ansibullbot commented 9 months ago

cc @eryx12o45 @jtyr click here for bot help

felixfontein commented 9 months ago

The top-level set_option method for the ldap module should still be there also according to the python-ldap docs (https://www.python-ldap.org/en/python-ldap-3.4.3/reference/ldap.html#ldap.set_option).

Maybe there's another Python module called ldap installed that gets used instead. Maybe add a task with the python_requirements_info module to see whether ansible is really using the Python you think it is using.

bepri commented 9 months ago

Because of the setup of user permissions on this computer (wonderful SELinux...), I can't really easily check using that method, sorry, but ansible --version does print out the Python I expect it to - /usr/bin/python3 (see initial post of this issue). Is there some variable I can print from a debug statement to verify this while Ansible runs?

I agree that it totally should have that set_option() method, especially considering I can import it myself too. Weird stuff.

felixfontein commented 9 months ago

Why does selinux prevent using the python_requirements_info module?

ansible --version only shows what ansible-core itself is using, but not what you are using in your playbook. delegate_to: localhost does not necessarily mean you are using the same Python, that depends on whether your inventory has an explicit localhost entry and if yes, what's it's configuration.

Also did you check whether /usr/lib/python3.9/site-packages/ansible contains a directory ldap, and if yes, what does it contain? python-ldap is installed in /usr/local/lib64/python3.9/site-packages, which is a different directory.

bepri commented 9 months ago

Ahh, I didn't think there would be a difference there, my bad. I might've misdiagnosed that as an selinux thing, not sure. My inventory doesn't have an explicit localhost, it currently contains just a single Macbook for testing purposes. If I delegate_to: localhost and use python_requirements_info, I can get one of two results depending on if I become: true or false.

true: Hangs forever (this is what I assumed was being caused by selinux as everything else seems to be right) false: Read permission error on /usr/local/lib64/python3.9/site-packages/python_ldap-3.4.4.dist-info

This might not be helpful, but I also tried without delegate_to: localhost to see if I could run it at all, and it seemed to succeed.

Here's exactly what I used:

        - name: Check install
          community.general.python_requirements_info:
            dependencies:
              - python-ldap
          delegate_to: localhost
          become: false
          register: ldap_found

        - name: debug
          ansible.builtin.debug:
            var: ldap_found

Also did you check whether /usr/lib/python3.9/site-packages/ansible contains a directory ldap

Doesn't look like it does. ...Did I miss a dependency?

felixfontein commented 9 months ago

Also did you check whether /usr/lib/python3.9/site-packages/ansible contains a directory ldap

Doesn't look like it does. ...Did I miss a dependency?

Actually I meant /usr/lib/python3.9/site-packages/, not its ansible subdirectory...

I'm asking this since it seems there is another Python package called ldap that's not coming from python-ldap. (Or your python-ldap installation is so broken that the above import error shows up.)

In any case the Read permission error on /usr/local/lib64/python3.9/site-packages/python_ldap-3.4.4.dist-info error seems pretty suspicious to me. Maybe something went wrong when installing python-ldap, or it's installed with permissions that don't allow your user to actually see it.

But you initially wrote:

(note - I run Ansible as root, and so I must run Python as root here to get the same libraries):

that kind of disagrees with your error above. If you really run ansible as root, then it should not have any permission problems when opening a directory / reading a file.

bepri commented 9 months ago

Actually I meant /usr/lib/python3.9/site-packages/, not its ansible subdirectory...

Still not in there :(

that kind of disagrees with your error above. If you really run ansible as root, then it should not have any permission problems when opening a directory / reading a file.

And you just caught what I think is the actual problem here. I use become: true as the default in my playbooks and I have ansible-playbook itself aliased such that it requires a password of me every time I run it, but I forgot why, as this was years ago. I assumed it was to become root. Looks like it's actually specifically sudo -u ansible ansible-playbook, so I would've had to install this Python dependency as the ansible user. My mistake. I'm on a Christmas vacation now and so I'm not in my office to test if this fixes things, but it probably will. I'll go ahead and close this once I'm back in the office if it does fix it (feel free to close after the 10th if I still haven't)

Sorry, lol. Thanks, Felix!

felixfontein commented 9 months ago

I'm glad to hear that it likely has a simple fix :) Broken Python installations can be pretty painful :) Enjoy your vacation!

bepri commented 8 months ago

Just about forgot to resolve this, but what I said was indeed the issue, combined with broken permissions on site-packages for my Python installation. Thanks!