##// END OF EJS Templates
processes: shorten the message and remove exit code which isn't shown properly anyway.
marcink -
r3492:a7095130 default
parent child Browse files
Show More
@@ -1,183 +1,182 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 import psutil
23 import psutil
24 import signal
24 import signal
25 from pyramid.view import view_config
25 from pyramid.view import view_config
26
26
27 from rhodecode.apps._base import BaseAppView
27 from rhodecode.apps._base import BaseAppView
28 from rhodecode.apps._base.navigation import navigation_list
28 from rhodecode.apps._base.navigation import navigation_list
29 from rhodecode.lib import system_info
29 from rhodecode.lib import system_info
30 from rhodecode.lib.auth import (
30 from rhodecode.lib.auth import (
31 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
31 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
32 from rhodecode.lib.utils2 import safe_int, StrictAttributeDict
32 from rhodecode.lib.utils2 import safe_int, StrictAttributeDict
33
33
34 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
35
35
36
36
37 class AdminProcessManagementView(BaseAppView):
37 class AdminProcessManagementView(BaseAppView):
38 def load_default_context(self):
38 def load_default_context(self):
39 c = self._get_local_tmpl_context()
39 c = self._get_local_tmpl_context()
40 return c
40 return c
41
41
42 def _format_proc(self, proc, with_children=False):
42 def _format_proc(self, proc, with_children=False):
43 try:
43 try:
44 mem = proc.memory_info()
44 mem = proc.memory_info()
45 proc_formatted = StrictAttributeDict({
45 proc_formatted = StrictAttributeDict({
46 'pid': proc.pid,
46 'pid': proc.pid,
47 'name': proc.name(),
47 'name': proc.name(),
48 'mem_rss': mem.rss,
48 'mem_rss': mem.rss,
49 'mem_vms': mem.vms,
49 'mem_vms': mem.vms,
50 'cpu_percent': proc.cpu_percent(),
50 'cpu_percent': proc.cpu_percent(),
51 'create_time': proc.create_time(),
51 'create_time': proc.create_time(),
52 'cmd': ' '.join(proc.cmdline()),
52 'cmd': ' '.join(proc.cmdline()),
53 })
53 })
54
54
55 if with_children:
55 if with_children:
56 proc_formatted.update({
56 proc_formatted.update({
57 'children': [self._format_proc(x)
57 'children': [self._format_proc(x)
58 for x in proc.children(recursive=True)]
58 for x in proc.children(recursive=True)]
59 })
59 })
60 except Exception:
60 except Exception:
61 log.exception('Failed to load proc')
61 log.exception('Failed to load proc')
62 proc_formatted = None
62 proc_formatted = None
63 return proc_formatted
63 return proc_formatted
64
64
65 def get_processes(self):
65 def get_processes(self):
66 proc_list = []
66 proc_list = []
67 for p in psutil.process_iter():
67 for p in psutil.process_iter():
68 if 'gunicorn' in p.name():
68 if 'gunicorn' in p.name():
69 proc = self._format_proc(p, with_children=True)
69 proc = self._format_proc(p, with_children=True)
70 if proc:
70 if proc:
71 proc_list.append(proc)
71 proc_list.append(proc)
72
72
73 return proc_list
73 return proc_list
74
74
75 def get_workers(self):
75 def get_workers(self):
76 workers = None
76 workers = None
77 try:
77 try:
78 rc_config = system_info.rhodecode_config().value['config']
78 rc_config = system_info.rhodecode_config().value['config']
79 workers = rc_config['server:main'].get('workers')
79 workers = rc_config['server:main'].get('workers')
80 except Exception:
80 except Exception:
81 pass
81 pass
82
82
83 return workers or '?'
83 return workers or '?'
84
84
85 @LoginRequired()
85 @LoginRequired()
86 @HasPermissionAllDecorator('hg.admin')
86 @HasPermissionAllDecorator('hg.admin')
87 @view_config(
87 @view_config(
88 route_name='admin_settings_process_management', request_method='GET',
88 route_name='admin_settings_process_management', request_method='GET',
89 renderer='rhodecode:templates/admin/settings/settings.mako')
89 renderer='rhodecode:templates/admin/settings/settings.mako')
90 def process_management(self):
90 def process_management(self):
91 _ = self.request.translate
91 _ = self.request.translate
92 c = self.load_default_context()
92 c = self.load_default_context()
93
93
94 c.active = 'process_management'
94 c.active = 'process_management'
95 c.navlist = navigation_list(self.request)
95 c.navlist = navigation_list(self.request)
96 c.gunicorn_processes = self.get_processes()
96 c.gunicorn_processes = self.get_processes()
97 c.gunicorn_workers = self.get_workers()
97 c.gunicorn_workers = self.get_workers()
98 return self._get_template_context(c)
98 return self._get_template_context(c)
99
99
100 @LoginRequired()
100 @LoginRequired()
101 @HasPermissionAllDecorator('hg.admin')
101 @HasPermissionAllDecorator('hg.admin')
102 @view_config(
102 @view_config(
103 route_name='admin_settings_process_management_data', request_method='GET',
103 route_name='admin_settings_process_management_data', request_method='GET',
104 renderer='rhodecode:templates/admin/settings/settings_process_management_data.mako')
104 renderer='rhodecode:templates/admin/settings/settings_process_management_data.mako')
105 def process_management_data(self):
105 def process_management_data(self):
106 _ = self.request.translate
106 _ = self.request.translate
107 c = self.load_default_context()
107 c = self.load_default_context()
108 c.gunicorn_processes = self.get_processes()
108 c.gunicorn_processes = self.get_processes()
109 return self._get_template_context(c)
109 return self._get_template_context(c)
110
110
111 @LoginRequired()
111 @LoginRequired()
112 @HasPermissionAllDecorator('hg.admin')
112 @HasPermissionAllDecorator('hg.admin')
113 @CSRFRequired()
113 @CSRFRequired()
114 @view_config(
114 @view_config(
115 route_name='admin_settings_process_management_signal',
115 route_name='admin_settings_process_management_signal',
116 request_method='POST', renderer='json_ext')
116 request_method='POST', renderer='json_ext')
117 def process_management_signal(self):
117 def process_management_signal(self):
118 pids = self.request.json.get('pids', [])
118 pids = self.request.json.get('pids', [])
119 result = []
119 result = []
120
120
121 def on_terminate(proc):
121 def on_terminate(proc):
122 msg = "process `PID:{}` terminated with exit code {}".format(
122 msg = "terminated"
123 proc.pid, proc.returncode or 0)
124 result.append(msg)
123 result.append(msg)
125
124
126 procs = []
125 procs = []
127 for pid in pids:
126 for pid in pids:
128 pid = safe_int(pid)
127 pid = safe_int(pid)
129 if pid:
128 if pid:
130 try:
129 try:
131 proc = psutil.Process(pid)
130 proc = psutil.Process(pid)
132 except psutil.NoSuchProcess:
131 except psutil.NoSuchProcess:
133 continue
132 continue
134
133
135 children = proc.children(recursive=True)
134 children = proc.children(recursive=True)
136 if children:
135 if children:
137 log.warning('Wont kill Master Process')
136 log.warning('Wont kill Master Process')
138 else:
137 else:
139 procs.append(proc)
138 procs.append(proc)
140
139
141 for p in procs:
140 for p in procs:
142 try:
141 try:
143 p.terminate()
142 p.terminate()
144 except psutil.AccessDenied as e:
143 except psutil.AccessDenied as e:
145 log.warning('Access denied: {}'.format(e))
144 log.warning('Access denied: {}'.format(e))
146
145
147 gone, alive = psutil.wait_procs(procs, timeout=10, callback=on_terminate)
146 gone, alive = psutil.wait_procs(procs, timeout=10, callback=on_terminate)
148 for p in alive:
147 for p in alive:
149 try:
148 try:
150 p.kill()
149 p.kill()
151 except psutil.AccessDenied as e:
150 except psutil.AccessDenied as e:
152 log.warning('Access denied: {}'.format(e))
151 log.warning('Access denied: {}'.format(e))
153
152
154 return {'result': result}
153 return {'result': result}
155
154
156 @LoginRequired()
155 @LoginRequired()
157 @HasPermissionAllDecorator('hg.admin')
156 @HasPermissionAllDecorator('hg.admin')
158 @CSRFRequired()
157 @CSRFRequired()
159 @view_config(
158 @view_config(
160 route_name='admin_settings_process_management_master_signal',
159 route_name='admin_settings_process_management_master_signal',
161 request_method='POST', renderer='json_ext')
160 request_method='POST', renderer='json_ext')
162 def process_management_master_signal(self):
161 def process_management_master_signal(self):
163 pid_data = self.request.json.get('pid_data', {})
162 pid_data = self.request.json.get('pid_data', {})
164 pid = safe_int(pid_data['pid'])
163 pid = safe_int(pid_data['pid'])
165 action = pid_data['action']
164 action = pid_data['action']
166 if pid:
165 if pid:
167 try:
166 try:
168 proc = psutil.Process(pid)
167 proc = psutil.Process(pid)
169 except psutil.NoSuchProcess:
168 except psutil.NoSuchProcess:
170 return {'result': 'failure_no_such_process'}
169 return {'result': 'failure_no_such_process'}
171
170
172 children = proc.children(recursive=True)
171 children = proc.children(recursive=True)
173 if children:
172 if children:
174 # master process
173 # master process
175 if action == '+' and len(children) <= 20:
174 if action == '+' and len(children) <= 20:
176 proc.send_signal(signal.SIGTTIN)
175 proc.send_signal(signal.SIGTTIN)
177 elif action == '-' and len(children) >= 2:
176 elif action == '-' and len(children) >= 2:
178 proc.send_signal(signal.SIGTTOU)
177 proc.send_signal(signal.SIGTTOU)
179 else:
178 else:
180 return {'result': 'failure_wrong_action'}
179 return {'result': 'failure_wrong_action'}
181 return {'result': 'success'}
180 return {'result': 'success'}
182
181
183 return {'result': 'failure_not_master'}
182 return {'result': 'failure_not_master'}
General Comments 0
You need to be logged in to leave comments. Login now