svn-support: Add subscriber to execute the svn.proxy.reload_cmd on config changes. #4271

This commit is contained in:
Martin Bornhold 2016-10-14 11:56:12 +02:00
parent 41c9d26f81
commit 9b4da4cb9b
3 changed files with 119 additions and 11 deletions

View file

@ -21,10 +21,13 @@
import logging
import os
from rhodecode import events
# Do not use `from rhodecode import events` here, it will be overridden by the
# events module in this package due to pythons import mechanism.
from rhodecode.events import RepoGroupEvent
from rhodecode.config.middleware import _bool_setting, _string_setting
from .subscribers import generate_config_subscriber
from .events import ModDavSvnConfigChange
from .subscribers import generate_config_subscriber, AsyncSubprocessSubscriber
from . import config_keys
@ -36,8 +39,17 @@ def includeme(config):
_sanitize_settings_and_apply_defaults(settings)
if settings[config_keys.generate_config]:
# Add subscriber to generate the Apache mod dav svn configuration on
# repository group events.
config.add_subscriber(generate_config_subscriber, RepoGroupEvent)
# Prepare reload command to pass it to the subprocess module and add a
# subscriber to execute it on configuration changes.
cmd = settings[config_keys.reload_command]
cmd = cmd.split(' ') if cmd else cmd
config.add_subscriber(
generate_config_subscriber, events.RepoGroupEvent)
AsyncSubprocessSubscriber(cmd=cmd, timeout=5),
ModDavSvnConfigChange)
def _sanitize_settings_and_apply_defaults(settings):

View file

@ -19,8 +19,10 @@
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
import subprocess32
from threading import Thread
from rhodecode.lib.utils import get_rhodecode_base_path
from .utils import generate_mod_dav_svn_config
@ -34,9 +36,97 @@ def generate_config_subscriber(event):
changes.
"""
try:
generate_mod_dav_svn_config(
settings=event.request.registry.settings,
parent_path_root=get_rhodecode_base_path())
generate_mod_dav_svn_config(event.request.registry)
except Exception:
log.exception(
'Exception while generating subversion mod_dav_svn configuration.')
class Subscriber(object):
def __call__(self, event):
self.run(event)
def run(self, event):
raise NotImplementedError('Subclass has to implement this.')
class AsyncSubscriber(Subscriber):
def __init__(self, *args, **kwargs):
self._init_args = args
self._init_kwargs = kwargs
def __call__(self, event):
kwargs = {'event': event}
kwargs.update(self._init_kwargs)
self.thread = Thread(
target=self.run, args=self._init_args, kwargs=kwargs)
self.thread.start()
class AsyncSubprocessSubscriber(AsyncSubscriber):
def run(self, event, cmd, timeout=None):
log.debug('Executing command %s.', cmd)
try:
output = subprocess32.check_output(
cmd, timeout=timeout, stderr=subprocess32.STDOUT)
log.debug('Command finished %s', cmd)
if output:
log.debug('Command output: %s', output)
except subprocess32.TimeoutExpired as e:
log.exception('Timeout while executing command.')
if e.output:
log.error('Command output: %s', e.output)
except subprocess32.CalledProcessError as e:
log.exception('Error while executing command.')
if e.output:
log.error('Command output: %s', e.output)
except:
log.exception(
'Exception while executing command %s.', cmd)
# class ReloadApacheSubscriber(object):
# """
# Subscriber to pyramids event system. It executes the Apache reload command
# if set in ini-file. The command is executed asynchronously in a separate
# task. This is done to prevent a delay of the function which triggered the
# event in case of a longer running command. If a timeout is passed to the
# constructor the command will be terminated after expiration.
# """
# def __init__(self, settings, timeout=None):
# self.thread = None
# cmd = self.get_command_from_settings(settings)
# if cmd:
# kwargs = {
# 'cmd': cmd,
# 'timeout': timeout,
# }
# self.thread = Thread(target=self.run, kwargs=kwargs)
# def __call__(self, event):
# if self.thread is not None:
# self.thread.start()
# def get_command_from_settings(self, settings):
# cmd = settings[config_keys.reload_command]
# return cmd.split(' ') if cmd else cmd
# def run(self, cmd, timeout=None):
# log.debug('Executing svn proxy reload command %s.', cmd)
# try:
# output = subprocess32.check_output(
# cmd, timeout=timeout, stderr=subprocess32.STDOUT)
# log.debug('Svn proxy reload command finished.')
# if output:
# log.debug('Command output: %s', output)
# except subprocess32.TimeoutExpired as e:
# log.exception('Timeout while executing svn proxy reload command.')
# if e.output:
# log.error('Command output: %s', e.output)
# except subprocess32.CalledProcessError as e:
# log.exception('Error while executing svn proxy reload command.')
# if e.output:
# log.error('Command output: %s', e.output)
# except:
# log.exception(
# 'Exception while executing svn proxy reload command %s.', cmd)

View file

@ -21,31 +21,37 @@
import codecs
import logging
import os
from pyramid.renderers import render
from rhodecode.lib.utils import get_rhodecode_realm
from rhodecode.events import trigger
from rhodecode.lib.utils import get_rhodecode_realm, get_rhodecode_base_path
from rhodecode.model.db import RepoGroup
from . import config_keys
from .events import ModDavSvnConfigChange
log = logging.getLogger(__name__)
def generate_mod_dav_svn_config(settings, parent_path_root):
def generate_mod_dav_svn_config(registry):
"""
Generate the configuration file for use with subversion's mod_dav_svn
module. The configuration has to contain a <Location> block for each
available repository group because the mod_dav_svn module does not support
repositories organized in sub folders.
"""
settings = registry.settings
config = _render_mod_dav_svn_config(
parent_path_root=parent_path_root,
parent_path_root=get_rhodecode_base_path(),
list_parent_path=settings[config_keys.list_parent_path],
location_root=settings[config_keys.location_root],
repo_groups=RepoGroup.get_all_repo_groups())
_write_mod_dav_svn_config(config, settings[config_keys.config_file_path])
# Trigger an event on mod dav svn configuration change.
trigger(ModDavSvnConfigChange(), registry)
def _render_mod_dav_svn_config(
parent_path_root, list_parent_path, location_root, repo_groups):