We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
community.general.gitlab_runner SSLError cert verify failed
### Summary

I am trying to register some gitlab runners. On new openstack instances.
I get a SSL certificate verify failed error as the return.

If I curl the gitlab url from the command line of the box that I am trying to register I get a response back no TLS issues. 
The gitlab servers certificate is signed by an internal CA, which is installed into the system ca-trust /etc/pki/ca-trust/source/anchors and update-ca-trust has been run.

I am unable to copy and paste the actual out from the servers. Due to interal work policy

### Issue Type

Bug Report

### Component Name

gitlab_runner

### Ansible Version

```console (paste below)
$ ansible --version

```
ansible 2.9.33
python version 3.9.5

### Configuration

```

```


### OS / Environment

CentOS 8 on Openstack train
Gitlab 14.0.1 runner same version


### Steps to Reproduce

<!--- Paste example playbooks or commands between quotes below -->
```yaml (paste below)
- name: register gitlab runner
  community.general.gitlab_runner
    api_url: https://gitlab.internal.addressing
    api_token: abc
    registration_token: def
    description: "{{ anisble_hostname }}"
    state: present
    active: false
    tag_list: shell
    run_untagged: false
    locked: false
```


### Expected Results

The ansible task to connect to the gitlab server and register the runner

### Actual Results

```console (paste below)
SSLError "Certificate_verify_failed"
```


### 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/module_utils/gitlab.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)
4 # Copyright (c) 2018, Marcus Watkins <marwatk@marcuswatkins.net>
5 # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
6 # SPDX-License-Identifier: GPL-3.0-or-later
7 
8 from __future__ import (absolute_import, division, print_function)
9 __metaclass__ = type
10 
11 from ansible.module_utils.basic import missing_required_lib
12 from ansible.module_utils.common.text.converters import to_native
13 from ansible.module_utils.six import integer_types, string_types
14 
15 from ansible_collections.community.general.plugins.module_utils.version import LooseVersion
16 
17 try:
18     from urlparse import urljoin
19 except ImportError:
20     from urllib.parse import urljoin  # Python 3+
21 
22 import traceback
23 
24 GITLAB_IMP_ERR = None
25 try:
26     import gitlab
27     import requests
28     HAS_GITLAB_PACKAGE = True
29 except Exception:
30     gitlab = None
31     GITLAB_IMP_ERR = traceback.format_exc()
32     HAS_GITLAB_PACKAGE = False
33 
34 
35 def auth_argument_spec(spec=None):
36     arg_spec = (dict(
37         api_token=dict(type='str', no_log=True),
38         api_oauth_token=dict(type='str', no_log=True),
39         api_job_token=dict(type='str', no_log=True),
40     ))
41     if spec:
42         arg_spec.update(spec)
43     return arg_spec
44 
45 
46 def find_project(gitlab_instance, identifier):
47     try:
48         project = gitlab_instance.projects.get(identifier)
49     except Exception as e:
50         current_user = gitlab_instance.user
51         try:
52             project = gitlab_instance.projects.get(current_user.username + '/' + identifier)
53         except Exception as e:
54             return None
55 
56     return project
57 
58 
59 def find_group(gitlab_instance, identifier):
60     try:
61         project = gitlab_instance.groups.get(identifier)
62     except Exception as e:
63         return None
64 
65     return project
66 
67 
68 def ensure_gitlab_package(module):
69     if not HAS_GITLAB_PACKAGE:
70         module.fail_json(
71             msg=missing_required_lib("python-gitlab", url='https://python-gitlab.readthedocs.io/en/stable/'),
72             exception=GITLAB_IMP_ERR
73         )
74 
75 
76 def gitlab_authentication(module):
77     gitlab_url = module.params['api_url']
78     validate_certs = module.params['validate_certs']
79     gitlab_user = module.params['api_username']
80     gitlab_password = module.params['api_password']
81     gitlab_token = module.params['api_token']
82     gitlab_oauth_token = module.params['api_oauth_token']
83     gitlab_job_token = module.params['api_job_token']
84 
85     ensure_gitlab_package(module)
86 
87     try:
88         # python-gitlab library remove support for username/password authentication since 1.13.0
89         # Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0
90         # This condition allow to still support older version of the python-gitlab library
91         if LooseVersion(gitlab.__version__) < LooseVersion("1.13.0"):
92             gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,
93                                             private_token=gitlab_token, api_version=4)
94         else:
95             # We can create an oauth_token using a username and password
96             # https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
97             if gitlab_user:
98                 data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}
99                 resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=validate_certs)
100                 resp_data = resp.json()
101                 gitlab_oauth_token = resp_data["access_token"]
102 
103             gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token,
104                                             oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)
105 
106         gitlab_instance.auth()
107     except (gitlab.exceptions.GitlabAuthenticationError, gitlab.exceptions.GitlabGetError) as e:
108         module.fail_json(msg="Failed to connect to GitLab server: %s" % to_native(e))
109     except (gitlab.exceptions.GitlabHttpError) as e:
110         module.fail_json(msg="Failed to connect to GitLab server: %s. \
111             GitLab remove Session API now that private tokens are removed from user API endpoints since version 10.2." % to_native(e))
112 
113     return gitlab_instance
114 
115 
116 def filter_returned_variables(gitlab_variables):
117     # pop properties we don't know
118     existing_variables = [dict(x.attributes) for x in gitlab_variables]
119     KNOWN = ['key', 'value', 'masked', 'protected', 'variable_type', 'environment_scope', 'raw']
120     for item in existing_variables:
121         for key in list(item.keys()):
122             if key not in KNOWN:
123                 item.pop(key)
124     return existing_variables
125 
126 
127 def vars_to_variables(vars, module):
128     # transform old vars to new variables structure
129     variables = list()
130     for item, value in vars.items():
131         if isinstance(value, (string_types, integer_types, float)):
132             variables.append(
133                 {
134                     "name": item,
135                     "value": str(value),
136                     "masked": False,
137                     "protected": False,
138                     "raw": False,
139                     "variable_type": "env_var",
140                 }
141             )
142 
143         elif isinstance(value, dict):
144             new_item = {
145                 "name": item,
146                 "value": value.get('value'),
147                 "masked": value.get('masked'),
148                 "protected": value.get('protected'),
149                 "raw": value.get('raw'),
150                 "variable_type": value.get('variable_type'),
151             }
152 
153             if value.get('environment_scope'):
154                 new_item['environment_scope'] = value.get('environment_scope')
155 
156             variables.append(new_item)
157 
158         else:
159             module.fail_json(msg="value must be of type string, integer, float or dict")
160 
161     return variables
162
```

Path: `plugins/doc_fragments/gitlab.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) Ansible project
3 # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
4 # SPDX-License-Identifier: GPL-3.0-or-later
5 
6 from __future__ import (absolute_import, division, print_function)
7 __metaclass__ = type
8 
9 
10 class ModuleDocFragment(object):
11 
12     # Standard files documentation fragment
13     DOCUMENTATION = r'''
14 requirements:
15   - requests (Python library U(https://pypi.org/project/requests/))
16 
17 options:
18   api_token:
19     description:
20       - GitLab access token with API permissions.
21     type: str
22   api_oauth_token:
23     description:
24       - GitLab OAuth token for logging in.
25     type: str
26     version_added: 4.2.0
27   api_job_token:
28     description:
29       - GitLab CI job token for logging in.
30     type: str
31     version_added: 4.2.0
32 '''
33
```
--- 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/doc_fragments/gitlab.py b/plugins/doc_fragments/gitlab.py
--- a/plugins/doc_fragments/gitlab.py
+++ b/plugins/doc_fragments/gitlab.py
@@ -29,4 +29,9 @@
       - GitLab CI job token for logging in.
     type: str
     version_added: 4.2.0
+  ca_path:
+    description:
+      - The CA certificates bundle to use to verify GitLab server certificate.
+    type: str
+    version_added: 8.1.0
 '''
diff --git a/plugins/module_utils/gitlab.py b/plugins/module_utils/gitlab.py
--- a/plugins/module_utils/gitlab.py
+++ b/plugins/module_utils/gitlab.py
@@ -34,6 +34,7 @@
 
 def auth_argument_spec(spec=None):
     arg_spec = (dict(
+        ca_path=dict(type='str'),
         api_token=dict(type='str', no_log=True),
         api_oauth_token=dict(type='str', no_log=True),
         api_job_token=dict(type='str', no_log=True),
@@ -76,6 +77,7 @@
 def gitlab_authentication(module):
     gitlab_url = module.params['api_url']
     validate_certs = module.params['validate_certs']
+    ca_path = module.params['ca_path']
     gitlab_user = module.params['api_username']
     gitlab_password = module.params['api_password']
     gitlab_token = module.params['api_token']
@@ -84,23 +86,25 @@
 
     ensure_gitlab_package(module)
 
+    verify = ca_path if validate_certs and ca_path else validate_certs
+
     try:
         # python-gitlab library remove support for username/password authentication since 1.13.0
         # Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0
         # This condition allow to still support older version of the python-gitlab library
         if LooseVersion(gitlab.__version__) < LooseVersion("1.13.0"):
-            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,
+            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, email=gitlab_user, password=gitlab_password,
                                             private_token=gitlab_token, api_version=4)
         else:
             # We can create an oauth_token using a username and password
             # https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow
             if gitlab_user:
                 data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}
-                resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=validate_certs)
+                resp = requests.post(urljoin(gitlab_url, "oauth/token"), data=data, verify=verify)
                 resp_data = resp.json()
                 gitlab_oauth_token = resp_data["access_token"]
 
-            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token,
+            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, private_token=gitlab_token,
                                             oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)
 
         gitlab_instance.auth()

{"golden_diff": "diff --git a/plugins/doc_fragments/gitlab.py b/plugins/doc_fragments/gitlab.py\n--- a/plugins/doc_fragments/gitlab.py\n+++ b/plugins/doc_fragments/gitlab.py\n@@ -29,4 +29,9 @@\n       - GitLab CI job token for logging in.\n     type: str\n     version_added: 4.2.0\n+  ca_path:\n+    description:\n+      - The CA certificates bundle to use to verify GitLab server certificate.\n+    type: str\n+    version_added: 8.1.0\n '''\ndiff --git a/plugins/module_utils/gitlab.py b/plugins/module_utils/gitlab.py\n--- a/plugins/module_utils/gitlab.py\n+++ b/plugins/module_utils/gitlab.py\n@@ -34,6 +34,7 @@\n \n def auth_argument_spec(spec=None):\n     arg_spec = (dict(\n+        ca_path=dict(type='str'),\n         api_token=dict(type='str', no_log=True),\n         api_oauth_token=dict(type='str', no_log=True),\n         api_job_token=dict(type='str', no_log=True),\n@@ -76,6 +77,7 @@\n def gitlab_authentication(module):\n     gitlab_url = module.params['api_url']\n     validate_certs = module.params['validate_certs']\n+    ca_path = module.params['ca_path']\n     gitlab_user = module.params['api_username']\n     gitlab_password = module.params['api_password']\n     gitlab_token = module.params['api_token']\n@@ -84,23 +86,25 @@\n \n     ensure_gitlab_package(module)\n \n+    verify = ca_path if validate_certs and ca_path else validate_certs\n+\n     try:\n         # python-gitlab library remove support for username/password authentication since 1.13.0\n         # Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0\n         # This condition allow to still support older version of the python-gitlab library\n         if LooseVersion(gitlab.__version__) < LooseVersion(\"1.13.0\"):\n-            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,\n+            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, email=gitlab_user, password=gitlab_password,\n                                             private_token=gitlab_token, api_version=4)\n         else:\n             # We can create an oauth_token using a username and password\n             # https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow\n             if gitlab_user:\n                 data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}\n-                resp = requests.post(urljoin(gitlab_url, \"oauth/token\"), data=data, verify=validate_certs)\n+                resp = requests.post(urljoin(gitlab_url, \"oauth/token\"), data=data, verify=verify)\n                 resp_data = resp.json()\n                 gitlab_oauth_token = resp_data[\"access_token\"]\n \n-            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token,\n+            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, private_token=gitlab_token,\n                                             oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)\n \n         gitlab_instance.auth()\n", "issue": "community.general.gitlab_runner SSLError cert verify failed\n### Summary\n\nI am trying to register some gitlab runners. On new openstack instances.\r\nI get a SSL certificate verify failed error as the return.\r\n\r\nIf I curl the gitlab url from the command line of the box that I am trying to register I get a response back no TLS issues. \r\nThe gitlab servers certificate is signed by an internal CA, which is installed into the system ca-trust /etc/pki/ca-trust/source/anchors and update-ca-trust has been run.\r\n\r\nI am unable to copy and paste the actual out from the servers. Due to interal work policy\n\n### Issue Type\n\nBug Report\n\n### Component Name\n\ngitlab_runner\n\n### Ansible Version\n\n```console (paste below)\r\n$ ansible --version\r\n\r\n```\r\nansible 2.9.33\r\npython version 3.9.5\n\n### Configuration\n\n```\r\n\r\n```\r\n\n\n### OS / Environment\n\nCentOS 8 on Openstack train\r\nGitlab 14.0.1 runner same version\r\n\n\n### Steps to Reproduce\n\n<!--- Paste example playbooks or commands between quotes below -->\r\n```yaml (paste below)\r\n- name: register gitlab runner\r\n  community.general.gitlab_runner\r\n    api_url: https://gitlab.internal.addressing\r\n    api_token: abc\r\n    registration_token: def\r\n    description: \"{{ anisble_hostname }}\"\r\n    state: present\r\n    active: false\r\n    tag_list: shell\r\n    run_untagged: false\r\n    locked: false\r\n```\r\n\n\n### Expected Results\n\nThe ansible task to connect to the gitlab server and register the runner\n\n### Actual Results\n\n```console (paste below)\r\nSSLError \"Certificate_verify_failed\"\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": "# -*- coding: utf-8 -*-\n\n# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)\n# Copyright (c) 2018, Marcus Watkins <marwatk@marcuswatkins.net>\n# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nfrom ansible.module_utils.basic import missing_required_lib\nfrom ansible.module_utils.common.text.converters import to_native\nfrom ansible.module_utils.six import integer_types, string_types\n\nfrom ansible_collections.community.general.plugins.module_utils.version import LooseVersion\n\ntry:\n    from urlparse import urljoin\nexcept ImportError:\n    from urllib.parse import urljoin  # Python 3+\n\nimport traceback\n\nGITLAB_IMP_ERR = None\ntry:\n    import gitlab\n    import requests\n    HAS_GITLAB_PACKAGE = True\nexcept Exception:\n    gitlab = None\n    GITLAB_IMP_ERR = traceback.format_exc()\n    HAS_GITLAB_PACKAGE = False\n\n\ndef auth_argument_spec(spec=None):\n    arg_spec = (dict(\n        api_token=dict(type='str', no_log=True),\n        api_oauth_token=dict(type='str', no_log=True),\n        api_job_token=dict(type='str', no_log=True),\n    ))\n    if spec:\n        arg_spec.update(spec)\n    return arg_spec\n\n\ndef find_project(gitlab_instance, identifier):\n    try:\n        project = gitlab_instance.projects.get(identifier)\n    except Exception as e:\n        current_user = gitlab_instance.user\n        try:\n            project = gitlab_instance.projects.get(current_user.username + '/' + identifier)\n        except Exception as e:\n            return None\n\n    return project\n\n\ndef find_group(gitlab_instance, identifier):\n    try:\n        project = gitlab_instance.groups.get(identifier)\n    except Exception as e:\n        return None\n\n    return project\n\n\ndef ensure_gitlab_package(module):\n    if not HAS_GITLAB_PACKAGE:\n        module.fail_json(\n            msg=missing_required_lib(\"python-gitlab\", url='https://python-gitlab.readthedocs.io/en/stable/'),\n            exception=GITLAB_IMP_ERR\n        )\n\n\ndef gitlab_authentication(module):\n    gitlab_url = module.params['api_url']\n    validate_certs = module.params['validate_certs']\n    gitlab_user = module.params['api_username']\n    gitlab_password = module.params['api_password']\n    gitlab_token = module.params['api_token']\n    gitlab_oauth_token = module.params['api_oauth_token']\n    gitlab_job_token = module.params['api_job_token']\n\n    ensure_gitlab_package(module)\n\n    try:\n        # python-gitlab library remove support for username/password authentication since 1.13.0\n        # Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0\n        # This condition allow to still support older version of the python-gitlab library\n        if LooseVersion(gitlab.__version__) < LooseVersion(\"1.13.0\"):\n            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, email=gitlab_user, password=gitlab_password,\n                                            private_token=gitlab_token, api_version=4)\n        else:\n            # We can create an oauth_token using a username and password\n            # https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow\n            if gitlab_user:\n                data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}\n                resp = requests.post(urljoin(gitlab_url, \"oauth/token\"), data=data, verify=validate_certs)\n                resp_data = resp.json()\n                gitlab_oauth_token = resp_data[\"access_token\"]\n\n            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=validate_certs, private_token=gitlab_token,\n                                            oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)\n\n        gitlab_instance.auth()\n    except (gitlab.exceptions.GitlabAuthenticationError, gitlab.exceptions.GitlabGetError) as e:\n        module.fail_json(msg=\"Failed to connect to GitLab server: %s\" % to_native(e))\n    except (gitlab.exceptions.GitlabHttpError) as e:\n        module.fail_json(msg=\"Failed to connect to GitLab server: %s. \\\n            GitLab remove Session API now that private tokens are removed from user API endpoints since version 10.2.\" % to_native(e))\n\n    return gitlab_instance\n\n\ndef filter_returned_variables(gitlab_variables):\n    # pop properties we don't know\n    existing_variables = [dict(x.attributes) for x in gitlab_variables]\n    KNOWN = ['key', 'value', 'masked', 'protected', 'variable_type', 'environment_scope', 'raw']\n    for item in existing_variables:\n        for key in list(item.keys()):\n            if key not in KNOWN:\n                item.pop(key)\n    return existing_variables\n\n\ndef vars_to_variables(vars, module):\n    # transform old vars to new variables structure\n    variables = list()\n    for item, value in vars.items():\n        if isinstance(value, (string_types, integer_types, float)):\n            variables.append(\n                {\n                    \"name\": item,\n                    \"value\": str(value),\n                    \"masked\": False,\n                    \"protected\": False,\n                    \"raw\": False,\n                    \"variable_type\": \"env_var\",\n                }\n            )\n\n        elif isinstance(value, dict):\n            new_item = {\n                \"name\": item,\n                \"value\": value.get('value'),\n                \"masked\": value.get('masked'),\n                \"protected\": value.get('protected'),\n                \"raw\": value.get('raw'),\n                \"variable_type\": value.get('variable_type'),\n            }\n\n            if value.get('environment_scope'):\n                new_item['environment_scope'] = value.get('environment_scope')\n\n            variables.append(new_item)\n\n        else:\n            module.fail_json(msg=\"value must be of type string, integer, float or dict\")\n\n    return variables\n", "path": "plugins/module_utils/gitlab.py"}, {"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Ansible project\n# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\n\nclass ModuleDocFragment(object):\n\n    # Standard files documentation fragment\n    DOCUMENTATION = r'''\nrequirements:\n  - requests (Python library U(https://pypi.org/project/requests/))\n\noptions:\n  api_token:\n    description:\n      - GitLab access token with API permissions.\n    type: str\n  api_oauth_token:\n    description:\n      - GitLab OAuth token for logging in.\n    type: str\n    version_added: 4.2.0\n  api_job_token:\n    description:\n      - GitLab CI job token for logging in.\n    type: str\n    version_added: 4.2.0\n'''\n", "path": "plugins/doc_fragments/gitlab.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright (c) 2019, Guillaume Martinez (lunik@tiwabbit.fr)\n# Copyright (c) 2018, Marcus Watkins <marwatk@marcuswatkins.net>\n# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\nfrom ansible.module_utils.basic import missing_required_lib\nfrom ansible.module_utils.common.text.converters import to_native\nfrom ansible.module_utils.six import integer_types, string_types\n\nfrom ansible_collections.community.general.plugins.module_utils.version import LooseVersion\n\ntry:\n    from urlparse import urljoin\nexcept ImportError:\n    from urllib.parse import urljoin  # Python 3+\n\nimport traceback\n\nGITLAB_IMP_ERR = None\ntry:\n    import gitlab\n    import requests\n    HAS_GITLAB_PACKAGE = True\nexcept Exception:\n    gitlab = None\n    GITLAB_IMP_ERR = traceback.format_exc()\n    HAS_GITLAB_PACKAGE = False\n\n\ndef auth_argument_spec(spec=None):\n    arg_spec = (dict(\n        ca_path=dict(type='str'),\n        api_token=dict(type='str', no_log=True),\n        api_oauth_token=dict(type='str', no_log=True),\n        api_job_token=dict(type='str', no_log=True),\n    ))\n    if spec:\n        arg_spec.update(spec)\n    return arg_spec\n\n\ndef find_project(gitlab_instance, identifier):\n    try:\n        project = gitlab_instance.projects.get(identifier)\n    except Exception as e:\n        current_user = gitlab_instance.user\n        try:\n            project = gitlab_instance.projects.get(current_user.username + '/' + identifier)\n        except Exception as e:\n            return None\n\n    return project\n\n\ndef find_group(gitlab_instance, identifier):\n    try:\n        project = gitlab_instance.groups.get(identifier)\n    except Exception as e:\n        return None\n\n    return project\n\n\ndef ensure_gitlab_package(module):\n    if not HAS_GITLAB_PACKAGE:\n        module.fail_json(\n            msg=missing_required_lib(\"python-gitlab\", url='https://python-gitlab.readthedocs.io/en/stable/'),\n            exception=GITLAB_IMP_ERR\n        )\n\n\ndef gitlab_authentication(module):\n    gitlab_url = module.params['api_url']\n    validate_certs = module.params['validate_certs']\n    ca_path = module.params['ca_path']\n    gitlab_user = module.params['api_username']\n    gitlab_password = module.params['api_password']\n    gitlab_token = module.params['api_token']\n    gitlab_oauth_token = module.params['api_oauth_token']\n    gitlab_job_token = module.params['api_job_token']\n\n    ensure_gitlab_package(module)\n\n    verify = ca_path if validate_certs and ca_path else validate_certs\n\n    try:\n        # python-gitlab library remove support for username/password authentication since 1.13.0\n        # Changelog : https://github.com/python-gitlab/python-gitlab/releases/tag/v1.13.0\n        # This condition allow to still support older version of the python-gitlab library\n        if LooseVersion(gitlab.__version__) < LooseVersion(\"1.13.0\"):\n            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, email=gitlab_user, password=gitlab_password,\n                                            private_token=gitlab_token, api_version=4)\n        else:\n            # We can create an oauth_token using a username and password\n            # https://docs.gitlab.com/ee/api/oauth2.html#authorization-code-flow\n            if gitlab_user:\n                data = {'grant_type': 'password', 'username': gitlab_user, 'password': gitlab_password}\n                resp = requests.post(urljoin(gitlab_url, \"oauth/token\"), data=data, verify=verify)\n                resp_data = resp.json()\n                gitlab_oauth_token = resp_data[\"access_token\"]\n\n            gitlab_instance = gitlab.Gitlab(url=gitlab_url, ssl_verify=verify, private_token=gitlab_token,\n                                            oauth_token=gitlab_oauth_token, job_token=gitlab_job_token, api_version=4)\n\n        gitlab_instance.auth()\n    except (gitlab.exceptions.GitlabAuthenticationError, gitlab.exceptions.GitlabGetError) as e:\n        module.fail_json(msg=\"Failed to connect to GitLab server: %s\" % to_native(e))\n    except (gitlab.exceptions.GitlabHttpError) as e:\n        module.fail_json(msg=\"Failed to connect to GitLab server: %s. \\\n            GitLab remove Session API now that private tokens are removed from user API endpoints since version 10.2.\" % to_native(e))\n\n    return gitlab_instance\n\n\ndef filter_returned_variables(gitlab_variables):\n    # pop properties we don't know\n    existing_variables = [dict(x.attributes) for x in gitlab_variables]\n    KNOWN = ['key', 'value', 'masked', 'protected', 'variable_type', 'environment_scope', 'raw']\n    for item in existing_variables:\n        for key in list(item.keys()):\n            if key not in KNOWN:\n                item.pop(key)\n    return existing_variables\n\n\ndef vars_to_variables(vars, module):\n    # transform old vars to new variables structure\n    variables = list()\n    for item, value in vars.items():\n        if isinstance(value, (string_types, integer_types, float)):\n            variables.append(\n                {\n                    \"name\": item,\n                    \"value\": str(value),\n                    \"masked\": False,\n                    \"protected\": False,\n                    \"raw\": False,\n                    \"variable_type\": \"env_var\",\n                }\n            )\n\n        elif isinstance(value, dict):\n            new_item = {\n                \"name\": item,\n                \"value\": value.get('value'),\n                \"masked\": value.get('masked'),\n                \"protected\": value.get('protected'),\n                \"raw\": value.get('raw'),\n                \"variable_type\": value.get('variable_type'),\n            }\n\n            if value.get('environment_scope'):\n                new_item['environment_scope'] = value.get('environment_scope')\n\n            variables.append(new_item)\n\n        else:\n            module.fail_json(msg=\"value must be of type string, integer, float or dict\")\n\n    return variables\n", "path": "plugins/module_utils/gitlab.py"}, {"content": "# -*- coding: utf-8 -*-\n# Copyright (c) Ansible project\n# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nfrom __future__ import (absolute_import, division, print_function)\n__metaclass__ = type\n\n\nclass ModuleDocFragment(object):\n\n    # Standard files documentation fragment\n    DOCUMENTATION = r'''\nrequirements:\n  - requests (Python library U(https://pypi.org/project/requests/))\n\noptions:\n  api_token:\n    description:\n      - GitLab access token with API permissions.\n    type: str\n  api_oauth_token:\n    description:\n      - GitLab OAuth token for logging in.\n    type: str\n    version_added: 4.2.0\n  api_job_token:\n    description:\n      - GitLab CI job token for logging in.\n    type: str\n    version_added: 4.2.0\n  ca_path:\n    description:\n      - The CA certificates bundle to use to verify GitLab server certificate.\n    type: str\n    version_added: 8.1.0\n'''\n", "path": "plugins/doc_fragments/gitlab.py"}]}