##// END OF EJS Templates
core: code changes to handle branch-permissions / locking / incorrect client support
super-admin -
r1323:a1a9e846 default
parent child Browse files
Show More
@@ -53,12 +53,6 b' def ArchiveException(org_exc=None):'
53 return _make_exception_wrapper
53 return _make_exception_wrapper
54
54
55
55
56 def ClientNotSupportedException(org_exc=None):
57 def _make_exception_wrapper(*args):
58 return _make_exception('client_not_supported', org_exc, *args)
59 return _make_exception_wrapper
60
61
62 def LookupException(org_exc=None):
56 def LookupException(org_exc=None):
63 def _make_exception_wrapper(*args):
57 def _make_exception_wrapper(*args):
64 return _make_exception('lookup', org_exc, *args)
58 return _make_exception('lookup', org_exc, *args)
@@ -82,6 +76,10 b' def RepositoryBranchProtectedException(o'
82 return _make_exception('repo_branch_protected', org_exc, *args)
76 return _make_exception('repo_branch_protected', org_exc, *args)
83 return _make_exception_wrapper
77 return _make_exception_wrapper
84
78
79 def ClientNotSupportedException(org_exc=None):
80 def _make_exception_wrapper(*args):
81 return _make_exception('client_not_supported', org_exc, *args)
82 return _make_exception_wrapper
85
83
86 def RequirementException(org_exc=None):
84 def RequirementException(org_exc=None):
87 def _make_exception_wrapper(*args):
85 def _make_exception_wrapper(*args):
@@ -118,9 +116,18 b' class HTTPRepoLocked(HTTPLocked):'
118 super().__init__(**kwargs)
116 super().__init__(**kwargs)
119
117
120
118
121 class HTTPRepoBranchProtected(HTTPForbidden):
119 class HTTPRepoBranchProtected(HTTPLocked):
122 def __init__(self, *args, **kwargs):
120 def __init__(self, title, status_code=None, **kwargs):
123 super(HTTPForbidden, self).__init__(*args, **kwargs)
121 self.code = status_code or HTTPLocked.code
122 self.title = title
123 super().__init__(**kwargs)
124
125
126 class HTTPClientNotSupported(HTTPLocked):
127 def __init__(self, title, status_code=None, **kwargs):
128 self.code = status_code or HTTPLocked.code
129 self.title = title
130 super().__init__(**kwargs)
124
131
125
132
126 class RefNotFoundException(KeyError):
133 class RefNotFoundException(KeyError):
@@ -1,5 +1,5 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2023 RhodeCode GmbH
2 # Copyright (C) 2014-2024 RhodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
@@ -56,6 +56,9 b' class HooksCeleryClient:'
56 self.celery_app = celery_app
56 self.celery_app = celery_app
57
57
58 def __call__(self, method, extras):
58 def __call__(self, method, extras):
59 # NOTE: exception handling for those tasks executed is in
60 # @adapt_for_celery decorator
61 # also see: _maybe_handle_exception which is handling exceptions
59 inquired_task = self.celery_app.signature(
62 inquired_task = self.celery_app.signature(
60 f'rhodecode.lib.celerylib.tasks.{method}'
63 f'rhodecode.lib.celerylib.tasks.{method}'
61 )
64 )
@@ -83,11 +86,8 b' class HgMessageWriter(RemoteMessageWrite'
83 self.ui = ui
86 self.ui = ui
84
87
85 def write(self, message: str):
88 def write(self, message: str):
86 # TODO: Check why the quiet flag is set by default.
89 args = (message.encode('utf-8'),)
87 old = self.ui.quiet
90 self.ui._writemsg(self.ui._fmsgerr, type=b'status', *args)
88 self.ui.quiet = False
89 self.ui.status(message.encode('utf-8'))
90 self.ui.quiet = old
91
91
92
92
93 class GitMessageWriter(RemoteMessageWriter):
93 class GitMessageWriter(RemoteMessageWriter):
@@ -97,7 +97,7 b' class GitMessageWriter(RemoteMessageWrit'
97 self.stdout = stdout or sys.stdout
97 self.stdout = stdout or sys.stdout
98
98
99 def write(self, message: str):
99 def write(self, message: str):
100 self.stdout.write(message)
100 self.stdout.write(message + "\n" if message else "")
101
101
102
102
103 class SvnMessageWriter(RemoteMessageWriter):
103 class SvnMessageWriter(RemoteMessageWriter):
@@ -111,28 +111,30 b' class SvnMessageWriter(RemoteMessageWrit'
111 self.stderr.write(message)
111 self.stderr.write(message)
112
112
113
113
114 def _maybe_handle_exception(result):
114 def _maybe_handle_exception(writer, result):
115
115 """
116 adopt_for_celery defines the exception/exception_traceback
117 Ths result is a direct output from a celery task
118 """
116
119
117 exception_class = result.get('exception')
120 exception_class = result.get('exception')
118 exception_traceback = result.get('exception_traceback')
121 exception_traceback = result.get('exception_traceback')
119 if not exception_class:
120 return
121
122
122 log.debug('Handling hook-call exception: %s', exception_class)
123 match exception_class:
123
124 # NOTE: the underlying exceptions are setting _vcs_kind special marker
124 if exception_traceback:
125 # which is later handled by `handle_vcs_exception` and translated into a special HTTP exception
125 log.error('Got traceback from remote call:%s', exception_traceback)
126 # propagated later to the client
126
127 case 'HTTPLockedRepo':
127 if exception_class == 'HTTPLockedRepo':
128 raise exceptions.LockedRepoException()(*result['exception_args'])
128 raise exceptions.LockedRepoException()(*result['exception_args'])
129 elif exception_class == 'ClientNotSupportedError':
129 case 'ClientNotSupported':
130 raise exceptions.ClientNotSupportedException()(*result['exception_args'])
130 raise exceptions.ClientNotSupportedException()(*result['exception_args'])
131 elif exception_class == 'HTTPBranchProtected':
131 case 'HTTPBranchProtected':
132 raise exceptions.RepositoryBranchProtectedException()(*result['exception_args'])
132 raise exceptions.RepositoryBranchProtectedException()(*result['exception_args'])
133 elif exception_class == 'RepositoryError':
133 case 'RepositoryError':
134 raise exceptions.VcsException()(*result['exception_args'])
134 raise exceptions.VcsException()(*result['exception_args'])
135 elif exception_class:
135 case _:
136 if exception_class:
137 log.error('Handling hook-call exception. Got traceback from remote call:%s', exception_traceback)
136 raise Exception(
138 raise Exception(
137 f"""Got remote exception "{exception_class}" with args "{result['exception_args']}" """
139 f"""Got remote exception "{exception_class}" with args "{result['exception_args']}" """
138 )
140 )
@@ -156,7 +158,7 b' def _call_hook(hook_name, extras, writer'
156 log.debug('Hooks, using client:%s', hooks_client)
158 log.debug('Hooks, using client:%s', hooks_client)
157 result = hooks_client(hook_name, extras)
159 result = hooks_client(hook_name, extras)
158 log.debug('Hooks got result: %s', result)
160 log.debug('Hooks got result: %s', result)
159 _maybe_handle_exception(result)
161 _maybe_handle_exception(writer, result)
160 writer.write(result['output'])
162 writer.write(result['output'])
161
163
162 return result['status']
164 return result['status']
@@ -47,7 +47,7 b' from vcsserver.server import VcsServer'
47 from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
47 from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
48 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
48 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
49 from vcsserver.echo_stub.echo_app import EchoApp
49 from vcsserver.echo_stub.echo_app import EchoApp
50 from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected
50 from vcsserver.exceptions import HTTPRepoLocked, HTTPRepoBranchProtected, HTTPClientNotSupported
51 from vcsserver.lib.exc_tracking import store_exception, format_exc
51 from vcsserver.lib.exc_tracking import store_exception, format_exc
52 from vcsserver.lib.str_utils import safe_int
52 from vcsserver.lib.str_utils import safe_int
53 from vcsserver.lib.statsd_client import StatsdClient
53 from vcsserver.lib.statsd_client import StatsdClient
@@ -635,19 +635,21 b' class HTTPApplication:'
635 return _git_stream
635 return _git_stream
636
636
637 def handle_vcs_exception(self, exception, request):
637 def handle_vcs_exception(self, exception, request):
638 _vcs_kind = getattr(exception, '_vcs_kind', '')
639
638
640 if _vcs_kind == 'repo_locked':
639 match _vcs_kind := getattr(exception, '_vcs_kind', ''):
640 case 'repo_locked':
641 headers_call_context = get_headers_call_context(request.environ)
641 headers_call_context = get_headers_call_context(request.environ)
642 status_code = safe_int(headers_call_context['locked_status_code'])
642 status_code = safe_int(headers_call_context['locked_status_code'])
643
643
644 return HTTPRepoLocked(
644 return HTTPRepoLocked(
645 title=str(exception), status_code=status_code, headers=[('X-Rc-Locked', '1')])
645 title=str(exception), status_code=status_code, headers=[('X-Rc-Locked', '1')])
646
646 case 'repo_branch_protected':
647 elif _vcs_kind == 'repo_branch_protected':
648 # Get custom repo-branch-protected status code if present.
647 # Get custom repo-branch-protected status code if present.
649 return HTTPRepoBranchProtected(
648 return HTTPRepoBranchProtected(
650 title=str(exception), headers=[('X-Rc-Branch-Protection', '1')])
649 title=str(exception), headers=[('X-Rc-Branch-Protection', '1')])
650 case 'client_not_supported':
651 return HTTPClientNotSupported(
652 title=str(exception), headers=[('X-Rc-Client-Not-Supported', '1')])
651
653
652 exc_info = request.exc_info
654 exc_info = request.exc_info
653 store_exception(id(exc_info), exc_info)
655 store_exception(id(exc_info), exc_info)
@@ -415,6 +415,7 b' class SubprocessIOChunker:'
415 return_code = _p.poll()
415 return_code = _p.poll()
416 ret_code_ok = return_code in [None, 0]
416 ret_code_ok = return_code in [None, 0]
417 ret_code_fail = return_code is not None and return_code != 0
417 ret_code_fail = return_code is not None and return_code != 0
418
418 if (
419 if (
419 (ret_code_fail and fail_on_return_code) or
420 (ret_code_fail and fail_on_return_code) or
420 (ret_code_ok and fail_on_stderr and bg_err.length)
421 (ret_code_ok and fail_on_stderr and bg_err.length)
General Comments 0
You need to be logged in to leave comments. Login now