We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Allow community.general.ldap_search to be used even in check mode
### Summary

It looks like community.general.ldap_search does no return data if using check mode. You have to use "check_mode=no" to get data if testing. It's a search, so nothing should be changed anyways. So whether or not "--check" is used when calling the playbook the correct result should be returned. 


### Issue Type

Feature Idea

### Component Name

community.general.ldap_search

### Additional Information

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)

```


### Code of Conduct

- [X] I agree to follow the Ansible Code of Conduct

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `plugins/modules/net_tools/ldap/ldap_search.py`
Content:
```
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3 
4 # Copyright: (c) 2016, Peter Sagerson <psagers@ignorare.net>
5 # Copyright: (c) 2020, Sebastian Pfahl <eryx@gmx.net>
6 # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
7 
8 from __future__ import absolute_import, division, print_function
9 __metaclass__ = type
10 
11 DOCUMENTATION = r"""
12 ---
13 module: ldap_search
14 version_added: '0.2.0'
15 short_description: Search for entries in a LDAP server
16 description:
17   - Return the results of an LDAP search.
18 notes:
19   - The default authentication settings will attempt to use a SASL EXTERNAL
20     bind over a UNIX domain socket. This works well with the default Ubuntu
21     install for example, which includes a C(cn=peercred,cn=external,cn=auth) ACL
22     rule allowing root to modify the server configuration. If you need to use
23     a simple bind to access your server, pass the credentials in I(bind_dn)
24     and I(bind_pw).
25 author:
26   - Sebastian Pfahl (@eryx12o45)
27 requirements:
28   - python-ldap
29 options:
30   dn:
31     required: true
32     type: str
33     description:
34       - The LDAP DN to search in.
35   scope:
36     choices: [base, onelevel, subordinate, children]
37     default: base
38     type: str
39     description:
40       - The LDAP scope to use.
41   filter:
42     default: '(objectClass=*)'
43     type: str
44     description:
45       - Used for filtering the LDAP search result.
46   attrs:
47     type: list
48     elements: str
49     description:
50       - A list of attributes for limiting the result. Use an
51         actual list or a comma-separated string.
52   schema:
53     default: false
54     type: bool
55     description:
56       - Set to C(true) to return the full attribute schema of entries, not
57         their attribute values. Overrides I(attrs) when provided.
58 extends_documentation_fragment:
59     - community.general.ldap.documentation
60 """
61 
62 EXAMPLES = r"""
63 - name: Return all entries within the 'groups' organizational unit.
64   community.general.ldap_search:
65     dn: "ou=groups,dc=example,dc=com"
66   register: ldap_groups
67 
68 - name: Return GIDs for all groups
69   community.general.ldap_search:
70     dn: "ou=groups,dc=example,dc=com"
71     scope: "onelevel"
72     attrs:
73       - "gidNumber"
74   register: ldap_group_gids
75 """
76 
77 import traceback
78 
79 from ansible.module_utils.basic import AnsibleModule, missing_required_lib
80 from ansible.module_utils.common.text.converters import to_native
81 from ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs
82 
83 LDAP_IMP_ERR = None
84 try:
85     import ldap
86 
87     HAS_LDAP = True
88 except ImportError:
89     LDAP_IMP_ERR = traceback.format_exc()
90     HAS_LDAP = False
91 
92 
93 def main():
94     module = AnsibleModule(
95         argument_spec=gen_specs(
96             dn=dict(type='str', required=True),
97             scope=dict(type='str', default='base', choices=['base', 'onelevel', 'subordinate', 'children']),
98             filter=dict(type='str', default='(objectClass=*)'),
99             attrs=dict(type='list', elements='str'),
100             schema=dict(type='bool', default=False),
101         ),
102         supports_check_mode=True,
103     )
104 
105     if not HAS_LDAP:
106         module.fail_json(msg=missing_required_lib('python-ldap'),
107                          exception=LDAP_IMP_ERR)
108 
109     if not module.check_mode:
110         try:
111             LdapSearch(module).main()
112         except Exception as exception:
113             module.fail_json(msg="Attribute action failed.", details=to_native(exception))
114 
115     module.exit_json(changed=False)
116 
117 
118 def _extract_entry(dn, attrs):
119     extracted = {'dn': dn}
120     for attr, val in list(attrs.items()):
121         if len(val) == 1:
122             extracted[attr] = val[0]
123         else:
124             extracted[attr] = val
125     return extracted
126 
127 
128 class LdapSearch(LdapGeneric):
129     def __init__(self, module):
130         LdapGeneric.__init__(self, module)
131 
132         self.dn = self.module.params['dn']
133         self.filterstr = self.module.params['filter']
134         self.attrlist = []
135         self._load_scope()
136         self._load_attrs()
137         self._load_schema()
138 
139     def _load_schema(self):
140         self.schema = self.module.boolean(self.module.params['schema'])
141         if self.schema:
142             self.attrsonly = 1
143         else:
144             self.attrsonly = 0
145 
146     def _load_scope(self):
147         spec = dict(
148             base=ldap.SCOPE_BASE,
149             onelevel=ldap.SCOPE_ONELEVEL,
150             subordinate=ldap.SCOPE_SUBORDINATE,
151             children=ldap.SCOPE_SUBTREE,
152         )
153         self.scope = spec[self.module.params['scope']]
154 
155     def _load_attrs(self):
156         self.attrlist = self.module.params['attrs'] or None
157 
158     def main(self):
159         results = self.perform_search()
160         self.module.exit_json(changed=False, results=results)
161 
162     def perform_search(self):
163         try:
164             results = self.connection.search_s(
165                 self.dn,
166                 self.scope,
167                 filterstr=self.filterstr,
168                 attrlist=self.attrlist,
169                 attrsonly=self.attrsonly
170             )
171             ldap_entries = []
172             for result in results:
173                 if isinstance(result[1], dict):
174                     if self.schema:
175                         ldap_entries.append(dict(dn=result[0], attrs=list(result[1].keys())))
176                     else:
177                         ldap_entries.append(_extract_entry(result[0], result[1]))
178             return ldap_entries
179         except ldap.NO_SUCH_OBJECT:
180             self.module.fail_json(msg="Base not found: {0}".format(self.dn))
181 
182 
183 if __name__ == '__main__':
184     main()
185
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/plugins/modules/net_tools/ldap/ldap_search.py b/plugins/modules/net_tools/ldap/ldap_search.py
--- a/plugins/modules/net_tools/ldap/ldap_search.py
+++ b/plugins/modules/net_tools/ldap/ldap_search.py
@@ -106,11 +106,10 @@
         module.fail_json(msg=missing_required_lib('python-ldap'),
                          exception=LDAP_IMP_ERR)
 
-    if not module.check_mode:
-        try:
-            LdapSearch(module).main()
-        except Exception as exception:
-            module.fail_json(msg="Attribute action failed.", details=to_native(exception))
+    try:
+        LdapSearch(module).main()
+    except Exception as exception:
+        module.fail_json(msg="Attribute action failed.", details=to_native(exception))
 
     module.exit_json(changed=False)

{"golden_diff": "diff --git a/plugins/modules/net_tools/ldap/ldap_search.py b/plugins/modules/net_tools/ldap/ldap_search.py\n--- a/plugins/modules/net_tools/ldap/ldap_search.py\n+++ b/plugins/modules/net_tools/ldap/ldap_search.py\n@@ -106,11 +106,10 @@\n         module.fail_json(msg=missing_required_lib('python-ldap'),\n                          exception=LDAP_IMP_ERR)\n \n-    if not module.check_mode:\n-        try:\n-            LdapSearch(module).main()\n-        except Exception as exception:\n-            module.fail_json(msg=\"Attribute action failed.\", details=to_native(exception))\n+    try:\n+        LdapSearch(module).main()\n+    except Exception as exception:\n+        module.fail_json(msg=\"Attribute action failed.\", details=to_native(exception))\n \n     module.exit_json(changed=False)\n", "issue": "Allow community.general.ldap_search to be used even in check mode\n### Summary\n\nIt looks like community.general.ldap_search does no return data if using check mode. You have to use \"check_mode=no\" to get data if testing. It's a search, so nothing should be changed anyways. So whether or not \"--check\" is used when calling the playbook the correct result should be returned. \r\n\n\n### Issue Type\n\nFeature Idea\n\n### Component Name\n\ncommunity.general.ldap_search\n\n### Additional Information\n\n<!--- Paste example playbooks or commands between quotes below -->\r\n```yaml (paste below)\r\n\r\n```\r\n\n\n### Code of Conduct\n\n- [X] I agree to follow the Ansible Code of Conduct\n", "before_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# Copyright: (c) 2016, Peter Sagerson <psagers@ignorare.net>\n# Copyright: (c) 2020, Sebastian Pfahl <eryx@gmx.net>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nDOCUMENTATION = r\"\"\"\n---\nmodule: ldap_search\nversion_added: '0.2.0'\nshort_description: Search for entries in a LDAP server\ndescription:\n  - Return the results of an LDAP search.\nnotes:\n  - The default authentication settings will attempt to use a SASL EXTERNAL\n    bind over a UNIX domain socket. This works well with the default Ubuntu\n    install for example, which includes a C(cn=peercred,cn=external,cn=auth) ACL\n    rule allowing root to modify the server configuration. If you need to use\n    a simple bind to access your server, pass the credentials in I(bind_dn)\n    and I(bind_pw).\nauthor:\n  - Sebastian Pfahl (@eryx12o45)\nrequirements:\n  - python-ldap\noptions:\n  dn:\n    required: true\n    type: str\n    description:\n      - The LDAP DN to search in.\n  scope:\n    choices: [base, onelevel, subordinate, children]\n    default: base\n    type: str\n    description:\n      - The LDAP scope to use.\n  filter:\n    default: '(objectClass=*)'\n    type: str\n    description:\n      - Used for filtering the LDAP search result.\n  attrs:\n    type: list\n    elements: str\n    description:\n      - A list of attributes for limiting the result. Use an\n        actual list or a comma-separated string.\n  schema:\n    default: false\n    type: bool\n    description:\n      - Set to C(true) to return the full attribute schema of entries, not\n        their attribute values. Overrides I(attrs) when provided.\nextends_documentation_fragment:\n    - community.general.ldap.documentation\n\"\"\"\n\nEXAMPLES = r\"\"\"\n- name: Return all entries within the 'groups' organizational unit.\n  community.general.ldap_search:\n    dn: \"ou=groups,dc=example,dc=com\"\n  register: ldap_groups\n\n- name: Return GIDs for all groups\n  community.general.ldap_search:\n    dn: \"ou=groups,dc=example,dc=com\"\n    scope: \"onelevel\"\n    attrs:\n      - \"gidNumber\"\n  register: ldap_group_gids\n\"\"\"\n\nimport traceback\n\nfrom ansible.module_utils.basic import AnsibleModule, missing_required_lib\nfrom ansible.module_utils.common.text.converters import to_native\nfrom ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs\n\nLDAP_IMP_ERR = None\ntry:\n    import ldap\n\n    HAS_LDAP = True\nexcept ImportError:\n    LDAP_IMP_ERR = traceback.format_exc()\n    HAS_LDAP = False\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=gen_specs(\n            dn=dict(type='str', required=True),\n            scope=dict(type='str', default='base', choices=['base', 'onelevel', 'subordinate', 'children']),\n            filter=dict(type='str', default='(objectClass=*)'),\n            attrs=dict(type='list', elements='str'),\n            schema=dict(type='bool', default=False),\n        ),\n        supports_check_mode=True,\n    )\n\n    if not HAS_LDAP:\n        module.fail_json(msg=missing_required_lib('python-ldap'),\n                         exception=LDAP_IMP_ERR)\n\n    if not module.check_mode:\n        try:\n            LdapSearch(module).main()\n        except Exception as exception:\n            module.fail_json(msg=\"Attribute action failed.\", details=to_native(exception))\n\n    module.exit_json(changed=False)\n\n\ndef _extract_entry(dn, attrs):\n    extracted = {'dn': dn}\n    for attr, val in list(attrs.items()):\n        if len(val) == 1:\n            extracted[attr] = val[0]\n        else:\n            extracted[attr] = val\n    return extracted\n\n\nclass LdapSearch(LdapGeneric):\n    def __init__(self, module):\n        LdapGeneric.__init__(self, module)\n\n        self.dn = self.module.params['dn']\n        self.filterstr = self.module.params['filter']\n        self.attrlist = []\n        self._load_scope()\n        self._load_attrs()\n        self._load_schema()\n\n    def _load_schema(self):\n        self.schema = self.module.boolean(self.module.params['schema'])\n        if self.schema:\n            self.attrsonly = 1\n        else:\n            self.attrsonly = 0\n\n    def _load_scope(self):\n        spec = dict(\n            base=ldap.SCOPE_BASE,\n            onelevel=ldap.SCOPE_ONELEVEL,\n            subordinate=ldap.SCOPE_SUBORDINATE,\n            children=ldap.SCOPE_SUBTREE,\n        )\n        self.scope = spec[self.module.params['scope']]\n\n    def _load_attrs(self):\n        self.attrlist = self.module.params['attrs'] or None\n\n    def main(self):\n        results = self.perform_search()\n        self.module.exit_json(changed=False, results=results)\n\n    def perform_search(self):\n        try:\n            results = self.connection.search_s(\n                self.dn,\n                self.scope,\n                filterstr=self.filterstr,\n                attrlist=self.attrlist,\n                attrsonly=self.attrsonly\n            )\n            ldap_entries = []\n            for result in results:\n                if isinstance(result[1], dict):\n                    if self.schema:\n                        ldap_entries.append(dict(dn=result[0], attrs=list(result[1].keys())))\n                    else:\n                        ldap_entries.append(_extract_entry(result[0], result[1]))\n            return ldap_entries\n        except ldap.NO_SUCH_OBJECT:\n            self.module.fail_json(msg=\"Base not found: {0}\".format(self.dn))\n\n\nif __name__ == '__main__':\n    main()\n", "path": "plugins/modules/net_tools/ldap/ldap_search.py"}], "after_files": [{"content": "#!/usr/bin/python\n# -*- coding: utf-8 -*-\n\n# Copyright: (c) 2016, Peter Sagerson <psagers@ignorare.net>\n# Copyright: (c) 2020, Sebastian Pfahl <eryx@gmx.net>\n# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)\n\nfrom __future__ import absolute_import, division, print_function\n__metaclass__ = type\n\nDOCUMENTATION = r\"\"\"\n---\nmodule: ldap_search\nversion_added: '0.2.0'\nshort_description: Search for entries in a LDAP server\ndescription:\n  - Return the results of an LDAP search.\nnotes:\n  - The default authentication settings will attempt to use a SASL EXTERNAL\n    bind over a UNIX domain socket. This works well with the default Ubuntu\n    install for example, which includes a C(cn=peercred,cn=external,cn=auth) ACL\n    rule allowing root to modify the server configuration. If you need to use\n    a simple bind to access your server, pass the credentials in I(bind_dn)\n    and I(bind_pw).\nauthor:\n  - Sebastian Pfahl (@eryx12o45)\nrequirements:\n  - python-ldap\noptions:\n  dn:\n    required: true\n    type: str\n    description:\n      - The LDAP DN to search in.\n  scope:\n    choices: [base, onelevel, subordinate, children]\n    default: base\n    type: str\n    description:\n      - The LDAP scope to use.\n  filter:\n    default: '(objectClass=*)'\n    type: str\n    description:\n      - Used for filtering the LDAP search result.\n  attrs:\n    type: list\n    elements: str\n    description:\n      - A list of attributes for limiting the result. Use an\n        actual list or a comma-separated string.\n  schema:\n    default: false\n    type: bool\n    description:\n      - Set to C(true) to return the full attribute schema of entries, not\n        their attribute values. Overrides I(attrs) when provided.\nextends_documentation_fragment:\n    - community.general.ldap.documentation\n\"\"\"\n\nEXAMPLES = r\"\"\"\n- name: Return all entries within the 'groups' organizational unit.\n  community.general.ldap_search:\n    dn: \"ou=groups,dc=example,dc=com\"\n  register: ldap_groups\n\n- name: Return GIDs for all groups\n  community.general.ldap_search:\n    dn: \"ou=groups,dc=example,dc=com\"\n    scope: \"onelevel\"\n    attrs:\n      - \"gidNumber\"\n  register: ldap_group_gids\n\"\"\"\n\nimport traceback\n\nfrom ansible.module_utils.basic import AnsibleModule, missing_required_lib\nfrom ansible.module_utils.common.text.converters import to_native\nfrom ansible_collections.community.general.plugins.module_utils.ldap import LdapGeneric, gen_specs\n\nLDAP_IMP_ERR = None\ntry:\n    import ldap\n\n    HAS_LDAP = True\nexcept ImportError:\n    LDAP_IMP_ERR = traceback.format_exc()\n    HAS_LDAP = False\n\n\ndef main():\n    module = AnsibleModule(\n        argument_spec=gen_specs(\n            dn=dict(type='str', required=True),\n            scope=dict(type='str', default='base', choices=['base', 'onelevel', 'subordinate', 'children']),\n            filter=dict(type='str', default='(objectClass=*)'),\n            attrs=dict(type='list', elements='str'),\n            schema=dict(type='bool', default=False),\n        ),\n        supports_check_mode=True,\n    )\n\n    if not HAS_LDAP:\n        module.fail_json(msg=missing_required_lib('python-ldap'),\n                         exception=LDAP_IMP_ERR)\n\n    try:\n        LdapSearch(module).main()\n    except Exception as exception:\n        module.fail_json(msg=\"Attribute action failed.\", details=to_native(exception))\n\n    module.exit_json(changed=False)\n\n\ndef _extract_entry(dn, attrs):\n    extracted = {'dn': dn}\n    for attr, val in list(attrs.items()):\n        if len(val) == 1:\n            extracted[attr] = val[0]\n        else:\n            extracted[attr] = val\n    return extracted\n\n\nclass LdapSearch(LdapGeneric):\n    def __init__(self, module):\n        LdapGeneric.__init__(self, module)\n\n        self.dn = self.module.params['dn']\n        self.filterstr = self.module.params['filter']\n        self.attrlist = []\n        self._load_scope()\n        self._load_attrs()\n        self._load_schema()\n\n    def _load_schema(self):\n        self.schema = self.module.boolean(self.module.params['schema'])\n        if self.schema:\n            self.attrsonly = 1\n        else:\n            self.attrsonly = 0\n\n    def _load_scope(self):\n        spec = dict(\n            base=ldap.SCOPE_BASE,\n            onelevel=ldap.SCOPE_ONELEVEL,\n            subordinate=ldap.SCOPE_SUBORDINATE,\n            children=ldap.SCOPE_SUBTREE,\n        )\n        self.scope = spec[self.module.params['scope']]\n\n    def _load_attrs(self):\n        self.attrlist = self.module.params['attrs'] or None\n\n    def main(self):\n        results = self.perform_search()\n        self.module.exit_json(changed=False, results=results)\n\n    def perform_search(self):\n        try:\n            results = self.connection.search_s(\n                self.dn,\n                self.scope,\n                filterstr=self.filterstr,\n                attrlist=self.attrlist,\n                attrsonly=self.attrsonly\n            )\n            ldap_entries = []\n            for result in results:\n                if isinstance(result[1], dict):\n                    if self.schema:\n                        ldap_entries.append(dict(dn=result[0], attrs=list(result[1].keys())))\n                    else:\n                        ldap_entries.append(_extract_entry(result[0], result[1]))\n            return ldap_entries\n        except ldap.NO_SUCH_OBJECT:\n            self.module.fail_json(msg=\"Base not found: {0}\".format(self.dn))\n\n\nif __name__ == '__main__':\n    main()\n", "path": "plugins/modules/net_tools/ldap/ldap_search.py"}]}