diff --git a/rhodecode/apps/admin/__init__.py b/rhodecode/apps/admin/__init__.py
--- a/rhodecode/apps/admin/__init__.py
+++ b/rhodecode/apps/admin/__init__.py
@@ -64,6 +64,13 @@ def admin_routes(config):
name='admin_settings_sessions_cleanup',
pattern='/settings/sessions/cleanup')
+ config.add_route(
+ name='admin_settings_process_management',
+ pattern='/settings/process_management')
+ config.add_route(
+ name='admin_settings_process_management_signal',
+ pattern='/settings/process_management/signal')
+
# global permissions
config.add_route(
name='admin_permissions_ips',
diff --git a/rhodecode/apps/admin/navigation.py b/rhodecode/apps/admin/navigation.py
--- a/rhodecode/apps/admin/navigation.py
+++ b/rhodecode/apps/admin/navigation.py
@@ -94,6 +94,8 @@ class NavigationRegistry(object):
'global_integrations_home', pyramid=True),
NavEntry('system', _('System Info'),
'admin_settings_system', pyramid=True),
+ NavEntry('process_management', _('Processes'),
+ 'admin_settings_process_management', pyramid=True),
NavEntry('sessions', _('User Sessions'),
'admin_settings_sessions', pyramid=True),
NavEntry('open_source', _('Open Source Licenses'),
diff --git a/rhodecode/apps/admin/views/process_management.py b/rhodecode/apps/admin/views/process_management.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/apps/admin/views/process_management.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2016-2017 RhodeCode GmbH
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License, version 3
+# (only), as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+# This program is dual-licensed. If you wish to learn more about the
+# RhodeCode Enterprise Edition, including its added features, Support services,
+# and proprietary license terms, please see https://rhodecode.com/licenses/
+
+import logging
+
+import psutil
+from pyramid.view import view_config
+
+from rhodecode.apps._base import BaseAppView
+from rhodecode.apps.admin.navigation import navigation_list
+from rhodecode.lib import helpers as h
+from rhodecode.lib.auth import (
+ LoginRequired, HasPermissionAllDecorator, CSRFRequired)
+from vcsserver.utils import safe_int
+
+log = logging.getLogger(__name__)
+
+
+class AdminProcessManagementView(BaseAppView):
+ def load_default_context(self):
+ c = self._get_local_tmpl_context()
+ self._register_global_c(c)
+ return c
+
+ @LoginRequired()
+ @HasPermissionAllDecorator('hg.admin')
+ @view_config(
+ route_name='admin_settings_process_management', request_method='GET',
+ renderer='rhodecode:templates/admin/settings/settings.mako')
+ def process_management(self):
+ _ = self.request.translate
+ c = self.load_default_context()
+
+ c.active = 'process_management'
+ c.navlist = navigation_list(self.request)
+ c.gunicorn_processes = (
+ p for p in psutil.process_iter() if 'gunicorn' in p.name())
+ return self._get_template_context(c)
+
+ @LoginRequired()
+ @HasPermissionAllDecorator('hg.admin')
+ @CSRFRequired()
+ @view_config(
+ route_name='admin_settings_process_management_signal',
+ request_method='POST', renderer='json_ext')
+ def process_management_signal(self):
+ pids = self.request.json.get('pids', [])
+ result = []
+ def on_terminate(proc):
+ msg = "process `PID:{}` terminated with exit code {}".format(
+ proc.pid, proc.returncode)
+ result.append(msg)
+
+ procs = []
+ for pid in pids:
+ pid = safe_int(pid)
+ if pid:
+ try:
+ proc = psutil.Process(pid)
+ except psutil.NoSuchProcess:
+ continue
+
+ children = proc.children(recursive=True)
+ if children:
+ print('Wont kill Master Process')
+ else:
+ procs.append(proc)
+
+ for p in procs:
+ p.terminate()
+ gone, alive = psutil.wait_procs(procs, timeout=10, callback=on_terminate)
+ for p in alive:
+ p.kill()
+
+ return {'result': result}
diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js
--- a/rhodecode/public/js/rhodecode/routes.js
+++ b/rhodecode/public/js/rhodecode/routes.js
@@ -73,6 +73,8 @@ function registerRCRoutes() {
pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
+ pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
+ pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
pyroutes.register('users', '/_admin/users', []);
pyroutes.register('users_data', '/_admin/users_data', []);
diff --git a/rhodecode/templates/admin/settings/settings_process_management.mako b/rhodecode/templates/admin/settings/settings_process_management.mako
new file mode 100644
--- /dev/null
+++ b/rhodecode/templates/admin/settings/settings_process_management.mako
@@ -0,0 +1,83 @@
+
+
+
${_('Checking for updates...')}
+
+
+
+
+
+
${_('Gunicorn process management')}
+
+
+
+
List of Gunicorn processes on this machine
+
+ % for proc in c.gunicorn_processes:
+ <% mem = proc.memory_info()%>
+
+
+
+
+ ${proc.pid} - ${proc.name()}
+
+ |
+
+ RSS:${h.format_byte_size_binary(mem.rss)}
+ |
+
+ VMS:${h.format_byte_size_binary(mem.vms)}
+ |
+
+ <% is_master = proc.children(recursive=True) %>
+ % if is_master:
+ MASTER
+ % else:
+
+ restart
+
+ % endif
+ |
+
+ % endfor
+
+
+
+
+
+