1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Add Gitlab group runners support (#3935)

This commit is contained in:
Léo GATELLIER 2023-03-25 08:23:20 +01:00 committed by GitHub
parent b1d94385ae
commit f3be0076af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 7 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- 'gitlab_runner - allow to register group runner (https://github.com/ansible-collections/community.general/pull/3935).'

View file

@ -44,10 +44,17 @@ attributes:
support: none support: none
options: options:
group:
description:
- ID or full path of the group in the form group/subgroup.
- Mutually exclusive with I(owned) and I(project).
type: str
version_added: '6.5.0'
project: project:
description: description:
- ID or full path of the project in the form of group/name. - ID or full path of the project in the form of group/name.
- Mutually exclusive with I(owned) since community.general 4.5.0. - Mutually exclusive with I(owned) since community.general 4.5.0.
- Mutually exclusive with I(group).
type: str type: str
version_added: '3.7.0' version_added: '3.7.0'
description: description:
@ -73,6 +80,7 @@ options:
description: description:
- Searches only runners available to the user when searching for existing, when false admin token required. - Searches only runners available to the user when searching for existing, when false admin token required.
- Mutually exclusive with I(project) since community.general 4.5.0. - Mutually exclusive with I(project) since community.general 4.5.0.
- Mutually exclusive with I(group).
default: false default: false
type: bool type: bool
version_added: 2.0.0 version_added: 2.0.0
@ -209,21 +217,23 @@ except NameError:
class GitLabRunner(object): class GitLabRunner(object):
def __init__(self, module, gitlab_instance, project=None): def __init__(self, module, gitlab_instance, group=None, project=None):
self._module = module self._module = module
self._gitlab = gitlab_instance self._gitlab = gitlab_instance
self.runner_object = None
# Whether to operate on GitLab-instance-wide or project-wide runners # Whether to operate on GitLab-instance-wide or project-wide runners
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/60774 # See https://gitlab.com/gitlab-org/gitlab-ce/issues/60774
# for group runner token access # for group runner token access
if project: if project:
self._runners_endpoint = project.runners.list self._runners_endpoint = project.runners.list
elif group:
self._runners_endpoint = group.runners.list
elif module.params['owned']: elif module.params['owned']:
self._runners_endpoint = gitlab_instance.runners.list self._runners_endpoint = gitlab_instance.runners.list
else: else:
self._runners_endpoint = gitlab_instance.runners.all self._runners_endpoint = gitlab_instance.runners.all
self.runner_object = None
def create_or_update_runner(self, description, options): def create_or_update_runner(self, description, options):
changed = False changed = False
@ -360,6 +370,7 @@ def main():
maximum_timeout=dict(type='int', default=3600), maximum_timeout=dict(type='int', default=3600),
registration_token=dict(type='str', no_log=True), registration_token=dict(type='str', no_log=True),
project=dict(type='str'), project=dict(type='str'),
group=dict(type='str'),
state=dict(type='str', default="present", choices=["absent", "present"]), state=dict(type='str', default="present", choices=["absent", "present"]),
)) ))
@ -372,6 +383,8 @@ def main():
['api_token', 'api_oauth_token'], ['api_token', 'api_oauth_token'],
['api_token', 'api_job_token'], ['api_token', 'api_job_token'],
['project', 'owned'], ['project', 'owned'],
['group', 'owned'],
['project', 'group'],
], ],
required_together=[ required_together=[
['api_username', 'api_password'], ['api_username', 'api_password'],
@ -396,6 +409,7 @@ def main():
maximum_timeout = module.params['maximum_timeout'] maximum_timeout = module.params['maximum_timeout']
registration_token = module.params['registration_token'] registration_token = module.params['registration_token']
project = module.params['project'] project = module.params['project']
group = module.params['group']
if access_level is None: if access_level is None:
message = "The option 'access_level' is unspecified, so 'ref_protected' is assumed. "\ message = "The option 'access_level' is unspecified, so 'ref_protected' is assumed. "\
@ -408,13 +422,20 @@ def main():
gitlab_instance = gitlab_authentication(module) gitlab_instance = gitlab_authentication(module)
gitlab_project = None gitlab_project = None
gitlab_group = None
if project: if project:
try: try:
gitlab_project = gitlab_instance.projects.get(project) gitlab_project = gitlab_instance.projects.get(project)
except gitlab.exceptions.GitlabGetError as e: except gitlab.exceptions.GitlabGetError as e:
module.fail_json(msg='No such a project %s' % project, exception=to_native(e)) module.fail_json(msg='No such a project %s' % project, exception=to_native(e))
elif group:
try:
gitlab_group = gitlab_instance.groups.get(group)
except gitlab.exceptions.GitlabGetError as e:
module.fail_json(msg='No such a group %s' % group, exception=to_native(e))
gitlab_runner = GitLabRunner(module, gitlab_instance, gitlab_project) gitlab_runner = GitLabRunner(module, gitlab_instance, gitlab_group, gitlab_project)
runner_exists = gitlab_runner.exists_runner(runner_description) runner_exists = gitlab_runner.exists_runner(runner_description)
if state == 'absent': if state == 'absent':

View file

@ -213,6 +213,31 @@ def resp_get_group(url, request):
return response(200, content, headers, None, 5, request) return response(200, content, headers, None, 5, request)
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/foo-bar", method="get")
def resp_get_group_by_name(url, request):
headers = {'content-type': 'application/json'}
content = ('{"id": 1, "name": "Foobar Group", "path": "foo-bar",'
'"description": "An interesting group", "visibility": "public",'
'"lfs_enabled": true, "avatar_url": "http://localhost:3000/uploads/group/avatar/1/foo.jpg",'
'"web_url": "http://localhost:3000/groups/foo-bar", "request_access_enabled": false,'
'"full_name": "Foobar Group", "full_path": "foo-bar",'
'"project_creation_level": "maintainer", "subgroup_creation_level": "maintainer",'
'"require_two_factor_authentication": true,'
'"file_template_project_id": 1, "parent_id": null, "projects": [{"id": 1,"description": null, "default_branch": "master",'
'"ssh_url_to_repo": "git@example.com:diaspora/diaspora-client.git",'
'"http_url_to_repo": "http://example.com/diaspora/diaspora-client.git",'
'"web_url": "http://example.com/diaspora/diaspora-client",'
'"readme_url": "http://example.com/diaspora/diaspora-client/blob/master/README.md",'
'"tag_list": ["example","disapora client"],"name": "Diaspora Client",'
'"name_with_namespace": "Diaspora / Diaspora Client","path": "diaspora-client",'
'"path_with_namespace": "diaspora/diaspora-client","created_at": "2013-09-30T13:46:02Z",'
'"last_activity_at": "2013-09-30T13:46:02Z","forks_count": 0,'
'"avatar_url": "http://example.com/uploads/project/avatar/4/uploads/avatar.png",'
'"star_count": 0}]}')
content = content.encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1", method="get") @urlmatch(scheme="http", netloc="localhost", path="/api/v4/groups/1", method="get")
def resp_get_missing_group(url, request): def resp_get_missing_group(url, request):
headers = {'content-type': 'application/json'} headers = {'content-type': 'application/json'}
@ -600,6 +625,40 @@ def resp_find_runners_list(url, request):
return response(200, content, headers, None, 5, request) return response(200, content, headers, None, 5, request)
@urlmatch(scheme="http", netloc="localhost", path=r'/api/v4/projects/1/runners$', method="get")
def resp_find_project_runners(url, request):
headers = {'content-type': 'application/json',
"X-Page": 1,
"X-Next-Page": 2,
"X-Per-Page": 1,
"X-Total-Pages": 1,
"X-Total": 2}
content = ('[{"active": true,"description": "test-1-20220210","id": 1,'
'"is_shared": false,"ip_address": "127.0.0.1","name": null,'
'"online": true,"status": "online"},{"active": true,'
'"description": "test-2-20220210","id": 2,"ip_address": "127.0.0.1",'
'"is_shared": false,"name": null,"online": false,"status": "offline"}]')
content = content.encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(scheme="http", netloc="localhost", path=r'/api/v4/groups/1/runners$', method="get")
def resp_find_group_runners(url, request):
headers = {'content-type': 'application/json',
"X-Page": 1,
"X-Next-Page": 2,
"X-Per-Page": 1,
"X-Total-Pages": 1,
"X-Total": 2}
content = ('[{"active": true,"description": "test-3-20220210","id": 1,'
'"is_shared": false,"ip_address": "127.0.0.1","name": null,'
'"online": true,"status": "online"},{"active": true,'
'"description": "test-4-20220210","id": 2,"ip_address": "127.0.0.1",'
'"is_shared": false,"name": null,"online": false,"status": "offline"}]')
content = content.encode("utf-8")
return response(200, content, headers, None, 5, request)
@urlmatch(scheme="http", netloc="localhost", path=r'/api/v4/runners/1$', method="put") @urlmatch(scheme="http", netloc="localhost", path=r'/api/v4/runners/1$', method="put")
def resp_update_runner(url, request): def resp_update_runner(url, request):
headers = {'content-type': 'application/json', headers = {'content-type': 'application/json',

View file

@ -5,6 +5,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
import gitlab
__metaclass__ = type __metaclass__ = type
import pytest import pytest
@ -23,9 +25,11 @@ try:
from .gitlab import (FakeAnsibleModule, from .gitlab import (FakeAnsibleModule,
GitlabModuleTestCase, GitlabModuleTestCase,
python_version_match_requirement, python_version_match_requirement,
resp_find_runners_all, resp_find_runners_all, resp_find_runners_list,
resp_find_runners_list, resp_get_runner, resp_find_project_runners, resp_find_group_runners,
resp_create_runner, resp_delete_runner) resp_get_runner,
resp_create_runner, resp_delete_runner,
resp_get_project_by_name, resp_get_group_by_name)
# GitLab module requirements # GitLab module requirements
if python_version_match_requirement(): if python_version_match_requirement():
@ -76,6 +80,37 @@ class TestGitlabRunner(GitlabModuleTestCase):
self.assertEqual(rvalue, False) self.assertEqual(rvalue, False)
@with_httmock(resp_find_project_runners)
@with_httmock(resp_get_runner)
@with_httmock(resp_get_project_by_name)
def test_project_runner_exist(self):
gitlab_project = self.gitlab_instance.projects.get('foo-bar/diaspora-client')
module_util = GitLabRunner(module=FakeAnsibleModule(), gitlab_instance=self.gitlab_instance, project=gitlab_project)
rvalue = module_util.exists_runner("test-1-20220210")
self.assertEqual(rvalue, True)
rvalue = module_util.exists_runner("test-3-00000000")
self.assertEqual(rvalue, False)
@with_httmock(resp_find_group_runners)
@with_httmock(resp_get_group_by_name)
@with_httmock(resp_get_runner)
@pytest.mark.skipif(gitlab.__version__ < "2.3.0", reason="require python-gitlab >= 2.3.0")
def test_group_runner_exist(self):
gitlab_group = self.gitlab_instance.groups.get('foo-bar')
module_util = GitLabRunner(module=FakeAnsibleModule(), gitlab_instance=self.gitlab_instance, group=gitlab_group)
rvalue = module_util.exists_runner("test-3-20220210")
self.assertEqual(rvalue, True)
rvalue = module_util.exists_runner("test-3-00000000")
self.assertEqual(rvalue, False)
@with_httmock(resp_create_runner) @with_httmock(resp_create_runner)
def test_create_runner(self): def test_create_runner(self):
runner = self.module_util_all.create_runner({"token": "token", "description": "test-1-20150125"}) runner = self.module_util_all.create_runner({"token": "token", "description": "test-1-20150125"})